You've already forked Tricky-Addon-Update-Target-List
mirror of
https://github.com/KOWX712/Tricky-Addon-Update-Target-List.git
synced 2025-09-06 06:37:09 +00:00
Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3050ecf84c | ||
|
|
83cd9a0ac8 | ||
|
|
bf8fdb8419 | ||
|
|
edfe2986e7 | ||
|
|
473bd64770 | ||
|
|
68ed991d98 | ||
|
|
553df593ae | ||
|
|
dfc6726e10 | ||
|
|
5a66cba009 | ||
|
|
f8dfe50a0c | ||
|
|
24c00f124d | ||
|
|
5e3836f41f | ||
|
|
41b434f2bb | ||
|
|
5441eb0830 | ||
|
|
046af031d8 | ||
|
|
4977695022 | ||
|
|
0427153ea6 | ||
|
|
2980bda649 | ||
|
|
0821e88fdc | ||
|
|
25ecc49a77 | ||
|
|
42f0b6df77 | ||
|
|
006ca27100 | ||
|
|
f36f5bf7db | ||
|
|
41430b4386 | ||
|
|
6ee2b65b75 | ||
|
|
1a50c322d9 | ||
|
|
83469179e6 | ||
|
|
d534185d48 | ||
|
|
7324d92aeb | ||
|
|
6cd29416ec | ||
|
|
39c303e04e | ||
|
|
8d67689d76 | ||
|
|
2886b7e742 | ||
|
|
2447312286 | ||
|
|
895b3ff1bd | ||
|
|
e18871754f | ||
|
|
a4c08ba08c | ||
|
|
66e048d5a1 | ||
|
|
b81d95d31f |
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -3,8 +3,9 @@
|
||||
*.prop text eol=lf
|
||||
*.md text eol=lf
|
||||
*.xml text eol=lf
|
||||
*.json text eol=lf
|
||||
.extra text eol=lf
|
||||
META-INF/** text eol=lf
|
||||
|
||||
# Denote all files that are truly binary and should not be modified.
|
||||
common/addon/**/tools/** binary
|
||||
module/bin/**/** binary
|
||||
15
.github/workflows/build.yml
vendored
15
.github/workflows/build.yml
vendored
@@ -21,17 +21,20 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 2
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
|
||||
- name: Extract Module Info
|
||||
id: extract_info
|
||||
run: |
|
||||
MODULE_VERSION=$(grep -oP '^version=\K.*' module/module.prop)
|
||||
BUILD_COUNT=$((1000 + ${{ github.run_number }}))
|
||||
ARTIFACT_NAME="TrickyAddonModule-${MODULE_VERSION}-canary-${BUILD_COUNT}"
|
||||
MODULE_VERSION=$(grep '^version=' module/module.prop | sed 's/version=//')
|
||||
COMMIT_NUM=$(git rev-list --count HEAD)
|
||||
BUILD_COUNT=${{ github.run_number }}
|
||||
ARTIFACT_NAME="TrickyAddonModule-${MODULE_VERSION}-${COMMIT_NUM}${BUILD_COUNT}-canary"
|
||||
sed -i "s/^version=.*/& (${COMMIT_NUM}${BUILD_COUNT}-canary)/" module/module.prop
|
||||
echo "MODULE_VERSION=${MODULE_VERSION}" >> $GITHUB_ENV
|
||||
echo "ARTIFACT_NAME=${ARTIFACT_NAME}" >> $GITHUB_ENV
|
||||
echo "VERSION=${MODULE_VERSION}" >> $GITHUB_ENV
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
@@ -46,9 +49,9 @@ jobs:
|
||||
if [ "${{ github.event_name }}" = "pull_request" ]; then
|
||||
echo "version_tag_exists=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
VERSION=$(grep '^version=' module/module.prop | sed 's/version=//')
|
||||
git fetch --tags
|
||||
if git tag | grep -qx "^$VERSION"; then
|
||||
VERSION=${{ env.VERSION }}
|
||||
if git tag | grep -qx "^${VERSION}"; then
|
||||
echo "version_tag_exists=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "version_tag_exists=false" >> $GITHUB_OUTPUT
|
||||
|
||||
21
changelog.md
21
changelog.md
@@ -8,6 +8,23 @@ GitHub release: [Tricky Addon: Update Target List](https://github.com/KOWX712/Tr
|
||||
Telegram channel: [KOW's Little World](https://t.me/kowchannel)
|
||||
|
||||
## Changelog
|
||||
### v3.4
|
||||
- **WebUI:** Allow import custom keybox from device storage.
|
||||
- **WebUI:** Allow custom config security patch in WebUI, save empty to disable auto config.
|
||||
- **WebUI:** Update Turkish translation (#16, @berkmirsatk)
|
||||
- **WebUI:** Fix wrong changelog version displayed in update changelog.
|
||||
- **MMRL:** Display a guide to enable the JavaScript API in MMRL. Directly request API permission on v33045+
|
||||
- More minor improvements
|
||||
|
||||
### v3.3.1
|
||||
- Fixed security patch logic, use pif.json to get security patch date.
|
||||
- No auto config `security_patch.txt` for security patch lesser than one year.
|
||||
|
||||
### v3.3
|
||||
- Support auto config `security_patch.txt` for Tricky Store v1.2.1 or higher.
|
||||
- No longer need to add `!` to Play Store for devices that have security patch older than one year to get strong integrity in new A13+ check.
|
||||
- **Magisk:** automatically add apps from DenyList to `target.txt` on boot. To enable this feature, click "Select from DenyList" once in WebUI after update.
|
||||
|
||||
### v3.2
|
||||
- Add `android` and `com.android.vending` by default.
|
||||
- Handle `ro.vendor.build.security_patch` if the value is different.
|
||||
@@ -34,7 +51,7 @@ Telegram channel: [KOW's Little World](https://t.me/kowchannel)
|
||||
- Optimized scripts, thanks to @backslashxx.
|
||||
- Fixed freeze in weak connection.
|
||||
- Added Spanish, thanks to @Keinta15.
|
||||
- Removed rescriction on installation but module will still be removed if tricky store is not found after reboot.
|
||||
- Removed restriction on installation but module will still be removed if Tricky Store is not found after reboot.
|
||||
|
||||
### v2.8
|
||||
- Fixed all KSUWebUIStandalone freeze issue, removed visible option.
|
||||
@@ -52,7 +69,7 @@ Telegram channel: [KOW's Little World](https://t.me/kowchannel)
|
||||
- Press any position of app card to select/deselct.
|
||||
|
||||
### v2.6
|
||||
- Invisible module, intergrate action button & webui on tricky store card. You can stil use visible option if you found any issue with invisble module. Thanks for idea from @backslashxx.
|
||||
- Invisible module, integrate action button & WebUI on Tricky Store card. You can still use visible option if you found any issue with invisible module. Thanks for idea from @backslashxx.
|
||||
- To uninstall invisble module, scroll down to the bottom of WebUI and press Uninstall WebUI.
|
||||
- Add update prompt if found new version in webui, and show module if found an update. (invisible)
|
||||
- Reduced WebUI loading time
|
||||
|
||||
@@ -14,22 +14,22 @@ abort() {
|
||||
}
|
||||
|
||||
download() {
|
||||
local type=${1#--}
|
||||
local url=$2
|
||||
local output=$3
|
||||
download_type=${1#--}
|
||||
download_url=$2
|
||||
download_output=$3
|
||||
|
||||
PATH=/data/adb/magisk:/data/data/com.termux/files/usr/bin:$PATH
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
if [ "$type" = "output" ]; then
|
||||
timeout 10 curl -Lo "$output" "$url"
|
||||
if [ "$download_type" = "output" ]; then
|
||||
timeout 10 curl -Lo "$download_output" "$download_url"
|
||||
else
|
||||
timeout 2 curl -s "$url"
|
||||
timeout 2 curl -s "$download_url"
|
||||
fi
|
||||
else
|
||||
if [ "$type" = "output" ]; then
|
||||
timeout 10 busybox wget --no-check-certificate -qO "$output" "$url"
|
||||
if [ "$download_type" = "output" ]; then
|
||||
timeout 10 busybox wget --no-check-certificate -qO "$download_output" "$download_url"
|
||||
else
|
||||
timeout 2 busybox wget --no-check-certificate -qO- "$url"
|
||||
timeout 2 busybox wget --no-check-certificate -qO- "$download_url"
|
||||
fi
|
||||
fi
|
||||
PATH="$ORG_PATH"
|
||||
|
||||
@@ -5,28 +5,35 @@ SKIPLIST="$MODPATH/tmp/skiplist"
|
||||
OUTPUT="$MODPATH/tmp/exclude-list"
|
||||
KBOUTPUT="$MODPATH/tmp/.extra"
|
||||
|
||||
if [ "$MODPATH" = "/data/adb/modules/.TA_utl/common" ]; then
|
||||
MODDIR="/data/adb/modules/.TA_utl"
|
||||
MAGISK="true"
|
||||
else
|
||||
MODDIR="/data/adb/modules/TA_utl"
|
||||
fi
|
||||
|
||||
aapt() { "$MODPATH/aapt" "$@"; }
|
||||
|
||||
# probe for downloaders
|
||||
# wget = low pref, no ssl.
|
||||
# curl, has ssl on android, we use it if found
|
||||
download() {
|
||||
local type=${1#--}
|
||||
local url=$2
|
||||
local output=$3
|
||||
download_type=${1#--}
|
||||
download_url=$2
|
||||
download_output=$3
|
||||
|
||||
PATH=/data/adb/ap/bin:/data/adb/ksu/bin:/data/adb/magisk:/data/data/com.termux/files/usr/bin:$PATH
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
if [ "$type" = "output" ]; then
|
||||
timeout 10 curl -Lo "$output" "$url"
|
||||
if [ "$download_type" = "output" ]; then
|
||||
timeout 10 curl -Lo "$download_output" "$download_url"
|
||||
else
|
||||
timeout 3 curl -s "$url"
|
||||
timeout 3 curl -s "$download_url"
|
||||
fi
|
||||
else
|
||||
if [ "$type" = "output" ]; then
|
||||
timeout 10 busybox wget --no-check-certificate -qO "$output" "$url"
|
||||
if [ "$download_type" = "output" ]; then
|
||||
timeout 10 busybox wget --no-check-certificate -qO "$download_output" "$download_url"
|
||||
else
|
||||
timeout 3 busybox wget --no-check-certificate -qO- "$url"
|
||||
timeout 3 busybox wget --no-check-certificate -qO- "$download_url"
|
||||
fi
|
||||
fi
|
||||
PATH="$ORG_PATH"
|
||||
@@ -57,11 +64,12 @@ get_unnecessary() {
|
||||
}
|
||||
|
||||
check_update() {
|
||||
[ -f "$MODDIR/disable" ] && rm -f "$MODDIR/disable"
|
||||
JSON=$(download --fetch "https://raw.githubusercontent.com/KOWX712/Tricky-Addon-Update-Target-List/main/update.json") || exit 1
|
||||
REMOTE_VERSION=$(echo "$JSON" | grep -o '"versionCode": *[0-9]*' | awk -F: '{print $2}' | tr -d ' ')
|
||||
LOCAL_VERSION=$(grep -o 'versionCode=[0-9]*' "$MODPATH/update/module.prop" | awk -F= '{print $2}')
|
||||
if [ "$REMOTE_VERSION" -gt "$LOCAL_VERSION" ] && [ ! -f "/data/adb/modules/TA_utl/update" ]; then
|
||||
if [ "$MODPATH" = "/data/adb/modules/.TA_utl/common" ]; then
|
||||
if [ "$MAGISK" = "true" ]; then
|
||||
[ -d "/data/adb/modules/TA_utl" ] && rm -rf "/data/adb/modules/TA_utl"
|
||||
cp -rf "$MODPATH/update" "/data/adb/modules/TA_utl"
|
||||
else
|
||||
@@ -72,8 +80,7 @@ check_update() {
|
||||
}
|
||||
|
||||
uninstall() {
|
||||
if [ "$MODPATH" = "/data/adb/modules/.TA_utl/common" ]; then
|
||||
[ -d "/data/adb/modules/TA_utl" ] && rm -rf "/data/adb/modules/TA_utl"
|
||||
if [ "$MAGISK" = "true" ]; then
|
||||
cp -rf "$MODPATH/update" "/data/adb/modules/TA_utl"
|
||||
else
|
||||
cp -f "$MODPATH/update/module.prop" "/data/adb/modules/TA_utl/module.prop"
|
||||
@@ -85,6 +92,7 @@ get_update() {
|
||||
JSON=$(download --fetch "https://raw.githubusercontent.com/KOWX712/Tricky-Addon-Update-Target-List/main/update.json") || exit 1
|
||||
ZIP_URL=$(echo "$JSON" | grep -o '"zipUrl": "[^"]*"' | cut -d '"' -f 4) || exit 1
|
||||
CHANGELOG_URL=$(echo "$JSON" | grep -o '"changelog": "[^"]*"' | cut -d '"' -f 4) || exit 1
|
||||
echo "$JSON" | grep '"version"' | sed 's/.*: "//; s/".*//' > "$MODPATH/tmp/version" || exit 1
|
||||
download --output "$ZIP_URL" "$MODPATH/tmp/module.zip" || exit 1
|
||||
download --output "$CHANGELOG_URL" "$MODPATH/tmp/changelog.md" || exit 1
|
||||
}
|
||||
@@ -99,24 +107,48 @@ install_update() {
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -f "$MODPATH/tmp/module.zip"
|
||||
rm -f "$MODPATH/tmp/changelog.md"
|
||||
rm -f "$MODPATH/tmp/version"
|
||||
}
|
||||
|
||||
release_note() {
|
||||
awk '
|
||||
/^### v[0-9]+\.[0-9]+$/ {
|
||||
if (!found) {
|
||||
version = $0;
|
||||
VERSION=$(grep 'v' "$MODPATH/tmp/version")
|
||||
awk -v header="### $VERSION" '
|
||||
$0 == header {
|
||||
print;
|
||||
found = 1;
|
||||
next
|
||||
} else {
|
||||
exit
|
||||
}
|
||||
}
|
||||
found && !/^###/ { content = content $0 "\n" }
|
||||
END { if (found) { print version; print content } }
|
||||
' "$MODPATH/tmp/changelog.md"
|
||||
found && /^###/ { exit }
|
||||
found { print }
|
||||
' "$MODPATH/tmp/changelog.md"
|
||||
}
|
||||
|
||||
set_security_patch() {
|
||||
# Find pif.json
|
||||
[ -f "/data/adb/modules/playintegrityfix/pif.json" ] && PIF="/data/adb/modules/playintegrityfix/pif.json"
|
||||
[ -f "/data/adb/pif.json" ] && PIF="/data/adb/pif.json"
|
||||
[ -f "/data/adb/modules/playintegrityfix/custom.pif.json" ] && PIF="/data/adb/modules/playintegrityfix/custom.pif.json"
|
||||
|
||||
security_patch=$(grep '"SECURITY_PATCH"' "$PIF" | sed 's/.*: "//; s/".*//')
|
||||
[ -z "$security_patch" ] && security_patch=$(getprop ro.build.version.security_patch) # Fallback
|
||||
|
||||
formatted_security_patch=$(echo "$security_patch" | sed 's/-//g')
|
||||
security_patch_after_1y=$(echo "$formatted_security_patch + 10000" | bc)
|
||||
TODAY=$(date +%Y%m%d)
|
||||
if [ -n "$formatted_security_patch" ] && [ "$TODAY" -lt "$security_patch_after_1y" ]; then
|
||||
TS_version=$(grep "versionCode=" "$TS/module.prop" | cut -d'=' -f2)
|
||||
if [ "$TS_version" -lt 158 ]; then
|
||||
resetprop ro.vendor.build.security_patch "$security_patch"
|
||||
resetprop ro.build.version.security_patch "$security_patch"
|
||||
fi
|
||||
echo "all=$formatted_security_patch" > "/data/adb/tricky_store/security_patch.txt"
|
||||
chmod 644 "/data/adb/tricky_store/security_patch.txt"
|
||||
else
|
||||
echo "not set"
|
||||
fi
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
@@ -152,4 +184,8 @@ case "$1" in
|
||||
release_note
|
||||
exit
|
||||
;;
|
||||
--security-patch)
|
||||
set_security_patch
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -8,19 +8,23 @@ MODID=`grep_prop id $TMPDIR/module.prop`
|
||||
NEW_MODID=".TA_utl"
|
||||
kb="$COMPATH/.default"
|
||||
|
||||
ui_print " ";
|
||||
ui_print " "
|
||||
if [ "$APATCH" ]; then
|
||||
ui_print "- APatch:$APATCH_VER│$APATCH_VER_CODE"
|
||||
ACTION=false
|
||||
elif [ "$KSU" ]; then
|
||||
ui_print "- KSU:$KSU_KERNEL_VER_CODE│$KSU_VER_CODE"
|
||||
if [ "$KSU_NEXT" ]; then
|
||||
ui_print "- KernelSU Next:$KSU_KERNEL_VER_CODE│$KSU_VER_CODE"
|
||||
else
|
||||
ui_print "- KernelSU:$KSU_KERNEL_VER_CODE│$KSU_VER_CODE"
|
||||
fi
|
||||
ACTION=false
|
||||
elif [ "$MAGISK_VER_CODE" ]; then
|
||||
ui_print "- Magisk:$MAGISK_VER│$MAGISK_VER_CODE"
|
||||
else
|
||||
ui_print " ";
|
||||
ui_print "! recovery is not supported";
|
||||
abort " ";
|
||||
ui_print " "
|
||||
ui_print "! recovery is not supported"
|
||||
abort " "
|
||||
fi
|
||||
|
||||
[ -d "$TS" ] || ui_print "! Warning: Tricky store module not found"
|
||||
@@ -32,7 +36,7 @@ initialize
|
||||
|
||||
ui_print "- Finalizing..."
|
||||
find_config
|
||||
migrate_old_boot_hash
|
||||
migrate_config
|
||||
|
||||
rm -f "$MODPATH/install_func.sh"
|
||||
|
||||
|
||||
@@ -31,10 +31,19 @@ find_config() {
|
||||
[ -d "$CONFIG_DIR" ] && rm -rf "$CONFIG_DIR"
|
||||
}
|
||||
|
||||
migrate_old_boot_hash() {
|
||||
migrate_config() {
|
||||
# Migrate boot_hash
|
||||
if [ ! -f "/data/adb/boot_hash" ]; then
|
||||
mv "$COMPATH/boot_hash" "/data/adb/boot_hash"
|
||||
else
|
||||
rm -f "$COMPATH/boot_hash"
|
||||
fi
|
||||
|
||||
# Migrate security_patch config*
|
||||
if [ ! -s "/data/adb/security_patch" ]; then
|
||||
echo "#Tricky Addon security patch auto config" > "/data/adb/security_patch"
|
||||
fi
|
||||
if ! grep -q "^auto_config=" "/data/adb/security_patch"; then
|
||||
echo "auto_config=1" >> "/data/adb/security_patch"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
id=TA_utl
|
||||
name=Tricky Addon - Update Target List
|
||||
version=v3.2
|
||||
versionCode=320
|
||||
version=v3.4
|
||||
versionCode=340
|
||||
author=KOWX712
|
||||
description=A WebUI to conifgure tricky store target.txt
|
||||
updateJson=https://raw.githubusercontent.com/KOWX712/Tricky-Addon-Update-Target-List/main/update.json
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
MODPATH=${0%/*}
|
||||
HIDE_DIR="/data/adb/modules/.TA_utl"
|
||||
TS="/data/adb/modules/tricky_store"
|
||||
SCRIPT_DIR="/data/adb/tricky_store"
|
||||
TSPA="/data/adb/modules/tsupport-advance"
|
||||
|
||||
aapt() { "$MODPATH/common/aapt" "$@"; }
|
||||
@@ -23,18 +22,17 @@ add_denylist_to_target() {
|
||||
done
|
||||
}
|
||||
|
||||
# Spoof security patch
|
||||
if grep -q "^auto_config=1" "/data/adb/security_patch"; then
|
||||
sh "$MODPATH/common/get_extra.sh" --security-patch
|
||||
fi
|
||||
|
||||
# Reset verified Boot Hash
|
||||
hash_value=$(grep -v '^#' "/data/adb/boot_hash" | tr -d '[:space:]')
|
||||
if [ -n "$hash_value" ]; then
|
||||
resetprop -n ro.boot.vbmeta.digest "$hash_value"
|
||||
fi
|
||||
|
||||
# Reset vendor patch if different with security patch
|
||||
security_patch=$(getprop ro.build.version.security_patch)
|
||||
vendor_patch=$(getprop ro.vendor.build.security_patch)
|
||||
if [ "$vendor_patch" != "$security_patch" ]; then
|
||||
resetprop ro.vendor.build.security_patch "$security_patch"
|
||||
fi
|
||||
|
||||
# Disable TSupport-A auto update target to prevent overwrite
|
||||
if [ -d "$TSPA" ]; then
|
||||
@@ -73,32 +71,41 @@ fi
|
||||
# Optimization
|
||||
OUTPUT_APP="$MODPATH/common/tmp/applist"
|
||||
OUTPUT_SKIP="$MODPATH/common/tmp/skiplist"
|
||||
OUTPUT_TMP="$MODPATH/common/tmp/tmp_applist"
|
||||
|
||||
until [ "$(getprop sys.boot_completed)" = "1" ]; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# Create temporary directory
|
||||
mkdir -p "$MODPATH/common/tmp"
|
||||
pm list packages -3 2>/dev/null | awk -F: '{print $2}' > "$OUTPUT_TMP"
|
||||
|
||||
# Additional system apps
|
||||
SYSTEM_APP="com.google.android.gms|com.google.android.gsf|com.android.vending"
|
||||
pm list package -s | awk -F: '{print $2}' | grep -Ex "$SYSTEM_APP" >> "$OUTPUT_TMP"
|
||||
|
||||
# Initialize cache files to save app list and skip list
|
||||
echo "# This file is generated from service.sh to speed up load time" > "$OUTPUT_APP"
|
||||
echo "# This file is generated from service.sh to speed up load time" > "$OUTPUT_SKIP"
|
||||
cat "$OUTPUT_TMP" | while read -r PACKAGE; do
|
||||
|
||||
# Get list of third party apps and specific system apps, then cache app name
|
||||
# Check Xposed module
|
||||
{
|
||||
pm list packages -3 2>/dev/null
|
||||
pm list package -s | grep -E "$SYSTEM_APP"
|
||||
} | awk -F: '{print $2}' | while read -r PACKAGE; do
|
||||
# Get APK path for the package
|
||||
APK_PATH=$(pm path "$PACKAGE" 2>/dev/null | grep "base.apk" | awk -F: '{print $2}' | tr -d '\r')
|
||||
[ -z "$APK_PATH" ] && APK_PATH=$(pm path "$PACKAGE" 2>/dev/null | grep ".apk" | awk -F: '{print $2}' | tr -d '\r')
|
||||
|
||||
if [ -n "$APK_PATH" ]; then
|
||||
# Extract app name and save package info
|
||||
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_APP"
|
||||
else
|
||||
echo "app-name: Unknown App package-name: $PACKAGE" >> "$OUTPUT_APP"
|
||||
fi
|
||||
|
||||
# Check if app is Xposed module and add to skip list if not
|
||||
if ! aapt dump xmltree "$APK_PATH" AndroidManifest.xml 2>/dev/null | grep -qE "xposed.category|xposeddescription"; then
|
||||
echo "$PACKAGE" >> "$OUTPUT_SKIP"
|
||||
fi
|
||||
done
|
||||
|
||||
rm -f "$OUTPUT_TMP"
|
||||
|
||||
@@ -10,6 +10,7 @@ fi
|
||||
# Remove residue and restore aosp keybox.
|
||||
rm -rf "/data/adb/modules/.TA_utl"
|
||||
rm -f "/data/adb/boot_hash"
|
||||
rm -f "/data/adb/security_patch"
|
||||
rm -f "/data/adb/tricky_store/target_from_denylist"
|
||||
if [ -d "$TS" ]; then
|
||||
[ -L "$TS/webroot" ] && rm -f "$TS/webroot"
|
||||
|
||||
@@ -12,10 +12,12 @@
|
||||
<link rel="stylesheet" href="styles/boot-hash.css" type="text/css">
|
||||
<link rel="stylesheet" href="styles/header.css" type="text/css">
|
||||
<link rel="stylesheet" href="styles/search_menu.css" type="text/css">
|
||||
<link rel="stylesheet" href="styles/security-patch.css" type="text/css">
|
||||
<script type="module" crossorigin src="scripts/main.js"></script>
|
||||
<script type="module" crossorigin src="scripts/about.js"></script>
|
||||
<script type="module" crossorigin src="scripts/help.js"></script>
|
||||
<script type="module" crossorigin src="scripts/vbmeta-digest.js"></script>
|
||||
<script type="module" crossorigin src="scripts/security_patch.js"></script>
|
||||
<script src="scripts/marked.min.js"></script>
|
||||
</head>
|
||||
|
||||
@@ -76,8 +78,10 @@
|
||||
<li id="select-denylist" data-i18n="menu.select_denylist"></li>
|
||||
<li id="deselect-unnecessary" data-i18n="menu.deselect_unnecessary"></li>
|
||||
<li id="aospkb" data-i18n="menu.set_aosp_keybox"></li>
|
||||
<li id="extrakb" data-i18n="menu.set_valid_keybox"></li>
|
||||
<li id="validkb" data-i18n="menu.set_valid_keybox"></li>
|
||||
<li id="customkb" data-i18n="menu.set_custom_keybox"></li>
|
||||
<li id="boot-hash" data-i18n="menu.set_verified_boot_hash"></li>
|
||||
<li id="security-patch" data-i18n="menu.set_security_patch"></li>
|
||||
<li id="about" data-i18n="menu.about"></li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -185,6 +189,20 @@
|
||||
</ul>
|
||||
</li>
|
||||
<br>
|
||||
<li id="set_custom_keybox">
|
||||
<strong data-i18n="help.set_custom_keybox"></strong>
|
||||
<ul>
|
||||
<li data-i18n="help.set_custom_keybox_description"></li>
|
||||
</ul>
|
||||
</li>
|
||||
<br>
|
||||
<li id="set_security_patch">
|
||||
<strong data-i18n="help.set_security_patch"></strong>
|
||||
<ul>
|
||||
<li data-i18n="help.set_security_patch_description"></li>
|
||||
</ul>
|
||||
</li>
|
||||
<br>
|
||||
<li id="set_verified_boot_hash">
|
||||
<strong data-i18n="help.set_verified_boot_hash"></strong>
|
||||
<ul>
|
||||
@@ -254,6 +272,66 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- MMRL Permission Request Overlay -->
|
||||
<div id="permission-popup" class="permission-popup hidden">
|
||||
<div class="permission-content">
|
||||
<h2 id="permission-title">Please allow JavaScript API in MMRL settings</h2>
|
||||
<div class="permission-steps">
|
||||
<p>1. Settings</p>
|
||||
<p>2. Security</p>
|
||||
<p>3. Allow JavaScript API</p>
|
||||
<p>4. Tricky Store</p>
|
||||
<p>5. Enable Allow Advanced KernelSU API</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Security Patch Overlay -->
|
||||
<div id="security-patch-overlay" class="security-patch-overlay"></div>
|
||||
<div id="security-patch-card" class="security-patch-card">
|
||||
<div class="security-patch-header" data-i18n="security_patch.title"></div>
|
||||
<div class="security-patch-content">
|
||||
<div id="normal-mode-inputs" class="normal-mode-inputs">
|
||||
<div class="input-group">
|
||||
<label id="security_patch-all">All</label>
|
||||
<input type="text" id="all-patch" placeholder="20250101" maxlength="8" autocapitalize="none">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="advanced-mode-inputs" class="advanced-mode-inputs hidden">
|
||||
<div class="input-group">
|
||||
<label id="security_patch-system">System</label>
|
||||
<input type="text" id="system-patch" placeholder="202501" maxlength="6" autocapitalize="none">
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label id="security_patch-boot">Boot</label>
|
||||
<input type="text" id="boot-patch" placeholder="2025-01-01" autocapitalize="none" oninput="formatDate(this, 'boot')" maxlength="10">
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label id="security_patch-vendor">Vendor</label>
|
||||
<input type="text" id="vendor-patch" placeholder="2025-01-01" autocapitalize="none" oninput="formatDate(this, 'vendor')" maxlength="10">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="advanced-toggle">
|
||||
<input type="checkbox" class="checkbox" id="advanced-mode" />
|
||||
<label for="advanced-mode" class="custom-checkbox">
|
||||
<span class="tick-symbol">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -3 26 26" width="16px" height="16px" fill="#fff">
|
||||
<path d="M 22.566406 4.730469 L 20.773438 3.511719 C 20.277344 3.175781 19.597656 3.304688 19.265625 3.796875 L 10.476563 16.757813 L 6.4375 12.71875 C 6.015625 12.296875 5.328125 12.296875 4.90625 12.71875 L 3.371094 14.253906 C 2.949219 14.675781 2.949219 15.363281 3.371094 15.789063 L 9.582031 22 C 9.929688 22.347656 10.476563 22.613281 10.96875 22.613281 C 11.460938 22.613281 11.957031 22.304688 12.277344 21.839844 L 22.855469 6.234375 C 23.191406 5.742188 23.0625 5.066406 22.566406 4.730469 Z"/>
|
||||
</svg>
|
||||
</span>
|
||||
</label>
|
||||
<label for="advanced-mode" data-i18n="security_patch.advanced_mode"></label>
|
||||
</div>
|
||||
|
||||
<div class="button-container">
|
||||
<button id="auto-config" class="auto-button" data-i18n="security_patch.auto">Auto</button>
|
||||
<button id="save-patch" class="save-button" data-i18n="security_patch.save">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<div class="footer">
|
||||
<div class="uninstall-container hidden-uninstall">
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
"deselect_unnecessary_description": "Unnecessary category: Xposed module, root manager, root-related apps, and general apps that never check bootloader status. This option requires Internet connection.",
|
||||
"set_keybox": "Set AOSP & Valid Keybox",
|
||||
"set_keybox_description": "Replace tricky store keybox.xml. AOSP keybox will be replaced if there's no more valid keybox. Valid keybox option requires Internet connection.",
|
||||
"set_custom_keybox": "Set Custom Keybox",
|
||||
"set_custom_keybox_description": "Import keybox from your device storage. Only support xml file.",
|
||||
"set_security_patch": "Set Security Patch",
|
||||
"set_security_patch_description": "Set custom security patch spoof. Auto config will use security patch from PIF module, enabled by default. Leave blank and save to disable auto config.",
|
||||
"set_verified_boot_hash": "Set Verified Boot Hash",
|
||||
"set_verified_boot_hash_description": "Get verifiedBootHash value from Key Attestation Demo. Fix abnormal boot state by resetting ro.boot.vbmeta.digest."
|
||||
},
|
||||
@@ -45,7 +49,9 @@
|
||||
"deselect_unnecessary": "Deselect Unnecessary",
|
||||
"set_aosp_keybox": "Set AOSP Keybox",
|
||||
"set_valid_keybox": "Set Valid Keybox",
|
||||
"set_custom_keybox": "Set Custom Keybox",
|
||||
"set_verified_boot_hash": "Set Verified Boot Hash",
|
||||
"set_security_patch": "Set Security Patch",
|
||||
"about": "About"
|
||||
},
|
||||
"reset_vbmeta": {
|
||||
@@ -81,6 +87,24 @@
|
||||
"installed": "Installed successfully, reboot now.",
|
||||
"install_fail": "Fail to install, please update manual",
|
||||
"rebooting": "Rebooting...",
|
||||
"reboot_fail": "Fail to reboot, please reboot manually"
|
||||
"reboot_fail": "Fail to reboot, please reboot manually",
|
||||
"custom_key_set": "Custom keybox set successfully",
|
||||
"custom_key_set_error": "Failed to set custom keybox",
|
||||
"no_file_selected": "No file selected"
|
||||
},
|
||||
"security_patch": {
|
||||
"title": "Security Patch",
|
||||
"advanced_mode": "Advanced",
|
||||
"auto": "Auto",
|
||||
"save": "Save",
|
||||
"auto_success": "Auto config enabled successfully",
|
||||
"auto_failed": "Failed to enable auto config",
|
||||
"save_success": "Security patch saved successfully",
|
||||
"save_failed": "Failed to save security patch",
|
||||
"value_empty": "Security patch configuration is disabled",
|
||||
"invalid_all": "Invalid format",
|
||||
"invalid_boot": "Invalid boot format",
|
||||
"invalid_system": "Invalid system format",
|
||||
"invalid_vendor": "Invalid vendor format"
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,10 @@
|
||||
"deselect_unnecessary_description": "Unnecessary category: Xposed module, root manager, root-related apps, and general apps that never check bootloader status. This option requires Internet connection.",
|
||||
"set_keybox": "Set AOSP & Valid Keybox",
|
||||
"set_keybox_description": "Replace tricky store keybox.xml. AOSP keybox will be replaced if there's no more valid keybox. Valid keybox option requires Internet connection.",
|
||||
"set_custom_keybox": "Set Custom Keybox",
|
||||
"set_custom_keybox_description": "Import keybox from your device storage. Only support xml file.",
|
||||
"set_security_patch": "Set Security Patch",
|
||||
"set_security_patch_description": "Set custom security patch spoof. Auto config will use security patch from PIF module, enabled by default. Leave blank and save to disable auto config.",
|
||||
"set_verified_boot_hash": "Set Verified Boot Hash",
|
||||
"set_verified_boot_hash_description": "Get verifiedBootHash value from Key Attestation Demo. Fix abnormal boot state by resetting ro.boot.vbmeta.digest."
|
||||
},
|
||||
@@ -45,7 +49,9 @@
|
||||
"deselect_unnecessary": "Deselect Unnecessary",
|
||||
"set_aosp_keybox": "Set AOSP Keybox",
|
||||
"set_valid_keybox": "Set Valid Keybox",
|
||||
"set_custom_keybox": "Set Custom Keybox",
|
||||
"set_verified_boot_hash": "Set Verified Boot Hash",
|
||||
"set_security_patch": "Set Security Patch",
|
||||
"about": "About"
|
||||
},
|
||||
"reset_vbmeta": {
|
||||
@@ -81,6 +87,24 @@
|
||||
"installed": "Installed successfully, reboot now.",
|
||||
"install_fail": "Fail to install, please update manual",
|
||||
"rebooting": "Rebooting...",
|
||||
"reboot_fail": "Fail to reboot, please reboot manually"
|
||||
"reboot_fail": "Fail to reboot, please reboot manually",
|
||||
"custom_key_set": "Custom keybox set successfully",
|
||||
"custom_key_set_error": "Failed to set custom keybox",
|
||||
"no_file_selected": "No file selected"
|
||||
},
|
||||
"security_patch": {
|
||||
"title": "Security Patch",
|
||||
"advanced_mode": "Advanced",
|
||||
"auto": "Auto",
|
||||
"save": "Save",
|
||||
"auto_success": "Auto config enabled successfully",
|
||||
"auto_failed": "Failed to enable auto config",
|
||||
"save_success": "Security patch saved successfully",
|
||||
"save_failed": "Failed to save security patch",
|
||||
"value_empty": "Security patch configuration is disabled",
|
||||
"invalid_all": "Invalid format",
|
||||
"invalid_boot": "Invalid boot format",
|
||||
"invalid_system": "Invalid system format",
|
||||
"invalid_vendor": "Invalid vendor format"
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,10 @@
|
||||
"deselect_unnecessary_description": "Categorías innecesarias: módulos Xposed, gestores de root, aplicaciones relacionadas con root y aplicaciones generales que nunca verifican el estado del bootloader. Esta opción requiere conexión a Internet.",
|
||||
"set_keybox": "Configurar AOSP y Keybox Válido",
|
||||
"set_keybox_description": "Reemplazar el archivo keybox.xml de Tricky Store. El AOSP Keybox será reemplazado si no hay un keybox válido. Esta opción requiere conexión a Internet.",
|
||||
"set_custom_keybox": "Establecer Keybox Personalizado",
|
||||
"set_custom_keybox_description": "Importar keybox desde el almacenamiento de tu dispositivo. Solo soporta archivos xml.",
|
||||
"set_security_patch": "Configurar Parche de Seguridad",
|
||||
"set_security_patch_description": "Configurar parche de seguridad personalizado. La configuración automática usará el parche de seguridad de PIF, habilitado por defecto. Deja en blanco y guarda para deshabilitar la configuración automática.",
|
||||
"set_verified_boot_hash": "Configurar Boot Hash Verificado",
|
||||
"set_verified_boot_hash_description": "Obtén el valor de verifiedBootHash del Key Attestation Demo. Corrige un estado de arranque anormal reiniciando ro.boot.vbmeta.digest."
|
||||
},
|
||||
@@ -45,6 +49,8 @@
|
||||
"deselect_unnecessary": "Deseleccionar innecesarios",
|
||||
"set_aosp_keybox": "Configurar AOSP Keybox",
|
||||
"set_valid_keybox": "Configurar Keybox Válido",
|
||||
"set_custom_keybox": "Establecer Keybox Personalizado",
|
||||
"set_security_patch": "Configurar Parche de Seguridad",
|
||||
"set_verified_boot_hash": "Configurar Boot Hash Verificado",
|
||||
"about": "Acerca de"
|
||||
},
|
||||
@@ -54,7 +60,7 @@
|
||||
},
|
||||
"about": {
|
||||
"module_name_line1": "Tricky Addon",
|
||||
"module_name_line2": "Update Target List",
|
||||
"module_name_line2": "Actualizar Lista de Objetivos",
|
||||
"by": "por",
|
||||
"telegram_channel": "Canal de Telegram",
|
||||
"github": "GitHub",
|
||||
@@ -81,6 +87,24 @@
|
||||
"installed": "Instalado con éxito, reinicia ahora.",
|
||||
"install_fail": "Error al instalar, actualiza manualmente",
|
||||
"rebooting": "Reiniciando...",
|
||||
"reboot_fail": "Error al reiniciar, reinicia manualmente"
|
||||
"reboot_fail": "Error al reiniciar, reinicia manualmente",
|
||||
"custom_key_set": "Keybox personalizado establecido con éxito",
|
||||
"custom_key_set_error": "Error al establecer el keybox personalizado",
|
||||
"no_file_selected": "Ningún archivo seleccionado"
|
||||
},
|
||||
"security_patch": {
|
||||
"title": "Parche de Seguridad",
|
||||
"advanced_mode": "Avanzado",
|
||||
"auto": "Automático",
|
||||
"save": "Guardar",
|
||||
"auto_success": "Configuración automática habilitada con éxito",
|
||||
"auto_failed": "Error al habilitar la configuración automática",
|
||||
"save_success": "Parche de seguridad guardado con éxito",
|
||||
"save_failed": "Error al guardar el parche de seguridad",
|
||||
"value_empty": "La configuración del parche de seguridad está deshabilitada",
|
||||
"invalid_all": "Formato inválido",
|
||||
"invalid_boot": "Formato de boot inválido",
|
||||
"invalid_system": "Formato de system inválido",
|
||||
"invalid_vendor": "Formato de vendor inválido"
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,10 @@
|
||||
"deselect_unnecessary_description": "不要なカテゴリー: Xposed モジュール、root マネージャー、root 関連アプリ、Bootloader の状態を確認しない一般的なアプリです。このオプションはインターネット接続が必要です。",
|
||||
"set_keybox": "AOSP と 有効な Keybox",
|
||||
"set_keybox_description": "Tricky Store の keybox.xml を置き換えます。有効な Keybox がなくなった場合は、AOSP Keybox に置き換えられます。インターネット接続が必要です。",
|
||||
"set_custom_keybox": "カスタム Keybox を設定",
|
||||
"set_custom_keybox_description": "デバイスのストレージからカスタム Keybox ファイルをインポートします。xml ファイルのみ対応。",
|
||||
"set_security_patch": "セキュリティパッチを設定",
|
||||
"set_security_patch_description": "カスタムセキュリティパッチの設定。自動設定は PIF モジュールのセキュリティパッチを使用します。空白のまま保存すると自動設定を無効にします。",
|
||||
"set_verified_boot_hash": "確認付きブートハッシュを設定",
|
||||
"set_verified_boot_hash_description": "Key Attestation Demo から確認付きブートハッシュの値を取得します。ro.boot.vbmeta.digest をリセットして異常なブート状態を修正します。"
|
||||
},
|
||||
@@ -45,7 +49,9 @@
|
||||
"deselect_unnecessary": "不要な選択を解除",
|
||||
"set_aosp_keybox": "AOSP Keybox を設定",
|
||||
"set_valid_keybox": "有効な Keybox を設定",
|
||||
"set_custom_keybox": "カスタム Keybox を設定",
|
||||
"set_verified_boot_hash": "確認付きブートハッシュを設定",
|
||||
"set_security_patch": "セキュリティパッチを設定",
|
||||
"about": "このアドオンについて"
|
||||
},
|
||||
"reset_vbmeta": {
|
||||
@@ -81,6 +87,24 @@
|
||||
"installed": "正常にインストールされました。再起動してください。",
|
||||
"install_fail": "インストールに失敗しました。手動で更新してください。",
|
||||
"rebooting": "再起動中...",
|
||||
"reboot_fail": "再起動に失敗しました。手動で再起動してください。"
|
||||
"reboot_fail": "再起動に失敗しました。手動で再起動してください。",
|
||||
"custom_key_set": "カスタム Keybox の設定に成功しました",
|
||||
"custom_key_set_error": "カスタム Keybox の設定に失敗しました",
|
||||
"no_file_selected": "ファイルが選択されていません"
|
||||
},
|
||||
"security_patch": {
|
||||
"title": "セキュリティ补丁",
|
||||
"advanced_mode": "高度",
|
||||
"auto": "自動",
|
||||
"save": "保存",
|
||||
"auto_success": "自動配置已成功啟用",
|
||||
"auto_failed": "自動設定を有効にできませんでした",
|
||||
"save_success": "セキュリティパッチが正常に保存されました",
|
||||
"save_failed": "セキュリティパッチの保存に失敗しました",
|
||||
"value_empty": "セキュリティパッチの設定は無効です",
|
||||
"invalid_all": "無効な形式です",
|
||||
"invalid_boot": "無効な boot 形式です",
|
||||
"invalid_system": "無効な system 形式です",
|
||||
"invalid_vendor": "無効な vendor 形式です"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,10 @@
|
||||
"deselect_unnecessary_description": "Ненужные категории: модули Xposed, менеджеры root, приложения, связанные с root, и общие приложения, которые никогда не проверяют статус загрузчика. Этот параметр требует подключения к интернету.",
|
||||
"set_keybox": "Установить AOSP и действующий Keybox",
|
||||
"set_keybox_description": "Замените tricky store keybox.xml. AOSP keybox будет заменен, если не будет найден действующий keybox. Опция с действующим keybox требует подключения к интернету.",
|
||||
"set_custom_keybox": "Установить пользовательский Keybox",
|
||||
"set_custom_keybox_description": "Импортируйте файл keybox из вашего устройства в хранилище. Поддерживаются только xml файлы.",
|
||||
"set_security_patch": "Установить Security Patch",
|
||||
"set_security_patch_description": "Установите пользовательский патч безопасности. Автоматическая настройка будет использовать патч безопасности из модуля PIF, включен по умолчанию. Оставьте пустым и сохраните, чтобы отключить автоматическую настройку.",
|
||||
"set_verified_boot_hash": "Установить Verified Boot Hash",
|
||||
"set_verified_boot_hash_description": "Получите значение verifiedBootHash из Key Attestation Demo. Исправьте аномальное состояние загрузки, сбросив ro.boot.vbmeta.digest."
|
||||
},
|
||||
@@ -45,6 +49,8 @@
|
||||
"deselect_unnecessary": "Отменить выбор ненужных",
|
||||
"set_aosp_keybox": "Установить AOSP Keybox",
|
||||
"set_valid_keybox": "Установить действующий Keybox",
|
||||
"set_custom_keybox": "Установить пользовательский Keybox",
|
||||
"set_security_patch": "Установить Security Patch",
|
||||
"set_verified_boot_hash": "Установить Verified Boot Hash",
|
||||
"about": "О программе"
|
||||
},
|
||||
@@ -81,6 +87,24 @@
|
||||
"installed": "Успешно установлено, перезагрузите устройство.",
|
||||
"install_fail": "Не удалось установить, обновите вручную",
|
||||
"rebooting": "Перезагрузка...",
|
||||
"reboot_fail": "Не удалось перезагрузить, перезагрузите вручную"
|
||||
"reboot_fail": "Не удалось перезагрузить, перезагрузите вручную",
|
||||
"custom_key_set": "Пользовательский keybox успешно установлен",
|
||||
"custom_key_set_error": "Не удалось установить пользовательский keybox",
|
||||
"no_file_selected": "Файл не выбран"
|
||||
},
|
||||
"security_patch": {
|
||||
"title": "Патч безопасности",
|
||||
"advanced_mode": "Расширенный",
|
||||
"auto": "Авто",
|
||||
"save": "Сохранить",
|
||||
"auto_success": "Автоматическая конфигурация успешно включена",
|
||||
"auto_failed": "Не удалось включить автоматическую конфигурацию",
|
||||
"save_success": "Патч безопасности успешно сохранен",
|
||||
"save_failed": "Не удалось сохранить патч безопасности",
|
||||
"value_empty": "Конфигурация патча безопасности отключена",
|
||||
"invalid_all": "Неверный формат",
|
||||
"invalid_boot": "Неверный формат boot",
|
||||
"invalid_system": "Неверный формат system",
|
||||
"invalid_vendor": "Неверный формат vendor"
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,11 @@
|
||||
"deselect_unnecessary": "Huwag Pumili ng Hindi Kinakailangan",
|
||||
"deselect_unnecessary_description": "Hindi kinakailangang kategorya: Xposed module, root manager, root-related apps, at mga karaniwang apps na hindi kailanman nire-refresh ang bootloader status. Nangangailangan ng koneksyon sa internet.",
|
||||
"set_keybox": "I-set ang AOSP at Valid Keybox",
|
||||
"set_keybox_description": "Palitan ang tricky store keybox.xml. Palitan ang AOSP keybox kung walang valid keybox. Nangangailangan ng koneksyon sa internet ang valid keybox option.",
|
||||
"set_keybox_description": "Palitan ang tricky store keybox. Palitan ang AOSP keybox kung walang valid keybox. Nangangailangan ng koneksyon sa internet ang valid keybox option.",
|
||||
"set_custom_keybox": "I-set ang Custom Keybox",
|
||||
"set_custom_keybox_description": "Mag-import ng custom keybox mula sa iyong device storage. Sumusuporta lamang ng xml file.",
|
||||
"set_security_patch": "I-set ang Security Patch",
|
||||
"set_security_patch_description": "I-set ang custom security patch. Ang auto config ay mag-use ng security patch mula sa PIF module, default enabled. I-leave blank at i-save para i-disable ang auto config.",
|
||||
"set_verified_boot_hash": "I-set ang Verified Boot Hash",
|
||||
"set_verified_boot_hash_description": "Kunin ang verifiedBootHash mula sa Key Attestation Demo. Ayusin ang abnormal na boot state sa pamamagitan ng pag-reset ng ro.boot.vbmeta.digest."
|
||||
},
|
||||
@@ -45,7 +49,9 @@
|
||||
"deselect_unnecessary": "Huwag Pumili ng Hindi Kinakailangan",
|
||||
"set_aosp_keybox": "I-set ang AOSP Keybox",
|
||||
"set_valid_keybox": "I-set ang Valid Keybox",
|
||||
"set_custom_keybox": "I-set ang Custom Keybox",
|
||||
"set_verified_boot_hash": "I-set ang Verified Boot Hash",
|
||||
"set_security_patch": "I-set ang Security Patch",
|
||||
"about": "Tungkol"
|
||||
},
|
||||
"reset_vbmeta": {
|
||||
@@ -81,6 +87,24 @@
|
||||
"installed": "Matagumpay na na-install, mag-reboot na ngayon.",
|
||||
"install_fail": "Nabigo ang pag-install, pakisubukang mag-update nang manu-mano",
|
||||
"rebooting": "Nag-re-reboot...",
|
||||
"reboot_fail": "Nabigo ang pag-reboot, pakisubukang mag-reboot nang manu-mano"
|
||||
"reboot_fail": "Nabigo ang pag-reboot, pakisubukang mag-reboot nang manu-mano",
|
||||
"custom_key_set": "Matagumpay na na-set ang Custom Keybox",
|
||||
"custom_key_set_error": "Nabigong i-set ang Custom Keybox",
|
||||
"no_file_selected": "Walang napiling file"
|
||||
},
|
||||
"security_patch": {
|
||||
"title": "Security Patch",
|
||||
"advanced_mode": "Advanced",
|
||||
"auto": "Auto",
|
||||
"save": "I-save",
|
||||
"auto_success": "Matagumpay na na-enable ang auto config",
|
||||
"auto_failed": "Nabigong i-enable ang auto config",
|
||||
"save_success": "Matagumpay na na-save ang security patch",
|
||||
"save_failed": "Nabigong i-save ang security patch",
|
||||
"value_empty": "Naka-disable ang configuration ng security patch",
|
||||
"invalid_all": "Invalid format",
|
||||
"invalid_boot": "Invalid boot format",
|
||||
"invalid_system": "Invalid system format",
|
||||
"invalid_vendor": "Invalid vendor format"
|
||||
}
|
||||
}
|
||||
@@ -12,13 +12,17 @@
|
||||
"select_deselect": "Tümünü Seç & Seçimi Kaldır",
|
||||
"select_description": "Mevcut arayüzdeki tüm uygulamaları seç veya seçimini kaldır.",
|
||||
"select_denylist": "Reddetme Listesinden Seç",
|
||||
"select_denylist_description": "Yalnızca Magisk’te mevcut, Reddetme Listesindeki uygulamaları seç. Tavsiye edilir.",
|
||||
"select_denylist_description": "Yalnızca Magisk'te mevcut, Reddetme Listesindeki uygulamaları seç. Tavsiye edilir.",
|
||||
"deselect_unnecessary": "Gereksizleri Seçme",
|
||||
"deselect_unnecessary_description": "Gereksiz kategori: Xposed modülü, root yöneticisi, root ile ilgili uygulamalar ve asla bootloader durumunu kontrol etmeyen genel uygulamalar. Bu seçenek internet bağlantısı gerektirir.",
|
||||
"set_keybox": "AOSP & Geçerli Keybox Ayarla",
|
||||
"set_keybox_description": "Tricky Store'daki keybox.xml dosyasını değiştirir. Eğer geçerli bir keybox yoksa AOSP keybox ile değiştirilecektir. Geçerli keybox seçeneği internet bağlantısı gerektirir.",
|
||||
"set_custom_keybox": "Özel Keybox Ayarla",
|
||||
"set_custom_keybox_description": "Cihaz depolamasından bir keybox dosyasını içe aktarın. Sadece xml dosyaları desteklenir.",
|
||||
"set_security_patch": "Güvenlik Yaması Ayarla",
|
||||
"set_security_patch_description": "Özel güvenlik yamasını ayarlayın. Otomatik yapılandırma PIF modülünün güvenlik yamasını kullanacaktır. Boş bırakın ve kaydedin ki otomatik yapılandırma devre dışı bırakılsın.",
|
||||
"set_verified_boot_hash": "Doğrulanmış Boot Hash Ayarla",
|
||||
"set_verified_boot_hash_description": "Key Attestation Demo’dan verifiedBootHash değerini alın. Abnormal boot durumunu ro.boot.vbmeta.digest’i sıfırlayarak düzeltin."
|
||||
"set_verified_boot_hash_description": "Key Attestation Demo'dan verifiedBootHash değerini alın. Abnormal boot durumunu ro.boot.vbmeta.digest'i sıfırlayarak düzeltin."
|
||||
},
|
||||
"update": {
|
||||
"update_available": "Yeni bir sürüm hazır",
|
||||
@@ -32,7 +36,7 @@
|
||||
},
|
||||
"functional_button": {
|
||||
"save_and_update_button": "Kaydet",
|
||||
"uninstall_webui": "WebUI’ı Kaldır"
|
||||
"uninstall_webui": "WebUI'ı Kaldır"
|
||||
},
|
||||
"loading": {
|
||||
"loading": "Yükleniyor..."
|
||||
@@ -45,11 +49,13 @@
|
||||
"deselect_unnecessary": "Gereksizleri Seçme",
|
||||
"set_aosp_keybox": "AOSP Keybox Ayarla",
|
||||
"set_valid_keybox": "Geçerli Keybox Ayarla",
|
||||
"set_custom_keybox": "Özel Keybox Ayarla",
|
||||
"set_security_patch": "Güvenlik Yaması Ayarla",
|
||||
"set_verified_boot_hash": "Doğrulanmış Boot Hash Ayarla",
|
||||
"about": "Hakkında"
|
||||
},
|
||||
"reset_vbmeta": {
|
||||
"boot_hash_input_placeholder": "Doğrulanmış Boot Hash’inizi buraya yapıştırın",
|
||||
"boot_hash_input_placeholder": "Doğrulanmış Boot Hash'inizi buraya yapıştırın",
|
||||
"boot_hash_save_button": "Kaydet"
|
||||
},
|
||||
"about": {
|
||||
@@ -58,8 +64,8 @@
|
||||
"by": "tarafından",
|
||||
"telegram_channel": "Telegram Kanalı",
|
||||
"github": "GitHub",
|
||||
"disclaimer": "Bu modül, Tricky Store modülünün bir parçası değildir. Herhangi bir sorun yaşarsanız, lütfen bunu Tricky Store’a rapor etmeyin.",
|
||||
"acknowledgment": "Teşekkür"
|
||||
"disclaimer": "Bu modül, Tricky Store modülünün bir parçası değildir. Herhangi bir sorun yaşarsanız, lütfen bunu Tricky Store'a rapor etmeyin.",
|
||||
"acknowledgment": "Teşekkürler"
|
||||
},
|
||||
"prompt": {
|
||||
"no_internet": "Lütfen internet bağlantınızı kontrol edin",
|
||||
@@ -81,6 +87,24 @@
|
||||
"installed": "Başarıyla yüklendi, şimdi yeniden başlatın.",
|
||||
"install_fail": "Yükleme başarısız oldu, lütfen manuel olarak güncelleyin",
|
||||
"rebooting": "Yeniden başlatılıyor...",
|
||||
"reboot_fail": "Yeniden başlatma başarısız, lütfen manuel olarak yeniden başlatın"
|
||||
"reboot_fail": "Yeniden başlatma başarısız, lütfen manuel olarak yeniden başlatın",
|
||||
"custom_key_set": "Özel keybox başarıyla ayarlandı",
|
||||
"custom_key_set_error": "Özel keybox ayarlanamadı",
|
||||
"no_file_selected": "Dosya seçilmedi"
|
||||
},
|
||||
"security_patch": {
|
||||
"title": "Güvenlik Yaması",
|
||||
"advanced_mode": "Gelişmiş",
|
||||
"auto": "Otomatik",
|
||||
"save": "Kaydet",
|
||||
"auto_success": "Otomatik yapılandırma başarıyla etkinleştirildi",
|
||||
"auto_failed": "Otomatik yapılandırma etkinleştirilemedi",
|
||||
"save_success": "Güvenlik yaması başarıyla kaydedildi",
|
||||
"save_failed": "Güvenlik yaması kaydedilemedi",
|
||||
"value_empty": "Güvenlik yaması yapılandırması devre dışı bırakıldı",
|
||||
"invalid_all": "Geçersiz format",
|
||||
"invalid_boot": "Geçersiz boot formatı",
|
||||
"invalid_system": "Geçersiz system formatı",
|
||||
"invalid_vendor": "Geçersiz vendor formatı"
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,10 @@
|
||||
"deselect_unnecessary_description": "非必要分类:Xposed 模块、root 管理器、与 root 相关的应用,以及从不检查 bootloader 状态的通用应用。此功能需连网使用。",
|
||||
"set_keybox": "设置 AOSP & 有效密钥",
|
||||
"set_keybox_description": "替换 Tricky Store 的密钥(keybox.xml)。如果没有有效密钥,将替换为 AOSP 密钥。有效密钥选项需连网使用。",
|
||||
"set_custom_keybox": "设置自定义密钥",
|
||||
"set_custom_keybox_description": "从设备存储导入自定义密钥。仅支持 xml 文件。",
|
||||
"set_security_patch": "设置安全补丁",
|
||||
"set_security_patch_description": "设置自定义安全补丁。自动配置将使用 PIF 模块的安全补丁,默认启用。留空保存则禁用自动配置。",
|
||||
"set_verified_boot_hash": "设置哈希值",
|
||||
"set_verified_boot_hash_description": "从 Key Attestation Demo 获取 verifiedBootHash(哈希值)。通过重置 ro.boot.vbmeta.digest 修复异常 boot 状态。"
|
||||
},
|
||||
@@ -45,6 +49,8 @@
|
||||
"deselect_unnecessary": "取消选择非必应用",
|
||||
"set_aosp_keybox": "设置 AOSP 密钥",
|
||||
"set_valid_keybox": "设置有效密钥",
|
||||
"set_custom_keybox": "设置自定义密钥",
|
||||
"set_security_patch": "设置安全补丁",
|
||||
"set_verified_boot_hash": "设置哈希值",
|
||||
"about": "关于"
|
||||
},
|
||||
@@ -81,6 +87,24 @@
|
||||
"installed": "安装完成,重启生效",
|
||||
"install_fail": "安装失败,请手动更新",
|
||||
"rebooting": "正在重启...",
|
||||
"reboot_fail": "重启失败,请手动重启"
|
||||
"reboot_fail": "重启失败,请手动重启",
|
||||
"custom_key_set": "成功设置自定义密钥",
|
||||
"custom_key_set_error": "设置自定义密钥失败",
|
||||
"no_file_selected": "未选择文件"
|
||||
},
|
||||
"security_patch": {
|
||||
"title": "安全补丁",
|
||||
"advanced_mode": "高级",
|
||||
"auto": "自动",
|
||||
"save": "保存",
|
||||
"auto_success": "自动配置成功启用",
|
||||
"auto_failed": "无法启用自动配置",
|
||||
"save_success": "安全补丁成功保存",
|
||||
"save_failed": "保存安全补丁失败",
|
||||
"value_empty": "安全补丁配置已禁用",
|
||||
"invalid_all": "无效格式",
|
||||
"invalid_boot": "无效 boot 格式",
|
||||
"invalid_system": "无效 system 格式",
|
||||
"invalid_vendor": "无效 vendor 格式"
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,10 @@
|
||||
"deselect_unnecessary_description": "非必要分類:Xposed 模組、root 管理器、與 root 相關的應用,以及從不檢查 bootloader 狀態的通用應用。此功能需連網使用。",
|
||||
"set_keybox": "設置 AOSP & 有效密鑰",
|
||||
"set_keybox_description": "替換 Tricky Store 的密鑰(keybox.xml)。如果沒有有效密鑰,將替換為 AOSP 密鑰。有效密鑰選項需連網使用。",
|
||||
"set_custom_keybox": "設置自定義密鑰",
|
||||
"set_custom_keybox_description": "從設備存儲導入自定義密鑰。僅支持 xml 文件。",
|
||||
"set_security_patch": "設置安全補丁",
|
||||
"set_security_patch_description": "設置自定義安全補丁。自動配置將使用 PIF 模組的安全補丁,預設啟用。留空保存則禁用自動配置。",
|
||||
"set_verified_boot_hash": "設置哈希值",
|
||||
"set_verified_boot_hash_description": "從 Key Attestation Demo 獲取 verifiedBootHash(哈希值)。通過重置 ro.boot.vbmeta.digest 修復異常 boot 狀態。"
|
||||
},
|
||||
@@ -45,6 +49,8 @@
|
||||
"deselect_unnecessary": "取消選擇非必要應用",
|
||||
"set_aosp_keybox": "設置 AOSP 密鑰",
|
||||
"set_valid_keybox": "設置有效密鑰",
|
||||
"set_custom_keybox": "設置自定義密鑰",
|
||||
"set_security_patch": "設置安全補丁",
|
||||
"set_verified_boot_hash": "設置哈希值",
|
||||
"about": "關於"
|
||||
},
|
||||
@@ -81,6 +87,24 @@
|
||||
"installed": "安裝完成,重啟生效",
|
||||
"install_fail": "安裝失敗,請手動更新",
|
||||
"rebooting": "正在重啟...",
|
||||
"reboot_fail": "重啟失敗,請手動重啟"
|
||||
"reboot_fail": "重啟失敗,請手動重啟",
|
||||
"custom_key_set": "成功設置自定義密鑰",
|
||||
"custom_key_set_error": "設置自定義密鑰失敗",
|
||||
"no_file_selected": "未選擇文件"
|
||||
},
|
||||
"security_patch": {
|
||||
"title": "安全補丁",
|
||||
"advanced_mode": "進階",
|
||||
"auto": "自動",
|
||||
"save": "保存",
|
||||
"auto_success": "自動配置成功啟用",
|
||||
"auto_failed": "無法啟用自動配置",
|
||||
"save_success": "安全補丁成功保存",
|
||||
"save_failed": "保存安全補丁失敗",
|
||||
"value_empty": "安全補丁配置已禁用",
|
||||
"invalid_all": "無效格式",
|
||||
"invalid_boot": "無效 boot 格式",
|
||||
"invalid_system": "無效 system 格式",
|
||||
"invalid_vendor": "無效 vendor 格式"
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { initializeAvailableLanguages, detectUserLanguage, loadTranslations, set
|
||||
import { aospkb } from './menu_option.js';
|
||||
import { searchMenuContainer, searchInput, clearBtn, setupMenuToggle } from './search_menu.js';
|
||||
import { updateCheck } from './update.js';
|
||||
import { securityPatch } from './security_patch.js';
|
||||
|
||||
// Header Elements
|
||||
const headerBlock = document.querySelector('.header-block');
|
||||
@@ -10,6 +11,7 @@ const title = document.querySelector('.header');
|
||||
export const noConnection = document.querySelector('.no-connection');
|
||||
|
||||
// Loading, Save and Prompt Elements
|
||||
const permissionPopup = document.getElementById('permission-popup');
|
||||
const loadingIndicator = document.querySelector('.loading');
|
||||
const prompt = document.getElementById('prompt');
|
||||
const floatingCard = document.querySelector('.floating-card');
|
||||
@@ -19,11 +21,12 @@ export const basePath = "set-path";
|
||||
export const appsWithExclamation = [];
|
||||
export const appsWithQuestion = [];
|
||||
const ADDITIONAL_APPS = [ "android", "com.android.vending", "com.google.android.gms", "io.github.vvb2060.keyattestation", "io.github.vvb2060.mahoshojo", "icu.nullptr.nativetest" ]; // Always keep default apps in target.txt
|
||||
const rippleClasses = ['.language-option', '.menu-button', '.menu-options li', '.search-card', '.card', '.update-card', '.link-icon', '.floating-btn', '.uninstall-container', '.boot-hash-save-button', '.boot-hash-value', '.reboot', '.install'];
|
||||
const rippleClasses = ['.language-option', '.menu-button', '.menu-options li', '.search-card', '.card', '.update-card', '.link-icon', '.floating-btn', '.uninstall-container', '.boot-hash-save-button', '.boot-hash-value', '.reboot', '.install', '.file-item', '.save-button', '.auto-button'];
|
||||
|
||||
// Variables
|
||||
let e = 0;
|
||||
let isRefreshing = false;
|
||||
let MMRL_API = true;
|
||||
|
||||
// Function to load the version from module.prop
|
||||
async function getModuleVersion() {
|
||||
@@ -66,6 +69,26 @@ async function refreshAppList() {
|
||||
isRefreshing = false;
|
||||
}
|
||||
|
||||
// Function to check tricky store version
|
||||
async 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") {
|
||||
console.log("Tricky Store version is 158 or higher, displaying element.");
|
||||
securityPatchElement.style.display = "flex";
|
||||
} else {
|
||||
console.log("Tricky Store version is below 158, leaving security patch element hidden.");
|
||||
}
|
||||
} catch (error) {
|
||||
toast("Failed to check Tricky Store version!");
|
||||
console.error("Error while checking Tricky Store version:", error);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to check if Magisk
|
||||
async function checkMagisk() {
|
||||
const selectDenylistElement = document.getElementById('select-denylist');
|
||||
@@ -162,15 +185,39 @@ document.querySelector(".uninstall-container").addEventListener("click", async (
|
||||
});
|
||||
|
||||
// Function to check if running in MMRL
|
||||
function adjustHeaderForMMRL() {
|
||||
async function checkMMRL() {
|
||||
if (typeof ksu !== 'undefined' && ksu.mmrl) {
|
||||
console.log("Running in MMRL");
|
||||
// Adjust elements position for MMRL
|
||||
title.style.top = 'var(--window-inset-top)';
|
||||
const insetTop = getComputedStyle(document.documentElement).getPropertyValue('--window-inset-top');
|
||||
const insetTopValue = parseInt(insetTop, 10);
|
||||
searchMenuContainer.style.top = `${insetTopValue + 40}px`;
|
||||
headerBlock.style.display = 'block';
|
||||
floatingCard.style.bottom = 'calc(var(--window-inset-bottom) + 50px)';
|
||||
|
||||
// Set status bars theme based on device theme
|
||||
try {
|
||||
$tricky_store.setLightStatusBars(!window.matchMedia('(prefers-color-scheme: dark)').matches)
|
||||
} catch (error) {
|
||||
console.log("Error setting status bars theme:", error)
|
||||
}
|
||||
|
||||
// Request API permission, supported version: 33045+
|
||||
try {
|
||||
$tricky_store.requestAdvancedKernelSUAPI();
|
||||
} catch (error) {
|
||||
console.log("Error requesting API:", error);
|
||||
}
|
||||
|
||||
// Check permissions
|
||||
try {
|
||||
await execCommand('ls /data/adb/modules');
|
||||
MMRL_API = true;
|
||||
} catch (error) {
|
||||
console.error('Permission check failed:', error);
|
||||
permissionPopup.classList.remove('hidden');
|
||||
MMRL_API = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,35 +231,35 @@ function hideFloatingBtn() {
|
||||
}
|
||||
|
||||
// Function to apply ripple effect
|
||||
function applyRippleEffect() {
|
||||
export function applyRippleEffect() {
|
||||
rippleClasses.forEach(selector => {
|
||||
document.querySelectorAll(selector).forEach(element => {
|
||||
if (element.dataset.rippleListener !== "true") {
|
||||
element.addEventListener("pointerdown", function (event) {
|
||||
if (isScrolling) return;
|
||||
if (modeActive) return;
|
||||
|
||||
|
||||
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.3 + (width / 800) * 0.3;
|
||||
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)";
|
||||
@@ -224,7 +271,7 @@ function applyRippleEffect() {
|
||||
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 = () => {
|
||||
@@ -273,8 +320,9 @@ window.addEventListener('scroll', () => {
|
||||
|
||||
// Initial load
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
await checkMMRL();
|
||||
if (!MMRL_API) return;
|
||||
hideFloatingBtn();
|
||||
adjustHeaderForMMRL();
|
||||
getModuleVersion();
|
||||
await initializeAvailableLanguages();
|
||||
const userLang = detectUserLanguage();
|
||||
@@ -283,8 +331,10 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
setupLanguageMenu();
|
||||
await fetchAppList();
|
||||
applyRippleEffect();
|
||||
checkTrickyStoreVersion();
|
||||
checkMagisk();
|
||||
updateCheck();
|
||||
securityPatch();
|
||||
loadingIndicator.style.display = "none";
|
||||
floatingBtn.style.opacity = '1';
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { basePath, execCommand, showPrompt, toast } from './main.js';
|
||||
import { basePath, execCommand, showPrompt, toast, applyRippleEffect } from './main.js';
|
||||
|
||||
// Function to check or uncheck all app
|
||||
function toggleCheckboxes(shouldCheck) {
|
||||
@@ -71,39 +71,272 @@ document.getElementById("deselect-unnecessary").addEventListener("click", async
|
||||
}
|
||||
});
|
||||
|
||||
// Function to backup previous keybox and set new keybox
|
||||
async function setKeybox(path) {
|
||||
try {
|
||||
await execCommand(`
|
||||
mv -f /data/adb/tricky_store/keybox.xml /data/adb/tricky_store/keybox.xml.bak 2>/dev/null
|
||||
echo '${path}' > /data/adb/tricky_store/keybox.xml
|
||||
chmod 644 /data/adb/tricky_store/keybox.xml
|
||||
`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Failed to set keybox:", error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to replace aosp kb
|
||||
export async function aospkb() {
|
||||
try {
|
||||
const sourcePath = `${basePath}common/.default`;
|
||||
const destinationPath = "/data/adb/tricky_store/keybox.xml";
|
||||
await execCommand(`mv -f ${destinationPath} ${destinationPath}.bak && xxd -r -p ${sourcePath} | base64 -d > ${destinationPath}`);
|
||||
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");
|
||||
} catch (error) {
|
||||
console.error("Failed to copy AOSP keybox:", error);
|
||||
} else {
|
||||
showPrompt("prompt.key_set_error", false);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to replace valid kb
|
||||
document.getElementById("extrakb").addEventListener("click", async () => {
|
||||
document.getElementById("validkb").addEventListener("click", async () => {
|
||||
setTimeout(async () => {
|
||||
await execCommand(`sh ${basePath}common/get_extra.sh --kb`);
|
||||
}, 100);
|
||||
const sourcePath = `${basePath}common/tmp/.extra`;
|
||||
const destinationPath = "/data/adb/tricky_store/keybox.xml";
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
const fileExists = await execCommand(`[ -f ${sourcePath} ] && echo "exists"`);
|
||||
try {
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
const fileExists = await execCommand(`[ -f ${sourcePath} ] && echo "exists"`);
|
||||
if (fileExists.trim() !== "exists") {
|
||||
throw new Error(".extra file not found");
|
||||
}
|
||||
await execCommand(`mv -f ${destinationPath} ${destinationPath}.bak && xxd -r -p ${sourcePath} | base64 -d > ${destinationPath}`);
|
||||
console.log("Valid keybox copied successfully.");
|
||||
showPrompt("prompt.valid_key_set");
|
||||
const source = await execCommand(`xxd -r -p ${sourcePath} | base64 -d`);
|
||||
const result = await setKeybox(source);
|
||||
if (result) {
|
||||
showPrompt("prompt.valid_key_set");
|
||||
} else {
|
||||
throw new Error("Failed to copy valid keybox");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to copy valid keybox:", error);
|
||||
await aospkb();
|
||||
showPrompt("prompt.no_valid_fallback", false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Add file selector dialog elements dynamically
|
||||
const fileSelector = document.createElement('div');
|
||||
fileSelector.className = 'file-selector-overlay';
|
||||
fileSelector.innerHTML = `
|
||||
<div class="file-selector">
|
||||
<div class="file-selector-header">
|
||||
<button class="back-button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M400-80 0-480l400-400 56 57-343 343 343 343-56 57Z"/></svg>
|
||||
</button>
|
||||
<div class="current-path">/storage/emulated/0/Download</div>
|
||||
<button class="close-selector">✕</button>
|
||||
</div>
|
||||
<div class="file-list"></div>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(fileSelector);
|
||||
|
||||
// Add styles for animations
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
.file-selector-overlay {
|
||||
transition: opacity 0.3s ease;
|
||||
opacity: 0;
|
||||
}
|
||||
.file-selector-overlay.visible {
|
||||
opacity: 1;
|
||||
}
|
||||
.file-list {
|
||||
transition: transform 0.3s ease, opacity 0.3s ease;
|
||||
}
|
||||
.file-list.switching {
|
||||
transform: scale(0.95);
|
||||
opacity: 0;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
|
||||
let currentPath = '/storage/emulated/0/Download';
|
||||
|
||||
function updateCurrentPath() {
|
||||
const currentPathElement = document.querySelector('.current-path');
|
||||
const segments = currentPath.split('/').filter(Boolean);
|
||||
|
||||
// Create spans with data-path attribute for each segment
|
||||
const pathHTML = segments.map((segment, index) => {
|
||||
const fullPath = '/' + segments.slice(0, index + 1).join('/');
|
||||
return `<span class="path-segment" data-path="${fullPath}">${segment}</span>`;
|
||||
}).join('<span class="separator">›</span>');
|
||||
|
||||
currentPathElement.innerHTML = pathHTML;
|
||||
currentPathElement.scrollTo({
|
||||
left: currentPathElement.scrollWidth,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
|
||||
// Function to list files in directory
|
||||
async function listFiles(path, skipAnimation = false) {
|
||||
const fileList = document.querySelector('.file-list');
|
||||
if (!skipAnimation) {
|
||||
fileList.classList.add('switching');
|
||||
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 => ({
|
||||
path: item,
|
||||
name: item.split('/').pop(),
|
||||
isDirectory: !item.endsWith('.xml')
|
||||
}));
|
||||
fileList.innerHTML = '';
|
||||
|
||||
// Add back button item if not in root directory
|
||||
if (currentPath !== '/storage/emulated/0') {
|
||||
const backItem = document.createElement('div');
|
||||
backItem.className = 'file-item';
|
||||
backItem.innerHTML = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24">
|
||||
<path d="M141-160q-24 0-42-18.5T81-220v-520q0-23 18-41.5t42-18.5h280l60 60h340q23 0 41.5 18.5T881-680v460q0 23-18.5 41.5T821-160H141Z"/>
|
||||
</svg>
|
||||
<span>..</span>
|
||||
`;
|
||||
backItem.addEventListener('click', async () => {
|
||||
currentPath = currentPath.split('/').slice(0, -1).join('/');
|
||||
if (currentPath === '') currentPath = '/storage/emulated/0';
|
||||
const currentPathElement = document.querySelector('.current-path');
|
||||
currentPathElement.innerHTML = currentPath.split('/').filter(Boolean).join('<span class="separator">›</span>');
|
||||
currentPathElement.scrollTo({
|
||||
left: currentPathElement.scrollWidth,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
await listFiles(currentPath);
|
||||
});
|
||||
|
||||
fileList.appendChild(backItem);
|
||||
}
|
||||
items.forEach(item => {
|
||||
if (item.path === path) return;
|
||||
const itemElement = document.createElement('div');
|
||||
itemElement.className = 'file-item';
|
||||
itemElement.innerHTML = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24">
|
||||
${item.isDirectory ?
|
||||
'<path d="M141-160q-24 0-42-18.5T81-220v-520q0-23 18-41.5t42-18.5h280l60 60h340q23 0 41.5 18.5T881-680v460q0 23-18.5 41.5T821-160H141Z"/>' :
|
||||
'<path d="M320-240h320v-80H320v80Zm0-160h320v-80H320v80ZM240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h320l240 240v480q0 33-23.5 56.5T720-80H240Zm280-520v-200H240v640h480v-440H520ZM240-800v200-200 640-640Z"/>'}
|
||||
</svg>
|
||||
<span>${item.name}</span>
|
||||
`;
|
||||
itemElement.addEventListener('click', async () => {
|
||||
if (item.isDirectory) {
|
||||
currentPath = item.path;
|
||||
const currentPathElement = document.querySelector('.current-path');
|
||||
currentPathElement.innerHTML = currentPath.split('/').filter(Boolean).join('<span class="separator">›</span>');
|
||||
currentPathElement.scrollTo({
|
||||
left: currentPathElement.scrollWidth,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
await listFiles(item.path);
|
||||
} else {
|
||||
const source = await execCommand(`cat "${item.path}"`);
|
||||
const result = await setKeybox(source);
|
||||
if (result) {
|
||||
fileSelector.style.display = 'none';
|
||||
showPrompt('prompt.custom_key_set');
|
||||
} else {
|
||||
showPrompt('prompt.custom_key_set_error');
|
||||
}
|
||||
}
|
||||
});
|
||||
fileList.appendChild(itemElement);
|
||||
});
|
||||
|
||||
if (!skipAnimation) {
|
||||
fileList.classList.remove('switching');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error listing files:', error);
|
||||
if (!skipAnimation) {
|
||||
fileList.classList.remove('switching');
|
||||
}
|
||||
}
|
||||
applyRippleEffect();
|
||||
updateCurrentPath();
|
||||
}
|
||||
|
||||
// Update click handler to use data-path attribute
|
||||
document.querySelector('.current-path').addEventListener('click', async (event) => {
|
||||
const segment = event.target.closest('.path-segment');
|
||||
if (!segment) return;
|
||||
|
||||
const targetPath = segment.dataset.path;
|
||||
if (!targetPath || targetPath === currentPath) return;
|
||||
|
||||
// Return if already at /storage/emulated/0
|
||||
const clickedSegment = segment.textContent;
|
||||
if ((clickedSegment === 'storage' || clickedSegment === 'emulated') &&
|
||||
currentPath === '/storage/emulated/0') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Always stay within /storage/emulated/0
|
||||
if (targetPath.split('/').length <= 3) {
|
||||
currentPath = '/storage/emulated/0';
|
||||
} else {
|
||||
currentPath = targetPath;
|
||||
}
|
||||
updateCurrentPath();
|
||||
await listFiles(currentPath);
|
||||
});
|
||||
|
||||
// Back button handler
|
||||
document.querySelector('.back-button').addEventListener('click', async () => {
|
||||
if (currentPath === '/storage/emulated/0') return;
|
||||
currentPath = currentPath.split('/').slice(0, -1).join('/');
|
||||
if (currentPath === '') currentPath = '/storage/emulated/0';
|
||||
const currentPathElement = document.querySelector('.current-path');
|
||||
currentPathElement.innerHTML = currentPath.split('/').filter(Boolean).join('<span class="separator">›</span>');
|
||||
currentPathElement.scrollTo({
|
||||
left: currentPathElement.scrollWidth,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
await listFiles(currentPath);
|
||||
});
|
||||
|
||||
// Close custom keybox selector
|
||||
document.querySelector('.close-selector').addEventListener('click', () => {
|
||||
fileSelector.classList.remove('visible');
|
||||
document.body.classList.remove("no-scroll");
|
||||
setTimeout(() => {
|
||||
fileSelector.style.display = 'none';
|
||||
}, 300);
|
||||
});
|
||||
fileSelector.addEventListener('click', (event) => {
|
||||
if (event.target === fileSelector) {
|
||||
fileSelector.classList.remove('visible');
|
||||
document.body.classList.remove("no-scroll");
|
||||
setTimeout(() => {
|
||||
fileSelector.style.display = 'none';
|
||||
}, 300);
|
||||
}
|
||||
});
|
||||
|
||||
// Open custom keybox selector
|
||||
document.getElementById('customkb').addEventListener('click', async () => {
|
||||
fileSelector.style.display = 'flex';
|
||||
document.body.classList.add("no-scroll");
|
||||
fileSelector.offsetHeight;
|
||||
fileSelector.classList.add('visible');
|
||||
currentPath = '/storage/emulated/0/Download';
|
||||
const currentPathElement = document.querySelector('.current-path');
|
||||
currentPathElement.innerHTML = currentPath.split('/').filter(Boolean).join('<span class="separator">›</span>');
|
||||
currentPathElement.scrollTo({
|
||||
left: currentPathElement.scrollWidth,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
await listFiles(currentPath, true);
|
||||
});
|
||||
|
||||
322
module/webui/scripts/security_patch.js
Normal file
322
module/webui/scripts/security_patch.js
Normal file
@@ -0,0 +1,322 @@
|
||||
import { basePath, execCommand, showPrompt } from './main.js';
|
||||
|
||||
const overlay = document.getElementById('security-patch-overlay');
|
||||
const card = document.getElementById('security-patch-card');
|
||||
const advancedToggle = document.getElementById('advanced-mode');
|
||||
const normalInputs = document.getElementById('normal-mode-inputs');
|
||||
const advancedInputs = document.getElementById('advanced-mode-inputs');
|
||||
const allPatchInput = document.getElementById('all-patch');
|
||||
const bootPatchInput = document.getElementById('boot-patch');
|
||||
const systemPatchInput = document.getElementById('system-patch');
|
||||
const vendorPatchInput = document.getElementById('vendor-patch');
|
||||
const autoButton = document.getElementById('auto-config');
|
||||
const saveButton = document.getElementById('save-patch');
|
||||
|
||||
// Show security patch dialog
|
||||
function showSecurityPatchDialog() {
|
||||
document.body.classList.add("no-scroll");
|
||||
overlay.style.display = 'block';
|
||||
card.style.display = 'block';
|
||||
setTimeout(() => {
|
||||
overlay.style.opacity = '1';
|
||||
card.style.opacity = '1';
|
||||
loadCurrentConfig();
|
||||
}, 10);
|
||||
}
|
||||
|
||||
// Hide security patch dialog
|
||||
function hideSecurityPatchDialog() {
|
||||
document.body.classList.remove("no-scroll");
|
||||
overlay.style.opacity = '0';
|
||||
card.style.opacity = '0';
|
||||
setTimeout(() => {
|
||||
overlay.style.display = 'none';
|
||||
card.style.display = 'none';
|
||||
}, 200);
|
||||
}
|
||||
|
||||
// Function to handle security patch operation
|
||||
async function handleSecurityPatch(mode, value = null) {
|
||||
if (mode === 'disable') {
|
||||
try {
|
||||
await execCommand(`
|
||||
sed -i "s/^auto_config=.*/auto_config=0/" /data/adb/security_patch
|
||||
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;
|
||||
}
|
||||
} else if (mode === 'manual') {
|
||||
try {
|
||||
await execCommand(`
|
||||
sed -i "s/^auto_config=.*/auto_config=0/" /data/adb/security_patch
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load current configuration
|
||||
async function loadCurrentConfig() {
|
||||
try {
|
||||
const result = await execCommand('cat /data/adb/security_patch');
|
||||
if (result) {
|
||||
const lines = result.split('\n');
|
||||
let autoConfig = '1', allValue = '0', systemValue = '0', bootValue = '0', vendorValue = '0';
|
||||
for (const line of lines) {
|
||||
if (line.startsWith('auto_config=')) {
|
||||
autoConfig = line.split('=')[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (autoConfig === '1') {
|
||||
allValue = null;
|
||||
systemValue = null;
|
||||
bootValue = null;
|
||||
vendorValue = null;
|
||||
overlay.classList.add('hidden');
|
||||
} 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');
|
||||
for (const line of trickyLines) {
|
||||
if (line.startsWith('all=')) {
|
||||
allValue = line.split('=')[1] || null;
|
||||
if (allValue !== null) allPatchInput.value = allValue;
|
||||
} else {
|
||||
allValue = null;
|
||||
}
|
||||
if (line.startsWith('system=')) {
|
||||
systemValue = line.split('=')[1] || null;
|
||||
if (systemValue !== null) systemPatchInput.value = systemValue;
|
||||
} else {
|
||||
systemValue = null;
|
||||
}
|
||||
if (line.startsWith('boot=')) {
|
||||
bootValue = line.split('=')[1] || null;
|
||||
if (bootValue !== null) bootPatchInput.value = bootValue;
|
||||
} else {
|
||||
bootValue = null;
|
||||
}
|
||||
if (line.startsWith('vendor=')) {
|
||||
vendorValue = line.split('=')[1] || null;
|
||||
if (vendorValue !== null) vendorPatchInput.value = vendorValue;
|
||||
} else {
|
||||
vendorValue = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
overlay.classList.add('hidden');
|
||||
}
|
||||
|
||||
// Check if in advanced mode
|
||||
if (autoConfig === '0' && allValue === null && (bootValue || systemValue || vendorValue)) {
|
||||
advancedToggle.checked = true;
|
||||
normalInputs.classList.add('hidden');
|
||||
advancedInputs.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load security patch config:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Unified date formatting function
|
||||
window.formatDate = function(input, type) {
|
||||
let value = input.value.replace(/-/g, '');
|
||||
let formatted = value.slice(0, 4);
|
||||
|
||||
// Allow 'no' input
|
||||
if (value === 'no') {
|
||||
input.value = 'no';
|
||||
input.setSelectionRange(2, 2);
|
||||
return 'no';
|
||||
}
|
||||
|
||||
if (value.startsWith('n')) {
|
||||
// Only allow 'o' after 'n'
|
||||
if (value.length > 1 && value[1] !== 'o') {
|
||||
value = 'n';
|
||||
}
|
||||
formatted = value.slice(0, 2);
|
||||
if (value.length > 2) {
|
||||
input.value = formatted;
|
||||
input.setSelectionRange(2, 2);
|
||||
return formatted;
|
||||
}
|
||||
} else {
|
||||
// Only allow numbers if not starting with 'n'
|
||||
const numbersOnly = value.replace(/\D/g, '');
|
||||
if (numbersOnly !== value) {
|
||||
input.value = numbersOnly;
|
||||
value = numbersOnly;
|
||||
formatted = numbersOnly.slice(0, 4);
|
||||
}
|
||||
|
||||
// Add hyphens on 5th and 7th character
|
||||
if (value.length >= 4) {
|
||||
formatted += '-'+ value.slice(4, 6);
|
||||
}
|
||||
if (value.length >= 6) {
|
||||
formatted += '-'+ value.slice(6, 8);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle backspace/delete
|
||||
const lastChar = value.slice(-1);
|
||||
if (lastChar === '-' || (isNaN(lastChar) && !['n'].includes(lastChar))) {
|
||||
formatted = formatted.slice(0, -1);
|
||||
}
|
||||
|
||||
// Update input value
|
||||
const startPos = input.selectionStart;
|
||||
input.value = formatted;
|
||||
const newLength = formatted.length;
|
||||
const shouldMoveCursor = (value.length === 4 || value.length === 6) && newLength > startPos;
|
||||
input.setSelectionRange(shouldMoveCursor ? newLength : startPos, shouldMoveCursor ? newLength : startPos);
|
||||
|
||||
return formatted;
|
||||
}
|
||||
|
||||
// Validate date format YYYY-MM-DD
|
||||
function isValidDateFormat(date) {
|
||||
if (date === 'no') return true;
|
||||
const regex = /^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$/;
|
||||
return regex.test(date);
|
||||
}
|
||||
|
||||
// Validate 6-digit format YYYYMM
|
||||
function isValid6Digit(value) {
|
||||
if (value === 'prop') return true;
|
||||
const regex = /^\d{6}$/;
|
||||
return regex.test(value);
|
||||
}
|
||||
|
||||
// Validate 8-digit format YYYYMMDD
|
||||
function isValid8Digit(value) {
|
||||
const regex = /^\d{8}$/;
|
||||
return regex.test(value);
|
||||
}
|
||||
|
||||
// Initialize event listeners
|
||||
export function securityPatch() {
|
||||
document.getElementById("security-patch").addEventListener("click", showSecurityPatchDialog);
|
||||
|
||||
// Toggle advanced mode
|
||||
advancedToggle.addEventListener('change', () => {
|
||||
normalInputs.classList.toggle('hidden');
|
||||
advancedInputs.classList.toggle('hidden');
|
||||
});
|
||||
|
||||
// Close on overlay click
|
||||
overlay.addEventListener('click', (e) => {
|
||||
if (e.target === overlay) {
|
||||
hideSecurityPatchDialog();
|
||||
}
|
||||
});
|
||||
|
||||
// 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(`sed -i "s/^auto_config=.*/auto_config=1/" /data/adb/security_patch`);
|
||||
// Reset inputs
|
||||
allPatchInput.value = '';
|
||||
systemPatchInput.value = '';
|
||||
bootPatchInput.value = '';
|
||||
vendorPatchInput.value = '';
|
||||
|
||||
// Uncheck advanced mode
|
||||
advancedToggle.checked = false;
|
||||
normalInputs.classList.remove('hidden');
|
||||
advancedInputs.classList.add('hidden');
|
||||
|
||||
showPrompt('security_patch.auto_success');
|
||||
}
|
||||
} catch (error) {
|
||||
showPrompt('security_patch.auto_failed', false);
|
||||
}
|
||||
hideSecurityPatchDialog();
|
||||
loadCurrentConfig();
|
||||
});
|
||||
|
||||
// Save button
|
||||
saveButton.addEventListener('click', async () => {
|
||||
if (!advancedToggle.checked) {
|
||||
// Normal mode validation
|
||||
const allValue = allPatchInput.value.trim();
|
||||
if (!allValue) {
|
||||
// Save empty value to disable auto config
|
||||
await handleSecurityPatch('disable');
|
||||
hideSecurityPatchDialog();
|
||||
return;
|
||||
}
|
||||
if (!isValid8Digit(allValue)) {
|
||||
showPrompt('security_patch.invalid_all', false);
|
||||
return;
|
||||
}
|
||||
const value = `all=${allValue}`;
|
||||
const result = await handleSecurityPatch('manual', value);
|
||||
if (result) {
|
||||
// Reset inputs
|
||||
systemPatchInput.value = '';
|
||||
bootPatchInput.value = '';
|
||||
vendorPatchInput.value = '';
|
||||
}
|
||||
} else {
|
||||
// Advanced mode validation
|
||||
const bootValue = formatDate(bootPatchInput, 'boot');
|
||||
const systemValue = systemPatchInput.value.trim();
|
||||
const vendorValue = vendorPatchInput.value.trim();
|
||||
|
||||
if (!bootValue && !systemValue && !vendorValue) {
|
||||
// Save empty values to disable auto config
|
||||
await handleSecurityPatch('disable');
|
||||
hideSecurityPatchDialog();
|
||||
return;
|
||||
}
|
||||
|
||||
if (systemValue && !isValid6Digit(systemValue)) {
|
||||
showPrompt('security_patch.invalid_system', false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bootValue && !isValidDateFormat(bootValue)) {
|
||||
showPrompt('security_patch.invalid_boot', false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (vendorValue && !isValidDateFormat(vendorValue)) {
|
||||
showPrompt('security_patch.invalid_vendor', false);
|
||||
return;
|
||||
}
|
||||
|
||||
const config = [
|
||||
systemValue ? `system=${systemValue}` : '',
|
||||
bootValue ? `boot=${bootValue}` : '',
|
||||
vendorValue ? `vendor=${vendorValue}` : ''
|
||||
].filter(Boolean);
|
||||
const value = config.filter(Boolean).join('\n');
|
||||
const result = await handleSecurityPatch('manual', value);
|
||||
if (result) {
|
||||
// Reset inputs
|
||||
allPatchInput.value = '';
|
||||
}
|
||||
}
|
||||
hideSecurityPatchDialog();
|
||||
loadCurrentConfig();
|
||||
});
|
||||
}
|
||||
@@ -41,6 +41,7 @@
|
||||
border: none;
|
||||
font-size: 18px;
|
||||
color: #ccc;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.link,
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
border-radius: 15px;
|
||||
text-align: left;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.close-update {
|
||||
@@ -182,7 +183,7 @@
|
||||
border-radius: 50px 50px;
|
||||
opacity: 0;
|
||||
transform: scale(0);
|
||||
transition: all 0.4s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
transition: all 0.2s ease;
|
||||
z-index: 1200;
|
||||
}
|
||||
|
||||
@@ -278,7 +279,7 @@
|
||||
border: 2px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
transition: border-color 1s ease, transform 0.3s ease, background-color 0.4s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
transition: border-color 1s ease, transform 0.3s ease, background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.tick-symbol {
|
||||
|
||||
@@ -47,11 +47,11 @@ body {
|
||||
color: white;
|
||||
font-size: 15px;
|
||||
padding: 5px 10px;
|
||||
z-index: 2000;
|
||||
z-index: 2050;
|
||||
width: auto;
|
||||
max-width: calc(100% - 40px);
|
||||
transform: translateY(100%);
|
||||
transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.prompt.error {
|
||||
@@ -113,6 +113,138 @@ body {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.file-selector-overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: 2000;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.file-selector {
|
||||
width: 90%;
|
||||
max-width: 600px;
|
||||
height: 80vh;
|
||||
background-color: #fff;
|
||||
border-radius: 15px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.file-selector-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.current-path .separator {
|
||||
color: #6E6E6E;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.back-button {
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 5px;
|
||||
margin-right: 10px;
|
||||
fill: #6E6E6E;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.current-path {
|
||||
flex-grow: 1;
|
||||
font-size: 16px;
|
||||
overflow: scroll;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.close-selector {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 20px;
|
||||
color: #ccc;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.file-list {
|
||||
flex-grow: 1;
|
||||
overflow-y: auto;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.file-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
background-color: #fff;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.file-item svg {
|
||||
margin-right: 10px;
|
||||
fill: #6E6E6E;
|
||||
}
|
||||
|
||||
.file-item span {
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.permission-popup {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.85);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.permission-popup.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.permission-content {
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
width: 80%;
|
||||
max-width: 400px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.permission-content h2 {
|
||||
color: #333;
|
||||
margin-bottom: 20px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.permission-steps {
|
||||
text-align: left;
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
||||
.permission-steps p {
|
||||
color: #333;
|
||||
margin: 10px 0;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.ripple {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
@@ -138,4 +270,38 @@ body {
|
||||
background-color: #121212;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.file-selector {
|
||||
background-color: #343434;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.file-selector-header {
|
||||
border-bottom: 1px solid #6E6E6E;
|
||||
}
|
||||
|
||||
.file-item {
|
||||
background-color: #343434;
|
||||
}
|
||||
|
||||
.current-path .separator {
|
||||
color: #C2C2C2;
|
||||
}
|
||||
|
||||
.back-button {
|
||||
fill: #C2C2C2;
|
||||
}
|
||||
|
||||
.file-item svg {
|
||||
fill: #C2C2C2;
|
||||
}
|
||||
|
||||
.permission-content {
|
||||
background-color: #343434;
|
||||
}
|
||||
|
||||
.permission-content h2,
|
||||
.permission-steps p {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
width: calc(100% - 10px);
|
||||
max-width: 1100px;
|
||||
background-color: #F5F5F5;
|
||||
transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
transition: transform 0.2s ease;
|
||||
z-index: 1100;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
@@ -25,7 +25,7 @@
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 1100;
|
||||
transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
transition: transform 0.4s ease;
|
||||
height: var(--window-inset-top);
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
right: 5px;
|
||||
background-color: white;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
z-index: 1800;
|
||||
@@ -75,7 +75,7 @@
|
||||
overflow-y: auto;
|
||||
transform: translateY(-30px) scale(0);
|
||||
transform-origin: top right;
|
||||
transition: all 0.4s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.language-menu.show {
|
||||
@@ -149,7 +149,7 @@
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
opacity: 0;
|
||||
transition: opacity 0.4s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
transition: opacity 0.4s ease;
|
||||
}
|
||||
|
||||
.help-overlay.show {
|
||||
@@ -180,6 +180,7 @@
|
||||
border: none;
|
||||
font-size: 20px;
|
||||
color: #ccc;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.help-content {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
width: calc(100% - 20px);
|
||||
max-width: 1100px;
|
||||
z-index: 1000;
|
||||
transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
transition: transform 0.4s ease;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
left: 0;
|
||||
@@ -86,7 +86,7 @@
|
||||
display: inline-block;
|
||||
fill: #000;
|
||||
transform: rotate(0deg);
|
||||
transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.menu-icon.menu-open {
|
||||
@@ -110,11 +110,12 @@
|
||||
white-space: nowrap;
|
||||
visibility: hidden;
|
||||
transform: translateX(120%);
|
||||
transition: all 0.4s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
transition: all 0.2s ease;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#select-denylist {
|
||||
#select-denylist,
|
||||
#security-patch {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
181
module/webui/styles/security-patch.css
Normal file
181
module/webui/styles/security-patch.css
Normal file
@@ -0,0 +1,181 @@
|
||||
.security-patch-overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: 2000;
|
||||
transition: opacity 0.2s ease;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.security-patch-card {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 10%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background-color: white;
|
||||
padding: 30px;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
z-index: 2001;
|
||||
width: calc(90% - 60px);
|
||||
max-width: 300px;
|
||||
max-height: calc(80% - 60px);
|
||||
overflow-y: auto;
|
||||
transition: opacity 0.2s ease;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.security-patch-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.security-patch-header {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 26px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.advanced-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.advanced-toggle .checkbox-wrapper {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.advanced-toggle .checkbox {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.advanced-toggle .custom-checkbox {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 2px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
transition: border-color 1s ease, transform 0.3s ease, background-color 0.4s ease;
|
||||
}
|
||||
|
||||
.advanced-toggle .tick-symbol {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%) scale(0);
|
||||
opacity: 0;
|
||||
transition: transform 0.2s ease-out, opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.advanced-toggle .checkbox:checked + .custom-checkbox {
|
||||
border-color: #007bff;
|
||||
background-color: #007bff;
|
||||
transition: border-color 0.1s ease;
|
||||
animation: checked-bounce 0.3s ease-out;
|
||||
}
|
||||
|
||||
.advanced-toggle .checkbox:checked + .custom-checkbox .tick-symbol {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.input-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.input-group label {
|
||||
padding-top: 10px;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.input-group input {
|
||||
padding: 15px;
|
||||
background-color: #F5F5F5;
|
||||
border: 1px solid #ccc;
|
||||
outline-color: #007bff;
|
||||
border-radius: 10px;
|
||||
font-size: 16px;
|
||||
transition: border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
width: 100%;
|
||||
gap: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.auto-button, .save-button {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.auto-button {
|
||||
background-color: #ddd;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.save-button {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.security-patch-overlay {
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.security-patch-card {
|
||||
background-color: #343434;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.input-group label {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.input-group input {
|
||||
background-color: #232323;
|
||||
color: #fff;
|
||||
border: 1px solid #6E6E6E;
|
||||
}
|
||||
|
||||
.auto-button {
|
||||
background-color: #6E6E6E;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"versionCode": 320,
|
||||
"version": "v3.2",
|
||||
"zipUrl": "https://github.com/KOWX712/Tricky-Addon-Update-Target-List/releases/download/v3.2/TrickyAddonModule-v3.2.zip",
|
||||
"versionCode": 340,
|
||||
"version": "v3.4",
|
||||
"zipUrl": "https://github.com/KOWX712/Tricky-Addon-Update-Target-List/releases/download/v3.4/TrickyAddonModule-v3.4.zip",
|
||||
"changelog": "https://raw.githubusercontent.com/KOWX712/Tricky-Addon-Update-Target-List/main/changelog.md"
|
||||
}
|
||||
Reference in New Issue
Block a user