Skip to content

Commit

Permalink
Merge pull request #1600 from bitmark-inc/encrypt_env_secret
Browse files Browse the repository at this point in the history
fix: encript env, decrypt when app run
  • Loading branch information
phuocbitmark authored Mar 29, 2024
2 parents 24da82a + 7bba15d commit f1576d5
Show file tree
Hide file tree
Showing 14 changed files with 254 additions and 38 deletions.
11 changes: 11 additions & 0 deletions .env.secret.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FERAL_FILE_SECRET_KEY_TESTNET=
FERAL_FILE_SECRET_KEY_MAINNET=
CHAT_SERVER_HMAC_KEY=
AU_CLAIM_SECRET_KEY=
MIXPANEL_KEY=
METRIC_SECRET_KEY=
BRANCH_KEY=
SENTRY_DSN=
ONESIGNAL_APP_ID=
METRIC_ENDPOINT=
WEB3_RPC_MAINNET_URL=
12 changes: 12 additions & 0 deletions .github/workflows/android-release-appcenter.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,22 @@ jobs:
${{ inputs.testnet == true }} && echo -e "${{ secrets.DEV_ENV }}" | sed 's/\\n/\n/g' >> .env || echo -e "${{ secrets.STAGING_ENV }}" | sed 's/\\n/\n/g' >> .env
cat .env
- name: Create env secret file
run: |
touch .env.secret
${{ inputs.testnet == true }} && echo -e "${{ secrets.DEV_ENV_SECRET }}" | sed 's/\\n/\n/g' >> .env.secret || echo -e "${{ secrets.STAGING_ENV_SECRET }}" | sed 's/\\n/\n/g' >> .env.secret
cat .env.secret
- name: Submoudles update
run: git -c submodule.auto-test.update=none submodule update --init --recursive
- run: flutter pub cache repair
- run: flutter pub get

# Encrypt secrets before use
- name: Encrypt Secrets
run: |
./script/encrypt_secrets.sh ${{ secrets.ENTROPY }}
- run: flutter build apk --flavor inhouse
- run: mv build/app/outputs/flutter-apk/app-inhouse-release.apk build/app/outputs/flutter-apk/app-inhouse-release-${{ env.NAME_SUFFIX }}.apk
- name: Distribute apk to App Center
Expand Down
16 changes: 14 additions & 2 deletions .github/workflows/bmvn_build_appcenter_android.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,22 @@ jobs:
${{ inputs.testnet == true }} && echo -e "${{ secrets.DEV_ENV }}" | sed 's/\\n/\n/g' >> .env || echo -e "${{ secrets.STAGING_ENV }}" | sed 's/\\n/\n/g' >> .env
cat .env
- name: Create env secret file
run: |
touch .env.secret
${{ inputs.testnet == true }} && echo -e "${{ secrets.DEV_ENV_SECRET }}" | sed 's/\\n/\n/g' >> .env.secret || echo -e "${{ secrets.STAGING_ENV_SECRET }}" | sed 's/\\n/\n/g' >> .env.secret
cat .env
- name: Submoudles update
run: git -c submodule.auto-test.update=none submodule update --init --recursive
- run: flutter pub cache repair
- run: flutter pub get

# Encrypt secrets before use
- name: Encrypt Secrets
run: |
./script/encrypt_secrets.sh ${{ secrets.ENTROPY }}
- run: flutter build apk --flavor inhouse
- run: mv build/app/outputs/flutter-apk/app-inhouse-release.apk build/app/outputs/flutter-apk/app-inhouse-release-${{ env.NAME_SUFFIX }}.apk
- name: Distribute apk to App Center
Expand All @@ -95,7 +107,7 @@ jobs:
release_notes: ${{ inputs.message }}

