misc: move execCommand to exec

This commit is contained in:
KOWX712
2025-05-04 19:04:03 +08:00
parent 5a8097b40c
commit 770f107559
8 changed files with 374 additions and 413 deletions

View File

@@ -1,11 +1,11 @@
import { linkRedirect } from './main.js';
const aboutOverlay = document.getElementById('about-overlay');
const aboutContent = document.querySelector('.about-menu');
const closeAbout = document.getElementById('close-about');
// Function to show about overlay
document.getElementById("about").addEventListener("click", () => {
const aboutOverlay = document.getElementById('about-overlay');
const aboutContent = document.querySelector('.about-menu');
const closeAbout = document.getElementById('close-about');
// Show about menu
setTimeout(() => {
document.body.classList.add("no-scroll");
@@ -15,20 +15,20 @@ document.getElementById("about").addEventListener("click", () => {
aboutContent.classList.add('open');
}, 10);
}, 80);
});
const hideMenu = () => {
document.body.classList.remove("no-scroll");
aboutOverlay.style.opacity = '0';
aboutContent.classList.remove('open');
setTimeout(() => {
aboutOverlay.style.display = 'none';
}, 200);
};
const hideMenu = () => {
document.body.classList.remove("no-scroll");
aboutOverlay.style.opacity = '0';
aboutContent.classList.remove('open');
setTimeout(() => {
aboutOverlay.style.display = 'none';
}, 200);
};
closeAbout.addEventListener("click", hideMenu);
aboutOverlay.addEventListener('click', (event) => {
if (event.target === aboutOverlay) hideMenu();
});
closeAbout.addEventListener("click", hideMenu);
aboutOverlay.addEventListener('click', (event) => {
if (event.target === aboutOverlay) hideMenu();
});
// Event listener for link redirect

View File

