refactor: clean up usages of ~/Aliucord

This commit is contained in:
rushiiMachine 2024-07-31 15:39:04 -07:00
parent 0cdf2ee743
commit 8d295979be
No known key found for this signature in database
GPG key ID: DCBE5952BB3B6420
4 changed files with 49 additions and 30 deletions

View file

@ -6,7 +6,6 @@
package com.aliucord.manager
import android.os.Bundle
import android.os.Environment
import androidx.activity.ComponentActivity
import androidx.activity.compose.BackHandler
import androidx.activity.compose.setContent
@ -27,9 +26,6 @@ import com.aliucord.manager.ui.widgets.updater.UpdaterDialog
import com.aliucord.manager.util.IS_CUSTOM_BUILD
import org.koin.android.ext.android.inject
// TODO: move to a path provider in DI
val aliucordDir = Environment.getExternalStorageDirectory().resolve("Aliucord")
class MainActivity : ComponentActivity() {
private val preferences: PreferencesManager by inject()

View file

@ -5,13 +5,15 @@
package com.aliucord.manager.installer.util
import com.aliucord.manager.aliucordDir
import com.aliucord.manager.manager.PathManager
import com.android.apksig.ApkSigner
import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
import org.bouncycastle.cert.X509v3CertificateBuilder
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder
import org.koin.core.component.KoinComponent
import org.koin.core.component.get
import java.io.File
import java.math.BigInteger
import java.security.*
@ -20,21 +22,22 @@ import java.security.cert.X509Certificate
import java.util.Date
import java.util.Locale
object Signer {
object Signer : KoinComponent {
private val paths = get<PathManager>()
private val password = "password".toCharArray()
private val signerConfig: ApkSigner.SignerConfig by lazy {
val keyStore = KeyStore.getInstance(KeyStore.getDefaultType())
aliucordDir.resolve("ks.keystore").also {
if (!it.exists()) {
aliucordDir.mkdir()
newKeystore(it)
}
}.inputStream().use { stream ->
keyStore.load(stream, null)
// Create new keystore if it doesn't exist
if (!paths.keystoreFile.exists()) {
paths.aliucordDir.mkdirs()
newKeystore(paths.keystoreFile)
}
paths.keystoreFile.inputStream()
.use { keyStore.load(it, /* password = */ null) }
val alias = keyStore.aliases().nextElement()
val certificate = keyStore.getCertificate(alias) as X509Certificate
@ -45,13 +48,13 @@ object Signer {
).build()
}
private fun newKeystore(out: File?) {
private fun newKeystore(out: File) {
val key = createKey()
with(KeyStore.getInstance(KeyStore.getDefaultType())) {
load(null, password)
setKeyEntry("alias", key.privateKey, password, arrayOf<Certificate>(key.publicKey))
store(out?.outputStream(), password)
store(out.outputStream(), password)
}
}
@ -81,18 +84,18 @@ object Signer {
}
fun signApk(apkFile: File) {
val outputApk = aliucordDir.resolve(apkFile.name)
val tmpApk = apkFile.resolveSibling(apkFile.name + ".tmp")
ApkSigner.Builder(listOf(signerConfig))
.setV1SigningEnabled(false) // TODO: enable so api <24 devices can work, however zip-alignment breaks
.setV2SigningEnabled(true)
.setV3SigningEnabled(true)
.setInputApk(apkFile)
.setOutputApk(outputApk)
.setOutputApk(tmpApk)
.build()
.sign()
outputApk.renameTo(apkFile)
tmpApk.renameTo(apkFile)
}
private class KeySet(val publicKey: X509Certificate, val privateKey: PrivateKey)

View file

@ -1,12 +1,34 @@
package com.aliucord.manager.manager
import android.content.Context
import android.os.Environment
import java.io.File
/**
* A central place to provide all system paths that are used.
*/
class PathManager(context: Context) {
/**
* The Aliucord folder in which plugins/settings/themes are stored.
* Standard path: `~/Aliucord`
*/
val aliucordDir = Environment.getExternalStorageDirectory().resolve("Aliucord")
/**
* The directory in external storage in which plugins are stored by Aliucord.
*/
val pluginsDir = aliucordDir.resolve("plugins")
/**
* The settings file in which Aliucord's core uses.
*/
val coreSettingsFile = aliucordDir.resolve("settings/Aliucord.json")
/**
* Global keystore used for signing APKs.
*/
val keystoreFile = aliucordDir.resolve("ks.keystore")
private val externalCacheDir = context.externalCacheDir
?: throw Error("External cache directory isn't supported")

View file

@ -5,13 +5,15 @@ import androidx.compose.runtime.*
import cafe.adriel.voyager.core.model.ScreenModel
import cafe.adriel.voyager.core.model.screenModelScope
import com.aliucord.manager.BuildConfig
import com.aliucord.manager.aliucordDir
import com.aliucord.manager.domain.model.Plugin
import com.aliucord.manager.manager.PathManager
import kotlinx.coroutines.*
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.*
class PluginsModel : ScreenModel {
class PluginsModel(
private val paths: PathManager,
) : ScreenModel {
var showChangelogDialog by mutableStateOf(false)
private set
@ -57,8 +59,6 @@ class PluginsModel : ScreenModel {
plugins.remove(plugin)
}
private val settingsFile = aliucordDir.resolve("settings/Aliucord.json")
fun setPluginEnabled(plugin: String, enable: Boolean) {
screenModelScope.launch(Dispatchers.IO) {
withContext(Dispatchers.Main) {
@ -69,13 +69,13 @@ class PluginsModel : ScreenModel {
@OptIn(ExperimentalSerializationApi::class)
try {
val settings = settingsFile.inputStream()
val settings = paths.coreSettingsFile.inputStream()
.use { Json.decodeFromStream<Map<String, JsonElement>>(it) }
.toMutableMap()
settings["AC_PM_$plugin"] = JsonPrimitive(enable)
settingsFile.outputStream()
paths.coreSettingsFile.outputStream()
.use { Json.encodeToStream(settings, it) }
} catch (t: Throwable) {
Log.e(BuildConfig.TAG, "Failed to write Aliucord.json: ${Log.getStackTraceString(t)}")
@ -85,11 +85,11 @@ class PluginsModel : ScreenModel {
}
private suspend fun loadEnabled(): Map<String, Boolean> = withContext(Dispatchers.IO) {
if (!settingsFile.exists()) return@withContext emptyMap()
if (!paths.coreSettingsFile.exists()) return@withContext emptyMap()
@OptIn(ExperimentalSerializationApi::class)
try {
settingsFile.inputStream()
paths.coreSettingsFile.inputStream()
.use { Json.decodeFromStream<Map<String, JsonElement>>(it) }
.filterKeys { it.startsWith("AC_PM_") }
.mapKeys { it.key.substring("AC_PM_".length) }
@ -107,14 +107,12 @@ class PluginsModel : ScreenModel {
}
screenModelScope.launch(Dispatchers.IO) {
val pluginsDir = aliucordDir.resolve("plugins")
if (!pluginsDir.exists() && !pluginsDir.mkdirs()) {
if (!paths.pluginsDir.exists() && !paths.pluginsDir.mkdirs()) {
Log.e(BuildConfig.TAG, "Failed to create plugins dir. Missing Permissions?")
return@launch
}
val files = pluginsDir.listFiles { file -> file.extension == "zip" } ?: return@launch
val files = paths.pluginsDir.listFiles { file -> file.extension == "zip" } ?: return@launch
val loadedPlugins = files.mapNotNull { file ->
try {
Plugin(file)