mirror of
https://github.com/chiteroman/PlayIntegrityFix.git
synced 2025-04-29 01:22:07 +08:00
rewrite webui, option to toggle sppofVendingSdk in webui
This commit is contained in:
parent
e6261c628e
commit
aa3a813f29
@ -9,6 +9,35 @@
|
||||
<script type="module" crossorigin src="scripts.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="output">[+] Fetching pif.json, please wait...</div>
|
||||
<div class="content">
|
||||
<div class="header">
|
||||
<h3>
|
||||
Play Integrity Fix
|
||||
<span id="version-text"></span>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="button-box">
|
||||
<div class="toggle-list ripple-element" id="fetch">
|
||||
<span class="toggle-text">Fetch pif.json</span>
|
||||
</div>
|
||||
<div class="toggle-list ripple-element" id="sdk-vending-toggle-container">
|
||||
<span class="toggle-text">Spoof sdk version to Play Store</span>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" id="toggle-sdk-vending" disabled>
|
||||
<span class="slider round"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="output-terminal">
|
||||
<div class="output-terminal-header">
|
||||
<span>output</span>
|
||||
<div class="clear-terminal">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="14px" viewBox="0 -960 960 960" width="14px" fill="#ccc"><path d="M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z" /></svg>
|
||||
<span class="clear-terminal-text">clear</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="output-terminal-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,3 +1,9 @@
|
||||
let actionRunning = false;
|
||||
let initialPinchDistance = null;
|
||||
let currentFontSize = 14;
|
||||
const MIN_FONT_SIZE = 8;
|
||||
const MAX_FONT_SIZE = 24;
|
||||
|
||||
// Execute shell commands with ksu.exec
|
||||
async function execCommand(command) {
|
||||
const callbackName = `exec_callback_${Date.now()}`;
|
||||
@ -10,34 +16,204 @@ async function execCommand(command) {
|
||||
});
|
||||
}
|
||||
|
||||
// Function to run the script and display its output
|
||||
async function runAction() {
|
||||
const output = document.querySelector('.output');
|
||||
// Apply button event listeners
|
||||
function applyButtonEventListeners() {
|
||||
const fetchButton = document.getElementById('fetch');
|
||||
const sdkVendingToggle = document.getElementById('sdk-vending-toggle-container');
|
||||
const clearButton = document.querySelector('.clear-terminal');
|
||||
|
||||
fetchButton.addEventListener('click', runAction);
|
||||
sdkVendingToggle.addEventListener('click', async () => {
|
||||
try {
|
||||
const scriptOutput = await execCommand("sh /data/adb/modules/playintegrityfix/action.sh");
|
||||
output.innerHTML = '';
|
||||
const lines = scriptOutput.split('\n');
|
||||
lines.forEach(line => {
|
||||
const lineElement = document.createElement('div');
|
||||
lineElement.style.whiteSpace = 'pre-wrap';
|
||||
lineElement.textContent = line;
|
||||
if (line === '') {
|
||||
lineElement.innerHTML = ' ';
|
||||
const pifPath = await execCommand(`
|
||||
[ ! -f /data/adb/modules/playintegrityfix/pif.json ] || echo /data/adb/modules/playintegrityfix/pif.json
|
||||
[ ! -f /data/adb/pif.json ] || echo /data/adb/pif.json
|
||||
`);
|
||||
if (pifPath.trim() === "") {
|
||||
appendToOutput("[!] No pif.json found");
|
||||
return;
|
||||
}
|
||||
output.appendChild(lineElement);
|
||||
});
|
||||
const isChecked = document.getElementById('toggle-sdk-vending').checked;
|
||||
const paths = pifPath.trim().split('\n');
|
||||
for (const path of paths) {
|
||||
if (path) {
|
||||
await execCommand(`sed -i 's/"spoofVendingSdk": [01]/"spoofVendingSdk": ${isChecked ? 0 : 1}/' ${path}`);
|
||||
}
|
||||
}
|
||||
appendToOutput(`[+] Successfully changed spoofVendingSdk to ${isChecked ? 0 : 1}`);
|
||||
document.getElementById('toggle-sdk-vending').checked = !isChecked;
|
||||
} catch (error) {
|
||||
console.error('Script execution failed:', error);
|
||||
if (typeof ksu !== 'undefined' && ksu.mmrl) {
|
||||
output.innerHTML = '[!] Please allow permission in MMRL settings<br><br>[-] Settings<br>[-] Security<br>[-] Allow JavaScript API<br>[-] Play Integrity Fix<br>[-] Enable Allow Advanced KernelSU API';
|
||||
} else {
|
||||
output.innerHTML = '[!] Error: Fail to execute action.sh';
|
||||
appendToOutput("[-] Failed to change spoofVendingSdk");
|
||||
console.error('Failed to toggle sdk vending:', error);
|
||||
}
|
||||
});
|
||||
clearButton.addEventListener('click', () => {
|
||||
const output = document.querySelector('.output-terminal-content');
|
||||
output.innerHTML = '';
|
||||
currentFontSize = 14;
|
||||
updateFontSize(currentFontSize);
|
||||
});
|
||||
|
||||
const terminal = document.querySelector('.output-terminal-content');
|
||||
|
||||
terminal.addEventListener('touchstart', (e) => {
|
||||
if (e.touches.length === 2) {
|
||||
e.preventDefault();
|
||||
initialPinchDistance = getDistance(e.touches[0], e.touches[1]);
|
||||
}
|
||||
}, { passive: false });
|
||||
|
||||
terminal.addEventListener('touchmove', (e) => {
|
||||
if (e.touches.length === 2) {
|
||||
e.preventDefault();
|
||||
const currentDistance = getDistance(e.touches[0], e.touches[1]);
|
||||
|
||||
if (initialPinchDistance === null) {
|
||||
initialPinchDistance = currentDistance;
|
||||
return;
|
||||
}
|
||||
|
||||
const scale = currentDistance / initialPinchDistance;
|
||||
const newFontSize = currentFontSize * scale;
|
||||
updateFontSize(newFontSize);
|
||||
initialPinchDistance = currentDistance;
|
||||
}
|
||||
}, { passive: false });
|
||||
|
||||
terminal.addEventListener('touchend', () => {
|
||||
initialPinchDistance = null;
|
||||
});
|
||||
}
|
||||
|
||||
// Function to load the version from module.prop
|
||||
async function loadVersionFromModuleProp() {
|
||||
const versionElement = document.getElementById('version-text');
|
||||
try {
|
||||
const version = await execCommand("grep '^version=' /data/adb/modules/playintegrityfix/module.prop | cut -d'=' -f2");
|
||||
versionElement.textContent = version.trim();
|
||||
} catch (error) {
|
||||
appendToOutput("[-] Failed to read version from module.prop");
|
||||
console.error("Failed to read version from module.prop:", error);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to load spoofVendingSdk config
|
||||
async function loadSpoofVendingSdkConfig() {
|
||||
const sdkVendingToggle = document.getElementById('toggle-sdk-vending');
|
||||
const isChecked = await execCommand(`grep -o '"spoofVendingSdk": [01]' /data/adb/modules/playintegrityfix/pif.json | cut -d' ' -f2`);
|
||||
if (isChecked === '0') {
|
||||
sdkVendingToggle.checked = false;
|
||||
} else {
|
||||
sdkVendingToggle.checked = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to append element in output terminal
|
||||
function appendToOutput(content) {
|
||||
const output = document.querySelector('.output-terminal-content');
|
||||
if (content.trim() === "") {
|
||||
const lineBreak = document.createElement('br');
|
||||
output.appendChild(lineBreak);
|
||||
} else {
|
||||
const line = document.createElement('p');
|
||||
line.className = 'output-content';
|
||||
line.textContent = content;
|
||||
output.appendChild(line);
|
||||
}
|
||||
output.scrollTop = output.scrollHeight;
|
||||
}
|
||||
|
||||
// Function to run the script and display its output
|
||||
async function runAction() {
|
||||
if (actionRunning) return;
|
||||
actionRunning = true;
|
||||
try {
|
||||
appendToOutput("[+] Fetching pif.json...");
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
const scriptOutput = await execCommand("sh /data/adb/modules/playintegrityfix/action.sh");
|
||||
const lines = scriptOutput.split('\n');
|
||||
lines.forEach(line => {
|
||||
appendToOutput(line)
|
||||
});
|
||||
appendToOutput("");
|
||||
} catch (error) {
|
||||
console.error('Script execution failed:', error);
|
||||
if (typeof ksu !== 'undefined' && ksu.mmrl) {
|
||||
appendToOutput("");
|
||||
appendToOutput("[!] Please allow permission in MMRL settings");
|
||||
appendToOutput("[-] Settings");
|
||||
appendToOutput("[-] Security");
|
||||
appendToOutput("[-] Allow JavaScript API");
|
||||
appendToOutput("[-] Play Integrity Fix");
|
||||
appendToOutput("[-] Enable Allow Advanced KernelSU API");
|
||||
appendToOutput("");
|
||||
} else {
|
||||
appendToOutput("[!] Error: Fail to execute action.sh");
|
||||
appendToOutput("");
|
||||
}
|
||||
}
|
||||
actionRunning = false;
|
||||
}
|
||||
|
||||
// Function to apply ripple effect
|
||||
function applyRippleEffect() {
|
||||
document.querySelectorAll('.ripple-element').forEach(element => {
|
||||
if (element.dataset.rippleListener !== "true") {
|
||||
element.addEventListener("pointerdown", function (event) {
|
||||
const ripple = document.createElement("span");
|
||||
ripple.classList.add("ripple");
|
||||
|
||||
// Calculate ripple size and position
|
||||
const rect = element.getBoundingClientRect();
|
||||
const width = rect.width;
|
||||
const size = Math.max(rect.width, rect.height);
|
||||
const x = event.clientX - rect.left - size / 2;
|
||||
const y = event.clientY - rect.top - size / 2;
|
||||
|
||||
// Determine animation duration
|
||||
let duration = 0.2 + (width / 800) * 0.4;
|
||||
duration = Math.min(0.8, Math.max(0.2, duration));
|
||||
|
||||
// Set ripple styles
|
||||
ripple.style.width = ripple.style.height = `${size}px`;
|
||||
ripple.style.left = `${x}px`;
|
||||
ripple.style.top = `${y}px`;
|
||||
ripple.style.animationDuration = `${duration}s`;
|
||||
ripple.style.transition = `opacity ${duration}s ease`;
|
||||
|
||||
// Adaptive color
|
||||
const computedStyle = window.getComputedStyle(element);
|
||||
const bgColor = computedStyle.backgroundColor || "rgba(0, 0, 0, 0)";
|
||||
const textColor = computedStyle.color;
|
||||
const isDarkColor = (color) => {
|
||||
const rgb = color.match(/\d+/g);
|
||||
if (!rgb) return false;
|
||||
const [r, g, b] = rgb.map(Number);
|
||||
return (r * 0.299 + g * 0.587 + b * 0.114) < 96; // Luma formula
|
||||
};
|
||||
ripple.style.backgroundColor = isDarkColor(bgColor) ? "rgba(255, 255, 255, 0.2)" : "";
|
||||
|
||||
// Append ripple and handle cleanup
|
||||
element.appendChild(ripple);
|
||||
const handlePointerUp = () => {
|
||||
ripple.classList.add("end");
|
||||
setTimeout(() => {
|
||||
ripple.classList.remove("end");
|
||||
ripple.remove();
|
||||
}, duration * 1000);
|
||||
element.removeEventListener("pointerup", handlePointerUp);
|
||||
element.removeEventListener("pointercancel", handlePointerUp);
|
||||
};
|
||||
element.addEventListener("pointerup", handlePointerUp);
|
||||
element.addEventListener("pointercancel", handlePointerUp);
|
||||
});
|
||||
element.dataset.rippleListener = "true";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Function to check if running in MMRL
|
||||
function checkMMRL() {
|
||||
async function checkMMRL() {
|
||||
if (typeof ksu !== 'undefined' && ksu.mmrl) {
|
||||
// Set status bars theme based on device theme
|
||||
try {
|
||||
@ -52,12 +228,40 @@ function checkMMRL() {
|
||||
} catch (error) {
|
||||
console.log("Error requesting API:", error);
|
||||
}
|
||||
try {
|
||||
await execCommand("whoami");
|
||||
} catch (error) {
|
||||
appendToOutput("");
|
||||
appendToOutput("[!] Please allow permission in MMRL settings");
|
||||
appendToOutput("[-] Settings");
|
||||
appendToOutput("[-] Security");
|
||||
appendToOutput("[-] Allow JavaScript API");
|
||||
appendToOutput("[-] Play Integrity Fix");
|
||||
appendToOutput("[-] Enable Allow Advanced KernelSU API");
|
||||
appendToOutput("");
|
||||
}
|
||||
} else {
|
||||
console.log("Not running in MMRL environment.");
|
||||
}
|
||||
}
|
||||
|
||||
function getDistance(touch1, touch2) {
|
||||
return Math.hypot(
|
||||
touch1.clientX - touch2.clientX,
|
||||
touch1.clientY - touch2.clientY
|
||||
);
|
||||
}
|
||||
|
||||
function updateFontSize(newSize) {
|
||||
currentFontSize = Math.min(Math.max(newSize, MIN_FONT_SIZE), MAX_FONT_SIZE);
|
||||
const terminal = document.querySelector('.output-terminal-content');
|
||||
terminal.style.fontSize = `${currentFontSize}px`;
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
checkMMRL();
|
||||
setTimeout(runAction, 200);
|
||||
loadVersionFromModuleProp();
|
||||
loadSpoofVendingSdkConfig();
|
||||
applyButtonEventListeners();
|
||||
applyRippleEffect();
|
||||
});
|
@ -6,17 +6,186 @@
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Mono';
|
||||
background-color: #F5F5F5;
|
||||
padding-top: var(--window-inset-top);
|
||||
padding-bottom: var(--window-inset-bottom);
|
||||
}
|
||||
|
||||
.output {
|
||||
font-size: 14px;
|
||||
left: 10px;
|
||||
width: calc(100vw - 20px);
|
||||
.header {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-bottom: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.button-box {
|
||||
width: calc(85vw + 30px);
|
||||
max-width: 800px;
|
||||
background-color: #fff;
|
||||
border: none;
|
||||
border-radius: 15px;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.toggle-list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
padding: 10px 20px;
|
||||
white-space: nowrap;
|
||||
word-break: break-all;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ccc;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.toggle-list:last-child {
|
||||
border-bottom: none;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.toggle-text {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
white-space: wrap;
|
||||
max-width: calc(100% - 76px);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.toggle-switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin-left: auto;
|
||||
width: 40px;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.toggle-switch input {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.slider {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
-webkit-transition: .4s;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 19px;
|
||||
width: 19px;
|
||||
left: 3px;
|
||||
bottom: 3px;
|
||||
background-color: white;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
input:checked+.slider {
|
||||
background-color: #007bff;
|
||||
}
|
||||
|
||||
input:focus+.slider {
|
||||
box-shadow: 0 0 1px #007bff;
|
||||
}
|
||||
|
||||
input:checked+.slider:before {
|
||||
transform: translateX(15px);
|
||||
}
|
||||
|
||||
.slider.round {
|
||||
border-radius: 25px;
|
||||
}
|
||||
|
||||
.slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.output-terminal {
|
||||
width: calc(85vw + 30px);
|
||||
max-width: 800px;
|
||||
height: 600px;
|
||||
background-color: #fff;
|
||||
box-sizing: border-box;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.output-terminal-header {
|
||||
display: flex;
|
||||
padding: 5px 15px;
|
||||
font-size: 14px;
|
||||
justify-content: space-between;
|
||||
background-color: #E0E0E0;
|
||||
color: #333;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.clear-terminal {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.clear-terminal svg {
|
||||
fill: #333;
|
||||
}
|
||||
|
||||
.output-terminal-content {
|
||||
font-family: 'Mono';
|
||||
font-size: 14px;
|
||||
padding: 10px;
|
||||
width: calc(100% - 20px);
|
||||
height: calc(100% - 50px);
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.output-content {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.ripple-element {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ripple {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
transform: scale(0);
|
||||
opacity: 1;
|
||||
animation: ripple-animation ease-out forwards;
|
||||
pointer-events: none;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.ripple.end {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@keyframes ripple-animation {
|
||||
to {
|
||||
transform: scale(3);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
@ -24,4 +193,30 @@ body {
|
||||
background-color: #121212;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.toggle-list,
|
||||
.button-box,
|
||||
.output-terminal-header {
|
||||
background-color: #343434;
|
||||
}
|
||||
|
||||
.output-terminal-header {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.clear-terminal svg {
|
||||
fill: #ccc;
|
||||
}
|
||||
|
||||
.output-terminal {
|
||||
background-color: #232323;
|
||||
}
|
||||
|
||||
.toggle-list {
|
||||
border-bottom: 1px solid #6E6E6E;
|
||||
}
|
||||
|
||||
.slider {
|
||||
background-color: #6E6E6E;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user