Skip to content

Commit

Permalink
Merge branch 'main' into main_android
Browse files Browse the repository at this point in the history
  • Loading branch information
hawkbee1 committed Oct 9, 2023
2 parents 3e694a9 + ce59719 commit 99ee2dc
Show file tree
Hide file tree
Showing 15 changed files with 312 additions and 21 deletions.
1 change: 1 addition & 0 deletions lib/app/shared/constants/secure_storage_keys.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class SecureStorageKeys {
static const String ssiKey = 'ssi/key';

static const String p256PrivateKey = 'p256PrivateKey';
static const String p256PrivateKey2 = 'p256PrivateKey2';

static const String cryptoAccount = 'cryptoAccount';
static const String cryptoAccounTrackingIndex = 'cryptoAccounTrackingIndex';
Expand Down
30 changes: 28 additions & 2 deletions lib/app/shared/helper_functions/helper_functions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ Future<String> web3RpcMainnetInfuraURL() async {
return '$prefixUrl$infuraApiKey';
}

Future<String> getRandomP256PrivateKey(
Future<String> getEBSIV3P256PrivateKey(
SecureStorageProvider secureStorage,
) async {
final String? p256PrivateKey = await secureStorage.get(
Expand Down Expand Up @@ -273,6 +273,32 @@ Future<String> getRandomP256PrivateKey(
}
}

Future<String> getP256PrivateKey(SecureStorageProvider secureStorage) async {
final String? p256PrivateKey = await secureStorage.get(
SecureStorageKeys.p256PrivateKey2,
);

if (p256PrivateKey == null) {
final jwk = JsonWebKey.generate('ES256');

final json = jwk.toJson();

// Sort the keys in ascending order and remove alg
final sortedJwk = Map.fromEntries(
json.entries.toList()..sort((e1, e2) => e1.key.compareTo(e2.key)),
)..remove('keyOperations');

await secureStorage.set(
SecureStorageKeys.p256PrivateKey2,
jsonEncode(sortedJwk),
);

return jsonEncode(sortedJwk);
} else {
return p256PrivateKey;
}
}

Future<String> fetchPrivateKey({
required OIDC4VC oidc4vc,
required SecureStorageProvider secureStorage,
Expand All @@ -283,7 +309,7 @@ Future<String> fetchPrivateKey({
final index = getIndexValue(isEBSIV3: true);

if (isEBSIV3) {
privateKey = await getRandomP256PrivateKey(getSecureStorage);
privateKey = await getEBSIV3P256PrivateKey(getSecureStorage);
} else {
final OIDC4VC oidc4vc = OIDC4VC();
final mnemonic = await getSecureStorage.get(SecureStorageKeys.ssiMnemonic);
Expand Down
2 changes: 2 additions & 0 deletions lib/dashboard/drawer/ssi/manage_did/manage_did.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export 'view/did_ebsi_v3/did_ebsi_v3_private_key_page.dart';
export 'view/did_ebsi_v3/manage_did_ebsi_v3_page.dart';
export 'view/did_edDSA/did_ed_dsa_private_key_page.dart';
export 'view/did_edDSA/manage_did_ed_dsa_page.dart';
export 'view/did_p256/did_p256_private_key_page.dart';
export 'view/did_p256/manage_did_p256_page.dart';
export 'view/did_polygon_id/manage_did_polygon_id_page.dart';
export 'view/did_secp256k1/did_secp256k1_private_key_page.dart';
export 'view/did_secp256k1/manage_did_secp256k1_page.dart';
Expand Down
6 changes: 6 additions & 0 deletions lib/dashboard/drawer/ssi/manage_did/view/did_menu.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ class DidView extends StatelessWidget {
.push<void>(ManageDidEbsiV3Page.route());
},
),
DrawerItem(
title: l10n.keyDecentralizedIDP256,
onTap: () {
Navigator.of(context).push<void>(ManageDidP256Page.route());
},
),
DrawerItem(
title: l10n.polygonDecentralizedID,
onTap: () async {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import 'package:altme/app/app.dart';
import 'package:altme/l10n/l10n.dart';
import 'package:altme/theme/theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:oidc4vc/oidc4vc.dart';
import 'package:secure_storage/secure_storage.dart';

class DidP256PrivateKeyPage extends StatefulWidget {
const DidP256PrivateKeyPage({super.key});

static Route<dynamic> route() {
return MaterialPageRoute<void>(
builder: (_) => const DidP256PrivateKeyPage(),
settings: const RouteSettings(name: '/DidP256PrivateKeyPage'),
);
}

@override
State<DidP256PrivateKeyPage> createState() => _DidP256PrivateKeyPageState();
}

class _DidP256PrivateKeyPageState extends State<DidP256PrivateKeyPage>
with SingleTickerProviderStateMixin {
late Animation<double> animation;
late AnimationController animationController;

Future<String> getKey() async {
final privateKey = await getP256PrivateKey(getSecureStorage);
return privateKey;
}

@override
void initState() {
super.initState();
animationController = AnimationController(
vsync: this,
duration: const Duration(seconds: 20),
);

final Tween<double> rotationTween = Tween(begin: 20, end: 0);

animation = rotationTween.animate(animationController)
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
Navigator.pop(context);
}
});
animationController.forward();
}

@override
void dispose() {
animationController.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return BasePage(
scrollView: false,
title: l10n.decentralizedIDKey,
titleAlignment: Alignment.topCenter,
titleLeading: const BackLeadingButton(),
secureScreen: true,
body: BackgroundCard(
width: double.infinity,
height: double.infinity,
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
l10n.didPrivateKey,
style: Theme.of(context).textTheme.title,
),
const SizedBox(
height: Sizes.spaceNormal,
),
FutureBuilder<String>(
future: getKey(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.done:
return Column(
children: [
Text(
snapshot.data!,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: Sizes.spaceXLarge),
CopyButton(
onTap: () async {
await Clipboard.setData(
ClipboardData(text: snapshot.data!),
);
AlertMessage.showStateMessage(
context: context,
stateMessage: StateMessage.success(
stringMessage: l10n.copiedToClipboard,
),
);
},
),
],
);
case ConnectionState.waiting:
case ConnectionState.none:
case ConnectionState.active:
return const Text('');
}
},
),
Expanded(
child: Center(
child: AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget? child) {
return Text(
timeFormatter(timeInSecond: animation.value.toInt()),
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.displayMedium,
);
},
),
),
),
],
),
),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import 'package:altme/app/app.dart';
import 'package:altme/dashboard/dashboard.dart';
import 'package:altme/l10n/l10n.dart';
import 'package:did_kit/did_kit.dart';
import 'package:flutter/material.dart';
import 'package:oidc4vc/oidc4vc.dart';
import 'package:secure_storage/secure_storage.dart';

class ManageDidP256Page extends StatefulWidget {
const ManageDidP256Page({super.key});

static Route<dynamic> route() {
return MaterialPageRoute<void>(
builder: (_) => const ManageDidP256Page(),
settings: const RouteSettings(name: '/ManageDidP256Page'),
);
}

@override
State<ManageDidP256Page> createState() => _ManageDidP256PageState();
}

class _ManageDidP256PageState extends State<ManageDidP256Page> {
Future<String> getDid() async {
final privateKey = await getP256PrivateKey(getSecureStorage);

final (did, _) = await getDidAndKid(
isEBSIV3: false,
privateKey: privateKey,
didKitProvider: DIDKitProvider(),
);

return did;
}

@override
Widget build(BuildContext context) {
final l10n = context.l10n;
return BasePage(
title: l10n.keyDecentralizedIDP256,
titleAlignment: Alignment.topCenter,
scrollView: false,
titleLeading: const BackLeadingButton(),
body: BackgroundCard(
height: double.infinity,
width: double.infinity,
padding: const EdgeInsets.all(Sizes.spaceSmall),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
FutureBuilder<String>(
future: getDid(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.done:
final did = snapshot.data!;
return Did(did: did);
case ConnectionState.waiting:
case ConnectionState.none:
case ConnectionState.active:
return const SizedBox();
}
},
),
const Padding(
padding: EdgeInsets.symmetric(horizontal: Sizes.spaceNormal),
child: Divider(),
),
DidPrivateKey(route: DidP256PrivateKeyPage.route()),
],
),
),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,31 @@ class _CredentialsDetailsViewState extends State<CredentialsDetailsView> {
Theme.of(context).colorScheme.valueColor,
),
],
if (widget.credentialModel.pendingInfo != null) ...[
CredentialField(
padding: const EdgeInsets.symmetric(
horizontal: 0,
vertical: 8,
),
title: l10n.issuer,
value: widget.credentialModel.pendingInfo!.issuer,
titleColor:
Theme.of(context).colorScheme.titleColor,
valueColor:
Theme.of(context).colorScheme.valueColor,
),
CredentialField(
padding: EdgeInsets.zero,
title: l10n.dateOfRequest,
value: UiDate.formatDate(
widget.credentialModel.pendingInfo!.requestedAt,
),
titleColor:
Theme.of(context).colorScheme.titleColor,
valueColor:
Theme.of(context).colorScheme.valueColor,
),
],
],
if (state.credentialDetailTabStatus ==
CredentialDetailTabStatus.activity) ...[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ class HomeCredentialCategoryItem extends StatelessWidget {
itemCount: sortedCredentials.length + 1,
itemBuilder: (_, index) {
if (index == sortedCredentials.length) {
if (credentialCategory == CredentialCategory.pendingCards) {
return Container();
}
return AddCredentialButton(
credentialCategory: credentialCategory,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class PendingInfo extends Equatable {
required this.deferredCredentialEndpoint,
required this.format,
required this.url,
required this.issuer,
required this.requestedAt,
});

factory PendingInfo.fromJson(Map<String, dynamic> json) =>
Expand All @@ -19,6 +21,8 @@ class PendingInfo extends Equatable {
final String deferredCredentialEndpoint;
final String format;
final String url;
final String issuer;
final DateTime requestedAt;

Map<String, dynamic> toJson() => _$PendingInfoToJson(this);

Expand Down
22 changes: 11 additions & 11 deletions lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -605,17 +605,6 @@ class QRCodeScanCubit extends Cubit<QRCodeScanState> {
}
}

final scope = state.uri!.queryParameters['scope'];
if (scope == null || scope != 'openid') {
throw ResponseMessage(
data: {
'error': 'invalid_request',
'error_description':
'The openid scope is required in the scope list.',
},
);
}

final redirectUri = state.uri!.queryParameters['redirect_uri'];
final clientId = state.uri!.queryParameters['client_id'];
final isUrl = isURL(clientId.toString());
Expand All @@ -624,6 +613,17 @@ class QRCodeScanCubit extends Cubit<QRCodeScanState> {
if (responseType == 'id_token') {
/// verifier side (siopv2)
final scope = state.uri!.queryParameters['scope'];
if (scope == null || scope != 'openid') {
throw ResponseMessage(
data: {
'error': 'invalid_request',
'error_description':
'The openid scope is required in the scope list.',
},
);
}

if (redirectUri == null) {
throw ResponseMessage(
data: {
Expand Down
Loading

0 comments on commit 99ee2dc

Please sign in to comment.