Skip to content

Commit 867d886

Browse files
committed
v1.0.2: evoker.qzz.io mirror, IPv4-first asfetch, custom keybox + file manager
- keybox/status moved to http://evoker.qzz.io - asfetch rewritten to connect IPv4-first (fixes keybox-missing / stuck downloads on IPv6-advertised networks); http+https, redirects, chunked, custom -H headers, -O alias - fingerprint: native crawl of Google Pixel servers (fast) as primary, with a bounded autopif4 fallback then shipped static props; never shows a bare "offline" (one "trying with fallback" line), bounded timeouts - WebUI: custom keybox toggle + built-in file manager (breadcrumb path, size/date, sort by name/newest/oldest); shows the current keybox name (evokerrkeyNN) from the repo meta - every fetch falls back asfetch -> busybox wget -> curl -> wget - removed the "recheck in ~1 min" Action line
1 parent 294596d commit 867d886

18 files changed

Lines changed: 1096 additions & 188 deletions

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# Force git to check them out with LF on every platform.
33
*.sh text eol=lf
44
*.rule text eol=lf
5+
*.prop text eol=lf
56
module.prop text eol=lf
67
target.txt text eol=lf
78
daemon text eol=lf

CHANGELOG.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,30 @@
11
# AlwaysStrong changelog
22

3+
## v1.0.2
4+
5+
New keybox mirror, a far more reliable fetcher, a custom-keybox file picker in the WebUI, and a faster, steadier Action.
6+
7+
**Keybox & status**
8+
- Moved to the new mirror: keybox from `http://evoker.qzz.io/key`, status from `/status`.
9+
- The WebUI status now shows which keybox is in use (e.g. `evokerrkey27`) alongside the health.
10+
11+
**Custom keybox (WebUI)**
12+
- New "Custom keybox" toggle — use your own keybox instead of the auto one.
13+
- Built-in file manager to pick a keybox from storage: breadcrumb path, folder navigation, file size + date, and sort (name / newest / oldest).
14+
- While custom keybox is on, the module stops auto-fetching (Action shows "custom keybox — skip fetch").
15+
16+
**Fingerprint**
17+
- The fingerprint is now fetched by a native crawl of the same Google servers PlayIntegrityFork uses — fast and reliable on devices where autopif4's busybox-wget crawl used to hang. autopif4 is kept as a bounded fallback, and shipped static fingerprints guarantee one always lands.
18+
- The Action never shows a bare "offline": a failed primary is shown once as "trying with fallback", and it drops through quickly (bounded timeouts).
19+
20+
**Fetcher (asfetch)**
21+
- Rewritten to connect IPv4-first — fixes "keybox missing" and stuck downloads on networks that advertise IPv6 in DNS but have no working IPv6 route.
22+
- Handles http + https, redirects, chunked responses, and custom request headers.
23+
- Every download (keybox, status, fingerprint crawl, WebUI) falls back across asfetch → busybox wget → curl → wget, so it works on every device.
24+
25+
**Misc**
26+
- Removed the "recheck in ~1 min" line from the Action output.
27+
328
## v1.0.1
429

530
Hotfix, same upstream as v1.0.0.

module/action.sh

Lines changed: 146 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
#!/system/bin/sh
22
# AlwaysStrong action button.
3-
# Refreshes fingerprint (autopif4), enforces STRONG settings, syncs security
4-
# patch, then restarts PI consumers. Runs the whole chain silently and prints
5-
# one clean, framed summary: device, security patch, fingerprint, keybox.
3+
# Shows each step progressively with status feedback.
64