@@ -1,4 +1,4 @@
import { basePath, execCommand, hideFloatingBtn, appsWithExclamation, appsWithQuestion, toast } from './main.js';
import { basePath, exec, hideFloatingBtn, appsWithExclamation, appsWithQuestion, toast } from './main.js';
const appTemplate = document.getElementById('app-template').content;
const modeOverlay = document.querySelector('.mode-overlay');
@@ -10,13 +10,14 @@ export async function fetchAppList() {
try {
// fetch target list
let targetList = [];
try {
const targetFileContent = await execCommand('cat /data/adb/tricky_store/target.txt');
targetList = processTargetList(targetFileContent);
} catch (error) {
toast("Failed to read target.txt!");
console.error("Failed to read target.txt file:", error);
}
await exec('cat /data/adb/tricky_store/target.txt')
.then(({ errno, stdout }) => {
if (errno === 0) {
targetList = processTargetList(stdout);
} else {
toast("Failed to read target.txt!");
}
});
// fetch applist
const response = await fetch('applist.json');
@@ -28,35 +29,28 @@ export async function fetchAppList() {
// Get installed packages first
let appEntries = [], installedPackages = [];
try {
installedPackages = await execCommand(`
pm list packages -3 | awk -F: '{print $2}'
[ -s "/data/adb/tricky_store/system_app" ] && SYSTEM_APP=$(cat "/data/adb/tricky_store/system_app" | tr '\n' '|' | sed 's/|*$//') || SYSTEM_APP=""
[ -z "$SYSTEM_APP" ] || pm list packages -s | awk -F: '{print $2}' | grep -Ex "$SYSTEM_APP" 2>/dev/null || true
`)
installedPackages = installedPackages.split("\n").map(line => line.trim()).filter(Boolean);
appEntries = await Promise.all(installedPackages.map(async packageName => {
if (appNameMap[packageName]) {
return {
appName: appNameMap[packageName],
packageName
};
}
const appName = await execCommand(`
base_apk=$(pm path ${packageName} | head -n1 | awk -F: '{print $2}')
${basePath}/common/aapt dump badging $base_apk 2>/dev/null | grep "application-label:" | sed "s/application-label://; s/'//g"
`);
const { stdout } = await exec(`
pm list packages -3 | awk -F: '{print $2}'
[ -s "/data/adb/tricky_store/system_app" ] && SYSTEM_APP=$(cat "/data/adb/tricky_store/system_app" | tr '\n' '|' | sed 's/|*$//') || SYSTEM_APP=""
[ -z "$SYSTEM_APP" ] || pm list packages -s | awk -F: '{print $2}' | grep -Ex "$SYSTEM_APP" || true
`);
installedPackages = stdout.split("\n").map(line => line.trim()).filter(Boolean);
appEntries = await Promise.all(installedPackages.map(async (packageName) => {
if (appNameMap[packageName]) {
return {
appName: appName.trim() || packageName,
appName: appNameMap[packageName],
packageName
};
}));
} catch (error) {
appEntries = appList.map(app => ({
appName: app.app_name,
packageName: app.package_name
}));
}
}
const { stdout: appName } = await exec(`
base_apk=$(pm path ${packageName} | head -n1 | awk -F: '{print $2}')
aapt dump badging $base_apk 2>/dev/null | grep "application-label:" | sed "s/application-label://; s/'//g"
`, { env: { PATH: `$PATH:${basePath}/common:/data/data/com.termux/files/usr/bin` } });
return {
appName: appName || packageName,
packageName
};
}));
// Sort
const sortedApps = appEntries.sort((a, b) => {

View File

@@ -1,4 +1,4 @@
import { execCommand, showPrompt } from './main.js';
import { exec, showPrompt } from './main.js';
const bootHashOverlay = document.getElementById('boot-hash-overlay');
const bootHash = document.querySelector('.boot-hash-card');
@@ -20,50 +20,50 @@ document.getElementById("boot-hash").addEventListener("click", async () => {
bootHash.classList.add('open');
}, 10);
const closeBootHashMenu = () => {
document.body.classList.remove("no-scroll");
bootHashOverlay.style.opacity = 0;
bootHash.classList.remove('open');
setTimeout(() => {
bootHashOverlay.style.display = "none";
}, 200);
};
try {
const bootHashContent = await execCommand("cat /data/adb/boot_hash");
const validHash = bootHashContent
.split("\n")
.filter(line => !line.startsWith("#") && line.trim())[0];
inputBox.value = validHash || "";
} catch (error) {
console.warn("Failed to read boot_hash file. Defaulting to empty input.");
inputBox.value = "";
}
saveButton.addEventListener("click", async () => {
const inputValue = inputBox.value.trim();
try {
await execCommand(`
PATH=/data/adb/ap/bin:/data/adb/ksu/bin:/data/adb/magisk:$PATH
resetprop -n ro.boot.vbmeta.digest ${inputValue}
[ -z "${inputValue}" ] && rm -f /data/adb/boot_hash || {
echo "${inputValue}" > /data/adb/boot_hash
chmod 644 /data/adb/boot_hash
}
`);
// read current boot hash
exec("cat /data/adb/boot_hash")
.then(({ errno, stdout }) => {
if (errno !== 0) {
inputBox.value = "";
} else {
const validHash = stdout
.split("\n")
.filter(line => !line.startsWith("#") && line.trim())[0];
inputBox.value = validHash || "";
}
});
});
const closeBootHashMenu = () => {
document.body.classList.remove("no-scroll");
bootHashOverlay.style.opacity = 0;
bootHash.classList.remove('open');
setTimeout(() => {
bootHashOverlay.style.display = "none";
}, 200);
};
// Save button listener
saveButton.addEventListener("click", async () => {
const inputValue = inputBox.value.trim();
exec(`
resetprop -n ro.boot.vbmeta.digest ${inputValue}
[ -z "${inputValue}" ] && rm -f /data/adb/boot_hash || {
echo "${inputValue}" > /data/adb/boot_hash
chmod 644 /data/adb/boot_hash
}
`, { env: { PATH: "/data/adb/ap/bin:/data/adb/ksu/bin:/data/adb/magisk:$PATH" } })
.then(() => {
showPrompt("prompt.boot_hash_set");
closeBootHashMenu();
} catch (error) {
console.error("Failed to update boot_hash:", error);
showPrompt("prompt.boot_hash_set_error", false);
}
});
bootHashOverlay.addEventListener("click", (event) => {
if (event.target === bootHashOverlay) closeBootHashMenu();
});
});
});
// Enter to save
inputBox.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
saveButton.click();
}
});
bootHashOverlay.addEventListener("click", (event) => {
if (event.target === bootHashOverlay) closeBootHashMenu();
});
// Enter to save
inputBox.addEventListener('keydown', (e) => {
if (e.key === 'Enter') saveButton.click();
});

View File

