Niedzielski has uploaded a new change for review.
https://gerrit.wikimedia.org/r/230826
Change subject: Hygiene: use repo keystore for debug, dev, & alpha
......................................................................
Hygiene: use repo keystore for debug, dev, & alpha
* Add a public keystore and properties to repo.
The name "repo" is used to avoid confusion with build flavors, build
types, and key types. i.e., the repo keystore is applicable to more
than the dev flavor, so don't call it "dev", more than the debug build
type, so don't call it "debug", and like any keystore, contains both
public and private keys so don't call it "public".
Properties could be hardcoded in Groovy, but a properties file allows
for homogeneous handling of both repo and prod signing configurations.
* Change signing configurations:
* Override signingConfigs.debug to use repo. It is a little confusing
to call the repo signing configuration "debug" but we don't want the
implicit debug configuration leaking in. The alternative is to have
a dummy or redundant debig configuration, each of which is unhappy.
* Always use repo keystore for debug build types, and dev and alpha
flavors. Always use prod keystore for all other release flavors. For
dev and alpha builds, that means signatures are tied to package
names not build types. e.g., you can install a dev release build on
top of a dev debug build without uninstalling.
A dev keystore is recommend by Jake Wharton[0]. Using this keystore
for alpha builds as well keeps security concerns out of our Jenkins
alpha job.
[0] https://twitter.com/jakewharton/status/554242089236828160
* Dev and alpha builds have a new signature. Previously distributed
dev and alpha builds must be uninstalled which will cause data loss.
* Everyone can install each others' apps without uninstalling.
* Use lowercase.dot instead of UPPERCASE_SNAKE for keystore pre-dex properties.
UPPERCASE_SNAKE seems unconventional[0].
[0]
https://android.googlesource.com/platform/build/+/master/tools/buildinfo.sh
TODOs once merged:
* Send courtesy announcement alerting users that an alpha uninstall is
necessary.
* Update locale ~/.sign/signing.properties.
Notes on keystore generation
# Create a new keystore. Note: some tools guard against usage of
# keystores without passwords.
keytool \
-keystore repo.keystore \
-keyalg RSA \
-genkeypair \
-alias repo \
-keypass android \
-storepass android \
-dname 'CN=Wikimedia Foundation, OU=Mobile, O=Wikimedia Foundation, L=San
Francisco, ST=California, C=US' \
-validity 36524
Notes on keystore validation
# Convert to intermediate PKCS12.
keytool \
-importkeystore \
-srckeystore repo.keystore \
-destkeystore repo.p12 \
-deststoretype PKCS12 \
-srcstorepass android \
-storepass android \
-keypass android
# Convert to PEM for comparison with known good keys.
openssl \
pkcs12 \
-in repo.p12 \
-out repo.pem \
-nodes \
-passin pass:android
# Do some diffs against a standard Android debug keystores like
# Telecine[0] and the release keystore.
# [0] https://github.com/JakeWharton/Telecine/blob/master/debug.keystore
Notes on signing configuration validation
# Build all variants.
./gradlew -Ppre.dex=false clean assemble
# Verify APK signature.
# $1 keystore
# $2 key alias
# $3 apk
verify() {
jarsigner \
-verify \
-strict \
-sigalg MD5withRSA \
-digestalg SHA1 \
-keystore "$1" \
"$3" \
"$2"
}
alias verify-prod='verify prod.keystore prod'
alias verify-repo='verify repo.keystore repo'
# Verify all repo variants.
ls -1 app/build/outputs/apk/{*-debug*,*-dev-*,*-alpha-*} |
sort -u |
while IFS= read -r -d $'\n' i; do
echo "$i" &&
verify-repo "$i"
done
# Verify all prod variants.
ls -1 app/build/outputs/apk/* |
grep -Ev 'debug|dev|alpha' |
while IFS= read -r -d $'\n' i; do
echo "$i" &&
verify-prod "$i"
done
# Explicitly verify release prod variant.
verify-prod app/build/outputs/apk/app-prod-release.apk &&
! verify-repo app/build/outputs/apk/app-prod-release.apk
# Be paranoid. Download known good APK and verify.
scp \
caesium:/srv/org/wikimedia/releases/mobile/android/wikipedia/stable/wikipedia-2.0.108-releasesprod-2015-08-04.apk
\
. &&
verify-prod wikipedia-2.0.108-releasesprod-2015-08-04.apk &&
! verify-repo wikipedia-2.0.108-releasesprod-2015-08-04.apk
# Verify app installs and launches devDebyg variant from IDE.
# Verify IDE respects repo key configuration.
adb install -r app/build/outputs/apk/app-dev-release.apk
# Test no prod keystore with dev and alpha debug and release.
./gradlew -Ppre.dex=false clean assembleDebug assemble{Dev,Alpha}Release &&
ls app/build/outputs/apk
Change-Id: I7d562413e9f13be1ea514e47ffb8af94858e47aa
---
M app/build.gradle
A repo.keystore
A repo.properties
3 files changed, 50 insertions(+), 26 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/apps/android/wikipedia
refs/changes/26/230826/1
diff --git a/app/build.gradle b/app/build.gradle
index 1276ce5..bd7e5d7 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -5,10 +5,18 @@
import com.android.ddmlib.DdmPreferences
-final int ADB_TIMEOUT = 5 * 60 * 1000
+import java.util.concurrent.TimeUnit
+
+// Copy the signing.properties.sample file to ~/.sign/signing.properties and
adjust the values.
+final File PROD_PROPS_FILE = new File(System.getProperty('user.home'),
'.sign/signing.properties')
+final File REPO_PROPS_FILE = new File('repo.properties')
+final Properties PROD_PROPS = loadProperties(PROD_PROPS_FILE)
+final Properties REPO_PROPS = loadProperties(REPO_PROPS_FILE)
+
+final int ADB_TIMEOUT = TimeUnit.MINUTES.toMillis(5)
final boolean continuousIntegrationBuild = System.getenv('JENKINS_HOME') !=
null
-final boolean preDexEnabled = hasProperty('preDex') ?
- Boolean.valueOf(preDex.toString()) :
+final boolean preDexEnabled = hasProperty('pre.dex') ?
+ Boolean.valueOf(getProperty('pre.dex').toString()) :
!continuousIntegrationBuild
if (!preDexEnabled) {
println 'Pre-dexing disabled.'
@@ -52,43 +60,57 @@
versionCode 108
testApplicationId 'org.wikipedia.test'
}
+
signingConfigs {
- release
+ prod {
+ setSigningConfigKey(prod, PROD_PROPS)
+ }
+ debug {
+ setSigningConfigKey(debug, REPO_PROPS)
+ }
}
+
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
- signingConfig signingConfigs.release
}
}
+
productFlavors {
dev {
versionName computeVersionName("dev")
applicationId 'org.wikipedia.dev'
+ signingConfig signingConfigs.debug
}
prod {
versionName computeVersionName("r")
+ signingConfig signingConfigs.prod
}
releasesprod {
versionName computeVersionName("releasesprod")
+ signingConfig signingConfigs.prod
}
alpha {
versionName computeVersionName("alpha")
applicationId 'org.wikipedia.alpha'
+ signingConfig signingConfigs.debug
}
beta {
versionName computeVersionName("beta")
applicationId 'org.wikipedia.beta'
+ signingConfig signingConfigs.prod
}
amazon {
versionName computeVersionName("amazon")
+ signingConfig signingConfigs.prod
}
custom {
versionName computeVersionName(customChannel)
applicationId getProperty('customApplicationId')
// next line is for injecting a custom channel value into the
custom/AndroidManifest.xml
manifestPlaceholders =
[customChannel:getProperty('customChannel').toString()]
+ signingConfig signingConfigs.prod
}
}
// while we still have lint errors; remove once those are fixed
@@ -136,25 +158,23 @@
testCompile 'com.squareup.okhttp:mockwebserver:2.4.0'
}
-// The next block is for setting the release signing config from a file
outside the git repo
-// To make release builds work:
-// Copy the signing.properties.sample file to ~/.sign/signing.properties and
adjust the values.
-def Properties props = new Properties()
-def propFile = new File(System.getProperty('user.home'),
'.sign/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 {
- System.err.println propFile.toString() + ' found but some entries are
missing'
- android.buildTypes.release.signingConfig = null
+private setSigningConfigKey(config, Properties props) {
+ if (props) {
+ config.storeFile = props['keystore'] == null ? null :
file(props['keystore'])
+ config.storePassword = props['store.pass']
+ config.keyAlias = props['key.alias']
+ config.keyPassword = props['key.pass']
}
-} else {
- System.err.println propFile.toString() + ' not found'
- android.buildTypes.release.signingConfig = null
-}
\ No newline at end of file
+ return config
+}
+
+private @Nullable Properties loadProperties(File file) {
+ Properties props = null
+ if (file.canRead()) {
+ props = new Properties()
+ props.load(new FileInputStream(file))
+ } else {
+ System.err.println "\"${file}\" not found"
+ }
+ return props
+}
diff --git a/repo.keystore b/repo.keystore
new file mode 100644
index 0000000..f269e76
--- /dev/null
+++ b/repo.keystore
Binary files differ
diff --git a/repo.properties b/repo.properties
new file mode 100644
index 0000000..f643cc4
--- /dev/null
+++ b/repo.properties
@@ -0,0 +1,4 @@
+keystore=../repo.keystore
+store.pass=android
+key.alias=repo
+key.pass=android
\ No newline at end of file
--
To view, visit https://gerrit.wikimedia.org/r/230826
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I7d562413e9f13be1ea514e47ffb8af94858e47aa
Gerrit-PatchSet: 1
Gerrit-Project: apps/android/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Niedzielski <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits