Skip to content

Commit

Permalink
feat: Added developer mode dialog for OIDC4VCI authorization flow #1998
Browse files Browse the repository at this point in the history
  • Loading branch information
bibash28 committed Oct 23, 2023
1 parent 90fef75 commit e6eb623
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 57 deletions.
1 change: 1 addition & 0 deletions lib/app/shared/enum/status/qr_scan_status.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ enum QrScanStatus {
idle,
loading,
acceptHost,
authorizationFlow,
error,
success,
goBack,
Expand Down
14 changes: 14 additions & 0 deletions lib/app/shared/helper_functions/helper_functions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,20 @@ ${openidConfigurationResponse != null ? const JsonEncoder.withIndent(' ').conve
''';
}

String getFormattedStringOIDC4VCIAuthorizedCodeFlow({
required String url,
Map<String, dynamic>? statePayload,
Map<String, dynamic>? codeForAuthorisedFlowPayload,
}) {
return '''
<b>SCHEME :</b> ${getSchemeFromUrl(url)}\n
<b>STATE :</b>
${statePayload != null ? const JsonEncoder.withIndent(' ').convert(statePayload) : 'None'}\n
<b>CODE :</b>
${codeForAuthorisedFlowPayload != null ? const JsonEncoder.withIndent(' ').convert(codeForAuthorisedFlowPayload) : 'None'}
''';
}

Future<String> getFormattedStringOIDC4VPSIOPV2({
required String url,
required DioClient client,
Expand Down
71 changes: 22 additions & 49 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 @@ -1024,7 +1024,7 @@ class QRCodeScanCubit extends Cubit<QRCodeScanState> {
if (url != null) {
final uri = Uri.parse(url);
if (uri.toString().startsWith(Parameters.oidc4vcUniversalLink)) {
await authorizedFlowCompletion(uri);
await authorizedFlowStart(uri);
return;
}
}
Expand Down Expand Up @@ -1135,51 +1135,24 @@ class QRCodeScanCubit extends Cubit<QRCodeScanState> {
);
}

Future<void> authorizedFlowCompletion(Uri uri) async {
try {
final error = uri.queryParameters['error'];
final errorDescription = uri.queryParameters['error_description'];

if (error != null) {
throw ResponseMessage(
data: {
'error': error,
'error_description': errorDescription,
},
);
}

final codeForAuthorisedFlow = uri.queryParameters['code'];
final state = uri.queryParameters['state'];

if (codeForAuthorisedFlow == null) {
throw ResponseMessage(
data: {
'error': 'invalid_request',
'error_description': 'The code is missing.',
},
);
}
if (state == null) {
throw ResponseMessage(
data: {
'error': 'invalid_request',
'error_description': 'The state is missing.',
},
);
}
await dotenv.load();
final String authorizationUriSecretKey =
dotenv.get('AUTHORIZATION_URI_SECRET_KEY');

final jwt = JWT.verify(state, SecretKey(authorizationUriSecretKey));

final payload = jwt.payload as Map<String, dynamic>;
Future<void> authorizedFlowStart(Uri uri) async {
emit(
state.copyWith(
uri: uri,
qrScanStatus: QrScanStatus.authorizationFlow,
),
);
}

final containsAllRequiredKey = payload.containsKey('credentials') &&
payload.containsKey('codeVerifier') &&
payload.containsKey('issuer') &&
payload.containsKey('isEBSIV3');
Future<void> authorizedFlowCompletion({
required Map<String, dynamic> statePayload,
required String codeForAuthorisedFlow,
}) async {
try {
final containsAllRequiredKey = statePayload.containsKey('credentials') &&
statePayload.containsKey('codeVerifier') &&
statePayload.containsKey('issuer') &&
statePayload.containsKey('isEBSIV3');

if (!containsAllRequiredKey) {
throw ResponseMessage(
Expand All @@ -1190,10 +1163,10 @@ class QRCodeScanCubit extends Cubit<QRCodeScanState> {
);
}

final selectedCredentials = payload['credentials'] as List<dynamic>;
final String codeVerifier = payload['codeVerifier'].toString();
final String issuer = payload['issuer'].toString();
final bool isEBSIV3 = payload['isEBSIV3'] as bool;
final selectedCredentials = statePayload['credentials'] as List<dynamic>;
final String codeVerifier = statePayload['codeVerifier'].toString();
final String issuer = statePayload['issuer'].toString();
final bool isEBSIV3 = statePayload['isEBSIV3'] as bool;

await addCredentialsInLoop(
selectedCredentials: selectedCredentials,
Expand Down
6 changes: 4 additions & 2 deletions lib/oidc4vc/get_authorization_uri_for_issuer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ Future<void> getAuthorizationUriForIssuer({

final jwtToken = jwt.sign(SecretKey(authorizationUriSecretKey));

final Uri ebsiAuthenticationUri = await oidc4vc.getAuthorizationUriForIssuer(
final Uri oidc4vcAuthenticationUri =
await oidc4vc.getAuthorizationUriForIssuer(
selectedCredentials: selectedCredentials,
clientId: did,
redirectUri: Parameters.oidc4vcUniversalLink,
Expand All @@ -62,5 +63,6 @@ Future<void> getAuthorizationUriForIssuer({
state: jwtToken,
authorizationEndPoint: Parameters.authorizeEndPoint,
);
await LaunchUrl.launchUri(ebsiAuthenticationUri);

await LaunchUrl.launchUri(oidc4vcAuthenticationUri);
}
2 changes: 1 addition & 1 deletion lib/scan/cubit/scan_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ class ScanCubit extends Cubit<ScanState> {
final uri = Uri.parse(url);
if (uri.toString().startsWith(Parameters.oidc4vcUniversalLink)) {
emit(state.copyWith(status: ScanStatus.goBack));
await qrCodeScanCubit.authorizedFlowCompletion(uri);
await qrCodeScanCubit.authorizedFlowStart(uri);
return;
}
} else {
Expand Down
108 changes: 108 additions & 0 deletions lib/splash/bloclisteners/blocklisteners.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ import 'package:altme/scan/scan.dart';
import 'package:altme/splash/splash.dart';
import 'package:altme/wallet/wallet.dart';
import 'package:beacon_flutter/beacon_flutter.dart';
import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:jwt_decode/jwt_decode.dart';
import 'package:polygonid/polygonid.dart';
import 'package:share_plus/share_plus.dart';
Expand Down Expand Up @@ -417,6 +419,112 @@ final qrCodeBlocListener = BlocListener<QRCodeScanCubit, QRCodeScanState>(
}
}

if (state.status == QrScanStatus.authorizationFlow) {
try {
if (state.uri != null) {
LoadingView().show(context: context);
final profileCubit = context.read<ProfileCubit>();
final uri = state.uri!;
final error = uri.queryParameters['error'];
final errorDescription = uri.queryParameters['error_description'];

if (error != null) {
throw ResponseMessage(
data: {
'error': error,
'error_description': errorDescription,
},
);
}

final codeForAuthorisedFlow = uri.queryParameters['code'];
final stateValue = uri.queryParameters['state'];

if (codeForAuthorisedFlow == null) {
throw ResponseMessage(
data: {
'error': 'invalid_request',
'error_description': 'The code is missing.',
},
);
}
if (stateValue == null) {
throw ResponseMessage(
data: {
'error': 'invalid_request',
'error_description': 'The state is missing.',
},
);
}

await dotenv.load();
final String authorizationUriSecretKey =
dotenv.get('AUTHORIZATION_URI_SECRET_KEY');

final jwt =
JWT.verify(stateValue, SecretKey(authorizationUriSecretKey));

final statePayload = jwt.payload as Map<String, dynamic>;

/// if dev mode is ON show some dialog to show data
if (profileCubit.state.model.isDeveloperMode) {
final codeForAuthorisedFlowPayload =
JWTDecode().parseJwt(codeForAuthorisedFlow);

final String formattedData =
getFormattedStringOIDC4VCIAuthorizedCodeFlow(
url: state.uri.toString(),
codeForAuthorisedFlowPayload: codeForAuthorisedFlowPayload,
statePayload: statePayload,
);

LoadingView().hide();
final bool moveAhead = await showDialog<bool>(
context: context,
builder: (_) {
return DeveloperModeDialog(
onDisplay: () async {
Navigator.of(context).pop(false);
await Navigator.of(context).push<void>(
JsonViewerPage.route(
title: l10n.displayConfiguration,
data: formattedData,
),
);
return;
},
onDownload: () {
Navigator.of(context).pop(false);

final box = context.findRenderObject() as RenderBox?;
final subject = l10n.shareWith;

Share.share(
formattedData,
subject: subject,
sharePositionOrigin:
box!.localToGlobal(Offset.zero) & box.size,
);
},
onSkip: () {
Navigator.of(context).pop(true);
},
);
},
) ??
true;
if (!moveAhead) return;
}
await context.read<QRCodeScanCubit>().authorizedFlowCompletion(
statePayload: statePayload,
codeForAuthorisedFlow: codeForAuthorisedFlow,
);
}
} catch (e) {
context.read<QRCodeScanCubit>().emitError(e);
}
}

if (state.status == QrScanStatus.success) {
if (state.route != null) {
await Navigator.of(context).push<void>(state.route!);
Expand Down
2 changes: 1 addition & 1 deletion lib/splash/view/splash_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class _SplashViewState extends State<SplashView> {
}

if (uri.toString().startsWith(Parameters.oidc4vcUniversalLink)) {
await context.read<QRCodeScanCubit>().authorizedFlowCompletion(uri!);
await context.read<QRCodeScanCubit>().authorizedFlowStart(uri!);
return;
}

Expand Down
8 changes: 4 additions & 4 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -989,10 +989,10 @@ packages:
dependency: "direct main"
description:
name: flutter_olm
sha256: e6de66f733f18f552ca387745464b2bb2997d3f9ba3ae53ca6e930b80af57f08
sha256: "69aaac45d854e74d17d04dac8a0ca3f548266d271a0f0fa7600e006e81432417"
url: "https://pub.dev"
source: hosted
version: "1.3.1"
version: "1.3.2"
flutter_openssl_crypto:
dependency: "direct main"
description:
Expand Down Expand Up @@ -1525,10 +1525,10 @@ packages:
dependency: "direct main"
description:
name: mobile_scanner
sha256: "2fbc3914fe625e196c64ea8ffc4084cd36781d2be276d4d5923b11af3b5d44ff"
sha256: d1ce638a53b3d751a6cdbd61ed2705d20d38aa30ed26b6fb2526c34c934afe54
url: "https://pub.dev"
source: hosted
version: "3.4.1"
version: "3.5.0"
mockingjay:
dependency: "direct dev"
description:
Expand Down

0 comments on commit e6eb623

Please sign in to comment.