Skip to content

Commit

Permalink
feat: Support new didkey for enterprise
Browse files Browse the repository at this point in the history
  • Loading branch information
bibash28 committed Mar 14, 2024
1 parent 8c11a61 commit ed04b95
Show file tree
Hide file tree
Showing 16 changed files with 136 additions and 159 deletions.
9 changes: 9 additions & 0 deletions lib/app/shared/enum/type/profile/did_key_type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ enum DidKeyType {
ebsiv3,
@JsonValue('did:jwk:p-256')
jwkP256,
@JsonValue(
'urn:ietf:params:oauth:client-assertion-type:jwt-client-attestation',
)
jwtClientAttestation,
}

extension DidKeyTypeX on DidKeyType {
Expand All @@ -27,6 +31,8 @@ extension DidKeyTypeX on DidKeyType {
return 'did:key EBSI-V3';
case DidKeyType.jwkP256:
return 'did:jwk P-256';
case DidKeyType.jwtClientAttestation:
return '';
}
}

Expand All @@ -42,6 +48,8 @@ extension DidKeyTypeX on DidKeyType {
return l10n.ebsiV3DecentralizedId;
case DidKeyType.jwkP256:
return l10n.jwkDecentralizedIDP256;
case DidKeyType.jwtClientAttestation:
return '';
}
}