75
case "$0" in
86
*/*) MODPATH=$(cd "${0%/*}" 2>/dev/null && pwd) ;;
@@ -11,65 +9,152 @@ esac
119
[ -z "$MODPATH" ] && MODPATH="$PWD"
1210
cd "$MODPATH" 2>/dev/null
1311

14-
# disable busybox ash standalone mode — must run in current shell, not subshell
1512
set +o standalone 2>/dev/null
1613
unset ASH_STANDALONE
1714

1815
CONFIG_DIR=/data/adb/tricky_store
19-
LINE="━━━━━━━━━━━━━━━━━━━━━━━━━"
16+
LINE="========================="
2017
VER=$(grep -m1 '^version=' "$MODPATH/module.prop" 2>/dev/null | cut -d= -f2-)
2118

22-
# one consistent row style for every line (success or failure)
2319
row() { echo " $1 $2"; }
2420

21+
# --- ABI + fetchers ---
22+
case "$(uname -m)" in
23+
aarch64) ABI=arm64-v8a ;;
24+
armv7*|armv8l) ABI=armeabi-v7a ;;
25+
*) ABI="" ;;
26+
esac
27+
ASFETCH=""
28+
[ -n "$ABI" ] && [ -x "$MODPATH/bin/$ABI/asfetch" ] && ASFETCH="$MODPATH/bin/$ABI/asfetch"
29+
BB=""
30+
for bb in /data/adb/magisk/busybox /data/adb/ksu/bin/busybox /data/adb/ap/bin/busybox \
31+
/data/adb/modules/busybox-ndk/system/*/busybox; do
32+
[ -x "$bb" ] && BB="$bb" && break
33+
done
34+
35+
# asfetch first (connects IPv4-first, works on IPv6-only-DNS networks); fall
36+
# through to busybox wget / curl if it ever fails on a host.
37+
dl_out() {
38+
if [ -n "$ASFETCH" ]; then $ASFETCH -T 20 "$1" 2>/dev/null && return 0; fi
39+
if [ -n "$BB" ]; then $BB wget -q -T 20 -O - "$1" 2>/dev/null && return 0; fi
40+
if command -v curl >/dev/null 2>&1; then curl -fsSL --max-time 20 "$1" 2>/dev/null && return 0; fi
41+
if command -v wget >/dev/null 2>&1; then wget -q -T 20 -O - "$1" 2>/dev/null && return 0; fi
42+
return 1
43+
}
44+
dl_to() {
45+
if [ -n "$ASFETCH" ]; then rm -f "$1"; $ASFETCH -T 60 -o "$1" "$2" 2>/dev/null; [ -s "$1" ] && return 0; fi
46+
if [ -n "$BB" ]; then rm -f "$1"; $BB wget -q -T 60 -O "$1" "$2" 2>/dev/null; [ -s "$1" ] && return 0; fi
47+
if command -v curl >/dev/null 2>&1; then rm -f "$1"; curl -fsSL --max-time 60 -o "$1" "$2" 2>/dev/null; [ -s "$1" ] && return 0; fi
48+
if command -v wget >/dev/null 2>&1; then rm -f "$1"; wget -q -T 60 -O "$1" "$2" 2>/dev/null; [ -s "$1" ] && return 0; fi
49+
return 1
50+
}
51+
52+
# --- Header ---
2553
echo ""
2654
echo " $LINE"
2755
row "🛡️" "AlwaysStrong ${VER}"
2856
echo " $LINE"
2957
echo ""
30-
row "" "initializing, please wait"
31-
echo " $LINE"
58+
row "" "initializing..."
59+
sleep 3
3260

