Skip to content

Commit

Permalink
feat(core): Add secure storage module
Browse files Browse the repository at this point in the history
Adds a secure storage interface which uses FFI bindings to the platform-specific Keychain implementation.
  • Loading branch information
dnys1 committed Mar 6, 2024
1 parent a474b2f commit 2420125
Show file tree
Hide file tree
Showing 162 changed files with 14,653 additions and 41 deletions.
50 changes: 40 additions & 10 deletions .github/workflows/celest_core.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,50 @@ concurrency:
cancel-in-progress: true

jobs:
analyze_and_format:
runs-on: ubuntu-latest
timeout-minutes: 10
# analyze_and_format:
# runs-on: ubuntu-latest
# timeout-minutes: 10
# steps:
# - name: Git Checkout
# uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # 4.1.1
# - name: Setup Dart
# uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 # 1.6.2
# - name: Get Packages
# working-directory: packages/celest_core
# run: dart pub get
# - name: Analyze
# working-directory: packages/celest_core
# run: dart analyze --fatal-infos --fatal-warnings
# - name: Format
# working-directory: packages/celest_core
# run: dart format --set-exit-if-changed .
test:
# needs: analyze_and_format
runs-on: macos-xl
timeout-minutes: 15
steps:
- name: Git Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # 4.1.1
- name: Setup Dart
uses: dart-lang/setup-dart@fedb1266e91cf51be2fdb382869461a434b920a3 # 1.6.2
- name: Setup Flutter
uses: subosito/flutter-action@62f096cacda5168a3bd7b95793373be14fa4fbaf # 2.13.0
with:
cache: true
- name: Setup Android
uses: ReactiveCircus/android-emulator-runner@6b0df4b0efb23bb0ec63d881db79aefbc976e4b2 # 2.30.1
with:
api-level: 34
- name: Get Packages
working-directory: packages/celest_core
run: dart pub get
- name: Analyze
- name: Test
working-directory: packages/celest_core
run: dart analyze --fatal-infos --fatal-warnings
- name: Format
working-directory: packages/celest_core
run: dart format --set-exit-if-changed .
run: dart test
- name: Get Packages (Example)
working-directory: packages/celest_core/example
run: flutter pub get
- name: Test (Example)
working-directory: packages/celest_core/example
run: |
for OS in "sdk iPhone macos"; do
flutter test -d $OS integration_test/secure_storage_test.dart
done
6 changes: 6 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"files.associations": {
"__locale": "cpp",
"locale": "cpp"
}
}
4 changes: 4 additions & 0 deletions packages/celest_core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.2.2-wip

- Adds `Keychain` interface for secure storage of sensitive data.

## 0.2.1

- Overrides `toString` for `CloudException` types.
Expand Down
8 changes: 8 additions & 0 deletions packages/celest_core/android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
*.iml
.gradle
local.properties
.idea/
.DS_Store
build
captures
.cxx
62 changes: 62 additions & 0 deletions packages/celest_core/android/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
group 'dev.celest.celest_core'
version '1.0-SNAPSHOT'

buildscript {
ext.kotlin_version = '1.7.21'
repositories {
google()
mavenCentral()
}

dependencies {
classpath 'com.android.tools.build:gradle:7.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

rootProject.allprojects {
repositories {
google()
mavenCentral()
}
}

apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'

android {
// Conditional for compatibility with AGP <4.2.
if (project.android.hasProperty("namespace")) {
namespace 'dev.celest.celest_core'
}

compileSdk 31

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

kotlinOptions {
jvmTarget = '1.8'
}

sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}

defaultConfig {
minSdkVersion 21
consumerProguardFiles 'consumer-rules.pro'
}

buildTypes {
release {
minifyEnabled false
}
}
}

dependencies {
implementation 'androidx.security:security-crypto:[1.1.0-alpha04,)'
}
1 change: 1 addition & 0 deletions packages/celest_core/android/consumer-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-keep class dev.celest.celest_core.** { *; }
6 changes: 6 additions & 0 deletions packages/celest_core/android/settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
rootProject.name = 'celest_core'
dependencyResolutionManagement {
repositories {
google()
}
}
3 changes: 3 additions & 0 deletions packages/celest_core/android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="dev.celest.celest_core">
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package dev.celest.celest_core

import android.annotation.SuppressLint
import android.app.Activity
import android.content.SharedPreferences
import androidx.annotation.Keep
import androidx.annotation.Nullable
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey

// TODO(dnys1): Exclude from backup:
// - https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences
// - https://developer.android.com/guide/topics/data/autobackup#IncludingFiles
@Keep
class CelestSecureStorage(private val mainActivity: Activity, private val scope: String) {

private val sharedPreferences: SharedPreferences by lazy {
val masterKey = MasterKey.Builder(mainActivity)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()
val sharedPreferences = EncryptedSharedPreferences.create(
mainActivity,
scope,
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM,
)
sharedPreferences
}

private val editor: SharedPreferences.Editor
get() = sharedPreferences.edit()

fun write(dataKey: String, value: String?) {
with(editor) {
putString(dataKey, value)
apply()
}
}

fun read(dataKey: String): String? = sharedPreferences.getString(dataKey, null)

fun delete(dataKey: String): String? {
val current = read(dataKey)
with(editor) {
remove(dataKey)
apply()
}
return current
}

fun clear() {
with(editor) {
clear()
apply()
}
}

}
43 changes: 43 additions & 0 deletions packages/celest_core/example/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/

# IntelliJ related
*.iml
*.ipr
*.iws
.idea/

# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/

# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.pub-cache/
.pub/
/build/

# Symbolication related
app.*.symbols

# Obfuscation related
app.*.map.json

# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
45 changes: 45 additions & 0 deletions packages/celest_core/example/.metadata
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.

version:
revision: "7482962148e8d758338d8a28f589f317e1e42ba4"
channel: "stable"

project_type: app

# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
base_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
- platform: android
create_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
base_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
- platform: ios
create_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
base_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
- platform: linux
create_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
base_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
- platform: macos
create_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
base_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
- platform: web
create_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
base_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
- platform: windows
create_revision: 7482962148e8d758338d8a28f589f317e1e42ba4
base_revision: 7482962148e8d758338d8a28f589f317e1e42ba4

# User provided section

# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'
3 changes: 3 additions & 0 deletions packages/celest_core/example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# celest_core_example

A new Flutter project.
1 change: 1 addition & 0 deletions packages/celest_core/example/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include: package:flutter_lints/flutter.yaml
13 changes: 13 additions & 0 deletions packages/celest_core/example/android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java

# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties
**/*.keystore
**/*.jks
Loading

0 comments on commit 2420125

Please sign in to comment.