mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-24 10:35:19 +00:00
Update release config
This commit is contained in:
parent
eeb2e2e3af
commit
4063ef39a4
1
.gitignore
vendored
1
.gitignore
vendored
@ -24,3 +24,4 @@ test/androidTestEspresso/res/values/arrays.xml
|
||||
obj/
|
||||
jni/libspeex/.deps/
|
||||
*.sh
|
||||
pkcs11.password
|
||||
|
@ -4,7 +4,7 @@ RUN dpkg --add-architecture i386 && \
|
||||
apt-get update -y && \
|
||||
apt-get install -y software-properties-common && \
|
||||
apt-get update -y && \
|
||||
apt-get install -y libc6:i386=2.26-0ubuntu2.1 libncurses5:i386=6.0+20160625-1ubuntu1 libstdc++6:i386=7.2.0-8ubuntu3.2 lib32z1=1:1.2.11.dfsg-0ubuntu2 wget openjdk-8-jdk=8u171-b11-0ubuntu0.17.10.1 git unzip && \
|
||||
apt-get install -y libc6:i386=2.26-0ubuntu2.1 libncurses5:i386=6.0+20160625-1ubuntu1 libstdc++6:i386=7.2.0-8ubuntu3.2 lib32z1=1:1.2.11.dfsg-0ubuntu2 wget openjdk-8-jdk=8u171-b11-0ubuntu0.17.10.1 git unzip opensc pcscd && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
apt-get autoremove -y && \
|
||||
apt-get clean
|
||||
|
81
build.gradle
81
build.gradle
@ -1,3 +1,5 @@
|
||||
import org.signal.signing.ApkSignerUtil
|
||||
|
||||
import java.security.MessageDigest
|
||||
|
||||
buildscript {
|
||||
@ -321,10 +323,6 @@ android {
|
||||
exclude 'META-INF/proguard/androidx-annotations.pro'
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
release
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
minifyEnabled true
|
||||
@ -354,7 +352,6 @@ android {
|
||||
release {
|
||||
minifyEnabled true
|
||||
proguardFiles = buildTypes.debug.proguardFiles
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
|
||||
@ -406,13 +403,7 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
task assembleWebsiteDescriptor << {
|
||||
android.applicationVariants.all { variant ->
|
||||
if (variant.name.equals("websiteDebug") ||
|
||||
variant.name.equals("websiteRelease"))
|
||||
{
|
||||
File file = new File(variant.outputs[0].outputFile.path)
|
||||
|
||||
def assembleWebsiteDescriptor = { variant, file ->
|
||||
if (file.exists()) {
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
||||
file.eachByte 4096, {bytes, size ->
|
||||
@ -421,7 +412,7 @@ task assembleWebsiteDescriptor << {
|
||||
|
||||
String digest = md.digest().collect {String.format "%02x", it}.join();
|
||||
String url = variant.productFlavors.get(0).ext.websiteUpdateUrl
|
||||
String apkName = variant.outputs[0].outputFile.name
|
||||
String apkName = file.getName()
|
||||
|
||||
String descriptor = "{" +
|
||||
"\"versionCode\" : $project.android.defaultConfig.versionCode," +
|
||||
@ -430,12 +421,35 @@ task assembleWebsiteDescriptor << {
|
||||
"\"url\" : \"$url/$apkName\"" +
|
||||
"}"
|
||||
|
||||
File descriptorFile = new File(variant.outputs[0].outputFile.parent, apkName.replace(".apk", ".json"))
|
||||
File descriptorFile = new File(file.getParent(), apkName.replace(".apk", ".json"))
|
||||
|
||||
descriptorFile.write(descriptor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def signProductionRelease = { variant ->
|
||||
String apkName = variant.outputs[0].outputFile.name
|
||||
File inputFile = new File(variant.outputs[0].outputFile.path);
|
||||
File outputFile = new File(variant.outputs[0].outputFile.parent, apkName.replace("-unsigned", ""));
|
||||
|
||||
new ApkSignerUtil("sun.security.pkcs11.SunPKCS11",
|
||||
"pkcs11.config",
|
||||
"PKCS11",
|
||||
"file:pkcs11.password").calculateSignature(inputFile.getAbsolutePath(),
|
||||
outputFile.getAbsolutePath());
|
||||
|
||||
inputFile.delete();
|
||||
return outputFile
|
||||
}
|
||||
|
||||
task signProductionPlayRelease << {
|
||||
signProductionRelease(android.applicationVariants.find({ it.name.equals("playRelease") }))
|
||||
}
|
||||
|
||||
task signProductionWebsiteRelease << {
|
||||
def variant = android.applicationVariants.find({ it.name.equals("websiteRelease") })
|
||||
File signedRelease = signProductionRelease(variant)
|
||||
assembleWebsiteDescriptor(variant, signedRelease);
|
||||
}
|
||||
|
||||
tasks.whenTaskAdded { task ->
|
||||
@ -443,10 +457,12 @@ tasks.whenTaskAdded { task ->
|
||||
task.enabled = false
|
||||
}
|
||||
|
||||
if (task.name.equals("assembleWebsiteDebug") ||
|
||||
task.name.equals("assembleWebsiteRelease"))
|
||||
{
|
||||
task.finalizedBy assembleWebsiteDescriptor
|
||||
if (task.name.equals("assemblePlayRelease")) {
|
||||
task.finalizedBy signProductionPlayRelease
|
||||
}
|
||||
|
||||
if (task.name.equals("assembleWebsiteRelease")) {
|
||||
task.finalizedBy signProductionWebsiteRelease
|
||||
}
|
||||
}
|
||||
|
||||
@ -462,28 +478,3 @@ def getLastCommitTimestamp() {
|
||||
}
|
||||
}
|
||||
|
||||
def Properties props = new Properties()
|
||||
def propFile = new File('signing.properties')
|
||||
|
||||
if (propFile.canRead()){
|
||||
props.load(new FileInputStream(propFile))
|
||||
|
||||
if (props !=null &&
|
||||
props.containsKey('STORE_FILE') &&
|
||||
props.containsKey('STORE_PASSWORD') &&
|
||||
props.containsKey('KEY_ALIAS') &&
|
||||
props.containsKey('KEY_PASSWORD'))
|
||||
{
|
||||
android.signingConfigs.release.storeFile = file(props['STORE_FILE'])
|
||||
android.signingConfigs.release.storePassword = props['STORE_PASSWORD']
|
||||
android.signingConfigs.release.keyAlias = props['KEY_ALIAS']
|
||||
android.signingConfigs.release.keyPassword = props['KEY_PASSWORD']
|
||||
} else {
|
||||
println 'signing.properties found but some entries are missing'
|
||||
android.buildTypes.release.signingConfig = null
|
||||
}
|
||||
}else {
|
||||
println 'signing.properties not found'
|
||||
android.buildTypes.release.signingConfig = null
|
||||
}
|
||||
|
||||
|
9
buildSrc/build.gradle
Normal file
9
buildSrc/build.gradle
Normal file
@ -0,0 +1,9 @@
|
||||
apply plugin: 'java-gradle-plugin'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile group: 'com.android.tools.build', name: 'apksig', version: '2.3.0'
|
||||
}
|
141
buildSrc/src/main/java/org/signal/signing/ApkSignerUtil.java
Normal file
141
buildSrc/src/main/java/org/signal/signing/ApkSignerUtil.java
Normal file
@ -0,0 +1,141 @@
|
||||
package org.signal.signing;
|
||||
|
||||
import com.android.apksig.ApkSigner;
|
||||
import com.android.apksig.apk.ApkFormatException;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
import java.security.SignatureException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class ApkSignerUtil {
|
||||
|
||||
private final String providerClass;
|
||||
|
||||
private final String providerArgument;
|
||||
|
||||
private final String keyStoreType;
|
||||
|
||||
private final String keyStorePassword;
|
||||
|
||||
|
||||
public ApkSignerUtil(String providerClass, String providerArgument, String keyStoreType, String keyStorePassword) {
|
||||
this.providerClass = providerClass;
|
||||
this.providerArgument = providerArgument;
|
||||
this.keyStoreType = keyStoreType;
|
||||
this.keyStorePassword = keyStorePassword;
|
||||
}
|
||||
|
||||
public void calculateSignature(String inputApkFile, String outputApkFile)
|
||||
throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, ApkFormatException, InvalidKeyException, SignatureException
|
||||
{
|
||||
System.out.println("Running calculateSignature()...");
|
||||
|
||||
if (providerClass != null) {
|
||||
installProvider(providerClass, providerArgument);
|
||||
}
|
||||
|
||||
ApkSigner apkSigner = new ApkSigner.Builder(Collections.singletonList(loadKeyStore(keyStoreType, keyStorePassword)))
|
||||
.setV1SigningEnabled(true)
|
||||
.setV2SigningEnabled(true)
|
||||
.setInputApk(new File(inputApkFile))
|
||||
.setOutputApk(new File(outputApkFile))
|
||||
.setOtherSignersSignaturesPreserved(false)
|
||||
.build();
|
||||
|
||||
apkSigner.sign();
|
||||
}
|
||||
|
||||
private void installProvider(String providerName, String providerArgument) {
|
||||
try {
|
||||
Class<?> providerClass = Class.forName(providerName);
|
||||
|
||||
if (!Provider.class.isAssignableFrom(providerClass)) {
|
||||
throw new IllegalArgumentException("JCA Provider class " + providerClass + " not subclass of " + Provider.class.getName());
|
||||
}
|
||||
|
||||
Provider provider;
|
||||
|
||||
if (providerArgument != null) {
|
||||
provider = (Provider) providerClass.getConstructor(String.class).newInstance(providerArgument);
|
||||
} else {
|
||||
provider = (Provider) providerClass.getConstructor().newInstance();
|
||||
}
|
||||
|
||||
Security.addProvider(provider);
|
||||
} catch (ClassNotFoundException | InstantiationException | InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private ApkSigner.SignerConfig loadKeyStore(String keyStoreType, String keyStorePassword) throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException {
|
||||
KeyStore keyStoreEntity = KeyStore.getInstance(keyStoreType == null ? KeyStore.getDefaultType() : keyStoreType);
|
||||
char[] password = getPassword(keyStorePassword);
|
||||
keyStoreEntity.load(null, password);
|
||||
|
||||
Enumeration<String> aliases = keyStoreEntity.aliases();
|
||||
String keyAlias = null;
|
||||
|
||||
while (aliases != null && aliases.hasMoreElements()) {
|
||||
String alias = aliases.nextElement();
|
||||
if (keyStoreEntity.isKeyEntry(alias)) {
|
||||
keyAlias = alias;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (keyAlias == null) {
|
||||
throw new IllegalArgumentException("Keystore has no key entries!");
|
||||
}
|
||||
|
||||
PrivateKey privateKey = (PrivateKey) keyStoreEntity.getKey(keyAlias, password);
|
||||
Certificate[] certificates = keyStoreEntity.getCertificateChain(keyAlias);
|
||||
|
||||
if (certificates == null || certificates.length == 0) {
|
||||
throw new IllegalArgumentException("Unable to load certificates!");
|
||||
}
|
||||
|
||||
List<X509Certificate> results = new LinkedList<>();
|
||||
|
||||
for (Certificate certificate : certificates) {
|
||||
results.add((X509Certificate)certificate);
|
||||
}
|
||||
|
||||
|
||||
return new ApkSigner.SignerConfig.Builder("Signal Signer", privateKey, results).build();
|
||||
}
|
||||
|
||||
private char[] getPassword(String encoded) throws IOException {
|
||||
if (encoded.startsWith("file:")) {
|
||||
String name = encoded.substring("file:".length());
|
||||
BufferedReader reader = new BufferedReader(new FileReader(new File(name)));
|
||||
String password = reader.readLine();
|
||||
|
||||
if (password.length() == 0) {
|
||||
throw new IOException("Failed to read password from file: " + name);
|
||||
}
|
||||
|
||||
return password.toCharArray();
|
||||
} else {
|
||||
return encoded.toCharArray();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
5
pkcs11.config
Normal file
5
pkcs11.config
Normal file
@ -0,0 +1,5 @@
|
||||
name = OpenSC-PKCS11
|
||||
description = SunPKCS11 via OpenSC
|
||||
library = /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so
|
||||
slotListIndex = 0
|
||||
|
Loading…
Reference in New Issue
Block a user