Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use apksigner to extract ceritificate to support all signing schemes #57

Merged
merged 4 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
3 changes: 2 additions & 1 deletion buildSrc/src/main/kotlin/Versions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ object Versions {
val axmlParser = "1.0"
val bugsnag = "3.6.1"

val androidGradleVersion = "8.0.2"
val androidGradleVersion = "8.4.2"

val spek = "1.1.5"
val junit5 = "5.6.0"
Expand Down Expand Up @@ -66,6 +66,7 @@ object Libraries {
val ktorAuth = "io.ktor:ktor-client-auth-jvm:${Versions.ktor}"
val ktorApacheClient = "io.ktor:ktor-client-apache:${Versions.ktor}"
val axmlParser = "com.shazam:axmlparser:${Versions.axmlParser}"
val apkSig = "com.android.tools.build:apksig:${Versions.androidGradleVersion}"
val gson = "com.google.code.gson:gson:${Versions.gson}"
val apacheCommonsText = "org.apache.commons:commons-text:${Versions.apacheCommonsText}"
val apacheCommonsIO = "commons-io:commons-io:${Versions.apacheCommonsIO}"
Expand Down
6 changes: 3 additions & 3 deletions cli/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@ buildConfig {
}

sourceSets["main"].java {
srcDirs.add(File(buildDir, "gen"))
srcDirs.add(layout.buildDirectory.dir("gen").get().asFile)
}

// At the moment for non-Android projects you need to explicitly
// mark the generated code for correct highlighting in IDE.
idea {
module {
sourceDirs = sourceDirs + file("${project.buildDir}/gen/buildconfig/src/main")
generatedSourceDirs = generatedSourceDirs + file("${project.buildDir}/gen/buildconfig/src/main")
sourceDirs = sourceDirs + project.layout.buildDirectory.dir("gen/buildconfig/src/main").get().asFile
generatedSourceDirs = generatedSourceDirs + project.layout.buildDirectory.dir("gen/buildconfig/src/main").get().asFile
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ private fun createConfiguration(

private fun getOutputDirectory(project: Project, extensionConfig: MarathonExtension): File =
extensionConfig.baseOutputDir?.let { File(it) }
?: project.buildDir.resolve("reports/marathon")
?: project.layout.buildDirectory.dir("reports/marathon").get().asFile

private fun createAndroidConfiguration(
extension: MarathonExtension,
Expand Down
1 change: 1 addition & 0 deletions vendor/vendor-android/base/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ dependencies {
implementation(Libraries.kotlinLogging)
implementation(Libraries.dexTestParser)
implementation(Libraries.axmlParser)
implementation(Libraries.apkSig)
implementation(Libraries.jacksonAnnotations)
implementation(Libraries.scalr)
implementation(project(":core"))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,40 +1,28 @@
package com.malinskiy.marathon.android

import com.android.apksig.ApkVerifier
import com.malinskiy.marathon.io.FileHasher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File
import java.nio.file.FileSystems
import java.nio.file.Files
import java.nio.file.Paths
import java.security.MessageDigest
import java.util.HexFormat

/**
* Extracts digest of APK contents from signature file
*/
class ApkFileHasher : FileHasher {

override suspend fun getHash(file: File): String = withContext(Dispatchers.IO) {
val zipFile = Paths.get(file.absolutePath)

FileSystems.newFileSystem(zipFile, null as ClassLoader?)
.use { fileSystem ->
val certFile = fileSystem.getPath(SIGNATURE_FILE_PATH)
Files.newInputStream(certFile)
.use {
it
.bufferedReader()
.lineSequence()
.firstOrNull { line -> line.contains(DIGEST_MANIFEST_PROPERTY) }
?.substringAfter(PROPERTY_DELIMITER)
?.trim()
?: throw IllegalArgumentException("Manifest digest not found")
}
}
}
val sha256digest = MessageDigest.getInstance("SHA-256")

private companion object {
private const val SIGNATURE_FILE_PATH = "META-INF/CERT.SF"
private const val DIGEST_MANIFEST_PROPERTY = "-Digest-Manifest: "
private const val PROPERTY_DELIMITER = ": "
override suspend fun getHash(file: File): String = withContext(Dispatchers.IO) {
val result = ApkVerifier.Builder(file).build().verify()
if (result.signerCertificates.isNotEmpty()) {
val certificate = result.signerCertificates.first()
// https://cs.android.com/android/platform/superproject/main/+/main:tools/apksig/src/apksigner/java/com/android/apksigner/ApkSignerTool.java;l=1151;drc=d5137445c0d4067406cb3e38aade5507ff2fcd16
HexFormat.of().formatHex(sha256digest.digest(certificate.encoded))
} else {
throw IllegalArgumentException("Certificate not found")
}
}
}
Loading