Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## Unreleased

### Features
- Added TEESimulator v4 support for profile apps, keyboxes, and patch levels without replacing its WebUI. Multi-profile setups can select the managed profile in this addon's WebUI.

## v5.53.1 (2026-05-01)

### Bug Fixes
Expand Down
31 changes: 22 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ A single native daemon manages all background tasks — if anything dies, it res
| **APatch** | 11159+ | Built-in |
| **Magisk** | 20.4+ | [KSUWebUIStandalone](https://github.com/5ec1cff/KSUWebUIStandalone) or [WebUI-X](https://github.com/5ec1cff/WebUI-X) required |

**Requires:** [TEESimulator](https://github.com/JingMatrix/TEESimulator) or [TrickyStore](https://github.com/5ec1cff/TrickyStore) installed as the attestation engine.
**Requires:** [TEESimulator v4](https://github.com/JingMatrix/TEESimulator) or [TrickyStore](https://github.com/5ec1cff/TrickyStore) as the attestation engine.

---

Expand All @@ -144,7 +144,15 @@ During install, press **Vol−** for manual target mode (GMS/GSF only) or **Vol+

Conflicting modules are detected and `rm -rf`'d at install time, so an old TA fork or competing keybox/VBHash module is removed automatically.

The module captures VBHash, builds the exclude list, generates `target.txt`, fetches a valid keybox, sets security patch dates, and starts the daemon. Nothing else to do.
The module captures VBHash, configures protected apps, manages the keybox and patch levels, and starts the daemon. With TEESimulator v4, changes are applied only to the selected native profile.

TEESimulator and Tricky Addon Enhanced keep separate WebUIs.

One TEESimulator profile is selected automatically. With multiple profiles, choose one under **Tricky Addon Enhanced → Automation Settings → TEESimulator Profile**, or run:

```sh
ta-enhanced automation select-profile PROFILE_NAME
```

---

Expand Down Expand Up @@ -183,7 +191,7 @@ ta-enhanced config get keybox.source
ta-enhanced config set keybox.interval 3600
```

Config lives at `/data/adb/tricky_store/config.toml` and is preserved across reinstalls.
Addon config lives at `/data/adb/tricky_store/ta-enhanced/config.toml` and is preserved across reinstalls.

<details>
<summary><b>Config Reference</b></summary>
Expand All @@ -195,7 +203,7 @@ Config lives at `/data/adb/tricky_store/config.toml` and is preserved across rei
| `keybox.interval` | `300` | Seconds between fetch attempts |
| `security_patch.auto_update` | `true` | Auto patch date updates |
| `security_patch.interval` | `86400` | Seconds between patch checks |
| `automation.enabled` | `true` | Auto target.txt population |
| `automation.enabled` | `true` | Auto-populate TrickyStore targets or TEESimulator profile apps |
| `automation.use_inotify` | `true` | Use inotify for instant app detection |
| `health.enabled` | `true` | Attestation engine health monitor |
| `health.interval` | `10` | Seconds between health checks |
Expand All @@ -208,13 +216,18 @@ Config lives at `/data/adb/tricky_store/config.toml` and is preserved across rei
<summary><b>File Locations</b></summary>

```
/data/adb/teesim/ # TEESimulator-owned files
├── config.json # Profiles, apps, and patch levels
└── *.xml # Profile keyboxes

/data/adb/tricky_store/
├── config.toml # Module configuration
├── target.txt # Apps to protect
├── keybox.xml # Current keybox
├── keybox.xml.bak # Keybox backup
├── security_patch.txt # Patch dates
├── target.txt # TrickyStore target list / TEESimulator UI mirror
├── keybox.xml # TrickyStore current keybox
├── keybox.xml.bak # TrickyStore keybox backup
├── security_patch.txt # TrickyStore patch dates
├── .health_state # Health monitor state
└── ta-enhanced/
└── config.toml # Addon configuration

/data/adb/Tricky-addon-enhanced/logs/
├── daemon.log # Unified daemon log
Expand Down
9 changes: 6 additions & 3 deletions action.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ APK_PATH="$TMP_DIR/base.apk"

. "$MODPATH/common/common.sh"

WEBUI_MODULE_ID="tricky_store"
[ "$ENGINE" = "teesim" ] && WEBUI_MODULE_ID="TA_enhanced"

download() {
PATH=/data/adb/magisk:/data/data/com.termux/files/usr/bin:$PATH
if command -v curl >/dev/null 2>&1; then
Expand Down Expand Up @@ -47,16 +50,16 @@ get_webui() {
rm -f "$APK_PATH"

echo "- Launching WebUI..."
am start -n "io.github.a13e300.ksuwebui/.WebUIActivity" -e id "tricky_store"
am start -n "io.github.a13e300.ksuwebui/.WebUIActivity" -e id "$WEBUI_MODULE_ID"
}

if pm path io.github.a13e300.ksuwebui >/dev/null 2>&1; then
echo "- Launching WebUI in KSUWebUIStandalone..."
am start -n "io.github.a13e300.ksuwebui/.WebUIActivity" -e id "tricky_store"
am start -n "io.github.a13e300.ksuwebui/.WebUIActivity" -e id "$WEBUI_MODULE_ID"
elif pm path com.dergoogler.mmrl.wx > /dev/null 2>&1; then
echo "- Launching WebUI in WebUI X..."
am start -n "com.dergoogler.mmrl.wx/.ui.activity.webui.WebUIActivity" \
-e MOD_ID "tricky_store"
-e MOD_ID "$WEBUI_MODULE_ID"
else
echo "! No WebUI app found"
get_webui
Expand Down
Binary file modified bin/x86/ta-enhanced
Binary file not shown.
Binary file modified bin/x86_64/ta-enhanced
Binary file not shown.
4 changes: 3 additions & 1 deletion common/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ RP="/data/adb/tricky_store/ta-enhanced/bin/resetprop-rs"
TS="/data/adb/modules/tricky_store"
TS_DIR="/data/adb/tricky_store"

# TEESimulator v4 owns /data/adb/teesim and its own WebUI.
. "$MODDIR/common/detect_engine.sh"

# Unified log directory -- shell and Rust daemon both log here
LOG_BASE_DIR="/data/adb/tricky_store/ta-enhanced/logs"
mkdir -p "$LOG_BASE_DIR" 2>/dev/null || true
Expand Down Expand Up @@ -157,4 +160,3 @@ ensure_prop() {
_log "ERROR" "Failed to ensure: $name"
fi
}

15 changes: 15 additions & 0 deletions common/detect_engine.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Shared attestation-engine detection. Keep this in sync with rust/src/engine.rs.
ENGINE="tricky_store"
ENGINE_MODULE="/data/adb/modules/tricky_store"

for _tee_candidate in /data/adb/modules/teesim /data/adb/modules_update/teesim; do
[ -d "$_tee_candidate" ] || continue
[ -f "$_tee_candidate/remove" ] && continue
[ -f "$_tee_candidate/module.prop" ] || continue
grep -q '^id=teesim$' "$_tee_candidate/module.prop" 2>/dev/null || continue
ENGINE="teesim"
ENGINE_MODULE="$_tee_candidate"
break
done

unset _tee_candidate
47 changes: 40 additions & 7 deletions customize.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ SKIPUNZIP=0
DEBUG=false
COMPATH="$MODPATH/common"
TS="/data/adb/modules/tricky_store"
. "$MODPATH/common/detect_engine.sh"
SCRIPT_DIR="/data/adb/tricky_store"
CONFIG_DIR="$SCRIPT_DIR/target_list_config"
MODID=$(grep_prop id "$TMPDIR/module.prop")
Expand Down Expand Up @@ -38,7 +39,10 @@ else
abort " "
fi

if [ -d "$TS" ]; then
if [ "$ENGINE" = "teesim" ]; then
engine_name=$(grep_prop name "$ENGINE_MODULE/module.prop")
ui_print " 🔒 ${engine_name:-TEESimulator v4} detected"
elif [ -d "$TS" ]; then
engine_name=""
if [ -f "$TS/daemon" ]; then
engine_name=$(grep -o '\-\-nice-name=[^ ]*' "$TS/daemon" 2>/dev/null | cut -d= -f2)
Expand All @@ -57,6 +61,7 @@ case "$ABI" in
*) abort " ❌ Unsupported ABI: $ABI" ;;
esac
BIN="$MODPATH/bin/$ABI/ta-enhanced"
initialize

# Aggressive conflict purge. Hot-install means we cannot wait for the
# manager to process disable+remove on next boot, so rm -rf conflicting
Expand Down Expand Up @@ -97,6 +102,22 @@ done
[ "$PURGED_COUNT" -eq 0 ] && ui_print " ✅ $(_msg no_conflicts)"

HAS_TARGET=0
TEESIM_READY=1
if [ "$ENGINE" = "teesim" ]; then
if "$BIN" automation profile-ready >/dev/null 2>&1; then
"$BIN" automation export-target >/dev/null 2>&1 \
|| abort " ❌ Failed to read TEESimulator config.json"
elif PROFILE_ERROR=$("$BIN" automation profiles 2>&1); then
TEESIM_READY=0
ui_print " ⚠️ Select a TEESimulator profile in this addon's WebUI"
ui_print " ℹ️ TEESimulator will remain unchanged until then"
elif [ -f /data/adb/teesim/config.json ]; then
abort " ❌ Invalid TEESimulator config: $PROFILE_ERROR"
else
TEESIM_READY=0
ui_print " ⚠️ TEESimulator config is not available yet"
fi
fi
if [ -f "/data/adb/tricky_store/target.txt" ] && [ -s "/data/adb/tricky_store/target.txt" ]; then
HAS_TARGET=1
fi
Expand Down Expand Up @@ -131,7 +152,6 @@ fi
ui_print " "
ui_print " 📦 $(_msg installing)"

initialize
populate_system_app

if [ -x "$BIN" ]; then
Expand Down Expand Up @@ -169,6 +189,11 @@ else
generate_minimal_target
fi

if [ "$ENGINE" = "teesim" ] && [ "$TEESIM_READY" = "1" ]; then
"$BIN" automation sync-target >/dev/null 2>&1 \
|| abort " ❌ Failed to update TEESimulator config.json"
fi

TA_DIR="$SCRIPT_DIR/ta-enhanced"
mkdir -p "$TA_DIR/logs"

Expand Down Expand Up @@ -213,14 +238,22 @@ if [ -f "$SCRIPT_DIR/enhanced.conf" ]; then
|| ui_print " ⚠️ Legacy config migration failed"
fi

ui_print " 🛡️ Setting security patch dates..."
if "$BIN" security-patch update --force 2>/dev/null; then
ui_print " ✅ $(_msg sec_patch_ok)"
if [ "$ENGINE" = "teesim" ] && [ "$TEESIM_READY" = "0" ]; then
ui_print " ⚠️ TEESimulator updates paused: no profile selected"
ui_print " ℹ️ CLI: ta-enhanced automation select-profile PROFILE_NAME"
else
ui_print " ⚠️ $(_msg sec_patch_fail)"
ui_print " 🛡️ Setting security patch dates..."
if "$BIN" security-patch update --force 2>/dev/null; then
ui_print " ✅ $(_msg sec_patch_ok)"
else
ui_print " ⚠️ $(_msg sec_patch_fail)"
fi
fi

if [ -f "$SCRIPT_DIR/keybox.xml" ]; then
if [ "$ENGINE" = "teesim" ] && [ "$TEESIM_READY" = "0" ]; then
: # Do not read or replace a keybox until the user selects its owning profile.
elif { [ "$ENGINE" = "tricky_store" ] && [ -f "$SCRIPT_DIR/keybox.xml" ]; } \
|| { [ "$ENGINE" = "teesim" ] && "$BIN" keybox validate >/dev/null 2>&1; }; then
ui_print " 🔑 $(_msg keybox_kept)"
elif timeout 3 ping -c 1 -W 2 1.1.1.1 >/dev/null 2>&1; then
ui_print " 🔑 $(_msg keybox_fetch)"
Expand Down
1 change: 1 addition & 0 deletions package.sh
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ rm -f "$ZIP_PATH"
cd "$REPO_DIR"
zip -r9 "$ZIP_PATH" . \
-x ".git/*" \
-x ".amp/*" \
-x ".claude/*" \
-x ".mcp-vector-search/*" \
-x ".mcp.json" \
Expand Down
17 changes: 10 additions & 7 deletions post-fs-data.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ while [ -z "$(ls -A /data/adb/modules/ 2>/dev/null)" ]; do
sleep 0.5
done
_pfd_log "Modules directory ready (waited ${_wait_count} iterations)"
. "$MODPATH/common/detect_engine.sh"

# Self-removal if TrickyStore missing
if [ ! -d "$TS" ] || [ -f "$TS/remove" ]; then
_pfd_log "TrickyStore missing or removing - marking self for removal"
# Self-removal only when neither supported engine is present.
if { [ ! -d "$TS" ] || [ -f "$TS/remove" ]; } && [ "$ENGINE" != "teesim" ]; then
_pfd_log "No supported attestation engine - marking self for removal"
if [ -f "$MODPATH/action.sh" ]; then
# Magisk hidden module: recreate stub at real ID
rm -rf "/data/adb/modules/TA_enhanced" 2>/dev/null
Expand All @@ -38,10 +39,12 @@ if [ ! -d "$TS" ] || [ -f "$TS/remove" ]; then
fi
fi

# Clean stale symlinks
[ -L "$TS/webroot" ] && rm -f "$TS/webroot"
[ -L "$TS/action.sh" ] && rm -f "$TS/action.sh"
[ -L "$TS/banner.png" ] && rm -f "$TS/banner.png"
# Clean stale links only from TrickyStore. Never touch TEESimulator's WebUI.
if [ -d "$TS" ] && [ "$ENGINE" != "teesim" ]; then
[ -L "$TS/webroot" ] && rm -f "$TS/webroot"
[ -L "$TS/action.sh" ] && rm -f "$TS/action.sh"
[ -L "$TS/banner.png" ] && rm -f "$TS/banner.png"
fi

# Root Manager Detection
if [ -n "$APATCH" ]; then
Expand Down
1 change: 1 addition & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ edition = "2021"
[dependencies]
clap = { version = "= 4.5.57", features = ["derive"] }
serde = { version = "= 1.0.228", features = ["derive"] }
serde_json = "= 1.0.149"
serde_json = { version = "= 1.0.149", features = ["preserve_order"] }
toml = "= 0.8.23"
tracing = { version = "= 0.1.44", features = ["log"] }
tracing-subscriber = { version = "= 0.3.22", features = ["env-filter"] }
Expand Down
58 changes: 48 additions & 10 deletions rust/src/automation/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
pub mod watcher;
pub mod target;
pub mod watcher;

use serde::Serialize;
use crate::config::Config;
use crate::cli::AutomationAction;
use crate::config::Config;
use serde::Serialize;

#[derive(Debug, Serialize)]
pub struct DaemonStatus {
Expand All @@ -14,15 +14,53 @@ pub struct DaemonStatus {
}

pub fn handle_automation(action: AutomationAction, cfg: &Config) -> anyhow::Result<()> {
if !cfg.automation.enabled {
println!("automation disabled");
return Ok(());
}

match action {
AutomationAction::SyncTarget => {
crate::engine::import_target_mirror()?;
println!("target synchronized");
Ok(())
}
AutomationAction::ExportTarget => {
crate::engine::export_target_mirror()?;
println!("target synchronized");
Ok(())
}
AutomationAction::ProfileReady => {
crate::engine::ensure_profile_selected()?;
println!("profile ready");
Ok(())
}
AutomationAction::Profiles => {
println!(
"{}",
serde_json::to_string(&crate::engine::profile_status(
&cfg.general.teesim_profile
)?)?
);
Ok(())
}
AutomationAction::SelectProfile { name } => {
crate::engine::validate_profile_choice(name.trim())?;
let mut current = Config::load(None)?;
current.set("general.teesim_profile", &name)?;
Config::backup(None)?;
current.save(None)?;
if !name.trim().is_empty() {
crate::engine::export_target_mirror()?;
crate::security_patch::handle_security_patch(
crate::cli::SecurityPatchAction::ExportLegacy,
&current,
)?;
}
println!("TEESimulator profile selection updated");
Ok(())
}
_ if !cfg.automation.enabled => {
println!("automation disabled");
Ok(())
}
AutomationAction::Status => {
let status = watcher::show_status();
println!("{}", serde_json::to_string_pretty(&status)?);
println!("{}", serde_json::to_string_pretty(&watcher::show_status())?);
Ok(())
}
AutomationAction::Check => {
Expand Down
Loading