- name: Upload Sentry debug symbols
env:
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH }}
run: |
flutter packages pub run sentry_dart_plugin
flutter packages pub run sentry_dart_plugin
13 changes: 12 additions & 1 deletion .github/workflows/bmvn_build_appcenter_ios.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ jobs:
${{ inputs.testnet == true }} && echo -e "${{ secrets.DEV_ENV }}" | sed 's/\\n/\n/g' >> .env || echo -e "${{ secrets.STAGING_ENV }}" | sed 's/\\n/\n/g' >> .env
cat .env
- name: Create env secret file
run: |
touch .env.secret
${{ inputs.testnet == true }} && echo -e "${{ secrets.DEV_ENV_SECRET }}" | sed 's/\\n/\n/g' >> .env.secret || echo -e "${{ secrets.STAGING_ENV_SECRET }}" | sed 's/\\n/\n/g' >> .env.secret
cat .env
- name: Flutter doctor
run: flutter doctor
- name: Submoudles update
Expand All @@ -96,6 +102,11 @@ jobs:
cd ios/
pod install
# Encrypt secrets before use
- name: Encrypt Secrets
run: |
./script/encrypt_secrets.sh ${{ secrets.ENTROPY }}
- uses: mathieu-bour/setup-sentry-cli@main

# Build and deploy with Fastlane (by default, to ciappcenter track) 🚀.
Expand All @@ -120,7 +131,7 @@ jobs:
working-directory: ios

- name: Upload Sentry debug symbols
env:
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH }}
run: |
flutter packages pub run sentry_dart_plugin
11 changes: 11 additions & 0 deletions .github/workflows/ios-release-testflight.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ jobs:
echo -e "${{ secrets.PRODUCTION_ENV }}" | sed 's/\\n/\n/g' >> .env
cat .env
- name: Create env secret file
run: |
touch .env.secret
echo -e "${{ secrets.PRODUCTION_ENV_SECRET }}" | sed 's/\\n/\n/g' >> .env.secret
cat .env.secret
- name: Flutter doctor
run: flutter doctor
- name: Submoudles update
Expand All @@ -76,6 +82,11 @@ jobs:
cd ios/
pod install
# Encrypt secrets before use
- name: Encrypt Secrets
run: |
./script/encrypt_secrets.sh ${{ secrets.ENTROPY }}
- uses: mathieu-bour/setup-sentry-cli@main

# Build and deploy with Fastlane (by default, to ciappcenter track) 🚀.
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,7 @@ app.*.map.json
# app environment variables
.env
.env.development
.env.production
.env.production
.env.secret

lib/encrypt_env/secrets.g.dart
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,13 @@ Autonomy is the world’s first and only digital art wallet. It gives you one ea
3. Initialize submodule by running; `git submodule update --init --recursive`
- If you don't want to clone the auto-test package, simply run: `git -c submodule.auto-test.update=none submodule update --init --recursive`
4. Initialize the config file. `cp .env.example .env`
- Contact with Feral File app development team for development env.
5. Run `flutter run --flavor inhouse` to run Feral File app development on the connected device.
- Contact with Feral File app development team for development env.
5. Initialize the secret config file. `cp .env.secret.example .env.secret`
- There are credentials information. You may need to provide your own credentials.Contact with Feral File app development team for consultation.
6. Run ./script/encrypt_secrets.sh <-entropy-> to generate the encrypted secrets file.
- <-entropy-> is a random string. You can type a random string like akhrdsgl4893tynk3iu4y8hf
- You only need to run this script again when you want to update .env.secret.
7. Run `flutter run --flavor inhouse` to run Feral File app development on the connected device.

A few resources to get you started if this is your first Flutter project:

Expand Down
59 changes: 31 additions & 28 deletions lib/common/environment.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// that can be found in the LICENSE file.
//

import 'package:autonomy_flutter/encrypt_env/secrets.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';

