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

Reply via email to