Expand All @@ -50,6 +58,7 @@ extension DidKeyTypeX on DidKeyType {
case DidKeyType.secp256k1:
case DidKeyType.p256:
case DidKeyType.jwkP256:
case DidKeyType.jwtClientAttestation:
return true;
case DidKeyType.edDSA:
case DidKeyType.ebsiv3:
Expand Down
118 changes: 65 additions & 53 deletions lib/app/shared/helper_functions/helper_functions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -263,16 +263,17 @@ int getIndexValue({
return 6;

case DidKeyType.edDSA:
case DidKeyType.jwtClientAttestation:
return 0; // it is not needed, just assigned
}
}

Future<String> getPrivateKey({
required SecureStorageProvider secureStorage,
required ProfileCubit profileCubit,
required DidKeyType didKeyType,
required OIDC4VC oidc4vc,
}) async {
final mnemonic = await secureStorage.get(SecureStorageKeys.ssiMnemonic);
final mnemonic = await profileCubit.secureStorageProvider
.get(SecureStorageKeys.ssiMnemonic);

switch (didKeyType) {
case DidKeyType.edDSA:
Expand All @@ -284,7 +285,7 @@ Future<String> getPrivateKey({
isEBSIV3: true,
didKeyType: didKeyType,
);
final key = oidc4vc.privateKeyFromMnemonic(
final key = profileCubit.oidc4vc.privateKeyFromMnemonic(
mnemonic: mnemonic!,
indexValue: index,
);
Expand All @@ -298,12 +299,34 @@ Future<String> getPrivateKey({
didKeyType: didKeyType,
);

final key = oidc4vc.p256PrivateKeyFromMnemonics(
final key = profileCubit.oidc4vc.p256PrivateKeyFromMnemonics(
mnemonic: mnemonic!,
indexValue: indexValue,
);

return key;

case DidKeyType.jwtClientAttestation:
if (profileCubit.state.model.walletType != WalletType.enterprise) {
throw ResponseMessage(
data: {
'error': 'invalid_request',
'error_description': 'Please switch to enterprise account',
},
);
}

final walletAttestationData = await profileCubit.secureStorageProvider
.get(SecureStorageKeys.walletAttestationData);

if (walletAttestationData == null) {
throw Exception();
}

final p256KeyForWallet =
await getWalletP256Key(profileCubit.secureStorageProvider);

return p256KeyForWallet;
}
}

Expand Down Expand Up @@ -349,25 +372,22 @@ DidKeyType? getDidKeyFromString(String? didKeyTypeString) {
}

Future<String> fetchPrivateKey({
required SecureStorageProvider secureStorage,
required ProfileCubit profileCubit,
required DidKeyType didKeyType,
required OIDC4VC oidc4vc,
bool? isEBSIV3,
}) async {
if (isEBSIV3 != null && isEBSIV3) {
final privateKey = await getPrivateKey(
secureStorage: secureStorage,
profileCubit: profileCubit,
didKeyType: DidKeyType.ebsiv3,
oidc4vc: oidc4vc,
);

return privateKey;
}

final privateKey = await getPrivateKey(
secureStorage: secureStorage,
profileCubit: profileCubit,
didKeyType: didKeyType,
oidc4vc: oidc4vc,
);

return privateKey;
Expand Down Expand Up @@ -466,9 +486,8 @@ String getUtf8Message(String maybeHex) {

Future<(String, String)> getDidAndKid({
required String privateKey,
required SecureStorageProvider secureStorage,
required ProfileCubit profileCubit,
required DidKeyType didKeyType,
required DIDKitProvider? didKitProvider,
}) async {
late String did;
late String kid;
Expand Down Expand Up @@ -496,11 +515,32 @@ Future<(String, String)> getDidAndKid({
case DidKeyType.p256:
case DidKeyType.secp256k1:
case DidKeyType.edDSA:
if (didKitProvider == null) throw Exception();

const didMethod = AltMeStrings.defaultDIDMethod;
did = didKitProvider.keyToDID(didMethod, privateKey);
kid = await didKitProvider.keyToVerificationMethod(didMethod, privateKey);
did = profileCubit.didKitProvider.keyToDID(didMethod, privateKey);
kid = await profileCubit.didKitProvider
.keyToVerificationMethod(didMethod, privateKey);
case DidKeyType.jwtClientAttestation:
if (profileCubit.state.model.walletType != WalletType.enterprise) {
throw ResponseMessage(
data: {
'error': 'invalid_request',
'error_description': 'Please switch to enterprise account',
},
);
}

final walletAttestationData = await profileCubit.secureStorageProvider
.get(SecureStorageKeys.walletAttestationData);

if (walletAttestationData == null) {
throw Exception();
}

final walletAttestationDataPayload =
profileCubit.jwtDecode.parseJwt(walletAttestationData);

did = walletAttestationDataPayload['cnf']['jwk']['kid'].toString();
kid = walletAttestationDataPayload['cnf']['jwk']['kid'].toString();
}

return (did, kid);
Expand All @@ -509,16 +549,14 @@ Future<(String, String)> getDidAndKid({
Future<(String, String)> fetchDidAndKid({
required String privateKey,
bool? isEBSIV3,
required SecureStorageProvider secureStorage,
required ProfileCubit profileCubit,
required DidKeyType didKeyType,
DIDKitProvider? didKitProvider,
}) async {
if (isEBSIV3 != null && isEBSIV3) {
final (did, kid) = await getDidAndKid(
didKeyType: DidKeyType.ebsiv3,
privateKey: privateKey,
didKitProvider: DIDKitProvider(),
secureStorage: getSecureStorage,
profileCubit: profileCubit,
);

return (did, kid);
Expand All @@ -527,8 +565,7 @@ Future<(String, String)> fetchDidAndKid({
final (did, kid) = await getDidAndKid(
didKeyType: didKeyType,
privateKey: privateKey,
didKitProvider: DIDKitProvider(),
secureStorage: getSecureStorage,
profileCubit: profileCubit,
);

return (did, kid);
Expand Down Expand Up @@ -1376,8 +1413,6 @@ Future<(String?, String?, String?, String?)> getClientDetails({
required ProfileCubit profileCubit,
required bool isEBSIV3,
required String issuer,
required JWTDecode jwtDecode,
required OIDC4VC oidc4vc,
}) async {
try {
String? clientId;
Expand All @@ -1391,17 +1426,15 @@ Future<(String?, String?, String?, String?)> getClientDetails({
final didKeyType = customOidc4vcProfile.defaultDid;

final privateKey = await fetchPrivateKey(
oidc4vc: profileCubit.oidc4vc,
secureStorage: profileCubit.secureStorageProvider,
profileCubit: profileCubit,
isEBSIV3: isEBSIV3,
didKeyType: didKeyType,
);

final (did, _) = await fetchDidAndKid(
privateKey: privateKey,
isEBSIV3: isEBSIV3,
didKitProvider: profileCubit.didKitProvider,
secureStorage: profileCubit.secureStorageProvider,
profileCubit: profileCubit,
didKeyType: didKeyType,
);

Expand Down Expand Up @@ -1460,42 +1493,21 @@ Future<(String?, String?, String?, String?)> getClientDetails({
final walletAttestationData = await profileCubit.secureStorageProvider
.get(SecureStorageKeys.walletAttestationData);

if (walletAttestationData == null) {
throw Exception();
}
clientId = did;

final iat = (DateTime.now().millisecondsSinceEpoch / 1000).round();
final nbf = iat - 10;

final walletAttestationDataPayload =
jwtDecode.parseJwt(walletAttestationData);

final p256KeyForWallet =
await getWalletP256Key(profileCubit.secureStorageProvider);

clientId = walletAttestationDataPayload['sub'].toString();

final tokenParameter = TokenParameters(
privateKey: jsonDecode(p256KeyForWallet) as Map<String, dynamic>,
kid: walletAttestationDataPayload['cnf']['jwk']['kid'].toString(),
did: '', // just added as it is required field
mediaType: MediaType.basic, // just added as it is required field
clientType:
ClientType.jwkThumbprint, // just added as it is required field
proofHeaderType: customOidc4vcProfile.proofHeader,
clientId: '', // just added as it is required field
);

final payload = {
'iss': clientId,
'aud': issuer,
'nbf': nbf,
'exp': nbf + 60,
};

final jwtProofOfPossession = oidc4vc.generateToken(
final jwtProofOfPossession = profileCubit.oidc4vc.generateToken(
payload: payload,
tokenParameters: tokenParameter,
tokenParameters: tokenParameters,
clientSecretJwt: true,
);

Expand Down
5 changes: 2 additions & 3 deletions lib/app/view/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class App extends StatelessWidget {
oidc4vc: OIDC4VC(),
didKitProvider: DIDKitProvider(),
langCubit: context.read<LangCubit>(),
jwtDecode: JWTDecode(),
),
),
BlocProvider<AdvanceSettingsCubit>(
Expand All @@ -89,9 +90,6 @@ class App extends StatelessWidget {
BlocProvider(
create: (context) => KycVerificationCubit(
profileCubit: context.read<ProfileCubit>(),
didKitProvider: DIDKitProvider(),
oidc4vc: OIDC4VC(),
secureStorageProvider: getSecureStorage,
client: DioClient(
'',
Dio(),
Expand Down Expand Up @@ -166,6 +164,7 @@ class App extends StatelessWidget {
profileCubit: context.read<ProfileCubit>(),
walletCubit: context.read<WalletCubit>(),
oidc4vc: OIDC4VC(),
jwtDecode: JWTDecode(),
),
),
BlocProvider<QRCodeScanCubit>(
Expand Down
8 changes: 4 additions & 4 deletions lib/chat_room/matrix_chat/matrix_chat_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:altme/app/app.dart';
import 'package:altme/chat_room/chat_room.dart';
import 'package:altme/dashboard/dashboard.dart';
import 'package:crypto/crypto.dart';
import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';
import 'package:did_kit/did_kit.dart';
import 'package:dio/dio.dart';
import 'package:file_picker/file_picker.dart';
Expand All @@ -14,6 +15,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_chat_types/flutter_chat_types.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:image_picker/image_picker.dart';
import 'package:jwt_decode/jwt_decode.dart';
import 'package:matrix/matrix.dart' hide User;
import 'package:mime/mime.dart';
import 'package:oidc4vc/oidc4vc.dart';
Expand Down Expand Up @@ -60,16 +62,14 @@ class MatrixChatImpl extends MatrixChatInterface {
.selfSovereignIdentityOptions.customOidc4vcProfile.defaultDid;

final privateKey = await getPrivateKey(
secureStorage: getSecureStorage,
profileCubit: profileCubit,
didKeyType: didKeyType,
oidc4vc: oidc4vc,
);

final (did, kid) = await getDidAndKid(
didKeyType: didKeyType,
privateKey: privateKey,
secureStorage: getSecureStorage,
didKitProvider: didKitProvider,
profileCubit: profileCubit,
);

final username = did.replaceAll(':', '-');
Expand Down
9 changes: 3 additions & 6 deletions lib/credentials/cubit/credentials_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -505,16 +505,14 @@ class CredentialsCubit extends Cubit<CredentialsState> {
.selfSovereignIdentityOptions.customOidc4vcProfile.defaultDid;

final privateKey = await getPrivateKey(
secureStorage: getSecureStorage,
didKeyType: didKeyType,
oidc4vc: oidc4vc,
profileCubit: profileCubit,
);

final (did, _) = await getDidAndKid(
didKeyType: didKeyType,
privateKey: privateKey,
secureStorage: getSecureStorage,
didKitProvider: didKitProvider,
profileCubit: profileCubit,
);

final private = jsonDecode(privateKey) as Map<String, dynamic>;
Expand Down Expand Up @@ -602,9 +600,8 @@ class CredentialsCubit extends Cubit<CredentialsState> {
.selfSovereignIdentityOptions.customOidc4vcProfile.defaultDid;

final privateKey = await getPrivateKey(
secureStorage: getSecureStorage,
profileCubit: profileCubit,
didKeyType: didKeyType,
oidc4vc: oidc4vc,
);

final private = jsonDecode(privateKey) as Map<String, dynamic>;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import 'package:altme/app/app.dart';
import 'package:altme/dashboard/dashboard.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';
import 'package:flutter_bloc/flutter_bloc.dart';

class DidPrivateKeyPage extends StatefulWidget {
const DidPrivateKeyPage({
Expand Down Expand Up @@ -36,9 +36,8 @@ class _DidPrivateKeyPageState extends State<DidPrivateKeyPage>

Future<String> getKey() async {
final privateKey = await getPrivateKey(
secureStorage: getSecureStorage,
profileCubit: context.read<ProfileCubit>(),
didKeyType: widget.didKeyType,
oidc4vc: OIDC4VC(),
);
return privateKey;
}
Expand Down
Loading

0 comments on commit ed04b95

Please sign in to comment.