From f3bd95b25177411ea8d4f3c167796816daeac545 Mon Sep 17 00:00:00 2001 From: androidacy-user Date: Wed, 24 May 2023 19:05:11 -0400 Subject: [PATCH] MOOOOAAAAAAR KOTLIN Signed-off-by: androidacy-user --- .../main/java/com/fox2code/mmm/Constants.kt | 71 +-- .../java/com/fox2code/mmm/utils/io/Files.kt | 492 +++++++++--------- .../mmm/utils/io/GMSProviderInstaller.kt | 58 ++- .../java/com/fox2code/mmm/utils/io/Hashes.kt | 217 ++++---- 4 files changed, 432 insertions(+), 406 deletions(-) diff --git a/app/src/main/java/com/fox2code/mmm/Constants.kt b/app/src/main/java/com/fox2code/mmm/Constants.kt index 0395865..0627dd2 100644 --- a/app/src/main/java/com/fox2code/mmm/Constants.kt +++ b/app/src/main/java/com/fox2code/mmm/Constants.kt @@ -1,36 +1,39 @@ -package com.fox2code.mmm; +package com.fox2code.mmm -@SuppressWarnings("unused") -public enum Constants { +@Suppress("unused") +enum class Constants { ; - public static final int MAGISK_VER_CODE_FLAT_MODULES = 19000; - public static final int MAGISK_VER_CODE_UTIL_INSTALL = 20400; - public static final int MAGISK_VER_CODE_PATH_SUPPORT = 21000; - public static final int MAGISK_VER_CODE_INSTALL_COMMAND = 21200; - public static final int MAGISK_VER_CODE_MAGISK_ZYGOTE = 24000; - public static final String INTENT_INSTALL_INTERNAL = - BuildConfig.APPLICATION_ID + ".intent.action.INSTALL_MODULE_INTERNAL"; - public static final String INTENT_ANDROIDACY_INTERNAL = - BuildConfig.APPLICATION_ID + ".intent.action.OPEN_ANDROIDACY_INTERNAL"; - public static final String EXTRA_INSTALL_PATH = "extra_install_path"; - public static final String EXTRA_INSTALL_NAME = "extra_install_name"; - public static final String EXTRA_INSTALL_CONFIG = "extra_install_config"; - public static final String EXTRA_INSTALL_CHECKSUM = "extra_install_checksum"; - public static final String EXTRA_INSTALL_MMT_REBORN = "extra_install_mmt_reborn"; - public static final String EXTRA_INSTALL_NO_EXTENSIONS = "extra_install_no_extensions"; - public static final String EXTRA_INSTALL_TEST_ROOTLESS = "extra_install_test_rootless"; - public static final String EXTRA_ANDROIDACY_COMPAT_LEVEL = "extra_androidacy_compat_level"; - public static final String EXTRA_ANDROIDACY_ALLOW_INSTALL = "extra_androidacy_allow_install"; - public static final String EXTRA_ANDROIDACY_ACTIONBAR_TITLE = "extra_androidacy_actionbar_title"; - public static final String EXTRA_ANDROIDACY_ACTIONBAR_CONFIG = "extra_androidacy_actionbar_config"; - public static final String EXTRA_MARKDOWN_URL = "extra_markdown_url"; - public static final String EXTRA_MARKDOWN_TITLE = "extra_markdown_title"; - public static final String EXTRA_MARKDOWN_CONFIG = "extra_markdown_config"; - public static final String EXTRA_MARKDOWN_CHANGE_BOOT = "extra_markdown_change_boot"; - public static final String EXTRA_MARKDOWN_NEEDS_RAMDISK = "extra_markdown_needs_ramdisk"; - public static final String EXTRA_MARKDOWN_MIN_MAGISK = "extra_markdown_min_magisk"; - public static final String EXTRA_MARKDOWN_MIN_API = "extra_markdown_min_api"; - public static final String EXTRA_MARKDOWN_MAX_API = "extra_markdown_max_api"; - public static final String EXTRA_FADE_OUT = "extra_fade_out"; - public static final String EXTRA_FROM_MANAGER = "extra_from_manager"; -} + + companion object { + const val MAGISK_VER_CODE_FLAT_MODULES = 19000 + const val MAGISK_VER_CODE_UTIL_INSTALL = 20400 + const val MAGISK_VER_CODE_PATH_SUPPORT = 21000 + const val MAGISK_VER_CODE_INSTALL_COMMAND = 21200 + const val MAGISK_VER_CODE_MAGISK_ZYGOTE = 24000 + const val INTENT_INSTALL_INTERNAL = + BuildConfig.APPLICATION_ID + ".intent.action.INSTALL_MODULE_INTERNAL" + const val INTENT_ANDROIDACY_INTERNAL = + BuildConfig.APPLICATION_ID + ".intent.action.OPEN_ANDROIDACY_INTERNAL" + const val EXTRA_INSTALL_PATH = "extra_install_path" + const val EXTRA_INSTALL_NAME = "extra_install_name" + const val EXTRA_INSTALL_CONFIG = "extra_install_config" + const val EXTRA_INSTALL_CHECKSUM = "extra_install_checksum" + const val EXTRA_INSTALL_MMT_REBORN = "extra_install_mmt_reborn" + const val EXTRA_INSTALL_NO_EXTENSIONS = "extra_install_no_extensions" + const val EXTRA_INSTALL_TEST_ROOTLESS = "extra_install_test_rootless" + const val EXTRA_ANDROIDACY_COMPAT_LEVEL = "extra_androidacy_compat_level" + const val EXTRA_ANDROIDACY_ALLOW_INSTALL = "extra_androidacy_allow_install" + const val EXTRA_ANDROIDACY_ACTIONBAR_TITLE = "extra_androidacy_actionbar_title" + const val EXTRA_ANDROIDACY_ACTIONBAR_CONFIG = "extra_androidacy_actionbar_config" + const val EXTRA_MARKDOWN_URL = "extra_markdown_url" + const val EXTRA_MARKDOWN_TITLE = "extra_markdown_title" + const val EXTRA_MARKDOWN_CONFIG = "extra_markdown_config" + const val EXTRA_MARKDOWN_CHANGE_BOOT = "extra_markdown_change_boot" + const val EXTRA_MARKDOWN_NEEDS_RAMDISK = "extra_markdown_needs_ramdisk" + const val EXTRA_MARKDOWN_MIN_MAGISK = "extra_markdown_min_magisk" + const val EXTRA_MARKDOWN_MIN_API = "extra_markdown_min_api" + const val EXTRA_MARKDOWN_MAX_API = "extra_markdown_max_api" + const val EXTRA_FADE_OUT = "extra_fade_out" + const val EXTRA_FROM_MANAGER = "extra_from_manager" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/fox2code/mmm/utils/io/Files.kt b/app/src/main/java/com/fox2code/mmm/utils/io/Files.kt index bceb069..3867dd2 100644 --- a/app/src/main/java/com/fox2code/mmm/utils/io/Files.kt +++ b/app/src/main/java/com/fox2code/mmm/utils/io/Files.kt @@ -1,283 +1,303 @@ -package com.fox2code.mmm.utils.io; +package com.fox2code.mmm.utils.io -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.os.Build; -import android.provider.OpenableColumns; -import android.util.Log; +import android.content.Context +import android.net.Uri +import android.os.Build +import android.provider.OpenableColumns +import android.util.Log +import com.fox2code.mmm.MainApplication +import com.topjohnwu.superuser.io.SuFile +import com.topjohnwu.superuser.io.SuFileInputStream +import com.topjohnwu.superuser.io.SuFileOutputStream +import org.apache.commons.compress.archivers.zip.ZipArchiveEntry +import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream +import org.apache.commons.compress.archivers.zip.ZipFile +import org.apache.commons.io.FileUtils +import timber.log.Timber +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream +import java.io.Closeable +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream +import java.io.IOException +import java.io.InputStream +import java.io.OutputStream +import java.util.Objects +import java.util.zip.ZipEntry +import java.util.zip.ZipInputStream +import java.util.zip.ZipOutputStream -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.fox2code.mmm.MainApplication; -import com.topjohnwu.superuser.io.SuFile; -import com.topjohnwu.superuser.io.SuFileInputStream; -import com.topjohnwu.superuser.io.SuFileOutputStream; - -import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; -import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; -import org.apache.commons.compress.archivers.zip.ZipFile; -import org.apache.commons.io.FileUtils; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.Closeable; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Enumeration; -import java.util.Objects; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; -import java.util.zip.ZipOutputStream; - -import timber.log.Timber; - -/** @noinspection ResultOfMethodCallIgnored*/ -public enum Files { +/** @noinspection ResultOfMethodCallIgnored + */ +enum class Files { ; - private static final boolean is64bit = Build.SUPPORTED_64_BIT_ABIS.length > 0; - // stolen from https://stackoverflow.com/a/25005243 - public static @NonNull String getFileName(Context context, Uri uri) { - String result = null; - if (Objects.equals(uri.getScheme(), "content")) { - try (Cursor cursor = context.getContentResolver().query(uri, null, null, null, null)) { - if (cursor != null && cursor.moveToFirst()) { - int index = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); - if (index != -1) { - result = cursor.getString(index); + companion object { + private val is64bit = Build.SUPPORTED_64_BIT_ABIS.isNotEmpty() + + // stolen from https://stackoverflow.com/a/25005243 + @JvmStatic + fun getFileName(context: Context, uri: Uri): String { + var result: String? = null + if (uri.scheme == "content") { + context.contentResolver.query(uri, null, null, null, null).use { cursor -> + if (cursor != null && cursor.moveToFirst()) { + val index = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME) + if (index != -1) { + result = cursor.getString(index) + } } } } - } - if (result == null) { - result = uri.getPath(); - int cut = Objects.requireNonNull(result).lastIndexOf('/'); - if (cut != -1) { - result = result.substring(cut + 1); + if (result == null) { + result = uri.path + val cut = Objects.requireNonNull(result).lastIndexOf('/') + if (cut != -1) { + result = result!!.substring(cut + 1) + } } + return result!! } - return result; - } - // based on https://stackoverflow.com/a/63018108 - public static @Nullable Long getFileSize(Context context, Uri uri) { - Long result = null; - try { - String scheme = uri.getScheme(); - if (Objects.equals(scheme, "content")) { - Cursor returnCursor = context.getContentResolver(). - query(uri, null, null, null, null); - int sizeIndex = Objects.requireNonNull(returnCursor).getColumnIndex(OpenableColumns.SIZE); - returnCursor.moveToFirst(); - - long size = returnCursor.getLong(sizeIndex); - returnCursor.close(); - - result = size; - } - if (Objects.equals(scheme, "file")) { - result = new File(Objects.requireNonNull(uri.getPath())).length(); + // based on https://stackoverflow.com/a/63018108 + @JvmStatic + fun getFileSize(context: Context, uri: Uri): Long? { + var result: Long? = null + try { + val scheme = uri.scheme + if (scheme == "content") { + val returnCursor = context.contentResolver.query(uri, null, null, null, null) + val sizeIndex = + returnCursor?.getColumnIndex(OpenableColumns.SIZE) + returnCursor!!.moveToFirst() + val size = sizeIndex.let { it?.let { it1 -> returnCursor.getLong(it1) } } + returnCursor.close() + result = size + } + if (scheme == "file") { + result = File(Objects.requireNonNull(uri.path)).length() + } + } catch (e: Exception) { + Timber.e(Log.getStackTraceString(e)) + return null } - } catch (Exception e) { - Timber.e(Log.getStackTraceString(e)); - return result; + return result } - return result; - } - public static void write(File file, byte[] bytes) throws IOException { - // make the dir if necessary - Objects.requireNonNull(file.getParentFile()).mkdirs(); - try (OutputStream outputStream = new FileOutputStream(file)) { - outputStream.write(bytes); - outputStream.flush(); + @JvmStatic + @Throws(IOException::class) + fun write(file: File, bytes: ByteArray?) { + // make the dir if necessary + Objects.requireNonNull(file.parentFile).mkdirs() + FileOutputStream(file).use { outputStream -> + outputStream.write(bytes) + outputStream.flush() + } } - } - public static byte[] read(File file) throws IOException { - try (InputStream inputStream = new FileInputStream(file)) { - return readAllBytes(inputStream); + @JvmStatic + @Throws(IOException::class) + fun read(file: File?): ByteArray { + FileInputStream(file).use { inputStream -> return readAllBytes(inputStream) } } - } - public static void writeSU(File file, byte[] bytes) throws IOException { - // make the dir if necessary - Objects.requireNonNull(file.getParentFile()).mkdirs(); - try (OutputStream outputStream = SuFileOutputStream.open(file)) { - outputStream.write(bytes); - outputStream.flush(); + @JvmStatic + @Throws(IOException::class) + fun writeSU(file: File, bytes: ByteArray?) { + // make the dir if necessary + Objects.requireNonNull(file.parentFile).mkdirs() + SuFileOutputStream.open(file).use { outputStream -> + outputStream.write(bytes) + outputStream.flush() + } } - } - public static byte[] readSU(File file) throws IOException { - if (file.isFile() && file.canRead()) { - try { // Read as app if su not required - return read(file); - } catch (IOException ignored) { + @JvmStatic + @Throws(IOException::class) + fun readSU(file: File): ByteArray { + if (file.isFile && file.canRead()) { + try { // Read as app if su not required + return read(file) + } catch (ignored: IOException) { + } } + SuFileInputStream.open(file).use { inputStream -> return readAllBytes(inputStream) } } - try (InputStream inputStream = SuFileInputStream.open(file)) { - return readAllBytes(inputStream); - } - } - public static boolean existsSU(File file) { - return file.exists() || new SuFile(file.getAbsolutePath()).exists(); - } + @JvmStatic + fun existsSU(file: File): Boolean { + return file.exists() || SuFile(file.absolutePath).exists() + } - public static void copy(InputStream inputStream, OutputStream outputStream) throws IOException { - int nRead; - byte[] data = new byte[16384]; - while ((nRead = inputStream.read(data, 0, data.length)) != -1) { - outputStream.write(data, 0, nRead); + @JvmStatic + @Throws(IOException::class) + fun copy(inputStream: InputStream, outputStream: OutputStream) { + var nRead: Int + val data = ByteArray(16384) + while (inputStream.read(data, 0, data.size).also { nRead = it } != -1) { + outputStream.write(data, 0, nRead) + } + outputStream.flush() } - outputStream.flush(); - } - public static void closeSilently(Closeable closeable) { - try { - if (closeable != null) closeable.close(); - } catch (IOException ignored) { + @JvmStatic + fun closeSilently(closeable: Closeable?) { + try { + closeable?.close() + } catch (ignored: IOException) { + } } - } - public static ByteArrayOutputStream makeBuffer(long capacity) { - // Cap buffer to 1 Gib (or 512 Mib for 32bit) to avoid memory errors - return Files.makeBuffer((int) Math.min(capacity, is64bit ? 0x40000000 : 0x20000000)); - } + @JvmStatic + fun makeBuffer(capacity: Long): ByteArrayOutputStream { + // Cap buffer to 1 Gib (or 512 Mib for 32bit) to avoid memory errors + return makeBuffer( + capacity.coerceAtMost((if (is64bit) 0x40000000 else 0x20000000).toLong()).toInt() + ) + } - public static ByteArrayOutputStream makeBuffer(int capacity) { - return new ByteArrayOutputStream(Math.max(0x20, capacity)) { - @NonNull - @Override - public byte[] toByteArray() { - return this.buf.length == this.count ? - this.buf : super.toByteArray(); + private fun makeBuffer(capacity: Int): ByteArrayOutputStream { + return object : ByteArrayOutputStream(0x20.coerceAtLeast(capacity)) { + override fun toByteArray(): ByteArray { + return if (buf.size == count) buf else super.toByteArray() + } } - }; - } + } - public static byte[] readAllBytes(InputStream inputStream) throws IOException { - ByteArrayOutputStream buffer = Files.makeBuffer(inputStream.available()); - copy(inputStream, buffer); - return buffer.toByteArray(); - } + @JvmStatic + @Throws(IOException::class) + fun readAllBytes(inputStream: InputStream): ByteArray { + val buffer = makeBuffer(inputStream.available()) + copy(inputStream, buffer) + return buffer.toByteArray() + } - public static void fixJavaZipHax(byte[] bytes) { - if (bytes.length > 8 && bytes[0x6] == 0x0 && bytes[0x7] == 0x0 && bytes[0x8] == 0x8) - bytes[0x7] = 0x8; // Known hax to prevent java zip file read - } + @JvmStatic + fun fixJavaZipHax(bytes: ByteArray) { + if (bytes.size > 8 && bytes[0x6].toInt() == 0x0 && bytes[0x7].toInt() == 0x0 && bytes[0x8].toInt() == 0x8) bytes[0x7] = + 0x8 // Known hax to prevent java zip file read + } - public static void patchModuleSimple(byte[] bytes, OutputStream outputStream) throws IOException { - fixJavaZipHax(bytes); - patchModuleSimple(new ByteArrayInputStream(bytes), outputStream); - } + @JvmStatic + @Throws(IOException::class) + fun patchModuleSimple(bytes: ByteArray, outputStream: OutputStream?) { + fixJavaZipHax(bytes) + patchModuleSimple(ByteArrayInputStream(bytes), outputStream) + } - public static void patchModuleSimple(InputStream inputStream, OutputStream outputStream) throws IOException { - ZipInputStream zipInputStream = new ZipInputStream(inputStream); - ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream); - int nRead; - byte[] data = new byte[16384]; - ZipEntry zipEntry; - while ((zipEntry = zipInputStream.getNextEntry()) != null) { - String name = zipEntry.getName(); - int i = name.indexOf('/', 1); - if (i == -1) continue; - String newName = name.substring(i + 1); - if (newName.startsWith(".git")) continue; // Skip metadata - zipOutputStream.putNextEntry(new ZipEntry(newName)); - while ((nRead = zipInputStream.read(data, 0, data.length)) != -1) { - zipOutputStream.write(data, 0, nRead); + @Throws(IOException::class) + fun patchModuleSimple(inputStream: InputStream?, outputStream: OutputStream?) { + val zipInputStream = ZipInputStream(inputStream) + val zipOutputStream = ZipOutputStream(outputStream) + var nRead: Int + val data = ByteArray(16384) + var zipEntry: ZipEntry + while (zipInputStream.nextEntry.also { zipEntry = it } != null) { + val name = zipEntry.name + val i = name.indexOf('/', 1) + if (i == -1) continue + val newName = name.substring(i + 1) + if (newName.startsWith(".git")) continue // Skip metadata + zipOutputStream.putNextEntry(ZipEntry(newName)) + while (zipInputStream.read(data, 0, data.size).also { nRead = it } != -1) { + zipOutputStream.write(data, 0, nRead) + } + zipOutputStream.flush() + zipOutputStream.closeEntry() + zipInputStream.closeEntry() } - zipOutputStream.flush(); - zipOutputStream.closeEntry(); - zipInputStream.closeEntry(); + zipOutputStream.finish() + zipOutputStream.flush() + zipOutputStream.close() + zipInputStream.close() } - zipOutputStream.finish(); - zipOutputStream.flush(); - zipOutputStream.close(); - zipInputStream.close(); - } - public static void fixSourceArchiveShit(byte[] rawModule) { - // unzip the module, check if it has just one folder within. if so, switch to the folder and zip up contents, and replace the original file with that - try { - File tempDir = new File(MainApplication.getINSTANCE().getCacheDir(), "temp"); - if (tempDir.exists()) { - FileUtils.deleteDirectory(tempDir); - } - if (!tempDir.mkdirs()) { - throw new IOException("Unable to create temp dir"); - } - File tempFile = new File(tempDir, "module.zip"); - Files.write(tempFile, rawModule); - File tempUnzipDir = new File(tempDir, "unzip"); - if (!tempUnzipDir.mkdirs()) { - throw new IOException("Unable to create temp unzip dir"); - } - // unzip - Timber.d("Unzipping module to %s", tempUnzipDir.getAbsolutePath()); - try (ZipFile zipFile = new ZipFile(tempFile)) { - Enumeration files = zipFile.getEntries(); - // check if there is only one folder in the top level - int folderCount = 0; - while (files.hasMoreElements()) { - ZipArchiveEntry entry = files.nextElement(); - if (entry.isDirectory()) { - folderCount++; - } + @JvmStatic + fun fixSourceArchiveShit(rawModule: ByteArray?) { + // unzip the module, check if it has just one folder within. if so, switch to the folder and zip up contents, and replace the original file with that + try { + val tempDir = File(MainApplication.getINSTANCE().cacheDir, "temp") + if (tempDir.exists()) { + FileUtils.deleteDirectory(tempDir) } - if (folderCount == 1) { - files = zipFile.getEntries(); - while (files.hasMoreElements()) { - ZipArchiveEntry entry = files.nextElement(); - if (entry.isDirectory()) { - continue; - } - File file = new File(tempUnzipDir, entry.getName()); - if (!Objects.requireNonNull(file.getParentFile()).exists()) { - if (!file.getParentFile().mkdirs()) { - throw new IOException("Unable to create parent dir"); + if (!tempDir.mkdirs()) { + throw IOException("Unable to create temp dir") + } + val tempFile = File(tempDir, "module.zip") + write(tempFile, rawModule) + val tempUnzipDir = File(tempDir, "unzip") + if (!tempUnzipDir.mkdirs()) { + throw IOException("Unable to create temp unzip dir") + } + // unzip + Timber.d("Unzipping module to %s", tempUnzipDir.absolutePath) + try { + ZipFile(tempFile).use { zipFile -> + var files = zipFile.entries + // check if there is only one folder in the top level + var folderCount = 0 + while (files.hasMoreElements()) { + val entry = files.nextElement() + if (entry.isDirectory) { + folderCount++ } } - try (ZipArchiveOutputStream zipArchiveOutputStream = new ZipArchiveOutputStream(file)) { - zipArchiveOutputStream.putArchiveEntry(entry); - try (InputStream inputStream = zipFile.getInputStream(entry)) { - copy(inputStream, zipArchiveOutputStream); + if (folderCount == 1) { + files = zipFile.entries + while (files.hasMoreElements()) { + val entry = files.nextElement() + if (entry.isDirectory) { + continue + } + val file = File(tempUnzipDir, entry.name) + if (!Objects.requireNonNull(file.parentFile).exists()) { + if (!file.parentFile?.mkdirs()!!) { + throw IOException("Unable to create parent dir") + } + } + ZipArchiveOutputStream(file).use { zipArchiveOutputStream -> + zipArchiveOutputStream.putArchiveEntry(entry) + zipFile.getInputStream(entry).use { inputStream -> + copy( + inputStream, + zipArchiveOutputStream + ) + } + zipArchiveOutputStream.closeArchiveEntry() + } } - zipArchiveOutputStream.closeArchiveEntry(); - } - } - // zip up the contents of the folder but not the folder itself - File[] filesInFolder = Objects.requireNonNull(tempUnzipDir.listFiles()); - // create a new zip file - try (ZipArchiveOutputStream archive = new ZipArchiveOutputStream(new FileOutputStream("new.zip"))) { - for (File files2 : filesInFolder) { - // create a new ZipArchiveEntry and add it to the ZipArchiveOutputStream - ZipArchiveEntry entry = new ZipArchiveEntry(files2, files2.getName()); - archive.putArchiveEntry(entry); - try (InputStream input = new FileInputStream(files2)) { - copy(input, archive); + // zip up the contents of the folder but not the folder itself + val filesInFolder = Objects.requireNonNull(tempUnzipDir.listFiles()) + // create a new zip file + try { + ZipArchiveOutputStream(FileOutputStream("new.zip")).use { archive -> + for (files2 in filesInFolder) { + // create a new ZipArchiveEntry and add it to the ZipArchiveOutputStream + val entry = ZipArchiveEntry(files2, files2.name) + archive.putArchiveEntry(entry) + FileInputStream(files2).use { input -> + copy( + input, + archive + ) + } + archive.closeArchiveEntry() + } + } + } catch (e: IOException) { + Timber.e(e, "Unable to zip up module") } - archive.closeArchiveEntry(); + } else { + Timber.d("Module does not have a single folder in the top level, skipping") } - } catch (IOException e) { - Timber.e(e, "Unable to zip up module"); } - } else { - Timber.d("Module does not have a single folder in the top level, skipping"); + } catch (e: IOException) { + Timber.e(e, "Unable to unzip module") } - } catch (IOException e) { - Timber.e(e, "Unable to unzip module"); + } catch (e: IOException) { + Timber.e(e, "Unable to create temp dir") } - } catch (IOException e) { - Timber.e(e, "Unable to create temp dir"); } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/fox2code/mmm/utils/io/GMSProviderInstaller.kt b/app/src/main/java/com/fox2code/mmm/utils/io/GMSProviderInstaller.kt index f2fcb9e..35df92d 100644 --- a/app/src/main/java/com/fox2code/mmm/utils/io/GMSProviderInstaller.kt +++ b/app/src/main/java/com/fox2code/mmm/utils/io/GMSProviderInstaller.kt @@ -21,13 +21,11 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * */ +package com.fox2code.mmm.utils.io -package com.fox2code.mmm.utils.io; - -import android.content.Context; -import android.content.pm.PackageManager; - -import timber.log.Timber; +import android.content.Context +import android.content.pm.PackageManager +import timber.log.Timber /** * Open implementation of ProviderInstaller.installIfNeeded @@ -35,29 +33,33 @@ import timber.log.Timber; */ // Note: This code is MIT because I took it from another unpublished project I had // I might upstream this to MicroG at some point -public enum GMSProviderInstaller { +enum class GMSProviderInstaller { ; - private static boolean called = false; - public static void installIfNeeded(final Context context) { - if (context == null) { - throw new NullPointerException("Context must not be null"); - } - if (called) - return; - called = true; - try { - // Trust default GMS implementation - Context remote = context.createPackageContext("com.google.android.gms", Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); - Class cl = remote.getClassLoader().loadClass("com.google.android.gms.common.security.ProviderInstallerImpl"); - cl.getDeclaredMethod("insertProvider", Context.class).invoke(null, remote); - Timber.i("Installed GMS security providers!"); - } catch ( - PackageManager.NameNotFoundException e) { - Timber.w("No GMS Implementation are installed on this device"); - } catch ( - Exception e) { - Timber.w(e); + companion object { + private var called = false + @JvmStatic + fun installIfNeeded(context: Context?) { + if (context == null) { + throw NullPointerException("Context must not be null") + } + if (called) return + called = true + try { + // Trust default GMS implementation + val remote = context.createPackageContext( + "com.google.android.gms", + Context.CONTEXT_INCLUDE_CODE or Context.CONTEXT_IGNORE_SECURITY + ) + val cl = + remote.classLoader.loadClass("com.google.android.gms.common.security.ProviderInstallerImpl") + cl.getDeclaredMethod("insertProvider", Context::class.java).invoke(null, remote) + Timber.i("Installed GMS security providers!") + } catch (e: PackageManager.NameNotFoundException) { + Timber.w("No GMS Implementation are installed on this device") + } catch (e: Exception) { + Timber.w(e) + } } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/fox2code/mmm/utils/io/Hashes.kt b/app/src/main/java/com/fox2code/mmm/utils/io/Hashes.kt index 1c40abe..86b5b93 100644 --- a/app/src/main/java/com/fox2code/mmm/utils/io/Hashes.kt +++ b/app/src/main/java/com/fox2code/mmm/utils/io/Hashes.kt @@ -1,129 +1,130 @@ -package com.fox2code.mmm.utils.io; +@file:Suppress("UNUSED_PARAMETER") -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Locale; -import java.util.regex.Pattern; +package com.fox2code.mmm.utils.io -import timber.log.Timber; +import timber.log.Timber +import java.security.MessageDigest +import java.security.NoSuchAlgorithmException +import java.util.regex.Pattern -public enum Hashes { +@Suppress("UNUSED_EXPRESSION") +enum class Hashes { ; - private static final char[] HEX_ARRAY = "0123456789abcdef".toCharArray(); - private static final Pattern nonAlphaNum = Pattern.compile("[^a-zA-Z0-9]"); - public static String bytesToHex(byte[] bytes) { - char[] hexChars = new char[bytes.length * 2]; - for (int j = 0; j < bytes.length; j++) { - int v = bytes[j] & 0xFF; - hexChars[j * 2] = HEX_ARRAY[v >>> 4]; - hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; + companion object { + private val HEX_ARRAY = "0123456789abcdef".toCharArray() + private val nonAlphaNum = Pattern.compile("[^a-zA-Z0-9]") + @JvmStatic + fun bytesToHex(bytes: ByteArray): String { + val hexChars = CharArray(bytes.size * 2) + for (j in bytes.indices) { + val v = bytes[j].toInt() and 0xFF + hexChars[j * 2] = HEX_ARRAY[v ushr 4] + hexChars[j * 2 + 1] = HEX_ARRAY[v and 0x0F] + } + return String(hexChars) } - return String.valueOf(hexChars); - } - public static String hashMd5(byte[] input) { - throw new SecurityException("MD5 is not secure"); - } + @JvmStatic + fun hashMd5(ignoredInput: ByteArray?): String { + throw SecurityException("MD5 is not secure") + } - public static String hashSha1(byte[] input) { - throw new SecurityException("SHA-1 is not secure"); - } + @JvmStatic + fun hashSha1(ignoredInput: ByteArray?): String { + throw SecurityException("SHA-1 is not secure") + } - public static String hashSha256(byte[] input) { - try { - MessageDigest md = MessageDigest.getInstance("SHA-256"); + @JvmStatic + fun hashSha256(input: ByteArray?): String { + input ?: return "" + return try { + val md = MessageDigest.getInstance("SHA-256") + bytesToHex(md.digest(input)) + } catch (e: NoSuchAlgorithmException) { + throw RuntimeException(e) + } + } - return bytesToHex(md.digest(input)); - } catch ( - NoSuchAlgorithmException e) { - throw new RuntimeException(e); + @JvmStatic + fun hashSha512(input: ByteArray?): String { + input ?: return "" + return try { + val md = MessageDigest.getInstance("SHA-512") + bytesToHex(md.digest(input)) + } catch (e: NoSuchAlgorithmException) { + throw RuntimeException(e) + } } - } - public static String hashSha512(byte[] input) { - try { - MessageDigest md = MessageDigest.getInstance("SHA-512"); + /** + * Check if the checksum match a file by picking the correct + * hashing algorithm depending on the length of the checksum + */ + @JvmStatic + fun checkSumMatch(data: ByteArray?, checksum: String?): Boolean { + if (checksum == null) return false + val hash: String = when (checksum.length) { + 0 -> { + return true // No checksum + } - return bytesToHex(md.digest(input)); - } catch ( - NoSuchAlgorithmException e) { - throw new RuntimeException(e); + 32 -> hashMd5(data) + 40 -> hashSha1(data) + 64 -> hashSha256(data) + 128 -> hashSha512(data) + else -> { + Timber.e("No hash algorithm for " + checksum.length * 8 + "bit checksums") + return false + } + } + Timber.i("Checksum result (data: $hash,expected: $checksum)") + return hash == checksum.lowercase() } - } - /** - * Check if the checksum match a file by picking the correct - * hashing algorithm depending on the length of the checksum - */ - public static boolean checkSumMatch(byte[] data, String checksum) { - String hash; - if (checksum == null) - return false; - switch (checksum.length()) { - case 0: - return true; // No checksum - case 32: - hash = Hashes.hashMd5(data); - break; - case 40: - hash = Hashes.hashSha1(data); - break; - case 64: - hash = Hashes.hashSha256(data); - break; - case 128: - hash = Hashes.hashSha512(data); - break; - default: - Timber.e("No hash algorithm for " + checksum.length() * 8 + "bit checksums"); - return false; - } - Timber.i("Checksum result (data: " + hash + ",expected: " + checksum + ")"); - return hash.equals(checksum.toLowerCase(Locale.ROOT)); - } + @JvmStatic + fun checkSumValid(checksum: String?): Boolean { + return if (checksum == null) false else when (checksum.length) { + 32, 40, 64, 128 -> { + val len = checksum.length + for (i in 0 until len) { + val c = checksum[i] + if (c < '0' || c > 'f') return false + if (c > '9' && // Easier working with bits + c.code and 95 < 'A'.code + ) return false + } + true + } - @SuppressWarnings("BooleanMethodIsAlwaysInverted") - public static boolean checkSumValid(String checksum) { - if (checksum == null) - return false; - switch (checksum.length()) { - case 0: - default: - return false; - case 32: - case 40: - case 64: - case 128: - final int len = checksum.length(); - for (int i = 0; i < len; i++) { - char c = checksum.charAt(i); - if (c < '0' || c > 'f') - return false; - if (c > '9' && // Easier working with bits - (c & 0b01011111) < 'A') - return false; + else -> { + false } - return true; + } } - } - public static String checkSumName(String checksum) { - if (checksum == null) - return null; - return switch (checksum.length()) { - default -> null; - case 32 -> "MD5"; - case 40 -> "SHA-1"; - case 64 -> "SHA-256"; - case 128 -> "SHA-512"; - }; - } + @JvmStatic + fun checkSumName(checksum: String?): String? { + return if (checksum == null) null else when (checksum.length) { + 32 -> "MD5" + 40 -> "SHA-1" + 64 -> "SHA-256" + 128 -> "SHA-512" + else -> { + null + "MD5" + "SHA-1" + "SHA-256" + "SHA-512" + } + } + } - public static String checkSumFormat(String checksum) { - if (checksum == null) - return null; - // Remove all non-alphanumeric characters - return nonAlphaNum.matcher(checksum.trim()).replaceAll(""); + @JvmStatic + fun checkSumFormat(checksum: String?): String? { + return if (checksum == null) null else nonAlphaNum.matcher(checksum.trim { it <= ' ' }) + .replaceAll("") + // Remove all non-alphanumeric characters + } } -} +} \ No newline at end of file