From 4859ee2da9c9b7a893cd7d5ec8e2d7f90395efb7 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sun, 24 Mar 2019 06:20:57 -0400 Subject: [PATCH] Inject module-installer.sh if new format is detected --- .../main/java/com/topjohnwu/magisk/Const.java | 1 + .../components/DownloadModuleService.java | 26 ++++++++- .../com/topjohnwu/magisk/container/Repo.java | 16 +++++- .../main/java/com/topjohnwu/net/Request.java | 56 +++++++++++++++++-- 4 files changed, 89 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/Const.java b/app/src/main/java/com/topjohnwu/magisk/Const.java index 15c31acf4..d7f8a396a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/Const.java +++ b/app/src/main/java/com/topjohnwu/magisk/Const.java @@ -68,6 +68,7 @@ public class Const { public static final String REPO_URL = "https://api.github.com/users/Magisk-Modules-Repo/repos?per_page=100&sort=pushed&page=%d"; public static final String FILE_URL = "https://raw.githubusercontent.com/Magisk-Modules-Repo/%s/master/%s"; public static final String ZIP_URL = "https://github.com/Magisk-Modules-Repo/%s/archive/master.zip"; + public static final String MODULE_INSTALLER = "https://raw.githubusercontent.com/topjohnwu/Magisk/master/scripts/module_installer.sh"; public static final String PAYPAL_URL = "https://www.paypal.me/topjohnwu"; public static final String PATREON_URL = "https://www.patreon.com/topjohnwu"; public static final String TWITTER_URL = "https://twitter.com/topjohnwu"; diff --git a/app/src/main/java/com/topjohnwu/magisk/components/DownloadModuleService.java b/app/src/main/java/com/topjohnwu/magisk/components/DownloadModuleService.java index f0557b4b2..7e0788d51 100644 --- a/app/src/main/java/com/topjohnwu/magisk/components/DownloadModuleService.java +++ b/app/src/main/java/com/topjohnwu/magisk/components/DownloadModuleService.java @@ -63,7 +63,8 @@ public class DownloadModuleService extends Service { InputStream in = Networking.get(repo.getZipUrl()) .setDownloadProgressListener(progress) .execForInputStream().getResult(); - removeTopFolder(in, new BufferedOutputStream(new FileOutputStream(output))); + OutputStream out = new BufferedOutputStream(new FileOutputStream(output)); + processZip(in, out, repo.isNewInstaller()); if (install) { progress.dismiss(); Intent intent = new Intent(this, ClassMap.get(FlashActivity.class)); @@ -80,17 +81,36 @@ public class DownloadModuleService extends Service { } } - private void removeTopFolder(InputStream in, OutputStream out) throws IOException { + private void processZip(InputStream in, OutputStream out, boolean inject) + throws IOException { try (ZipInputStream zin = new ZipInputStream(in); ZipOutputStream zout = new ZipOutputStream(out)) { - ZipEntry entry; + + if (inject) { + // Inject latest module-installer.sh as update-binary + zout.putNextEntry(new ZipEntry("META-INF/")); + zout.putNextEntry(new ZipEntry("META-INF/com/")); + zout.putNextEntry(new ZipEntry("META-INF/com/google/")); + zout.putNextEntry(new ZipEntry("META-INF/com/google/android/")); + zout.putNextEntry(new ZipEntry("META-INF/com/google/android/update-binary")); + try (InputStream update_bin = Networking.get(Const.Url.MODULE_INSTALLER) + .execForInputStream().getResult()) { + ShellUtils.pump(update_bin, zout); + } + zout.putNextEntry(new ZipEntry("META-INF/com/google/android/updater-script")); + zout.write("#MAGISK\n".getBytes("UTF-8")); + } + int off = -1; + ZipEntry entry; while ((entry = zin.getNextEntry()) != null) { if (off < 0) off = entry.getName().indexOf('/') + 1; String path = entry.getName().substring(off); if (path.isEmpty()) continue; + if (inject && path.startsWith("META-INF")) + continue; zout.putNextEntry(new ZipEntry(path)); if (!entry.isDirectory()) ShellUtils.pump(zin, zout); diff --git a/app/src/main/java/com/topjohnwu/magisk/container/Repo.java b/app/src/main/java/com/topjohnwu/magisk/container/Repo.java index 7beed3db0..64a8fec10 100644 --- a/app/src/main/java/com/topjohnwu/magisk/container/Repo.java +++ b/app/src/main/java/com/topjohnwu/magisk/container/Repo.java @@ -8,6 +8,8 @@ import android.os.Parcelable; import com.topjohnwu.magisk.Const; import com.topjohnwu.magisk.utils.Logger; import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.net.Networking; +import com.topjohnwu.net.Request; import java.text.DateFormat; import java.util.Date; @@ -82,11 +84,21 @@ public class Repo extends BaseModule { } public String getPropUrl() { - return String.format(Const.Url.FILE_URL, getId(), "module.prop"); + return getFileUrl("module.prop"); } public String getDetailUrl() { - return String.format(Const.Url.FILE_URL, getId(), "README.md"); + return getFileUrl("README.md"); + } + + public String getFileUrl(String file) { + return String.format(Const.Url.FILE_URL, getId(), file); + } + + public boolean isNewInstaller() { + try (Request req = Networking.get(getFileUrl("install.sh"))) { + return req.connect().isSuccess(); + } } public String getLastUpdateString() { diff --git a/net/src/main/java/com/topjohnwu/net/Request.java b/net/src/main/java/com/topjohnwu/net/Request.java index 24ca2b11a..f0c7da503 100644 --- a/net/src/main/java/com/topjohnwu/net/Request.java +++ b/net/src/main/java/com/topjohnwu/net/Request.java @@ -8,6 +8,8 @@ import org.json.JSONObject; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.Closeable; import java.io.File; import java.io.FileOutputStream; import java.io.FilterInputStream; @@ -19,7 +21,7 @@ import java.io.Reader; import java.net.HttpURLConnection; import java.util.concurrent.Executor; -public class Request { +public class Request implements Closeable { private HttpURLConnection conn; private Executor executor = null; private DownloadProgressListener progress = null; @@ -42,6 +44,10 @@ public class Request { return code; } + public boolean isSuccess() { + return code >= 200 && code <= 299; + } + public HttpURLConnection getConnection() { return conn; } @@ -51,6 +57,11 @@ public class Request { conn = c; } + @Override + public void close() { + conn.disconnect(); + } + public Request addHeaders(String key, String value) { conn.setRequestProperty(key, value); return this; @@ -71,6 +82,16 @@ public class Request { return this; } + public Result connect() { + try { + connect0(); + } catch (IOException e) { + if (err != null) + err.onError(conn, e); + } + return new Result<>(); + } + public Result execForInputStream() { return exec(this::getInputStream); } @@ -83,6 +104,14 @@ public class Request { exec(() -> dlFile(out)); } + public void getAsBytes(ResponseListener rs) { + submit(this::dlBytes, rs); + } + + public Result execForBytes() { + return exec(this::dlBytes); + } + public void getAsString(ResponseListener rs) { submit(this::dlString, rs); } @@ -107,6 +136,11 @@ public class Request { return exec(this::dlJSONArray); } + private void connect0() throws IOException { + conn.connect(); + code = conn.getResponseCode(); + } + private Result exec(Requestor req) { Result res = new Result<>(); try { @@ -135,8 +169,7 @@ public class Request { } private BufferedInputStream getInputStream() throws IOException { - conn.connect(); - code = conn.getResponseCode(); + connect0(); InputStream in = conn.getInputStream(); if (progress != null) { in = new ProgressInputStream(in, conn.getContentLength(), progress) { @@ -162,7 +195,7 @@ public class Request { StringBuilder builder = new StringBuilder(); try (Reader reader = new InputStreamReader(getInputStream())) { int len; - char buf[] = new char[4096]; + char[] buf = new char[4096]; while ((len = reader.read(buf)) != -1) { builder.append(buf, 0, len); } @@ -182,11 +215,24 @@ public class Request { try (InputStream in = getInputStream(); OutputStream out = new BufferedOutputStream(new FileOutputStream(f))) { int len; - byte buf[] = new byte[4096]; + byte[] buf = new byte[4096]; while ((len = in.read(buf)) != -1) { out.write(buf, 0, len); } } return f; } + + private byte[] dlBytes() throws IOException { + int len = conn.getContentLength(); + len = len > 0 ? len : 32; + ByteArrayOutputStream out = new ByteArrayOutputStream(len); + try (InputStream in = getInputStream()) { + byte[] buf = new byte[4096]; + while ((len = in.read(buf)) != -1) { + out.write(buf, 0, len); + } + } + return out.toByteArray(); + } }