ALTME
– THE UNIVERSAL WALLET THAT WORKS FOR YOU
The Web 3 revolution is all about redistributing the power to the average consumer.
This is why we are building Altme, to help you get control over your data back.
Here is the last security audit done on our solution: AltMe security audit report for Web3 Digital Wallet.pdf
This project contains 3 flavors:
- development
- staging
- production
To run the desired flavor either use the launch configuration in VSCode/Android Studio or use the following commands:
# Development
$ flutter run --flavor development --target lib/main_development.dart
# Staging
$ flutter run --flavor staging --target lib/main_staging.dart
# Production
$ flutter run --flavor production --target lib/main_production.dart
*Altme works on iOS and Android.
To manually build Altme for either Android or iOS, you will need to install the following dependencies:
- Rust
- Java 7 or higher
- Flutter (
dev
channel) - DIDKit/SSI
- PolygonID Flutter SDK
It is recommended to use rustup to manage your Rust installation.
On Ubuntu you could run:
$ apt update
$ apt install openjdk-8-jdk
For more information, please refer to the documentation of your favorite flavour of Java and your operating system/package manager.
Please follow the official instalation instructions available here to install Flutter, don't forget to also install the build dependencies for the platform you will be building (Android SDK/NDK, Xcode, etc).
We currently only support build this project using the dev
channel of Flutter.
To change your installation to the dev
channel, please execute the following command:
$ flutter channel dev
$ flutter upgrade
To confirm that everything is setup correctly, please run the following command and resolve any issues that arise before proceeding to the next steps.
$ flutter doctor
This project also depends on two other Spruce
projects,
DIDKit
and
SSI
.
These projects are all configured to work with relative paths by default,
so it is recommended to clone them all under the same root directory, for
example $HOME/$FOLDER_NAME/{didkit,ssi,altme}
.
This is a flutter Plugin for PolygonID Mobile SDK (https://polygon.technology/polygon-id) This plugin provides a cross-platform tool (iOS, Android) to communicate with the PolygonID platform.
To build Altme for Android, you will require both the Android SDK and NDK.
These two dependencies can be easily obtained with Android Studio, which install further dependencies upon first being opened after installation. Installing the appropriate Android NDK (often not the newest) in Android Studio can be accomplished by going to Settings > Appearance & Behavior > System Settings > Android SDK and selecting to install the "NDK (Side by Side)".
An alternative method of installing SDK and NDK without Android Studio can be found in the script below:
cd $HOME
wget https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip
unzip sdk-tools-linux-4333796.zip -d Android
rm sdk-tools-linux-4333796.zip
wget https://dl.google.com/android/repository/commandlinetools-linux-6200805_latest.zip
unzip commandlinetools-linux-6200805_latest.zip -d Android/cmdline-tools
rm commandlinetools-linux-6200805_latest.zip
echo 'export ANDROID_SDK_ROOT=$HOME/Android' >> $HOME/.bashrc
echo 'export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64' >> $HOME/.bashrc
echo 'export PATH=$ANDROID_SDK_ROOT/cmdline-tools/tools/bin:"$PATH"' >> $HOME/.bashrc
echo 'export PATH=$ANDROID_SDK_ROOT/cmdline-tools/tools/lib:"$PATH"' >> $HOME/.bashrc
echo 'export PATH=$ANDROID_SDK_ROOT/tools:"$PATH"' >> $HOME/.bashrc
echo 'export PATH=$JAVA_HOME/bin:"$PATH"' >> $HOME/.bashrc
. $HOME/.bashrc
sdkmanager --sdk_root=$ANDROID_SDK_ROOT --install "system-images;android-29;google_apis;x86" "system-images;android-29;google_apis;x86_64" "platform-tools" "platforms;android-29" "build-tools;29.0.3" "ndk;22.0.7026061" "cmdline-tools;latest"
sdkmanager --licenses
If your Android SDK doesn't live at $HOME/Android/Sdk
you will need to set
ANDROID_SDK_ROOT
like so:
$ export ANDROID_SDK_ROOT=/path/to/Android/Sdk
Note: Some users have experienced difficulties with cross-compilation artefacts missing from the newest NDK, which is downloaded by default in the installation process. If you experience errors of this kind, you may have to manually downgrade or install multiple NDK versions as [shown here])(img/ndk_downgrade.png) in the Android Studio installer (screengrabbed from an Ubuntu installation).
If your build-tools
and/or NDK
live in different locations than the default ones inside /SDK/, or if you want to specify a specific NDK or build-tools version, you can manually configure the following two environment variables:
$ export ANDROID_TOOLS=/path/to/SDK/build-tools/XX.X.X/
$ export ANDROID_NDK_HOME=/path/to/SDK/ndk/XX.X.XXXXX/
:::
To build Altme for iOS you will need to install CocoaPods, which can be done with Homebrew on MacOS.
$ brew install cocoapods
To build DIDKit
for the Android targets, you will go to the root of DIDKit
and run:
$ make -C lib install-rustup-android
$ make -C lib ../target/test/java.stamp
$ make -C lib ../target/test/android.stamp
$ make -C lib ../target/test/flutter.stamp
$ cargo build
This may take some time as it compiles the entire project for multiple targets
To build DIDKit for the iOS targets, you will go to the root of DIDKit
and run:
$ make -C lib install-rustup-ios
$ make -C lib ../target/test/ios.stamp
$ cargo build
In order to handle installation of didkit, ssi, polygonid-flutter-sdk and altme, we can run shortcut script. We can also get the warnings if we have not configured the required things for building Altme.
For consistent app builts we can use fvm
.
You have to add the install_altme.sh
in the directory $HOME/$FOLDER_NAME/
. Then run the following command to
do the setup:
# Android
$ ./install_altme.sh -android
# iOS
$ ./install_altme.sh -ios
In order to generate all *.g.dart files, run the following command:
$ flutter packages pub run build_runner build --delete-conflicting-outputs
For smooth running of the functionalities of Altme, you need to add the following keys:
-
PASSBASE_WEBHOOK_AUTH_TOKEN
You can get this key fromhere
. -
PASSBASE_CHECK_DID_AUTH_TOKEN
The key is availablehere
. -
YOTI_AI_API_KEY
This key can be obtained fromhere
. -
TALAO_ISSUER_API_KEY
The key is availablehere
. -
INFURA_API_KEY
This key can be obtained fromhere
. -
MORALIS_API_KEY
You can get this key fromhere
. -
INFURA_URL
URL of the blockchain (eg: https://polygon-mumbai.infura.io/v3/) -
INFURA_RDP_URL
RDP URL (eg: wss://polygon-mumbai.infura.io/v3/) -
ID_STATE_CONTRACT_ADDR
The ID state contract (eg: 0x453A1BC32122E39A8398ec6288783389730807a5) -
PUSH_URL
The push notification URL (eg: https://push.service.io/api/v1) -
TALAO_MATRIX_API_KEY
The key is availablehere
.
For iOS only:
- Add to your app's Podfile the following post_install code:
post_install do |installer|
installer.pods_project.targets.each do |target|
...
end
# polygon-setup
if target.name == "Pods-Runner"
puts "Updating #{target.name} OTHER_LDFLAGS"
target.build_configurations.each do |config|
xcconfig_path = config.base_configuration_reference.real_path
xcconfig = File.read(xcconfig_path)
new_xcconfig = xcconfig.sub('OTHER_LDFLAGS = $(inherited)', 'OTHER_LDFLAGS = $(inherited) -force_load "${PODS_ROOT}/../.symlinks/plugins/polygonid_flutter_sdk/ios/librapidsnark.a" -force_load "${PODS_ROOT}/../.symlinks/plugins/polygonid_flutter_sdk/ios/libwitnesscalc_authV2.a" -force_load "${PODS_ROOT}/../.symlinks/plugins/polygonid_flutter_sdk/ios/libwitnesscalc_credentialAtomicQueryMTPV2.a" -force_load "${PODS_ROOT}/../.symlinks/plugins/polygonid_flutter_sdk/ios/libwitnesscalc_credentialAtomicQuerySigV2.a" -force_load "${PODS_ROOT}/../.symlinks/plugins/polygonid_flutter_sdk/ios/libgmp.a" -force_load "${PODS_ROOT}/../.symlinks/plugins/polygonid_flutter_sdk/ios/libpolygonid.a"')
File.open(xcconfig_path, "w") { |file| file << new_xcconfig }
end
end
end
end
Please check PolygonID Flutter SDK
for smooth running of polygonid-flutter-sdk.
P.S. Using iOS simulator for testing wallet sdk is right now under maintenance and will be available soon.
You are now ready to build or run Altme.
If you want to run the project on your connected device, you can use:
# Development
$ flutter run --flavor development --target lib/main_development.dart
# Staging
$ flutter run --flavor staging --target lib/main_staging.dart
# Production
$ flutter run --flavor production --target lib/main_production.dart
# Development
$ flutter build apk --release --split-per-abi --flavor development -t lib/main_development.dart
# Staging
$ flutter build apk --release --split-per-abi --flavor staging -t lib/main_staging.dart
# Production
$ flutter build apk --release --split-per-abi --flavor production -t lib/main_production.dart
# Development
$ flutter build appbundle --flavor "development" --target "lib/main_development.dart"
# Staging
$ flutter build appbundle --flavor "staging" --target "lib/main_staging.dart"
# Production
$ flutter build appbundle --flavor "production" --target "lib/main_production.dart"
# Development
$ flutter build ios --simulator --flavor "development" --target "lib/main_development.dart"
# Staging
$ flutter build ios --simulator --flavor "staging" --target "lib/main_staging.dart"
# Production
$ flutter build ios --simulator --flavor "production" --target "lib/main_production.dart"
# Development
$ flutter build ios --no-codesign --flavor "development" --target "lib/main_development.dart"
# Staging
$ flutter build ios --no-codesign --flavor "staging" --target "lib/main_staging.dart"
# Production
$ flutter build ios --no-codesign --flavor "production" --target "lib/main_production.dart"
# Development
$ flutter build ipa --flavor "development" --target "lib/main_development.dart"
# Staging
$ flutter build ipa --flavor "staging" --target "lib/main_staging.dart"
# Production
$ flutter build ipa --flavor "production" --target "lib/main_production.dart"
If you have setup the fastlane
for continuous delivery, then you can run the following command to publish:
$ flutter pub get
$ flutter packages pub run build_runner build --delete-conflicting-outputs
$ flutter build ios --release --flavor "production" --target "lib/main_production.dart"
$ $cd ios
$ fastlane beta
If you encounter any errors in the build process described here, please first try clean builds of the projects listed.
For instance, on Flutter, you can delete build files to start over by running:
$ flutter clean
Also, reviewing the
install_altme.sh
script may be helpful.
All QRCode interactions start as listed below:
- User scans a QRCode containing a URL;
- User is presented the choice to trust the domain in the URL;
- App makes a GET request to the URL;
Then, depending on the type of message, one of the following protocols will be executed.
After receiving a CredentialOffer
from a trusted host, the app calls the API
with subject_id
in the form body, that value is the didKey obtained from the
private key stored in the FlutterSecureStorage
, which is backed by KeyStore
on Android and Keychain on iOS.
The flow of events and actions is listed below:
- User is presented a credential preview to review and make a decision;
- App generates
didKey
from the stored private key usingDIDKit.keyToDIDKey
; - App makes a POST request to the initial URL with the subject set to the
didKey
; - App receives and stores the new credential;
- User is redirect back to the wallet.
And below is another version of the step-by-step:
Wallet | 1 | Server | |
---|---|---|---|
Scan QRCode 2 | |||
Trust Host | ○ / × | ||
HTTP GET | → | https://domain.tld/endpoint | |
← | CredentialOffer | ||
Preview Credential | |||
Choose DID | ○ / × | ||
HTTP POST 3 | → | https://domain.tld/endpoint | |
← | VerifiableCredential | ||
Verify Credential | |||
Store Credential |
1 Whether this action requires user confirmation, exiting the flow
early when the user denies.
2 The QRCode should contain the HTTP endpoint where the requests
will be made.
3 The body of the request contains a field subject_id
set to the
chosen DID.
After receiving a VerifiablePresentationRequest
from a trusted host, the app
calls the API with presentation
the form body, that value is a JSON encoded
string with the presentation obtained from the selected credential and signed
with the credential's private key using DIDKit.issuePresentation
.
Here are some of the parameters used to generate a presentation:
presentation
id
is set to a randomUUID.v4
string;holder
is set to the selected credential'sdidKey
;verifiableCredential
is set to the credential value;
options
verificationMethod
is set to the DID'sverificationMethod
id
;proofPurpose
is set to'authentication'
;challenge
is set to the request's `challenge';domain
is set to the request's `domain';
key
is the credential's stored private key;
The flow of events and actions is listed below:
- User is presented a presentation request to review and make a decision;
- App generates
didKey
from the stored private key usingDIDKit.keyToDIDKey
; - App issues a presentation using
DIDKit.issuePresentation
; - App makes a POST request to the initial URL with the presentation;
- User is redirect back to the wallet.
And below is another version of the step-by-step:
Wallet | 1 | Server | |
---|---|---|---|
Scan QRCode 2 | |||
Trust Host | ○ / × | ||
HTTP GET | → | https://domain.tld/endpoint | |
← | VerifiablePresentationRequest | ||
Preview Presentation | |||
Choose Verifiable Credential | ○ / × | ||
HTTP POST 3 | → | https://domain.tld/endpoint | |
← | Result |
To run all unit and widget tests use the following command:
$ flutter test --coverage --test-randomize-ordering-seed random
To view the generated coverage report you can use lcov.
# Generate Coverage Report
$ genhtml coverage/lcov.info -o coverage/
# Open Coverage Report
$ open coverage/index.html
This project relies on flutter_localizations and follows the official internationalization guide for Flutter.
- To add a new localizable string, open the
app_en.arb
file atlib/l10n/arb/app_en.arb
.
{
"@@locale": "en",
"counterAppBarTitle": "Counter",
"@counterAppBarTitle": {
"description": "Text shown in the AppBar of the Counter Page"
}
}
- Then add a new key/value and description
{
"@@locale": "en",
"counterAppBarTitle": "Counter",
"@counterAppBarTitle": {
"description": "Text shown in the AppBar of the Counter Page"
},
"helloWorld": "Hello World",
"@helloWorld": {
"description": "Hello World Text"
}
}
- Use the new string
import 'package:altme/l10n/l10n.dart';
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return Text(l10n.helloWorld);
}
Update the CFBundleLocalizations
array in the Info.plist
at ios/Runner/Info.plist
to include the new locale.
...
<key>CFBundleLocalizations</key>
<array>
<string>en</string>
<string>es</string>
</array>
...
- For each supported locale, add a new ARB file in
lib/l10n/arb
.
├── l10n
│ ├── arb
│ │ ├── app_en.arb
│ │ └── app_es.arb
- Add the translated strings to each
.arb
file:
app_en.arb
{
"@@locale": "en",
"counterAppBarTitle": "Counter",
"@counterAppBarTitle": {
"description": "Text shown in the AppBar of the Counter Page"
}
}
app_es.arb
{
"@@locale": "es",
"counterAppBarTitle": "Contador",
"@counterAppBarTitle": {
"description": "Texto mostrado en la AppBar de la página del contador"
}
}
# generate .g.dart files
$ ./script.sh -build_runner
# build app for development
$ ./script.sh -rundev
# build app for stage
$ ./script.sh -runstage
# build app for production
$ ./script.sh -run
# add/update pod
$ ./script.sh -pod install
# build app bundle for ios
$ ./script.sh -build appbundle
# deploy ios app with fastlane setup
$ ./script.sh -deploy ios
#For permission
$ sudo chmod 777 script.sh
prod altme android: 365 (2.2.3) ios: 365 (2.2.3) talao android: 363 (2.2.0) ios: 359 (2.2.0) test altme android: 368 (2.2.6) ios: 368 (2.2.6) talao android: 368 (2.2.6) ios: 368 (2.2.6)