33-
# --- target.txt + keybox (silent) ----------------------------------------
34-
# build_target_txt rewrites target.txt every tap: all user apps (pm -3) +
35-
# installed OEM wallet/store apps + forced GMS/GSF/Vending. Count what landed.
61+
# --- Step 1: Target list ---
3662
[ -x "$MODPATH/build_target_txt.sh" ] && \
3763
sh "$MODPATH/build_target_txt.sh" "$CONFIG_DIR/target.txt" >/dev/null 2>&1
3864
TGT_N=$(grep -cvE '^[[:space:]]*$' "$CONFIG_DIR/target.txt" 2>/dev/null)
39-
# Keybox: if we already hold a valid one, refresh it in the BACKGROUND so a
40-
# slow or unreachable mirror can't stall the Action (some networks reach
41-
# Google fine but not the keybox host). With no keybox yet, fetch synchronously
42-
# (still bounded by keybox_fetch's own wget timeout) because STRONG needs it now.
43-
if [ -x "$MODPATH/keybox_fetch.sh" ]; then
65+
row "🎯" "${TGT_N:-0} apps > target"
66+
sleep 1
67+
68+
# --- Step 2: Keybox ---
69+
# Custom-keybox mode (WebUI toggle): user supplied their own keybox, so we do
70+
# NOT fetch/overwrite it. Keep the note short.
71+
if [ -f "$CONFIG_DIR/custom_keybox" ]; then
72+
if [ -s "$CONFIG_DIR/keybox.xml" ] && head -c 4096 "$CONFIG_DIR/keybox.xml" | grep -q "Keybox"; then
73+
row "🔑" "custom keybox — skip fetch"
74+
row "ℹ️" "disable in webui for auto"
75+
else
76+
row "⚠️" "custom keybox not set"
77+
fi
78+
elif [ -x "$MODPATH/keybox_fetch.sh" ]; then
4479
if [ -s "$CONFIG_DIR/keybox.xml" ] && head -c 4096 "$CONFIG_DIR/keybox.xml" | grep -q "Keybox"; then
4580
sh "$MODPATH/keybox_fetch.sh" >/dev/null 2>&1 &
81+
row "🔑" "keybox ok"
4682
else
4783
sh "$MODPATH/keybox_fetch.sh" >/dev/null 2>&1
84+
if [ -s "$CONFIG_DIR/keybox.xml" ] && head -c 4096 "$CONFIG_DIR/keybox.xml" | grep -q "Keybox"; then
85+
row "🔑" "keybox updated"
86+
else
87+
row "⚠️" "keybox missing"
88+
fi
89+
fi
90+
else
91+
row "⚠️" "keybox fetch not available"
92+
fi
93+
sleep 1
94+
95+
# --- Step 3: Fingerprint ---
96+
# The fingerprint is fetched from Google's Pixel build servers. PlayIntegrityFork
97+
# (autopif4) does this with busybox wget, but its multi-step crawl hangs to its
98+
# timeout on some devices (~2 min wasted). So we run the SAME crawl ourselves
99+
# first (pif_native_fetch — busybox wget for Google is fast/reliable), and only
100+
# fall back to autopif4 (bounded), then an optional mirror, then shipped static
101+
# props. PIF itself still does the attestation spoofing; this only fetches the
102+
# fingerprint it consumes. A fingerprint is ALWAYS produced, and we never surface
103+
# a bare "offline" — a failed primary is shown as "trying fallback".
104+
FP_OK=0
105+
FP_SRC=""
106+
107+
# Primary: native crawl, bounded to 15s total so a slow network can't make it
108+
# grind through its ~7 requests — it drops to the fallback fast instead.
109+
if [ -x "$MODPATH/pif_native_fetch.sh" ]; then
110+
if command -v timeout >/dev/null 2>&1; then
111+
timeout 15 sh "$MODPATH/pif_native_fetch.sh" >"$CONFIG_DIR/autopif.log" 2>&1
112+
else
113+
sh "$MODPATH/pif_native_fetch.sh" >"$CONFIG_DIR/autopif.log" 2>&1
114+
fi
115+
if [ -s "$CONFIG_DIR/pif.prop" ] && grep -q "FINGERPRINT=" "$CONFIG_DIR/pif.prop"; then
116+
FP_OK=1; FP_SRC="native"
48117
fi
49118
fi
50119

