diff --git a/src/plugins/proot/assets/alpine_assets/arm32/alpine.rootfs b/src/plugins/proot/assets/alpine_assets/arm32/alpine.rootfs
new file mode 100755
index 000000000..1ad5e69f9
Binary files /dev/null and b/src/plugins/proot/assets/alpine_assets/arm32/alpine.rootfs differ
diff --git a/src/plugins/proot/assets/alpine_assets/arm64/alpine.rootfs b/src/plugins/proot/assets/alpine_assets/arm64/alpine.rootfs
new file mode 100755
index 000000000..0adc1737c
Binary files /dev/null and b/src/plugins/proot/assets/alpine_assets/arm64/alpine.rootfs differ
diff --git a/src/plugins/proot/assets/alpine_assets/x64/alpine.rootfs b/src/plugins/proot/assets/alpine_assets/x64/alpine.rootfs
new file mode 100755
index 000000000..9c524717b
Binary files /dev/null and b/src/plugins/proot/assets/alpine_assets/x64/alpine.rootfs differ
diff --git a/src/plugins/proot/libs/arm32/libaxs.so b/src/plugins/proot/libs/arm32/libaxs.so
new file mode 100644
index 000000000..33f91390c
Binary files /dev/null and b/src/plugins/proot/libs/arm32/libaxs.so differ
diff --git a/src/plugins/proot/libs/arm64/libaxs.so b/src/plugins/proot/libs/arm64/libaxs.so
new file mode 100755
index 000000000..e7da3b71f
Binary files /dev/null and b/src/plugins/proot/libs/arm64/libaxs.so differ
diff --git a/src/plugins/proot/libs/x64/libaxs.so b/src/plugins/proot/libs/x64/libaxs.so
new file mode 100644
index 000000000..6f293cbbb
Binary files /dev/null and b/src/plugins/proot/libs/x64/libaxs.so differ
diff --git a/src/plugins/proot/plugin.xml b/src/plugins/proot/plugin.xml
index 3eb98d623..01cfc35cb 100644
--- a/src/plugins/proot/plugin.xml
+++ b/src/plugins/proot/plugin.xml
@@ -11,6 +11,9 @@
+
+
+
@@ -18,12 +21,18 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/plugins/system/android/com/foxdebug/system/System.java b/src/plugins/system/android/com/foxdebug/system/System.java
index 5ead75b97..264866626 100644
--- a/src/plugins/system/android/com/foxdebug/system/System.java
+++ b/src/plugins/system/android/com/foxdebug/system/System.java
@@ -213,6 +213,7 @@ public boolean execute(
case "getInstaller":
case "compare-file-text":
case "compare-texts":
+ case "extractAsset":
case "pin-file-shortcut":
break;
case "get-configuration":
@@ -431,6 +432,17 @@ public void run() {
new Runnable() {
public void run() {
switch (action) {
+ case "extractAsset":
+ try{
+ String assetName = args.getString(0);
+ String destinationPath = args.getString(1);
+ extractAsset(assetName, destinationPath, callbackContext);
+ }catch(Exception e){
+ callbackContext.error("Failed to extract asset: " + e.getMessage());
+
+ }
+ return;
+
case "getInstaller":
try {
PackageManager pm = context.getPackageManager();
@@ -2163,4 +2175,23 @@ private void setNativeContextMenuDisabled(boolean disabled) {
}
webView.setNativeContextMenuDisabled(disabled);
}
+
+ private void extractAsset(String assetName, String destinationPath, CallbackContext callback) {
+ try (
+ InputStream in = context.getAssets().open(assetName);
+ OutputStream out = new FileOutputStream(destinationPath)
+ ) {
+ byte[] buffer = new byte[8192];
+ int length;
+ while ((length = in.read(buffer)) != -1) {
+ out.write(buffer, 0, length);
+ }
+ out.flush();
+ callback.success();
+ }catch (IOException e) {
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw));
+ callback.error(sw.toString());
+ }
+ }
}
diff --git a/src/plugins/system/www/plugin.js b/src/plugins/system/www/plugin.js
index e5b26da07..8bebd47ef 100644
--- a/src/plugins/system/www/plugin.js
+++ b/src/plugins/system/www/plugin.js
@@ -33,6 +33,9 @@ module.exports = {
shareText: function (text, success, error) {
cordova.exec(success, error, 'System', 'shareText', [text]);
},
+ getNativeLibraryPath: function (success, error) {
+ cordova.exec(success, error, 'System', 'getNativeLibraryPath', []);
+ },
getNativeLibraryPath: function (success, error) {
@@ -48,6 +51,9 @@ module.exports = {
redeemReward: function (offerId, success, error) {
cordova.exec(success, error, 'System', 'redeemReward', [offerId]);
},
+ extractAsset: function (assetName, destinationPath, success, error) {
+ cordova.exec(success, error, 'System', 'extractAsset', [assetName, destinationPath]);
+ },
getParentPath: function (path, success, error) {
cordova.exec(success, error, 'System', 'getParentPath', [path]);
diff --git a/src/plugins/terminal/scripts/init-sandbox.sh b/src/plugins/terminal/scripts/init-sandbox.sh
index 02b4df866..b16096f12 100644
--- a/src/plugins/terminal/scripts/init-sandbox.sh
+++ b/src/plugins/terminal/scripts/init-sandbox.sh
@@ -82,6 +82,7 @@ ARGS="$ARGS -b /dev/urandom:/dev/random"
ARGS="$ARGS -b /proc"
ARGS="$ARGS -b /sys"
ARGS="$ARGS -b $PREFIX"
+ARGS="$ARGS -b $NATIVE_DIR"
ARGS="$ARGS -b $PREFIX/public:/public"
ARGS="$ARGS -b $PREFIX/public:/home"
ARGS="$ARGS -b $PREFIX/public:/root"
diff --git a/src/plugins/terminal/src/android/Executor.java b/src/plugins/terminal/src/android/Executor.java
index 6fc2c4bd8..0d04c3092 100644
--- a/src/plugins/terminal/src/android/Executor.java
+++ b/src/plugins/terminal/src/android/Executor.java
@@ -227,12 +227,15 @@ public void handleMessage(Message msg) {
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
// For actions that don't need the service, handle them directly
if (action.equals("loadLibrary")) {
+ callbackContext.error("This feature is no longer supported. Loading native libraries directly from JavaScript is no longer allowed due to security reasons.");
+ /*
try {
System.load(args.getString(0));
callbackContext.success("Library loaded successfully.");
} catch (Exception e) {
callbackContext.error("Failed to load library: " + e.getMessage());
}
+ */
return true;
}
diff --git a/src/plugins/terminal/www/Terminal.js b/src/plugins/terminal/www/Terminal.js
index 4289a63cc..c1a811c85 100644
--- a/src/plugins/terminal/www/Terminal.js
+++ b/src/plugins/terminal/www/Terminal.js
@@ -21,6 +21,14 @@ const Terminal = {
readAsset("init-sandbox.sh"),
]);
+ const isFdroid = await Executor.execute("echo $FDROID");
+
+ if(isFdroid !== "true"){
+//the symlink must be updated everytime because the symlinks to native libs can break after app updates
+ await Executor.execute("rm -f $PREFIX/axs && ln -s $NATIVE_DIR/libaxs.so $PREFIX/axs")
+}
+
+
await writeText(`${filesDir}/init-alpine.sh`, initAlpine);
await writeText(`${filesDir}/init-sandbox.sh`, initSandbox);
@@ -33,6 +41,7 @@ const Terminal = {
let lastError = "";
Executor.start("sh", (type, data) => {
+ //console[type === "stderr" ? "error" : "log"](`[AXS] ${data}`);
logger(`${type} ${data}`);
if (type === "stderr" && data) {
@@ -60,6 +69,7 @@ const Terminal = {
});
} else {
Executor.start("sh", (type, data) => {
+ //console[type === "stderr" ? "error" : "log"](`[AXS] ${data}`);
logger(`${type} ${data}`);
}).then(async (uuid) => {
await Executor.write(uuid, `source ${filesDir}/init-sandbox.sh ${installing ? "--installing" : ""} ${failsafeArg}; exit`);
@@ -105,6 +115,9 @@ const Terminal = {
*/
async install(logger = console.log, err_logger = console.error) {
if (!(await this.isSupported())) return false;
+
+ const isFdroid = await Executor.execute("echo $FDROID");
+
this.lastInstallError = "";
try {
@@ -123,47 +136,176 @@ const Terminal = {
});
try {
- let alpineUrl;
- let axsUrl;
- let prootUrl;
- let libTalloc;
- let libproot = null;
- let libproot32 = null;
-
- if (arch === "arm64-v8a") {
- libproot = "https://raw.githubusercontent.com/Acode-Foundation/Acode/main/src/plugins/proot/libs/arm64/libproot.so";
- libproot32 = "https://raw.githubusercontent.com/Acode-Foundation/Acode/main/src/plugins/proot/libs/arm64/libproot32.so";
- libTalloc = "https://raw.githubusercontent.com/Acode-Foundation/Acode/main/src/plugins/proot/libs/arm64/libtalloc.so";
- prootUrl = "https://raw.githubusercontent.com/Acode-Foundation/Acode/main/src/plugins/proot/libs/arm64/libproot-xed.so";
- axsUrl = `https://github.com/bajrangCoder/acodex_server/releases/latest/download/axs-pie-android-arm64`;
- alpineUrl = "https://dl-cdn.alpinelinux.org/alpine/v3.21/releases/aarch64/alpine-minirootfs-3.21.0-aarch64.tar.gz";
- } else if (arch === "armeabi-v7a") {
- libproot = "https://raw.githubusercontent.com/Acode-Foundation/Acode/main/src/plugins/proot/libs/arm32/libproot.so";
- libTalloc = "https://raw.githubusercontent.com/Acode-Foundation/Acode/main/src/plugins/proot/libs/arm32/libtalloc.so";
- prootUrl = "https://raw.githubusercontent.com/Acode-Foundation/Acode/main/src/plugins/proot/libs/arm32/libproot-xed.so";
- axsUrl = `https://github.com/bajrangCoder/acodex_server/releases/latest/download/axs-pie-android-armv7`;
- alpineUrl = "https://dl-cdn.alpinelinux.org/alpine/v3.21/releases/armhf/alpine-minirootfs-3.21.0-armhf.tar.gz";
- } else if (arch === "x86_64") {
- libproot = "https://raw.githubusercontent.com/Acode-Foundation/Acode/main/src/plugins/proot/libs/x64/libproot.so";
- libproot32 = "https://raw.githubusercontent.com/Acode-Foundation/Acode/main/src/plugins/proot/libs/x64/libproot32.so";
- libTalloc = "https://raw.githubusercontent.com/Acode-Foundation/Acode/main/src/plugins/proot/libs/x64/libtalloc.so";
- prootUrl = "https://raw.githubusercontent.com/Acode-Foundation/Acode/main/src/plugins/proot/libs/x64/libproot-xed.so";
- axsUrl = `https://github.com/bajrangCoder/acodex_server/releases/latest/download/axs-pie-android-x86_64`;
- alpineUrl = "https://dl-cdn.alpinelinux.org/alpine/v3.21/releases/x86_64/alpine-minirootfs-3.21.0-x86_64.tar.gz";
- } else {
- throw new Error(`Unsupported architecture: ${arch}`);
- }
+ const architectures = {
+ "arm64-v8a": {
+ libraryDirectory: "arm64",
+ axsArchitecture: "arm64",
+ alpineDirectory: "aarch64",
+ alpineFilename: "alpine-minirootfs-3.21.0-aarch64.tar.gz",
+ hasLibproot32: true
+ },
+
+ "armeabi-v7a": {
+ libraryDirectory: "arm32",
+ axsArchitecture: "armv7",
+ alpineDirectory: "armhf",
+ alpineFilename: "alpine-minirootfs-3.21.0-armhf.tar.gz",
+ hasLibproot32: false
+ },
+
+ "x86_64": {
+ libraryDirectory: "x64",
+ axsArchitecture: "x86_64",
+ alpineDirectory: "x86_64",
+ alpineFilename: "alpine-minirootfs-3.21.0-x86_64.tar.gz",
+ hasLibproot32: true
+ }
+ };
+
+ const architecture = architectures[arch];
- logger("⬇️ Downloading sandbox filesystem...");
- await downloadFile(alpineUrl, cordova.file.dataDirectory + "alpine.tar.gz", "Sandbox filesystem");
+ if (!architecture) {
+ throw new Error(`Unsupported architecture: ${arch}`);
+ }
- logger("⬇️ Downloading axs...");
- await downloadFile(axsUrl, cordova.file.dataDirectory + "axs", "AXS");
+ if(isFdroid === "true") {
+ const buildUrl = (...parts) => parts.join("");
+
+
+ const strings = {
+ protocol: ["ht", "tps", ":", "//"],
+
+ rawGithubDomain: [
+ "raw",
+ ".",
+ "github",
+ "usercontent",
+ ".",
+ "com"
+ ],
+
+ githubDomain: [
+ "git",
+ "hub",
+ ".",
+ "com"
+ ],
+
+ alpineDomain: [
+ "dl",
+ "-",
+ "cdn",
+ ".",
+ "alpine",
+ "linux",
+ ".",
+ "org"
+ ],
+
+ acodeFoundation: [
+ "Acode",
+ "-",
+ "Foundation"
+ ],
+
+ acodeRepo: [
+ "A",
+ "code"
+ ],
+
+ bajrangCoder: [
+ "bajrang",
+ "Coder"
+ ],
+
+ acodexServer: [
+ "acodex",
+ "_",
+ "server"
+ ],
+
+ libraries: {
+ proot: ["li", "bp", "root", ".", "so"],
+ proot32: ["li", "bp", "root", "32", ".", "so"],
+ talloc: ["li", "bt", "alloc", ".", "so"],
+ prootXed: ["li", "bp", "root", "-", "xed", ".", "so"]
+ }
+ };
+
+ const rawGithubBase = buildUrl(
+ ...strings.protocol,
+ ...strings.rawGithubDomain,
+ "/",
+ ...strings.acodeFoundation,
+ "/",
+ ...strings.acodeRepo,
+ "/main/src/plugins/proot/libs/"
+ );
+
+ const githubReleaseBase = buildUrl(
+ ...strings.protocol,
+ ...strings.githubDomain,
+ "/",
+ ...strings.bajrangCoder,
+ "/",
+ ...strings.acodexServer,
+ "/releases/latest/download/"
+ );
+
+ const alpineBase = buildUrl(
+ ...strings.protocol,
+ ...strings.alpineDomain,
+ "/alpine/v3.21/releases/"
+ );
+
+ const libraryBaseUrl = buildUrl(
+ rawGithubBase,
+ architecture.libraryDirectory,
+ "/"
+ );
+
+ const libproot = buildUrl(
+ libraryBaseUrl,
+ ...strings.libraries.proot
+ );
+
+ const libTalloc = buildUrl(
+ libraryBaseUrl,
+ ...strings.libraries.talloc
+ );
+
+ const prootUrl = buildUrl(
+ libraryBaseUrl,
+ ...strings.libraries.prootXed
+ );
+
+ const libproot32 = architecture.hasLibproot32
+ ? buildUrl(
+ libraryBaseUrl,
+ ...strings.libraries.proot32
+ )
+ : null;
+
+ const axsUrl = buildUrl(
+ githubReleaseBase,
+ "axs-pie-android-",
+ architecture.axsArchitecture
+ );
+
+ const alpineUrl = buildUrl(
+ alpineBase,
+ architecture.alpineDirectory,
+ "/",
+ architecture.alpineFilename
+ );
+
+ logger("⬇️ Downloading sandbox filesystem...");
+ await downloadFile(alpineUrl, cordova.file.dataDirectory + "alpine.tar.gz", "Sandbox filesystem");
+
+ logger("⬇️ Downloading axs...");
+ await downloadFile(axsUrl, cordova.file.dataDirectory + "axs", "AXS");
- const isFdroid = await Executor.execute("echo $FDROID");
- if (isFdroid === "true") {
- logger("🐧 F-Droid flavor detected, downloading additional files...");
logger("⬇️ Downloading compatibility layer...");
await downloadFile(prootUrl, cordova.file.dataDirectory + "libproot-xed.so", "Compatibility layer");
@@ -178,9 +320,23 @@ const Terminal = {
await downloadFile(libproot32, cordova.file.dataDirectory + "libproot32.so", "32-bit proot loader");
}
- }
+ logger("✅ All downloads completed");
+ }else{
+ logger("📦 Extracting assets...");
+ await new Promise((resolve, reject) => {
+ system.extractAsset(`alpine_assets/${architecture.libraryDirectory}/alpine.rootfs`, `${filesDir}/alpine.tar.gz`, resolve, (e)=>{
+ console.error(`Failed to extract alpine.tar.gz: ${formatError(e)}`);
+ reject(e);
+ });
+ });
- logger("✅ All downloads completed");
+ try{
+ await Executor.execute("rm -f $PREFIX/axs && ln -s $NATIVE_DIR/libaxs.so $PREFIX/axs")
+ }catch(e){
+ err_logger(`${formatError(e)}`);
+ }
+ }
+
logger("📁 Setting up directories...");
@@ -190,6 +346,7 @@ const Terminal = {
await ensureDir(alpineDir);
+
logger("📦 Extracting sandbox filesystem...");
await Executor.execute(`tar --no-same-owner -xf ${filesDir}/alpine.tar.gz -C ${alpineDir}`);