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

Encrypt some preferences #576

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open

Encrypt some preferences #576

wants to merge 8 commits into from

Commits on Mar 8, 2024

  1. Implement a framework for encrypting some preferences

    The idea is as such: create a custom version of SharedPreferences that
    treats preference keys prefixed with `encrypted` differently, saving them
    to an instance of EncryptedSharedPreferences.
    
    To actually use this MultiSharedPreferences in a PreferenceFragmentCompat,
    we have to employ a little hack of writing its private field, as for some
    reason the fragment does not allow customizing it's shared preferences.
    oakkitten committed Mar 8, 2024
    Configuration menu
    Copy the full SHA
    98f7035 View commit details
    Browse the repository at this point in the history
  2. Configuration menu
    Copy the full SHA
    f3e7a7f View commit details
    Browse the repository at this point in the history
  3. Move applicationContext & mirror it for testing

    This moves `applicationContext` to the `utils` package.
    
    Additionally, it is mirrored in the tests to allow late initialization.
    This will be used in the following commit.
    
    This is highly experimental.
    I have no idea what I am doing.
    oakkitten committed Mar 8, 2024
    Configuration menu
    Copy the full SHA
    e3cb69d View commit details
    Browse the repository at this point in the history
  4. Implement a skeleton for testing preference migration

    Roboelectric is used to simplify testing with application context and
    platform APIs. It provides these things without running on a real device.
    
    We are using JUnit 5. Roboelectric needs JUnit 4; to make this work,
    we use org.junit.vintage:junit-vintage-engine.
    
    For in-memory implementation of shared preferences,
    we use io.github.ivanshafran:shared-preferences-mock.
    
    Please ignore this:
      testImplementation("androidx.test:runner:1.5.2")
      testImplementation("org.mockito:mockito-core:5.8.0")
    oakkitten committed Mar 8, 2024
    Configuration menu
    Copy the full SHA
    aca3d37 View commit details
    Browse the repository at this point in the history
  5. Encrypt relay password

    oakkitten committed Mar 8, 2024
    Configuration menu
    Copy the full SHA
    f926ab0 View commit details
    Browse the repository at this point in the history
  6. Configuration menu
    Copy the full SHA
    901ea47 View commit details
    Browse the repository at this point in the history
  7. Encrypt SSH password & key

    oakkitten committed Mar 8, 2024
    Configuration menu
    Copy the full SHA
    cd024b8 View commit details
    Browse the repository at this point in the history
  8. Add backup rules

    I would prefer to only use the `include` rules, but this is quite hard when
    it comes to shared preferences. The problem is that the default shared
    preferences file name contains the application id. While it is possible to
    use application id placeholder in the manifest, it is not currently possible
    in the resource files. It is also apparently not possible to use string
    resources, it just does not work. We could also use a Gradle plugin that
    gives us placeholder replacements, but Android Stem seems to be only parsing
    string resources, which is neat but doesn't fit our use. The only feasible
    way here would be duplicating the resources for every build variant.
    
    Rules for API ≤ 30 can be tested with the following Bash script,
    which is a modified version of the script suitable for > 30 found here:
    at https://developer.android.com/guide/topics/data/testingbackup
    
        #!/bin/bash -eu
        : "${1?"Usage: $0 package name"}"
    
        adb shell bmgr enable true
    
        # $ adb shell bmgr list transports
        #     android/com.android.internal.backup.LocalTransport
        #     com.google.android.gms/.backup.BackupTransportService
        adb shell bmgr transport android/com.android.internal.backup.LocalTransport | grep -q "Selected transport" || (echo "Error: error selecting local transport"; exit 1)
    
        adb shell settings put secure backup_local_transport_parameters 'is_encrypted=true'
        adb shell bmgr backupnow "$1" | grep -F "Package $1 with result: Success" || (echo "Backup failed"; exit 1)
    
        apk_path_list=$(adb shell pm path "$1")
        OIFS=$IFS
        IFS=$'\n'
        apk_number=0
        for apk_line in $apk_path_list
        do
            (( ++apk_number ))
            apk_path=${apk_line:8:1000}
            # MSYS_NO_PATHCONV=1 allows running this script in Git Bash
            # Copy before pulling to avoid “remote object ... does not exist” errors
            # See this answer josemigallas https://stackoverflow.com/questions/41150038/#43157127
            MSYS_NO_PATHCONV=1 adb shell cp "$apk_path" "/storage/emulated/0/Download/temp_base.apk"
            MSYS_NO_PATHCONV=1 adb pull "/storage/emulated/0/Download/temp_base.apk" "myapk${apk_number}.apk"
        done
        IFS=$OIFS
        adb shell pm uninstall --user 0 "$1"
        apks=$(seq -f 'myapk%.f.apk' 1 $apk_number)
    
        adb install -t "$apks"
    
        adb shell bmgr transport com.google.android.gms/.backup.BackupTransportService
        rm $apks
    
        echo "Done"
    oakkitten committed Mar 8, 2024
    Configuration menu
    Copy the full SHA
    f49f919 View commit details
    Browse the repository at this point in the history