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

[#234] Add secure local storage #253

Merged
merged 4 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ All the templates can be used to kick off a new Flutter project quickly.
- [Pre-set environments](bricks/template/__brick__/%7B%7Bproject_name.snakeCase()%7D%7D#setup): `Staging` and `Production`. Environment variables are supplied through `.env` files through [flutter_config](https://pub.dev/packages/flutter_config).
- Dependency Injection (DI), State Management, and Navigating with [get_it](https://pub.dev/packages/get_it), [flutter_riverpod](https://pub.dev/packages/flutter_riverpod), and [go_router](https://pub.dev/packages/go_router).
- Networking with [dio](https://pub.dev/packages/dio) and [retrofit](https://pub.dev/packages/retrofit), JSON serializing with [json_serializable](https://pub.dev/packages/json_serializable).
- Integrated local [secure storage](https://pub.dev/packages/flutter_secure_storage).
- [Localization](https://docs.flutter.dev/accessibility-and-localization/internationalization) integrated in [3 initial languages](bricks/template/__brick__/%7B%7Bproject_name.snakeCase()%7D%7D/lib/l10n).
- [Testing](https://docs.flutter.dev/testing)-ready (unit, integration, and widget testing), [production and deployment](https://docs.flutter.dev/deployment)-ready (to Firebase, Play Store, TestFlight, and AppStore).
- Built-in [GitHub templates & CI/CD workflows](bricks/template/__brick__/%7B%7Bproject_name.snakeCase()%7D%7D/.github) integrated with GitHub Actions to perform static code analysis, test, build and deploy app builds to app distribution services or app stores.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:injectable/injectable.dart';

const _keyAccessToken = 'KEY_ACCESS_TOKEN';

abstract class SecureStorage {
Future<String?> get accessToken;

Future<void> storeAccessToken(String accessToken);

Future<void> clearAll();
}

@Singleton(as: SecureStorage)
class SecureStorageImpl extends SecureStorage {
final FlutterSecureStorage _storage;

SecureStorageImpl(this._storage);

@override
Future<String?> get accessToken => _storage.read(key: _keyAccessToken);

@override
Future<void> storeAccessToken(String accessToken) {
return _storage.write(key: _keyAccessToken, value: accessToken);
}

@override
Future<void> clearAll() {
return _storage.deleteAll();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:injectable/injectable.dart';

@module
abstract class StorageModule {
@singleton
FlutterSecureStorage get flutterSecureStorage => const FlutterSecureStorage(
aOptions: AndroidOptions(encryptedSharedPreferences: true));
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ dependencies:
flutter_localizations:
sdk: flutter
flutter_riverpod: ^2.3.6
flutter_secure_storage: ^9.0.0
flutter_svg: ^2.0.7
freezed_annotation: ^2.2.0
get_it: ^7.6.0
Expand Down
7 changes: 4 additions & 3 deletions sample/.github/workflows/android_deploy_production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ jobs:
build_and_deploy_android:
name: Build & Deploy Android
runs-on: ubuntu-latest
environment: production
timeout-minutes: 30
steps:
- name: Check out
Expand All @@ -34,9 +35,9 @@ jobs:

- name: Set up .env
env:
ENV_PRODUCTION: ${{ secrets.ENV_PRODUCTION }}
ENV: ${{ secrets.ENV }}
run: |
echo $ENV_PRODUCTION > .env
echo "$ENV" > .env

# App Bundle requires Firebase connected to Play Store to upload https://appdistribution.page.link/KPoa
- name: Build Android apk
Expand All @@ -45,7 +46,7 @@ jobs:
- name: Deploy Android Production to Firebase
uses: wzieba/[email protected]
with:
appId: ${{ secrets.FIREBASE_ANDROID_APP_ID_PRODUCTION }}
appId: ${{ vars.FIREBASE_ANDROID_APP_ID }}
serviceCredentialsFileContent: ${{ secrets.FIREBASE_DISTRIBUTION_CREDENTIAL_JSON }}
groups: ${{ vars.FIREBASE_DISTRIBUTION_TESTER_GROUPS }}
file: build/app/outputs/flutter-apk/app-production-debug.apk
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ jobs:
build_and_deploy_android:
name: Build & Deploy Android
runs-on: ubuntu-latest
environment: production
timeout-minutes: 30
steps:
- name: Check out
Expand All @@ -34,17 +35,17 @@ jobs:

- name: Set up .env
env:
ENV_PRODUCTION: ${{ secrets.ENV_PRODUCTION }}
ENV: ${{ secrets.ENV }}
run: |
echo $ENV_PRODUCTION > .env
echo "$ENV" > .env

- name: Set up release signing configs
env:
ANDROID_RELEASE_KEYSTORE_BASE64: ${{ secrets.ANDROID_RELEASE_KEYSTORE_BASE64 }}
ANDROID_SIGNING_PROPERTIES_BASE64: ${{ secrets.ANDROID_SIGNING_PROPERTIES_BASE64 }}
ANDROID_SIGNING_PROPERTIES: ${{ secrets.ANDROID_SIGNING_PROPERTIES }}
run: |
echo $ANDROID_RELEASE_KEYSTORE_BASE64 | base64 --decode > android/config/release.keystore
echo $ANDROID_SIGNING_PROPERTIES_BASE64 | base64 --decode > android/signing.properties
echo "$ANDROID_SIGNING_PROPERTIES" > android/signing.properties

- name: Build Production App Bundle
run: flutter build appbundle --flavor production --release --build-number $GITHUB_RUN_NUMBER
Expand Down
7 changes: 4 additions & 3 deletions sample/.github/workflows/android_deploy_staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ jobs:
build_and_deploy_android:
name: Build & Deploy Android
runs-on: ubuntu-latest
environment: staging
timeout-minutes: 30
steps:
- name: Check out
Expand All @@ -34,9 +35,9 @@ jobs:

- name: Set up .env.staging
env:
ENV_STAGING: ${{ secrets.ENV_STAGING }}
ENV: ${{ secrets.ENV }}
run: |
echo $ENV_STAGING > .env.staging
echo "$ENV" > .env.staging

# App Bundle requires Firebase connected to Play Store to upload https://appdistribution.page.link/KPoa
- name: Build Android apk
Expand All @@ -45,7 +46,7 @@ jobs:
- name: Deploy Android Staging to Firebase
uses: wzieba/[email protected]
with:
appId: ${{ secrets.FIREBASE_ANDROID_APP_ID_STAGING }}
appId: ${{ vars.FIREBASE_ANDROID_APP_ID }}
serviceCredentialsFileContent: ${{ secrets.FIREBASE_DISTRIBUTION_CREDENTIAL_JSON }}
groups: ${{ vars.FIREBASE_DISTRIBUTION_TESTER_GROUPS }}
file: build/app/outputs/flutter-apk/app-staging-debug.apk
2 changes: 0 additions & 2 deletions sample/.github/workflows/bump_version.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ jobs:
steps:
- name: Check out
uses: actions/checkout@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}

- name: Set new version
run: |
Expand Down
7 changes: 4 additions & 3 deletions sample/.github/workflows/ios_deploy_staging_to_firebase.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ jobs:
build_and_upload_staging_app_to_firebase:
name: Build And Upload iOS Staging Application To Firebase
runs-on: macOS-latest
environment: staging
env:
TEAM_ID: ${{ secrets.TEAM_ID }}
FASTLANE_USER: ${{ secrets.FASTLANE_USER }}
Expand All @@ -18,7 +19,7 @@ jobs:
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
FIREBASE_CLI_TOKEN: ${{ secrets.FIREBASE_CLI_TOKEN }}
FIREBASE_APP_ID_STAGING: ${{ secrets.FIREBASE_IOS_APP_ID_STAGING }}
FIREBASE_APP_ID: ${{ vars.FIREBASE_IOS_APP_ID }}
FIREBASE_DISTRIBUTION_TESTER_GROUPS: ${{ vars.FIREBASE_DISTRIBUTION_TESTER_GROUPS }}
GITHUB_RUN_NUMBER: $GITHUB_RUN_NUMBER
steps:
Expand All @@ -41,9 +42,9 @@ jobs:

- name: Set up .env.staging
env:
ENV_STAGING: ${{ secrets.ENV_STAGING }}
ENV: ${{ secrets.ENV }}
run: |
echo $ENV_STAGING > .env.staging
echo "$ENV" > .env.staging

- name: Run code generator
run: flutter packages pub run build_runner build --delete-conflicting-outputs
Expand Down
1 change: 1 addition & 0 deletions sample/.github/workflows/ios_deploy_to_app_store.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ jobs:
build_and_upload_to_app_store:
name: Build And Upload iOS Application To AppStore
runs-on: macOS-latest
environment: staging
timeout-minutes: 30
env:
TEAM_ID: ${{ secrets.TEAM_ID }}
Expand Down
1 change: 1 addition & 0 deletions sample/.github/workflows/ios_deploy_to_testflight.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ jobs:
build_and_upload_to_testflight:
name: Build And Upload iOS Application To TestFlight
runs-on: macOS-latest
environment: staging
timeout-minutes: 30
env:
TEAM_ID: ${{ secrets.TEAM_ID }}
Expand Down
4 changes: 2 additions & 2 deletions sample/ios/fastlane/Constants/Environments.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ def self.FIREBASE_CLI_TOKEN
ENV['FIREBASE_CLI_TOKEN']
end

def self.FIREBASE_APP_ID_STAGING
ENV['FIREBASE_APP_ID_STAGING']
def self.FIREBASE_APP_ID
ENV['FIREBASE_APP_ID']
end

def self.FIREBASE_TESTER_GROUPS
Expand Down
2 changes: 1 addition & 1 deletion sample/ios/fastlane/Fastfile
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ platform :ios do
scheme_name: Constants.SCHEME_NAME_STAGING,
product_name: Constants.PRODUCT_NAME_STAGING,
bundle_id: Constants.BUNDLE_ID_STAGING,
app_id: Environments.FIREBASE_APP_ID_STAGING
app_id: Environments.FIREBASE_APP_ID
)
end

Expand Down
32 changes: 32 additions & 0 deletions sample/lib/data/local/secure_storage.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:injectable/injectable.dart';

const _keyAccessToken = 'KEY_ACCESS_TOKEN';

abstract class SecureStorage {
Future<String?> get accessToken;

Future<void> storeAccessToken(String accessToken);

Future<void> clearAll();
}

@Singleton(as: SecureStorage)
class SecureStorageImpl extends SecureStorage {
final FlutterSecureStorage _storage;

SecureStorageImpl(this._storage);

@override
Future<String?> get accessToken => _storage.read(key: _keyAccessToken);

@override
Future<void> storeAccessToken(String accessToken) {
return _storage.write(key: _keyAccessToken, value: accessToken);
}

@override
Future<void> clearAll() {
return _storage.deleteAll();
}
}
9 changes: 9 additions & 0 deletions sample/lib/di/module/storage_module.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:injectable/injectable.dart';

@module
abstract class StorageModule {
@singleton
FlutterSecureStorage get flutterSecureStorage => const FlutterSecureStorage(
aOptions: AndroidOptions(encryptedSharedPreferences: true));
}
1 change: 1 addition & 0 deletions sample/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ dependencies:
flutter_localizations:
sdk: flutter
flutter_riverpod: ^2.3.6
flutter_secure_storage: ^9.0.0
flutter_svg: ^2.0.7
freezed_annotation: ^2.2.0
get_it: ^7.6.0
Expand Down