Skip to content

Commit

Permalink
Merge pull request #6 from TBD54566975/use-real-pfi-widget-uri
Browse files Browse the repository at this point in the history
feat: use real widget uris for PFi
  • Loading branch information
wesbillman authored Jan 4, 2024
2 parents ef6609d + 9cb1458 commit cc5d696
Show file tree
Hide file tree
Showing 10 changed files with 116 additions and 34 deletions.
2 changes: 1 addition & 1 deletion frontend/ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Flutter Starter</string>
<string>DIDPay</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
Expand Down
2 changes: 1 addition & 1 deletion frontend/lib/features/account/account_did_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class AccountDidPage extends HookConsumerWidget {
appBar: AppBar(title: const Text('My DID')),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: Center(child: SelectableText(did))),
child: Center(child: SelectableText(did.uri))),
);
}
}
3 changes: 2 additions & 1 deletion frontend/lib/features/account/account_providers.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:tbdex/tbdex.dart';

final didProvider = Provider<String>((ref) => throw UnimplementedError());
final didProvider = Provider<Did>((ref) => throw UnimplementedError());
23 changes: 16 additions & 7 deletions frontend/lib/features/home/home_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_starter/features/pfis/pfi_providers.dart';
import 'package:flutter_starter/features/pfis/pfi_verification_page.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:tbdex/tbdex.dart';

class HomePage extends HookConsumerWidget {
const HomePage({super.key});
Expand All @@ -16,14 +17,22 @@ class HomePage extends HookConsumerWidget {
...pfis.map(
(pfi) => ListTile(
title: Text(pfi.name),
subtitle: Text(pfi.id),
subtitle: Text(pfi.didUri),
trailing: const Icon(Icons.chevron_right),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => PfiVerificationPage(pfi: pfi),
),
);
onTap: () async {
final result = await DidDht.resolve(pfi.didUri);
final widgetService = result.didDocument?.service
?.firstWhere((e) => e.type == 'kyc-widget');
if (widgetService?.serviceEndpoint != null) {
// ignore: use_build_context_synchronously
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => PfiVerificationPage(
widgetUri: widgetService!.serviceEndpoint,
),
),
);
}
},
),
)
Expand Down
4 changes: 2 additions & 2 deletions frontend/lib/features/pfis/pfi.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
class Pfi {
final String id;
final String name;
final String widgetUrl;
final String didUri;

Pfi({
required this.id,
required this.name,
required this.widgetUrl,
required this.didUri,
});
}
10 changes: 7 additions & 3 deletions frontend/lib/features/pfis/pfi_providers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';

final pfisProvider = Provider<List<Pfi>>(
(ref) => [
Pfi(
id: 'prototype',
name: 'Prototype PFI',
didUri: 'did:dht:3x1hbjobt577amnoeoxcenqrbjicym5mgsx6c6zszisf1igfj51y',
),
Pfi(
id: 'africa',
name: 'Africa',
widgetUrl: 'https://tbd.website',
didUri: 'coming soon...',
),
Pfi(
id: 'mexico',
name: 'Mexico',
widgetUrl:
'https://robustdisastrousstartups.wesbillman.repl.co/?proof=moeisreal&callback_uri=didpay://wes',
didUri: 'coming soon...',
),
],
);
8 changes: 4 additions & 4 deletions frontend/lib/features/pfis/pfi_verification_page.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import 'package:webview_flutter/webview_flutter.dart';
import 'package:flutter/material.dart';
import 'package:flutter_starter/features/pfis/pfi.dart';