class Environment {
Expand Down Expand Up @@ -42,8 +43,6 @@ class Environment {
? connectWebsocketTestnetURL
: connectWebsocketMainnetURL;

static String get auClaimSecretKey => dotenv.env['AU_CLAIM_SECRET_KEY'] ?? '';

static String get tokenWebviewPrefix =>
dotenv.env['TOKEN_WEBVIEW_PREFIX'] ?? '';

Expand All @@ -53,9 +52,6 @@ class Environment {
static String get indexerTestnetURL =>
dotenv.env['INDEXER_TESTNET_API_URL'] ?? '';

static String get web3RpcMainnetURL =>
dotenv.env['WEB3_RPC_MAINNET_URL'] ?? '';

static int get web3MainnetChainId =>
int.tryParse(dotenv.env['WEB3_MAINNET_CHAIN_ID'] ?? '1') ?? 1;

Expand All @@ -80,21 +76,15 @@ class Environment {
static String get feralFileAPIMainnetURL =>
dotenv.env['FERAL_FILE_API_MAINNET_URL'] ?? '';

static String get feralFileSecretKeyMainnet =>
dotenv.env['FERAL_FILE_SECRET_KEY_MAINNET'] ?? '';

static String get feralFileAPITestnetURL =>
dotenv.env['FERAL_FILE_API_TESTNET_URL'] ?? '';

static String get feralFileSecretKeyTestnet =>
dotenv.env['FERAL_FILE_SECRET_KEY_TESTNET'] ?? '';
static String get feralFileAssetURLTestnet =>
dotenv.env['FERAL_FILE_ASSET_URL_TESTNET'] ?? '';

static String get feralFileAssetURLMainnet =>
dotenv.env['FERAL_FILE_ASSET_URL_MAINNET'] ?? '';

static String get feralFileAssetURLTestnet =>
dotenv.env['FERAL_FILE_ASSET_URL_TESTNET'] ?? '';

static String get extensionSupportMainnetURL =>
dotenv.env['EXTENSION_SUPPORT_MAINNET_URL'] ?? '';

Expand All @@ -119,10 +109,6 @@ class Environment {

static String get pubdocURL => dotenv.env['AUTONOMY_PUBDOC_URL'] ?? '';

static String get sentryDSN => dotenv.env['SENTRY_DSN'] ?? '';

static String get onesignalAppID => dotenv.env['ONESIGNAL_APP_ID'] ?? '';

static String get awsIdentityPoolId =>
dotenv.env['AWS_IDENTITY_POOL_ID'] ?? '';

Expand All @@ -138,14 +124,6 @@ class Environment {
static bool get appTestnetConfig =>
dotenv.env['APP_TESTNET_CONFIG']?.toUpperCase() == 'TRUE';

static String get metricEndpoint => dotenv.env['METRIC_ENDPOINT'] ?? '';

static String get metricSecretKey => dotenv.env['METRIC_SECRET_KEY'] ?? '';

static String get branchKey => dotenv.env['BRANCH_KEY'] ?? '';

static String get mixpanelKey => dotenv.env['MIXPANEL_KEY'] ?? '';

static String get auClaimAPIURL => dotenv.env['AU_CLAIM_API_URL'] ?? '';

static List<String> get irlWhitelistUrls =>
Expand All @@ -166,9 +144,6 @@ class Environment {
static String get payToMintBaseUrl =>
dotenv.env['PAY_TO_MINT_BASE_URL'] ?? '';

static String get chatServerHmacKey =>
dotenv.env['CHAT_SERVER_HMAC_KEY'] ?? '';

static String get postcardChatServerUrl =>
dotenv.env['CHAT_SERVER_URL'] ?? '';

Expand All @@ -184,6 +159,34 @@ class Environment {

static String get autonomyActivationURL =>
dotenv.env['AUTONOMY_ACTIVATION_URL'] ?? '';

static String get chatServerHmacKey =>
cachedSecretEnv['CHAT_SERVER_HMAC_KEY'] ?? '';

static String get metricEndpoint => cachedSecretEnv['METRIC_ENDPOINT'] ?? '';

static String get metricSecretKey =>
cachedSecretEnv['METRIC_SECRET_KEY'] ?? '';

static String get branchKey => cachedSecretEnv['BRANCH_KEY'] ?? '';

static String get mixpanelKey => cachedSecretEnv['MIXPANEL_KEY'] ?? '';

static String get auClaimSecretKey =>
cachedSecretEnv['AU_CLAIM_SECRET_KEY'] ?? '';

static String get feralFileSecretKeyTestnet =>
cachedSecretEnv['FERAL_FILE_SECRET_KEY_TESTNET'] ?? '';

static String get feralFileSecretKeyMainnet =>
cachedSecretEnv['FERAL_FILE_SECRET_KEY_MAINNET'] ?? '';

static String get web3RpcMainnetURL =>
cachedSecretEnv['WEB3_RPC_MAINNET_URL'] ?? '';

static String get sentryDSN => cachedSecretEnv['SENTRY_DSN'] ?? '';

static String get onesignalAppID => cachedSecretEnv['ONESIGNAL_APP_ID'] ?? '';
}

class Secret {
Expand Down
1 change: 1 addition & 0 deletions lib/encrypt_env/secrets.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
late dynamic cachedSecretEnv;
5 changes: 5 additions & 0 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@
// ignore_for_file: avoid_annotating_with_dynamic

import 'dart:async';
import 'dart:convert';
import 'dart:isolate';
import 'dart:ui';

import 'package:autonomy_flutter/common/environment.dart';
import 'package:autonomy_flutter/common/injector.dart';
import 'package:autonomy_flutter/encrypt_env/secrets.dart';
import 'package:autonomy_flutter/encrypt_env/secrets.g.dart';
import 'package:autonomy_flutter/model/eth_pending_tx_amount.dart';
import 'package:autonomy_flutter/screen/app_router.dart';
import 'package:autonomy_flutter/service/configuration_service.dart';
Expand Down Expand Up @@ -47,6 +50,8 @@ import 'package:sentry_flutter/sentry_flutter.dart';

void main() async {
unawaited(runZonedGuarded(() async {
final json = await getSecretEnv();
cachedSecretEnv = jsonDecode(json);
await dotenv.load();
await SentryFlutter.init(
(options) {
Expand Down
24 changes: 20 additions & 4 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.3"
cryptography:
dependency: "direct main"
description:
name: cryptography
sha256: d146b76d33d94548cf035233fbc2f4338c1242fa119013bead807d033fc4ae05
url: "https://pub.dev"
source: hosted
version: "2.7.0"
cryptography_flutter:
dependency: "direct main"
description:
name: cryptography_flutter
sha256: a7fc3f0de42fb0947cbf213257aa3a69c89df561d104723ede8050658621f292
url: "https://pub.dev"
source: hosted
version: "2.3.2"
csslib:
dependency: transitive
description:
Expand Down Expand Up @@ -568,10 +584,10 @@ packages:
dependency: transitive
description:
name: ffi
sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99
sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
version: "2.1.2"
file:
dependency: transitive
description:
Expand Down Expand Up @@ -2979,5 +2995,5 @@ packages:
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.2.0-0 <4.0.0"
flutter: ">=3.10.0"
dart: ">=3.3.0-279.1.beta <4.0.0"
flutter: ">=3.13.0"
2 changes: 2 additions & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ dependencies:
image_gallery_saver: ^2.0.3
hand_signature: ^3.0.1
flutter_pdfview: ^1.3.2
cryptography: ^2.7.0
cryptography_flutter: ^2.3.2
dependency_overrides:
intl: 0.18.0

Expand Down
40 changes: 40 additions & 0 deletions script/encrypt.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// ignore_for_file: avoid_print

import 'dart:convert';
import 'dart:math';
import 'package:cryptography/cryptography.dart';

// Example function for encryption
Future<List<dynamic>> _encryptText(String text, String key) async {
final algorithm = Chacha20.poly1305Aead();
final bytes = utf8.encode(key);
final secretKey = await algorithm.newSecretKeyFromBytes(bytes);
final secretBox = await algorithm.encryptString(text, secretKey: secretKey);
final encryptText = secretBox.concatenation();
return [
base64Encode(encryptText),
secretBox.nonce.length,
secretBox.mac.bytes.length
];
}

String _generateKeyFromEntropy(String entropy, int length) {
final random = Random(entropy.hashCode); // Use entropy's hash code as seed
final entropyLength = entropy.length;
return String.fromCharCodes(Iterable.generate(
length, (_) => entropy.codeUnitAt(random.nextInt(entropyLength))));
}

void main(List<String> arguments) async {
if (arguments.length < 2) {
print('Usage: dart encrypt.dart <text_to_encrypt> <entropy>');
return;
}

String textToEncrypt = arguments[0];
String entropy = arguments[1];

final encryptedText =
await _encryptText(textToEncrypt, _generateKeyFromEntropy(entropy, 32));
print(encryptedText.join(' '));
}
Loading

0 comments on commit f1576d5

Please sign in to comment.