@@ -26,23 +26,16 @@ let isRefreshing = false;
// Function to set basePath
async function getBasePath() {
try {
await execCommand('[ -d /data/adb/modules/.TA_utl ]');
basePath = "/data/adb/modules/.TA_utl"
} catch (error) {
basePath = "/data/adb/modules/TA_utl"
}
const { errno } = await exec('[ -d /data/adb/modules/.TA_utl ]');
basePath = errno === 0 ? "/data/adb/modules/.TA_utl" : "/data/adb/modules/TA_utl";
}
// Function to load the version from module.prop
async function getModuleVersion() {
const moduleVersion = document.getElementById('module-version');
try {
const version = await execCommand(`grep '^version=' ${basePath}/common/update/module.prop | cut -d'=' -f2`);
moduleVersion.textContent = version;
} catch (error) {
console.error("Failed to read version from module.prop:", error);
}
function getModuleVersion() {
exec(`grep '^version=' ${basePath}/common/update/module.prop | cut -d'=' -f2`)
.then(({ stdout }) => {
document.getElementById('module-version').textContent = stdout;
});
}
// Function to refresh app list
@@ -59,13 +52,8 @@ export async function refreshAppList() {
await new Promise(resolve => setTimeout(resolve, 500));
window.scrollTo(0, 0);
if (noConnection.style.display === "flex") {
try {
updateCheck();
await execCommand(`[ -f ${basePath}/common/tmp/exclude-list ] && rm -f "${basePath}/common/tmp/exclude-list"`);
} catch (error) {
toast("Failed!");
console.error("Error occurred:", error);
}
updateCheck();
exec(`rm -f "${basePath}/common/tmp/exclude-list"`);
}
await fetchAppList();
applyRippleEffect();
@@ -75,30 +63,27 @@ export async function refreshAppList() {
}
// Function to check tricky store version
async function checkTrickyStoreVersion() {
function checkTrickyStoreVersion() {
const securityPatchElement = document.getElementById('security-patch');
try {
const version = await execCommand(`
TS_version=$(grep "versionCode=" "/data/adb/modules/tricky_store/module.prop" | cut -d'=' -f2)
[ "$TS_version" -ge 158 ] || echo "NO"
`);
if (version.trim() !== "NO") securityPatchElement.style.display = "flex";
} catch (error) {
toast("Failed to check Tricky Store version!");
console.error("Error while checking Tricky Store version:", error);
}
exec(`
TS_version=$(grep "versionCode=" "/data/adb/modules/tricky_store/module.prop" | cut -d'=' -f2)
[ "$TS_version" -ge 158 ]
`).then(({ errno }) => {
if (errno === 0) {
securityPatchElement.style.display = "flex";
} else {
console.log("Tricky Store version is lower than 158, or fail to check Tricky store version.");
}
});
}
// Function to check if Magisk
async function checkMagisk() {
function checkMagisk() {
const selectDenylistElement = document.getElementById('select-denylist');
try {
const magiskEnv = await execCommand(`command -v magisk >/dev/null 2>&1 || echo "NO"`);
if (magiskEnv.trim() !== "NO") selectDenylistElement.style.display = "flex";
} catch (error) {
toast("Failed to check Magisk!");
console.error("Error while checking denylist conditions:", error);
}
exec('command -v magisk')
.then(({ errno }) => {
if (errno === 0) selectDenylistElement.style.display = "flex";
});
}
// Function to show the prompt with a success or error message
@@ -117,18 +102,22 @@ export function showPrompt(key, isSuccess = true, duration = 3000) {
}, 100);
}
// Function to redirect link on external browser
export async function linkRedirect(link) {
try {
await execCommand(`am start -a android.intent.action.VIEW -d ${link}`);
} catch (error) {
toast("Failed!");
console.error('Error redirect link:', error);
}
/**
* Redirect to a link with am command
* @param {string} link - The link to redirect in browser
*/
export function linkRedirect(link) {
toast("Redirecting to " + link);
setTimeout(() => {
exec(`am start -a android.intent.action.VIEW -d ${link}`)
.then(({ errno }) => {
if (errno !== 0) toast("Failed to open link");
});
},100);
}
// Save configure and preserve ! and ? in target.txt
document.getElementById("save").addEventListener("click", async () => {
document.getElementById("save").addEventListener("click", () => {
const selectedApps = Array.from(appListContainer.querySelectorAll(".checkbox:checked"))
.map(checkbox => checkbox.closest(".card").querySelector(".content").getAttribute("data-package"));
let finalAppsList = new Set(selectedApps);
@@ -136,29 +125,30 @@ document.getElementById("save").addEventListener("click", async () => {
finalAppsList.add(app);
});
finalAppsList = Array.from(finalAppsList);
try {
const modifiedAppsList = finalAppsList.map(app => {
if (appsWithExclamation.includes(app)) {
return `${app}!`;
} else if (appsWithQuestion.includes(app)) {
return `${app}?`;
const modifiedAppsList = finalAppsList.map(app => {
if (appsWithExclamation.includes(app)) {
return `${app}!`;
} else if (appsWithQuestion.includes(app)) {
return `${app}?`;
}
return app;
});
const updatedTargetContent = modifiedAppsList.join("\n");
exec(`echo "${updatedTargetContent}" | sort -u > /data/adb/tricky_store/target.txt`)
.then(({ errno }) => {
if (errno === 0) {
for (const app of appsWithExclamation) {
exec(`sed -i 's/^${app}$/${app}!/' /data/adb/tricky_store/target.txt`);
}
for (const app of appsWithQuestion) {
exec(`sed -i 's/^${app}$/${app}?/' /data/adb/tricky_store/target.txt`);
}
showPrompt("prompt.saved_target");
refreshAppList();
} else {
showPrompt("prompt.save_error", false);
}
return app;
});
const updatedTargetContent = modifiedAppsList.join("\n");
await execCommand(`echo "${updatedTargetContent}" | sort -u > /data/adb/tricky_store/target.txt`);
showPrompt("prompt.saved_target");
for (const app of appsWithExclamation) {
await execCommand(`sed -i 's/^${app}$/${app}!/' /data/adb/tricky_store/target.txt`);
}
for (const app of appsWithQuestion) {
await execCommand(`sed -i 's/^${app}$/${app}?/' /data/adb/tricky_store/target.txt`);
}
} catch (error) {
console.error("Failed to update target.txt:", error);
showPrompt("prompt.save_error", false);
}
await refreshAppList();
});
// Uninstall WebUI
@@ -189,18 +179,16 @@ document.querySelector(".uninstall-container").addEventListener("click", () => {
})
confirmButton.addEventListener('click', () => {
closeuninstallOverlay();
uninstallWebUI();
exec(`sh ${basePath}/common/get_extra.sh --uninstall`)
.then(({ errno }) => {
if (errno === 0) {
showPrompt("prompt.uninstall_prompt");
} else {
showPrompt("prompt.uninstall_failed", false);
}
});
})
});
async function uninstallWebUI() {
try {
await execCommand(`sh ${basePath}/common/get_extra.sh --uninstall`);
showPrompt("prompt.uninstall_prompt");
} catch (error) {
console.error("Failed to execute uninstall command:", error);
showPrompt("prompt.uninstall_failed", false);
}
}
// Function to check if running in MMRL
function checkMMRL() {
@@ -323,24 +311,32 @@ document.addEventListener('DOMContentLoaded', async () => {
document.querySelector('.uninstall-container').classList.remove('hidden-uninstall');
});
// Function to execute shell commands
export async function execCommand(command) {
/**
* Execute shell command with ksu.exec
* @param {string} command - The command to execute
* @param {Object} [options={}] - Options object containing:
* - cwd <string> - Current working directory of the child process
* - env {Object} - Environment key-value pairs
* @returns {Promise<Object>} Resolves with:
* - errno {number} - Exit code of the command
* - stdout {string} - Standard output from the command
* - stderr {string} - Standard error from the command
*/
export function exec(command, options = {}) {
return new Promise((resolve, reject) => {
const callbackName = `exec_callback_${Date.now()}_${e++}`;
window[callbackName] = (errno, stdout, stderr) => {
delete window[callbackName];
if (errno === 0) {
resolve(stdout);
} else {
console.error(`Error executing command: ${stderr}`);
reject(stderr);
}
const callbackFuncName = `exec_callback_${Date.now()}_${e++}`;
window[callbackFuncName] = (errno, stdout, stderr) => {
resolve({ errno, stdout, stderr });
cleanup(callbackFuncName);
};
function cleanup(successName) {
delete window[successName];
}
try {
ksu.exec(command, "{}", callbackName);
ksu.exec(command, JSON.stringify(options), callbackFuncName);
} catch (error) {
console.error(`Execution error: ${error}`);
reject(error);
cleanup(callbackFuncName);
}
});
}

View File

@@ -1,4 +1,4 @@
import { basePath, execCommand, showPrompt, toast, applyRippleEffect, refreshAppList } from './main.js';
import { basePath, exec, showPrompt, toast, applyRippleEffect, refreshAppList } from './main.js';
// Function to check or uncheck all app
function toggleCheckboxes(shouldCheck) {
@@ -16,25 +16,23 @@ document.getElementById("select-all").addEventListener("click", () => toggleChec
document.getElementById("deselect-all").addEventListener("click", () => toggleCheckboxes(false));
// Function to read the denylist and check corresponding apps
document.getElementById("select-denylist").addEventListener("click", async () => {
try {
const result = await execCommand(`magisk --denylist ls 2>/dev/null | awk -F'|' '{print $1}' | grep -v "isolated" | sort -u`);
const denylistApps = result.split("\n").map(app => app.trim()).filter(Boolean);
const apps = document.querySelectorAll(".card");
apps.forEach(app => {
const contentElement = app.querySelector(".content");
const packageName = contentElement.getAttribute("data-package");
const checkbox = app.querySelector(".checkbox");
if (denylistApps.includes(packageName)) {
checkbox.checked = true;
document.getElementById("select-denylist").addEventListener("click", () => {
exec(`magisk --denylist ls 2>/dev/null | awk -F'|' '{print $1}' | grep -v "isolated" | sort -u`)
.then(({ errno, stdout }) => {
if (errno === 0) {
const denylistApps = stdout.split("\n").map(app => app.trim()).filter(Boolean);
document.querySelectorAll(".card").forEach(app => {
const contentElement = app.querySelector(".content");
const packageName = contentElement.getAttribute("data-package");
if (denylistApps.includes(packageName)) {
app.querySelector(".checkbox").checked = true;
}
});
exec('touch "/data/adb/tricky_store/target_from_denylist"');
} else {
toast("Failed to read DenyList!");
}
});
await execCommand('touch "/data/adb/tricky_store/target_from_denylist"');
console.log("Denylist apps selected successfully.");
} catch (error) {
toast("Failed to read DenyList!");
console.error("Failed to select Denylist apps:", error);
}
});
// Function to read the exclude list and uncheck corresponding apps
@@ -62,18 +60,18 @@ document.getElementById("deselect-unnecessary").addEventListener("click", async
toast("Failed to download unnecessary apps!");
throw error;
});
const xposed = await execCommand(`sh ${basePath}/common/get_extra.sh --xposed`);
const UnnecessaryApps = excludeList.split("\n").map(app => app.trim()).filter(Boolean).concat(xposed.split("\n").map(app => app.trim()).filter(Boolean));
const apps = document.querySelectorAll(".card");
apps.forEach(app => {
const contentElement = app.querySelector(".content");
const packageName = contentElement.getAttribute("data-package");
const checkbox = app.querySelector(".checkbox");
if (UnnecessaryApps.includes(packageName)) {
checkbox.checked = false;
}
});
console.log("Unnecessary apps deselected successfully.");
exec(`sh ${basePath}/common/get_extra.sh --xposed`)
.then(({ stdout }) => {
const unnecessaryApps = excludeList.split("\n").map(app => app.trim())
.filter(Boolean).concat(stdout.split("\n").map(app => app.trim()).filter(Boolean));
document.querySelectorAll(".card").forEach(app => {
const contentElement = app.querySelector(".content");
const packageName = contentElement.getAttribute("data-package");
if (unnecessaryApps.includes(packageName)) {
app.querySelector(".checkbox").checked = false;
}
});
});
} catch (error) {
toast("Failed to get unnecessary apps!");
console.error("Failed to get unnecessary apps:", error);
@@ -113,67 +111,58 @@ export async function setupSystemAppMenu() {
const input = document.getElementById("system-app-input");
const packageName = input.value.trim();
if (packageName) {
try {
const result = await execCommand(`pm list packages -s | grep -q ${packageName} || echo "false"`);
if (result.includes("false")) {
showPrompt("prompt.system_app_not_found", false);
} else {
await execCommand(`
touch "/data/adb/tricky_store/system_app"
echo "${packageName}" >> "/data/adb/tricky_store/system_app"
echo "${packageName}" >> "/data/adb/tricky_store/target.txt"
`);
systemAppInput.value = "";
closeSystemAppOverlay();
refreshAppList();
}
} catch (error) {
console.error("Error adding system app:", error);
showPrompt("prompt.add_system_app_error", false);
}
exec(`pm list packages -s | grep -q ${packageName}`)
.then(({ errno }) => {
if (errno !== 0) {
showPrompt("prompt.system_app_not_found", false);
} else {
exec(`
touch "/data/adb/tricky_store/system_app"
echo "${packageName}" >> "/data/adb/tricky_store/system_app"
echo "${packageName}" >> "/data/adb/tricky_store/target.txt"
`)
systemAppInput.value = "";
closeSystemAppOverlay();
refreshAppList();
}
});
}
});
// Display current system app list and remove button
async function renderSystemAppList() {
const currentSystemAppList = document.querySelector(".current-system-app-list");
const currentSystemAppListContent = document.querySelector(".current-system-app-list-content");
currentSystemAppListContent.innerHTML = "";
try {
const systemAppList = await execCommand(`[ -f "/data/adb/tricky_store/system_app" ] && cat "/data/adb/tricky_store/system_app" | sed '/^$/d' || echo "false"`);
if (systemAppList.trim() === 'false' || systemAppList.trim() === '') {
currentSystemAppList.style.display = "none";
} else {
systemAppList.split("\n").forEach(app => {
currentSystemAppListContent.innerHTML += `
<div class="system-app-item">
<span>${app}</span>
<button class="remove-system-app-button ripple-element">
<svg xmlns="http://www.w3.org/2000/svg" height="22px" viewBox="0 -960 960 960" width="22px" fill="#FFFFFF"><path d="M154-412v-136h652v136H154Z"/></svg>
</button>
</div>
`;
});
}
} catch (error) {
currentSystemAppList.style.display = "none";
console.error("Error displaying system app list:", error);
const systemAppList = document.querySelector(".current-system-app-list");
const systemAppListContent = document.querySelector(".current-system-app-list-content");
systemAppListContent.innerHTML = "";
const { errno, stdout } = await exec(`[ -f "/data/adb/tricky_store/system_app" ] && cat "/data/adb/tricky_store/system_app" | sed '/^$/d'`);
if (errno !== 0 || stdout.trim() === "") {
systemAppList.style.display = "none";
} else {
stdout.split("\n").forEach(app => {
if (app.trim() !== "") {
systemAppListContent.innerHTML += `
<div class="system-app-item">
<span>${app}</span>
<button class="remove-system-app-button ripple-element">
<svg xmlns="http://www.w3.org/2000/svg" height="22px" viewBox="0 -960 960 960" width="22px" fill="#FFFFFF"><path d="M154-412v-136h652v136H154Z"/></svg>
</button>
</div>
`;
}
});
}
const removeSystemAppButtons = document.querySelectorAll(".remove-system-app-button");
removeSystemAppButtons.forEach(button => {
button.addEventListener("click", async () => {
// Remove button listener
document.querySelectorAll(".remove-system-app-button").forEach(button => {
button.addEventListener("click", () => {
const app = button.closest(".system-app-item").querySelector("span").textContent;
try {
await execCommand(`
sed -i "/${app}/d" "/data/adb/tricky_store/system_app" || true
sed -i "/${app}/d" "/data/adb/tricky_store/target.txt" || true
`);
exec(`
sed -i "/${app}/d" "/data/adb/tricky_store/system_app"
sed -i "/${app}/d" "/data/adb/tricky_store/target.txt"
`).then(() => {
closeSystemAppOverlay();
refreshAppList();
} catch (error) {
console.error("Error removing system app:", error);
}
});
});
});
}
@@ -185,19 +174,15 @@ export async function setupSystemAppMenu() {
* @returns {Boolean}
*/
async function setKeybox(content) {
try {
await execCommand(`
mv -f /data/adb/tricky_store/keybox.xml /data/adb/tricky_store/keybox.xml.bak 2>/dev/null
cat << 'KB_EOF' > /data/adb/tricky_store/keybox.xml
await exec(`
mv -f /data/adb/tricky_store/keybox.xml /data/adb/tricky_store/keybox.xml.bak 2>/dev/null
cat << 'KB_EOF' > /data/adb/tricky_store/keybox.xml
${content}
KB_EOF
chmod 644 /data/adb/tricky_store/keybox.xml
`);
return true;
} catch (error) {
console.error("Failed to set keybox:", error);
return false;
}
chmod 644 /data/adb/tricky_store/keybox.xml
`).then(({ errno }) => {
return errno === 0;
});
}
/**
@@ -205,14 +190,9 @@ KB_EOF
* @returns {Promise<void>}
*/
async function aospkb() {
const source = await execCommand(`xxd -r -p ${basePath}/common/.default | base64 -d`);
const result = await setKeybox(source);
if (result) {
console.log("AOSP keybox copied successfully.");
showPrompt("prompt.aosp_key_set");
} else {
showPrompt("prompt.key_set_error", false);
}
const { stdout } = await exec(`xxd -r -p ${basePath}/common/.default | base64 -d`);
const result = setKeybox(stdout);
showPrompt(result ? "prompt.aosp_key_set" : "prompt.key_set_error", result);
}
// aosp kb eventlistener
@@ -310,8 +290,8 @@ async function listFiles(path, skipAnimation = false) {
await new Promise(resolve => setTimeout(resolve, 150));
}
try {
const result = await execCommand(`find "${path}" -maxdepth 1 -type f -name "*.xml" -o -type d ! -name ".*" | sort`);
const items = result.split('\n').filter(Boolean).map(item => ({
const { stdout } = await exec(`find "${path}" -maxdepth 1 -type f -name "*.xml" -o -type d ! -name ".*" | sort`);
const items = stdout.split('\n').filter(Boolean).map(item => ({
path: item,
name: item.split('/').pop(),
isDirectory: !item.endsWith('.xml')
@@ -356,14 +336,10 @@ async function listFiles(path, skipAnimation = false) {
});
await listFiles(item.path);
} else {
const source = await execCommand(`cat "${item.path}"`);
const result = await setKeybox(source);
if (result) {
closeCustomKeyboxSelector();
showPrompt('prompt.custom_key_set');
} else {
showPrompt('prompt.custom_key_set_error');
}
const { stdout } = await exec(`cat "${item.path}"`);
const result = setKeybox(stdout);
showPrompt(result ? "prompt.custom_key_set" : "prompt.custom_key_set_error", result);
closeCustomKeyboxSelector();
}
});
fileList.appendChild(itemElement);

View File

@@ -1,4 +1,4 @@
import { basePath, execCommand, showPrompt } from './main.js';
import { basePath, exec, showPrompt } from './main.js';
const overlay = document.getElementById('security-patch-overlay');
const overlayContent = document.querySelector('.security-patch-card');
@@ -24,32 +24,26 @@ const hideSecurityPatchDialog = () => {
}
// Function to handle security patch operation
async function handleSecurityPatch(mode, value = null) {
function handleSecurityPatch(mode, value = null) {
if (mode === 'disable') {
try {
await execCommand(`
rm -f /data/adb/tricky_store/security_patch_auto_config
rm -f /data/adb/tricky_store/security_patch.txt
`);
showPrompt('security_patch.value_empty');
return true;
} catch (error) {
showPrompt('security_patch.save_failed', false);
return false;
}
exec(`
rm -f /data/adb/tricky_store/security_patch_auto_config || true
rm -f /data/adb/tricky_store/security_patch.txt || true
`).then(({ errno }) => {
const result = errno === 0;
showPrompt(result ? 'security_patch.value_empty' : 'security_patch.save_failed', result);
return result;
});
} else if (mode === 'manual') {
try {
await execCommand(`
rm -f /data/adb/tricky_store/security_patch_auto_config
echo "${value}" > /data/adb/tricky_store/security_patch.txt
chmod 644 /data/adb/tricky_store/security_patch.txt
`);
showPrompt('security_patch.save_success');
return true;
} catch (error) {
showPrompt('security_patch.save_failed', false);
return false;
}
exec(`
rm -f /data/adb/tricky_store/security_patch_auto_config || true
echo "${value}" > /data/adb/tricky_store/security_patch.txt
chmod 644 /data/adb/tricky_store/security_patch.txt
`).then(({ errno }) => {
const result = errno === 0;
showPrompt(result ? 'security_patch.save_success' : 'security_patch.save_failed', result);
return result;
});
}
}
@@ -57,17 +51,17 @@ async function handleSecurityPatch(mode, value = null) {
async function loadCurrentConfig() {
let allValue, systemValue, bootValue, vendorValue;
try {
const autoConfig = await execCommand('[ -f /data/adb/tricky_store/security_patch_auto_config ] && echo "true" || echo "false"');
if (autoConfig.trim() === 'true') {
const { errno } = await exec('[ -f /data/adb/tricky_store/security_patch_auto_config ]');
if (errno === 0) {
allValue = null;
systemValue = null;
bootValue = null;
vendorValue = null;
} else {
// Read values from tricky_store if auto_config is 0
const trickyResult = await execCommand('cat /data/adb/tricky_store/security_patch.txt');
if (trickyResult) {
const trickyLines = trickyResult.split('\n');
// Read values from tricky_store if manual mode
const { stdout } = await exec('cat /data/adb/tricky_store/security_patch.txt');
if (stdout.trim() !== '') {
const trickyLines = stdout.split('\n');
for (const line of trickyLines) {
if (line.startsWith('all=')) {
allValue = line.split('=')[1] || null;
@@ -222,27 +216,25 @@ export function securityPatch() {
});
// Auto config button
autoButton.addEventListener('click', async () => {
try {
const output = await execCommand(`sh ${basePath}/common/get_extra.sh --security-patch`);
if (output.trim() === "not set") {
showPrompt('security_patch.auto_failed', false);
} else {
await execCommand(`touch /data/adb/tricky_store/security_patch_auto_config`);
// Reset inputs
allPatchInput.value = '';
systemPatchInput.value = '';
bootPatchInput.value = '';
vendorPatchInput.value = '';
autoButton.addEventListener('click', () => {
exec(`sh ${basePath}/common/get_extra.sh --security-patch`)
.then(({ errno, stdout }) => {
if (errno !== 0 || stdout.trim() === "not set") {
showPrompt('security_patch.auto_failed', false);
} else {
exec(`touch /data/adb/tricky_store/security_patch_auto_config`)
// Reset inputs
allPatchInput.value = '';
systemPatchInput.value = '';
bootPatchInput.value = '';
vendorPatchInput.value = '';
checkAdvanced(false);
showPrompt('security_patch.auto_success');
}
} catch (error) {
showPrompt('security_patch.auto_failed', false);
}
hideSecurityPatchDialog();
loadCurrentConfig();
checkAdvanced(false);
showPrompt('security_patch.auto_success');
}
hideSecurityPatchDialog();
loadCurrentConfig();
});
});
// Save button
@@ -252,7 +244,7 @@ export function securityPatch() {
const allValue = allPatchInput.value.trim();
if (!allValue) {
// Save empty value to disable auto config
await handleSecurityPatch('disable');
handleSecurityPatch('disable');
hideSecurityPatchDialog();
return;
}
@@ -261,7 +253,7 @@ export function securityPatch() {
return;
}
const value = `all=${allValue}`;
const result = await handleSecurityPatch('manual', value);
const result = handleSecurityPatch('manual', value);
if (result) {
// Reset inputs
systemPatchInput.value = '';
@@ -276,7 +268,7 @@ export function securityPatch() {
if (!bootValue && !systemValue && !vendorValue) {
// Save empty values to disable auto config
await handleSecurityPatch('disable');
handleSecurityPatch('disable');
hideSecurityPatchDialog();
return;
}
@@ -302,7 +294,7 @@ export function securityPatch() {
vendorValue ? `vendor=${vendorValue}` : ''
].filter(Boolean);
const value = config.filter(Boolean).join('\n');
const result = await handleSecurityPatch('manual', value);
const result = handleSecurityPatch('manual', value);
if (result) {
// Reset inputs
allPatchInput.value = '';
@@ -314,19 +306,22 @@ export function securityPatch() {
// Get button
getButton.addEventListener('click', async () => {
try {
showPrompt('security_patch.fetching');
await new Promise(resolve => setTimeout(resolve, 200));
const output = await execCommand(`sh ${basePath}/common/get_extra.sh --get-security-patch`);
showPrompt('security_patch.fetched', true, 1000);
checkAdvanced(true);
showPrompt('security_patch.fetching');
setTimeout(() => {
exec(`sh ${basePath}/common/get_extra.sh --get-security-patch`)
.then(({ errno, stdout }) => {
if (errno !== 0) {
showPrompt('security_patch.get_failed', false);
} else {
showPrompt('security_patch.fetched', true, 1000);
checkAdvanced(true);
allPatchInput.value = output.replace(/-/g, '');
systemPatchInput.value = 'prop';
bootPatchInput.value = output;
vendorPatchInput.value = output;
} catch (error) {
showPrompt('security_patch.get_failed', false);
}
allPatchInput.value = stdout.replace(/-/g, '');
systemPatchInput.value = 'prop';
bootPatchInput.value = stdout;
vendorPatchInput.value = stdout;
}
})
}, 200);
});
}

View File

@@ -1,4 +1,4 @@
import { basePath, execCommand, showPrompt, noConnection, linkRedirect } from './main.js';
import { basePath, exec, showPrompt, noConnection, linkRedirect } from './main.js';
import { updateCard } from './applist.js';
const updateMenu = document.querySelector('.update-overlay');
@@ -23,14 +23,12 @@ function downloadFile(targetURL, fileName) {
.then(blob => {
const file = new File([blob], fileName, { type: blob.type });
const reader = new FileReader();
reader.onload = async function() {
reader.onload = () => {
const base64Data = reader.result.split(',')[1];
try {
await execCommand(`echo ${base64Data} | base64 -d > ${basePath}/common/tmp/${fileName}`);
resolve();
} catch (error) {
reject(error);
}
exec(`echo ${base64Data} | base64 -d > ${basePath}/common/tmp/${fileName}`)
.then(({ errno, stderr }) => {
errno === 0 ? resolve() : reject(stderr);
});
};
reader.readAsDataURL(file);
})
@@ -53,8 +51,8 @@ export async function updateCheck() {
zipURL = data.zipUrl;
changelogURL = data.changelog;
const updateAvailable = await execCommand(`sh ${basePath}/common/get_extra.sh --check-update ${remoteVersionCode}`);
if (updateAvailable.includes("update")) {
const { stdout } = await exec(`sh ${basePath}/common/get_extra.sh --check-update ${remoteVersionCode}`);
if (stdout.includes("update")) {
showPrompt("prompt.new_update", true, 1500);
updateCard.style.display = "flex";
setupUpdateMenu();
@@ -67,26 +65,28 @@ export async function updateCheck() {
}
// Function to render changelog
async function renderChangelog() {
const changelog = await execCommand(`sh ${basePath}/common/get_extra.sh --release-note ${remoteVersion}`);
window.linkRedirect = linkRedirect;
marked.setOptions({
sanitize: true,
walkTokens(token) {
if (token.type === 'link') {
const href = token.href;
token.href = "javascript:void(0);";
token.type = "html";
token.text = `<a href="javascript:void(0);" onclick="linkRedirect('${href}')">${token.text}</a>`;
function renderChangelog() {
exec(`sh ${basePath}/common/get_extra.sh --release-note ${remoteVersion}`)
.then(({ stdout }) => {
window.linkRedirect = linkRedirect;
marked.setOptions({
sanitize: true,
walkTokens(token) {
if (token.type === 'link') {
const href = token.href;
token.href = "javascript:void(0);";
token.type = "html";
token.text = `<a href="javascript:void(0);" onclick="linkRedirect('${href}')">${token.text}</a>`;
}
}
}
});
const cleanedChangelog = stdout
.split('\n')
.filter(line => line.trim() !== '')
.join('\n');
const formattedChangelog = marked.parse(cleanedChangelog);
releaseNotes.innerHTML = formattedChangelog;
});
const cleanedChangelog = changelog
.split('\n')
.filter(line => line.trim() !== '')
.join('\n');
const formattedChangelog = marked.parse(cleanedChangelog);
releaseNotes.innerHTML = formattedChangelog;
}
// Function to setup update menu
@@ -111,38 +111,37 @@ function setupUpdateMenu() {
// Update card
updateCard.addEventListener('click', async () => {
try {
const module = await execCommand(`
const { stdout } = await exec(`
[ -f ${basePath}/common/tmp/module.zip ] || echo "noModule"
[ -f ${basePath}/common/tmp/changelog.md ] || echo "noChangelog"
[ ! -f /data/adb/modules/TA_utl/update ] || echo "updated"
`);
if (module.trim().includes("updated")) {
if (stdout.trim().includes("updated")) {
installButton.style.display = "none";
rebootButton.style.display = "flex";
openUpdateMenu();
} else if (module.trim().includes("noChangelog")) {
} else if (stdout.trim().includes("noChangelog")) {
showPrompt("prompt.downloading");
await downloadFile(changelogURL, "changelog.md");
await renderChangelog();
renderChangelog();
openUpdateMenu();
setTimeout(() => {
updateCard.click();
}, 200);
} else if (module.trim().includes("noModule")) {
} else if (stdout.trim().includes("noModule")) {
if (downloading) return;
downloading = true;
try {
await execCommand(`sh ${basePath}/common/get_extra.sh --get-update ${zipURL}`);
const { errno } = await exec(`sh ${basePath}/common/get_extra.sh --get-update ${zipURL}`);
if (errno === 0) {
showPrompt("prompt.downloaded");
installButton.style.display = "flex";
downloading = false;
} catch (error) {
} else {
showPrompt("prompt.download_fail", false);
downloading = false;
}
downloading = false;
} else {
installButton.style.display = "flex";
await renderChangelog();
renderChangelog();
openUpdateMenu();
}
} catch (error) {
@@ -159,16 +158,16 @@ function setupUpdateMenu() {
// Install button
installButton.addEventListener('click', async () => {
try {
showPrompt("prompt.installing");
await new Promise(resolve => setTimeout(resolve, 300));
await execCommand(`sh ${basePath}/common/get_extra.sh --install-update`);
showPrompt("prompt.installing");
await new Promise(resolve => setTimeout(resolve, 300));
const { errno, stderr } = await exec(`sh ${basePath}/common/get_extra.sh --install-update`);
if (errno === 0) {
showPrompt("prompt.installed");
installButton.style.display = "none";
rebootButton.style.display = "flex";
} catch (error) {
} else {
showPrompt("prompt.install_fail", false);
console.error('Fail to execute installation script:', error);
console.error('Fail to execute installation script:', stderr);
}
});
@@ -177,7 +176,7 @@ function setupUpdateMenu() {
try {
showPrompt("prompt.rebooting");
await new Promise(resolve => setTimeout(resolve, 1000));
await execCommand("svc power reboot");
await exec("svc power reboot");
} catch (error) {
showPrompt("prompt.reboot_fail", false);
console.error('Fail to reboot:', error);

View File

@@ -59,8 +59,9 @@
}
.update-content h3 {
font-size: 22px;
margin: 0;
font-size: 24px;
margin: 10px 0;
margin-top: 0;
}
.changelog {