51-
# --- autopif4: fetch a fresh Pixel fingerprint from Google ----------------
52-
# autopif4 pulls the latest Pixel build from several Google hosts (developer.
53-
# android.com, flash.android.com, content-flashstation-pa.googleapis.com, ...)
54-
# and exits non-zero if ANY single one fails — that is exactly what shows up
55-
# as "fingerprint cached (offline?)". Bound it with a timeout so a stalled
56-
# connection can't freeze the Action, retry once for transient failures, and
57-
# keep the real output in CONFIG_DIR/autopif.log (instead of /dev/null) so an
58-
# "offline" result is actually diagnosable.
59-
FP_OK=1
60-
if [ -f "$MODPATH/autopif4.sh" ]; then
61-
run_autopif() {
120+
if [ "$FP_OK" = 0 ]; then
121+
row "🔄" "trying with fallback"
122+
sleep 1
123+
124+
# Fallback A: autopif4 (PIF fork) — bounded to 10s so it can't stall the Action.
125+
if [ -f "$MODPATH/autopif4.sh" ]; then
62126
if command -v timeout >/dev/null 2>&1; then
63-
timeout 60 sh "$MODPATH/autopif4.sh" -s -m
127+
timeout 10 sh "$MODPATH/autopif4.sh" -s -m >>"$CONFIG_DIR/autopif.log" 2>&1 && FP_OK=1
64128
else
65-
sh "$MODPATH/autopif4.sh" -s -m
129+
sh "$MODPATH/autopif4.sh" -s -m >>"$CONFIG_DIR/autopif.log" 2>&1 && FP_OK=1
130+
fi
131+
[ "$FP_OK" = 1 ] && FP_SRC="pif"
132+
fi
133+
134+
# Fallback B: shipped static fingerprints (alternate between 2 each tap) —
135+
# guarantees a fingerprint even with no network at all.
136+
if [ "$FP_OK" = 0 ]; then
137+
IDX_FILE="$CONFIG_DIR/.fp_idx"
138+
IDX=$(cat "$IDX_FILE" 2>/dev/null)
139+
if [ "$IDX" = "2" ]; then IDX=1; else IDX=2; fi
140+
echo "$IDX" > "$IDX_FILE" 2>/dev/null
141+
142+
FB="$MODPATH/pif_fallback_${IDX}.prop"
143+
if [ -s "$FB" ] && grep -q "FINGERPRINT=" "$FB"; then
144+
cp -f "$FB" "$CONFIG_DIR/pif.prop"
145+
FP_OK=1; FP_SRC="local"
66146
fi
67-
}
68-
run_autopif >"$CONFIG_DIR/autopif.log" 2>&1 \
69-
|| { sleep 2; run_autopif >>"$CONFIG_DIR/autopif.log" 2>&1 || FP_OK=0; }
147+
fi
70148
fi
71149

72-
# --- enforce STRONG-friendly spoof settings on every pif variant ----------
150+
case "$FP_SRC" in
151+
pif|native) row "🌐" "fingerprint ok" ;;
152+
local) row "🌐" "fingerprint ok (local)" ;;
153+
*) row "⚠️" "fingerprint failed" ;;
154+
esac
155+
sleep 1
156+
157+
# --- Step 4: Spoof settings + security patch ---
73158
for f in "$MODPATH/custom.pif.prop" "$MODPATH/pif.prop" \
74159
"$CONFIG_DIR/custom.pif.prop" "$CONFIG_DIR/pif.prop"; do
75160
[ -f "$f" ] || continue
@@ -84,42 +169,41 @@ for f in "$MODPATH/custom.pif.prop" "$MODPATH/pif.prop" \
84169
done
85170
done
86171

87-
# --- sync security patch (attestation + Build) ---------------------------
88-
# Pass "boot" so this ALSO resetprops ro.build.version.security_patch (and the
89-
# vendor/system variants) to match the spoofed fingerprint. Without it the raw
90-
# system prop only gets refreshed at boot, so after an Action-driven fingerprint
91-
# bump the TEE patch (security_patch.txt) moves ahead while the system prop stays
92-
# at the device's real patch — an inconsistency that both looks like "patch not
93-
# updating" and can weaken the STRONG verdict. resetprop is available (root) in
94-
# the Action context, same as post-fs-data.
95172
PATCH=""
96173
[ -f "$MODPATH/sync_patch.sh" ] && PATCH=$(sh "$MODPATH/sync_patch.sh" boot 2>/dev/null)
97174

