Optimize + set verified boot hash in WebUI

Reduce load time by preload applist in service.sh. New function in WebUI: set verified boot hash in WebUI
This commit is contained in:
KOWX712
2024-11-23 21:22:23 +08:00
parent f4860d1a00
commit 213c4a2f13
4 changed files with 202 additions and 19 deletions

View File

@@ -1,8 +1,11 @@
MODPATH=${0%/*} MODPATH=${0%/*}
OUTPUT="$MODPATH/common/applist"
TS="/data/adb/modules/tricky_store" TS="/data/adb/modules/tricky_store"
SCRIPT_DIR="/data/adb/tricky_store" SCRIPT_DIR="/data/adb/tricky_store"
TSPA="/data/adb/modules/tsupport-advance" TSPA="/data/adb/modules/tsupport-advance"
aapt() { "$MODPATH/common/aapt" "$@"; }
hash_value=$(grep -v '^#' "/data/adb/boot_hash" | tr -d '[:space:]') hash_value=$(grep -v '^#' "/data/adb/boot_hash" | tr -d '[:space:]')
if [ -n "$hash_value" ]; then if [ -n "$hash_value" ]; then
resetprop -n ro.boot.vbmeta.digest "$hash_value" resetprop -n ro.boot.vbmeta.digest "$hash_value"
@@ -35,5 +38,15 @@ else
until [ "$(getprop sys.boot_completed)" = "1" ]; do until [ "$(getprop sys.boot_completed)" = "1" ]; do
sleep 1 sleep 1
done done
> "$OUTPUT"
pm list packages -3 | awk -F: '{print $2}' | while read -r PACKAGE; do
APK_PATH=$(pm path "$PACKAGE" | grep "base.apk" | awk -F: '{print $2}' | tr -d '\r')
if [ -n "$APK_PATH" ]; then
APP_NAME=$(aapt dump badging "$APK_PATH" 2>/dev/null | grep "application-label:" | sed "s/application-label://g; s/'//g")
echo "app-name: $APP_NAME, package-name: $PACKAGE" >> "$OUTPUT"
else
echo "app-name: Unknown App package-name: $PACKAGE" >> "$OUTPUT"
fi
done
. "$SCRIPT_DIR/UpdateTargetList.sh" . "$SCRIPT_DIR/UpdateTargetList.sh"
fi fi

View File

@@ -73,6 +73,13 @@
<li><br></li> <li><br></li>
</ul> </ul>
</li> </li>
<li>Set Verified Boot Hash
<ul>
<li>Get it from KeyAttesation Demo. Fix abnormal boot state by reset ro.boot.vbmeta.digest.
</li>
<li><br></li>
</ul>
</li>
</ul> </ul>
</div> </div>
</div> </div>
@@ -97,6 +104,7 @@
<li id="deselect-unnecessary">Deselect Unnecessary</li> <li id="deselect-unnecessary">Deselect Unnecessary</li>
<li id="aospkb">Set AOSP Keybox</li> <li id="aospkb">Set AOSP Keybox</li>
<li id="extrakb">Set Valid Keybox</li> <li id="extrakb">Set Valid Keybox</li>
<li id="boot-hash">Set Verified Boot Hash</li>
</ul> </ul>
</div> </div>
</div> </div>
@@ -113,6 +121,13 @@
</div> </div>
</div> </div>
</template> </template>
<div id="overlay" class="overlay"></div>
<div id="boot-hash-card" class="boot-hash-card">
<textarea id="boot-hash-input" class="input-box" placeholder="Paste your verified Boot Hash here"></textarea>
<div class="button-container">
<button id="save-button" class="button save-button">Save</button>
</div>
</div>
<div class="loading">Loading...</div> <div class="loading">Loading...</div>
<div class="acknowledgment">Credit to j-hc/zygisk-detach WebUI</div> <div class="acknowledgment">Credit to j-hc/zygisk-detach WebUI</div>
<div id="prompt" class="prompt"></div> <div id="prompt" class="prompt"></div>

View File

@@ -60,28 +60,54 @@ function isExcluded(appName) {
async function fetchAppList() { async function fetchAppList() {
try { try {
await readExcludeFile(); await readExcludeFile();
const result = await execCommand(` let applistMap = {};
pm list packages -3 | while read -r line; do try {
PACKAGE=$(echo "$line" | awk -F: '{print $2}') const applistResult = await execCommand(`cat ${basePath}applist`);
APK_PATH=$(pm path "$PACKAGE" | grep "base.apk" | awk -F: '{print $2}' | tr -d '\\r') applistMap = applistResult
if [ -n "$APK_PATH" ]; then .split("\n")
APP_NAME=$( ${basePath}aapt dump badging "$APK_PATH" 2>/dev/null | grep "application-label:" | sed "s/application-label://; s/'//g" ) .reduce((map, line) => {
echo "$APP_NAME|$PACKAGE" const match = line.match(/app-name:\s*(.+),\s*package-name:\s*(.+)/);
else if (match) {
echo "Unknown App|$PACKAGE" const appName = match[1].trim();
fi const packageName = match[2].trim();
done map[packageName] = appName;
`); }
const appEntries = result.split("\n").map(line => { return map;
const [appName, packageName] = line.split("|").map(item => item.trim()); }, {});
return { appName, packageName }; console.log("Applist loaded successfully.");
}).filter(entry => entry.packageName); // Remove invalid entries } catch (error) {
console.warn("Applist file not found or could not be loaded. Skipping applist lookup.");
}
const result = await execCommand("pm list packages -3");
const appEntries = result
.split("\n")
.map(line => {
const packageName = line.replace("package:", "").trim();
const appName = applistMap[packageName] || null;
return { appName, packageName };
})
.filter(entry => entry.packageName);
for (const entry of appEntries) {
if (!entry.appName) {
try {
const apkPath = await execCommand(`pm path ${entry.packageName} | grep "base.apk" | awk -F: '{print $2}' | tr -d '\\r'`);
if (apkPath) {
const appName = await execCommand(`${basePath}aapt dump badging ${apkPath.trim()} 2>/dev/null | grep "application-label:" | sed "s/application-label://; s/'//g"`);
entry.appName = appName.trim() || "Unknown App";
} else {
entry.appName = "Unknown App";
}
} catch (error) {
entry.appName = "Unknown App";
}
}
}
const sortedApps = appEntries.sort((a, b) => { const sortedApps = appEntries.sort((a, b) => {
const aInExclude = isExcluded(a.packageName); const aInExclude = isExcluded(a.packageName);
const bInExclude = isExcluded(b.packageName); const bInExclude = isExcluded(b.packageName);
return aInExclude === bInExclude ? a.appName.localeCompare(b.appName) : aInExclude ? 1 : -1; return aInExclude === bInExclude ? a.appName.localeCompare(b.appName) : aInExclude ? 1 : -1;
}); });
appListContainer.innerHTML = ""; // Clear the container before rendering appListContainer.innerHTML = "";
sortedApps.forEach(({ appName, packageName }) => { sortedApps.forEach(({ appName, packageName }) => {
const appElement = document.importNode(appTemplate, true); const appElement = document.importNode(appTemplate, true);
const contentElement = appElement.querySelector(".content"); const contentElement = appElement.querySelector(".content");
@@ -96,7 +122,6 @@ async function fetchAppList() {
} catch (error) { } catch (error) {
console.error("Failed to fetch or render app list with names:", error); console.error("Failed to fetch or render app list with names:", error);
} }
floatingBtn.style.transform = "translateY(-100px)"; floatingBtn.style.transform = "translateY(-100px)";
} }
@@ -252,6 +277,59 @@ async function extrakb() {
} }
} }
// Function to handle Verified Boot Hash
async function setBootHash() {
const overlay = document.getElementById("overlay");
const card = document.getElementById("boot-hash-card");
const inputBox = document.getElementById("boot-hash-input");
const saveButton = document.getElementById("save-button");
const showCard = () => {
overlay.style.display = "flex";
card.style.display = "flex";
requestAnimationFrame(() => {
overlay.classList.add("show");
card.classList.add("show");
});
document.body.style.overflow = "hidden";
};
const closeCard = () => {
overlay.classList.remove("show");
card.classList.remove("show");
setTimeout(() => {
overlay.style.display = "none";
card.style.display = "none";
document.body.style.overflow = "auto";
}, 200);
};
showCard();
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 = "";
}
// Save button click handler
saveButton.addEventListener("click", async () => {
const inputValue = inputBox.value.trim();
try {
await execCommand(`echo "${inputValue}" > /data/adb/boot_hash`);
await execCommand(`su -c resetprop -n ro.boot.vbmeta.digest ${inputValue}`);
showPrompt("Verified Boot Hash saved successfully.");
closeCard();
} catch (error) {
console.error("Failed to update boot_hash:", error);
showPrompt("Failed to update Verified Boot Hash.", false);
}
});
overlay.addEventListener("click", (event) => {
if (event.target === overlay) closeCard();
});
}
// Function to show the prompt with a success or error message // Function to show the prompt with a success or error message
function showPrompt(message, isSuccess = true) { function showPrompt(message, isSuccess = true) {
const prompt = document.getElementById('prompt'); const prompt = document.getElementById('prompt');
@@ -300,7 +378,7 @@ function setupMenuToggle() {
} }
}); });
const closeMenuItems = ['refresh', 'select-all', 'deselect-all', 'select-denylist', 'deselect-unnecessary', 'aospkb', 'extrakb']; const closeMenuItems = ['refresh', 'select-all', 'deselect-all', 'select-denylist', 'deselect-unnecessary', 'aospkb', 'extrakb', 'boot-hash'];
closeMenuItems.forEach(id => { closeMenuItems.forEach(id => {
const item = document.getElementById(id); const item = document.getElementById(id);
if (item) { if (item) {
@@ -427,6 +505,7 @@ document.addEventListener('DOMContentLoaded', async () => {
document.getElementById("deselect-unnecessary").addEventListener("click", deselectUnnecessaryApps); document.getElementById("deselect-unnecessary").addEventListener("click", deselectUnnecessaryApps);
document.getElementById("aospkb").addEventListener("click", aospkb); document.getElementById("aospkb").addEventListener("click", aospkb);
document.getElementById("extrakb").addEventListener("click", extrakb); document.getElementById("extrakb").addEventListener("click", extrakb);
document.getElementById("boot-hash").addEventListener("click", setBootHash);
await fetchAppList(); await fetchAppList();
checkMagisk(); checkMagisk();
runExtraScript(); runExtraScript();

View File

@@ -128,6 +128,79 @@ body {
color: inherit; color: inherit;
} }
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1000;
justify-content: center;
align-items: center;
opacity: 0;
visibility: hidden;
transition: opacity 0.2s ease, visibility 0.2s ease;
}
.boot-hash-card {
position: fixed;
top: 30%;
left: 50%;
transform: translate(-50%, -50%);
width: 80vw;
max-width: 600px;
background-color: #fff;
border-radius: 18px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
z-index: 1100;
padding: 20px;
display: none;
flex-direction: column;
gap: 15px;
opacity: 0;
transition: opacity 0.2s ease;
}
.overlay.show {
visibility: visible;
opacity: 1;
}
.boot-hash-card.show {
display: flex;
opacity: 1;
}
.input-box {
width: calc(100% - 23px);
height: 100px;
resize: none;
padding: 10px;
font-size: 16px;
background-color: #FFF;
border: 1px solid #ccc;
border-radius: 10px;
}
.button-container {
display: flex;
justify-content: flex-start;
}
.button {
padding: 10px 20px;
border: none;
border-radius: 38px;
font-size: 18px;
}
.save-button {
background-color: #007bff;
color: white;
margin-left: auto;
}
#apps-list { #apps-list {
margin-top: 100px; margin-top: 100px;
} }
@@ -397,11 +470,13 @@ body {
background-color: #121212; background-color: #121212;
} }
.input-box,
.help-button { .help-button {
color: #fff; color: #fff;
} }
.help-menu, .help-menu,
.boot-hash-card,
.card, .card,
.search-input, .search-input,
.search-card { .search-card {
@@ -416,6 +491,7 @@ body {
color: white; color: white;
} }
.input-box,
.menu-options, .menu-options,
#menu-button { #menu-button {
background-color: #343434; background-color: #343434;