class PfiVerificationPage extends StatelessWidget {
final Pfi pfi;
final String widgetUri;

const PfiVerificationPage({required this.pfi, super.key});
const PfiVerificationPage({required this.widgetUri, super.key});

@override
Widget build(BuildContext context) {
final fullPath = '$widgetUri?proof=moegrammer&callback_uri=didpay://kyc';
final controller = WebViewController()
..setBackgroundColor(Theme.of(context).colorScheme.background)
..setNavigationDelegate(
Expand All @@ -28,7 +28,7 @@ class PfiVerificationPage extends StatelessWidget {
},
),
)
..loadRequest(Uri.parse(pfi.widgetUrl));
..loadRequest(Uri.parse(fullPath));

return Scaffold(
appBar: AppBar(title: const Text('PFI Verification')),
Expand Down
26 changes: 14 additions & 12 deletions frontend/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:flutter_starter/features/account/account_providers.dart';
import 'package:flutter_starter/features/app/app.dart';
import 'package:flutter_starter/services/secure_storage_key_manager.dart';
import 'package:flutter_starter/services/service_providers.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:tbdex/tbdex.dart';
Expand All @@ -14,8 +15,8 @@ void main() async {
aOptions: AndroidOptions(encryptedSharedPreferences: true),
);

final did = await getOrCreateDid(storage);

final keyManager = SecureStorageKeyManager(storage);
final did = await getOrCreateDid(keyManager, storage);
runApp(ProviderScope(
overrides: [
secureStorage.overrideWithValue(storage),
Expand All @@ -25,16 +26,17 @@ void main() async {
));
}

Future<String> getOrCreateDid(FlutterSecureStorage storage) async {
const didKey = 'did';
final did = await storage.read(key: didKey);
if (did != null) {
return did;
Future<Did> getOrCreateDid(
KeyManager keyManager,
FlutterSecureStorage storage,
) async {
const didUriKey = 'did.uri';
final didUri = await storage.read(key: didUriKey);
if (didUri != null) {
return DidJwk(uri: didUri, keyManager: keyManager);
}

final keyManager = InMemoryKeyManager();
final jwt = await DidJwk.create(keyManager: keyManager);
await storage.write(key: didKey, value: jwt.uri);

return jwt.uri;
final did = await DidJwk.create(keyManager: keyManager);
await storage.write(key: didUriKey, value: did.uri);
return did;
}
42 changes: 42 additions & 0 deletions frontend/lib/services/secure_storage_key_manager.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import 'dart:convert';
import 'dart:typed_data';

import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:tbdex/tbdex.dart';

class SecureStorageKeyManager implements KeyManager {
final FlutterSecureStorage _storage;
SecureStorageKeyManager(this._storage);

@override
Future<String> generatePrivateKey(DsaName alg) async {
final privateKeyJwk = await DsaAlgorithms.generatePrivateKey(alg);
final thumbprint = privateKeyJwk.computeThumbprint();
await _storage.write(key: thumbprint, value: privateKeyJwk.toString());
return thumbprint;
}

@override
Future<Jwk> getPublicKey(String keyAlias) async {
final privateKeyJwkStr = await _storage.read(key: keyAlias);

if (privateKeyJwkStr == null) {
throw Exception('No key found with alias $keyAlias');
}

final privateKeyJwk = Jwk.fromJson(json.decode(privateKeyJwkStr));
return DsaAlgorithms.computePublicKey(privateKeyJwk);
}

@override
Future<Uint8List> sign(String keyAlias, Uint8List payload) async {
final privateKeyJwkStr = await _storage.read(key: keyAlias);

if (privateKeyJwkStr == null) {
throw Exception('No key found with alias $keyAlias');
}

final privateKeyJwk = Jwk.fromJson(json.decode(privateKeyJwkStr));
return DsaAlgorithms.sign(privateKeyJwk, payload);
}
}
30 changes: 27 additions & 3 deletions frontend/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.11.0"
base32:
dependency: transitive
description:
name: base32
sha256: ddad4ebfedf93d4500818ed8e61443b734ffe7cf8a45c668c9b34ef6adde02e2
url: "https://pub.dev"
source: hosted
version: "2.1.3"
boolean_selector:
dependency: transitive
description:
Expand Down Expand Up @@ -41,6 +49,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.18.0"
convert:
dependency: transitive
description:
name: convert
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
url: "https://pub.dev"
source: hosted
version: "3.1.1"
crypto:
dependency: transitive
description:
Expand Down Expand Up @@ -82,10 +98,10 @@ packages:
dependency: "direct main"
description:
name: flutter_hooks
sha256: "7c8db779c2d1010aa7f9ea3fbefe8f86524fcb87b69e8b0af31e1a4b55422dec"
sha256: "09f64db63fee3b2ab8b9038a1346be7d8986977fae3fec601275bf32455ccfc0"
url: "https://pub.dev"
source: hosted
version: "0.20.3"
version: "0.20.4"
flutter_lints:
dependency: "direct dev"
description:
Expand Down Expand Up @@ -301,6 +317,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.7"
pointycastle:
dependency: transitive
description:
name: pointycastle
sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c"
url: "https://pub.dev"
source: hosted
version: "3.7.3"
riverpod:
dependency: transitive
description:
Expand Down Expand Up @@ -359,7 +383,7 @@ packages:
description:
path: "."
ref: main
resolved-ref: "7ba39caf5a950196abfe881a0ffee307aa79c2c2"
resolved-ref: "16e4c095efa420e770a0ee32663f1f52dcfce095"
url: "https://github.com/TBD54566975/tbdex-dart.git"
source: git
version: "0.1.0"
Expand Down

0 comments on commit cc5d696

Please sign in to comment.