98-
# --- WebUI: Magisk only → fetch KsuWebUI from GitHub if absent (silent) ----
99-
dl_out() {
100-
if command -v curl >/dev/null 2>&1; then curl -fsSL --max-time 20 "$1"
101-
elif [ -x /data/adb/magisk/busybox ]; then /data/adb/magisk/busybox wget -q -T 20 -O - "$1"
102-
elif command -v wget >/dev/null 2>&1; then wget -q -T 20 -O - "$1"
103-
else return 1; fi
104-
}
105-
dl_to() {
106-
if command -v curl >/dev/null 2>&1; then curl -fsSL --max-time 60 -o "$1" "$2"
107-
elif [ -x /data/adb/magisk/busybox ]; then /data/adb/magisk/busybox wget -q -T 60 -O "$1" "$2"
108-
elif command -v wget >/dev/null 2>&1; then wget -q -T 60 -O "$1" "$2"
109-
else return 1; fi
175+
pick_pif() {
176+
for f in "$CONFIG_DIR/custom.pif.prop" "$MODPATH/custom.pif.prop" \
177+
"$CONFIG_DIR/pif.prop" "$MODPATH/pif.prop"; do
178+
[ -s "$f" ] && { echo "$f"; return 0; }
179+
done
180+
return 1
110181
}
111-
# Only Magisk needs the standalone WebUI app. KSU/KSU-Next/APatch host the
112-
# webroot natively from their own manager, so skip them. The APK download used
113-
# to run inline, which blocked the Action button for up to a minute on Magisk
114-
# on every tap the app wasn't installed yet. Do it in the BACKGROUND so the
115-
# summary prints immediately; a lock file keeps repeated taps from stacking
116-
# downloads, and a stale lock (tap that never finished) is cleared after 5 min.
117-
WEBUI_MSG=""
182+
PIF=$(pick_pif)
183+
MD=$(grep -m1 '^MODEL=' "$PIF" 2>/dev/null | cut -d= -f2-)
184+
[ -z "$PATCH" ] && PATCH=$(grep -m1 '^SECURITY_PATCH=' "$PIF" 2>/dev/null | cut -d= -f2-)
185+
186+
row "🗓️" "${PATCH:-unknown}"
187+
sleep 1
188+
189+
# --- Step 5: Device ---
190+
row "📱" "${MD:-unknown}"
191+
sleep 1
192+
193+
# --- Restart PI + status ---
194+
killall -9 com.google.android.gms.unstable 2>/dev/null
195+
killall -9 com.android.vending 2>/dev/null
196+
am force-stop com.android.vending >/dev/null 2>&1
197+
198+
if [ -x "$MODPATH/status_fetch.sh" ]; then
199+
MODPATH="$MODPATH" sh "$MODPATH/status_fetch.sh" manual >/dev/null 2>&1
200+
fi
201+
202+
# --- WebUI: Magisk only (background, silent) ---
118203
if [ -d /data/adb/magisk ] && [ "$KSU" != "true" ] && [ "$APATCH" != "true" ]; then
119204
PKG=io.github.a13e300.ksuwebui
120205
[ -n "$(find "$MODPATH/.webui_busy" -mmin +5 2>/dev/null)" ] && rm -f "$MODPATH/.webui_busy" 2>/dev/null
121206
if ! pm path "$PKG" >/dev/null 2>&1 && [ ! -f "$MODPATH/.webui_busy" ]; then
122-
WEBUI_MSG="📲|installing WebUI app (background)"
123207
: > "$MODPATH/.webui_busy"
124208
{
125209
T=/data/local/tmp/.aswebui.apk
@@ -136,48 +220,7 @@ if [ -d /data/adb/magisk ] && [ "$KSU" != "true" ] && [ "$APATCH" != "true" ]; t
136220
fi
137221
fi
138222

139-
# --- restart PI (silent) -------------------------------------------------
140-
killall -9 com.google.android.gms.unstable 2>/dev/null
141-
killall -9 com.android.vending 2>/dev/null
142-
am force-stop com.android.vending >/dev/null 2>&1
143-
144-
# --- update module.prop status indicator ---------------------------------
145-
if [ -x "$MODPATH/status_fetch.sh" ]; then
146-
MODPATH="$MODPATH" sh "$MODPATH/status_fetch.sh" manual >/dev/null 2>&1
147-
fi
148-
149-
# --- summary -------------------------------------------------------------
150-
pick_pif() {
151-
for f in "$CONFIG_DIR/custom.pif.prop" "$MODPATH/custom.pif.prop" \
152-
"$CONFIG_DIR/pif.prop" "$MODPATH/pif.prop"; do
153-
[ -s "$f" ] && { echo "$f"; return 0; }
154-
done
155-
return 1
156-
}
157-
PIF=$(pick_pif)
158-
MD=$(grep -m1 '^MODEL=' "$PIF" 2>/dev/null | cut -d= -f2-)
159-
[ -z "$PATCH" ] && PATCH=$(grep -m1 '^SECURITY_PATCH=' "$PIF" 2>/dev/null | cut -d= -f2-)
160-
161-
row "📱" "${MD:-unknown}"
162-
row "🗓️" "${PATCH:-unknown}"
163-
164-
if [ "$FP_OK" = 1 ]; then
165-
row "🌐" "fingerprint fresh"
166-
else
167-
row "⚠️" "fingerprint cached (offline?)"
168-
fi
169-
170-
KB="$CONFIG_DIR/keybox.xml"
171-
if [ -s "$KB" ] && head -c 4096 "$KB" | grep -q "Keybox"; then
172-
row "🔑" "keybox ok"
173-
else
174-
row "⚠️" "keybox missing"
175-
fi
176-
177-
[ -n "$TGT_N" ] && row "🎯" "${TGT_N} apps → target"
178-
179-
[ -n "$WEBUI_MSG" ] && row "${WEBUI_MSG%%|*}" "${WEBUI_MSG#*|}"
180-
223+
# --- Done ---
181224
echo " $LINE"
182225
row "" "done"
183226
echo " $LINE"

module/customize.sh

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ for f in module.prop service.sh post-fs-data.sh action.sh \
6565
uninstall.sh common_func.sh common_setup.sh sepolicy.rule \
6666
keybox_fetch.sh build_target_txt.sh status_fetch.sh description.txt \
6767
rom_spoof_block.sh conflict_scan.sh sync_patch.sh \
68-
autopif4.sh killpi.sh migrate.sh \
68+
autopif4.sh killpi.sh migrate.sh pif_native_fetch.sh \
69+
pif_fallback_1.prop pif_fallback_2.prop \
6970
app_replace_list.txt example.pif.prop target.txt daemon ; do
7071
install_file "$f" "$MODPATH"
7172
done
@@ -115,6 +116,12 @@ else
115116
ui_print "warning: no aswatcher binary for $ABI_DIR"
116117
fi
117118

119+
# --- asfetch native HTTPS fetcher (arm devices only; TLS fallback for CDNs)
120+
if unzip -l "$ZIPFILE" 2>/dev/null | grep -q "bin/$ABI_DIR/asfetch"; then
121+
install_file "bin/$ABI_DIR/asfetch" "$MODPATH/bin/$ABI_DIR"
122+
chmod 755 "$MODPATH/bin/$ABI_DIR/asfetch"
123+
fi
124+
118125
chmod 755 "$MODPATH/daemon" "$MODPATH/supervisor" "$MODPATH/inject" \
119126
"$MODPATH"/*.sh 2>/dev/null
120127

0 commit comments

Comments
 (0)