Skip to content

Commit

Permalink
Some localizations have been refactored to use local context instead …
Browse files Browse the repository at this point in the history
…of global context.
  • Loading branch information
frankmer committed Dec 13, 2024
1 parent 5e7b3a5 commit f58e74d
Show file tree
Hide file tree
Showing 83 changed files with 1,887 additions and 1,190 deletions.
68 changes: 52 additions & 16 deletions lib/api/impl/privacy_idea_container_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class PiContainerApi implements TokenContainerApi {
////////////////////////////// */

@override
Future<ContainerSyncUpdates?> sync(TokenContainerFinalized container, TokenState tokenState) async {
Future<ContainerSyncUpdates> sync(TokenContainerFinalized container, TokenState tokenState) async {
final containerTokenTemplates = tokenState.containerTokens(container.serial).toTemplates();

final notLinkedTokenTemplates = (container.policies.initialTokenTransfer) ? tokenState.notLinkedTokens.toTemplates() : <TokenTemplate>[];
Expand All @@ -75,7 +75,6 @@ class PiContainerApi implements TokenContainerApi {
syncResult: syncResult,
encKeyPair: encKeyPair,
);
if (decryptedContainerDict == null) return null;

final tokens = decryptedContainerDict[TokenContainer.DICT_TOKENS] as Map<String, dynamic>;
final newOtpAuthTokens = (tokens[TokenContainer.DICT_TOKENS_ADD] as List).whereType<String>().map(Uri.parse).toList();
Expand Down Expand Up @@ -125,7 +124,7 @@ class PiContainerApi implements TokenContainerApi {
}

@override
Future<Response> finalizeContainer(TokenContainerUnfinalized container, EccUtils eccUtils) async {
Future<ContainerFinalizationResponse> finalizeContainer(TokenContainerUnfinalized container, [EccUtils eccUtils = const EccUtils()]) async {
final ecPrivateClientKey = container.ecPrivateClientKey;
if (ecPrivateClientKey == null) {
throw LocalizedException(localizedMessage: (l) => l.errorMissingPrivateKey, unlocalizedMessage: AppLocalizationsEn().errorMissingPrivateKey);
Expand All @@ -143,17 +142,48 @@ class PiContainerApi implements TokenContainerApi {
final signature = eccUtils.signWithPrivateKey(ecPrivateClientKey, message);

final body = {
if (container.addDeviceInfos == true) TokenContainer.FINALIZE_DEVICE_BRAND: InfoUtils.deviceBrand,
if (container.addDeviceInfos == true) TokenContainer.FINALIZE_DEVICE_MODEL: InfoUtils.deviceModel,
TokenContainer.FINALIZE_CONTAINER_SERIAL: container.serial,
TokenContainer.FINALIZE_PUBLIC_CLIENT_KEY: container.publicClientKey,
ContainerChallenge.SIGNATURE: signature,
'container_serial': container.serial,
'public_client_key': container.publicClientKey,
'device_brand': InfoUtils.deviceBrand,
'device_model': InfoUtils.deviceModel,
'signature': signature,
};
return await _ioClient.doPost(url: container.registrationUrl, body: body, sslVerify: container.sslVerify);
final Response response = await _ioClient.doPost(url: container.registrationUrl, body: body, sslVerify: container.sslVerify);

PiServerResponse<ContainerFinalizationResponse>? piResponse;
try {
piResponse = response.asPiServerResponse<ContainerFinalizationResponse>();
} catch (e) {
Logger.error('Failed to parse response', error: e);
rethrow;
}

if (piResponse == null || piResponse.isError) {
Logger.debug('Status code: ${response.statusCode}');
Logger.debug('Response body: ${response.body}');
final error = piResponse?.asError;
if (error != null) throw error;
throw ResponseError(response);
}

ContainerFinalizationResponse finalizationResponse;
try {
finalizationResponse = piResponse.asSuccess!.resultValue;
} catch (e) {
Logger.error('Failed to parse response', error: e);
rethrow;
}

if (piResponse.isError) {
Logger.error('Error while getting container finalization response: ${piResponse.asError!.piServerResultError}');
throw piResponse.asError!.piServerResultError;
}

return finalizationResponse;
}

@override
Future<String> getTransferQrData(TokenContainerFinalized container) async {
Future<TransferQrData> getRolloverQrData(TokenContainerFinalized container) async {
if (container.policies.rolloverAllowed == false) {
throw LocalizedException(
localizedMessage: (l) => 'l.errorRolloverNotAllowed', // TODO: Add translation
Expand Down Expand Up @@ -189,18 +219,24 @@ class PiContainerApi implements TokenContainerApi {
throw piResponse.asError!.piServerResultError;
}

return piResponse.asSuccess!.resultValue.value;
return piResponse.asSuccess!.resultValue;
}

@override
Future<bool> unregister(TokenContainerFinalized container) async {
Future<UnregisterContainerResult> unregister(TokenContainerFinalized container) async {
if (container.policies.unregisterAllowed == false) {
throw LocalizedException(
localizedMessage: (l) => 'l.errorUnregisterNotAllowed', // TODO: Add translation
unlocalizedMessage: 'AppLocalizationsEn().errorUnregisterNotAllowed',
);
}
final unregisterUrl = container.unregisterUrl;
final ContainerChallenge challenge;
try {
challenge = await _getChallenge(container, unregisterUrl);
} on PiServerResultError catch (e) {
if (e.code == 3001) {
return true;
return UnregisterContainerResult(success: false);
}
rethrow;
}
Expand All @@ -212,12 +248,12 @@ class PiContainerApi implements TokenContainerApi {

final response = await _ioClient.doPost(url: unregisterUrl, body: body, sslVerify: container.sslVerify);

final piResponse = response.asPiServerResponse<UnregisterContainerResultValue>();
final piResponse = response.asPiServerResponse<UnregisterContainerResult>();
final errorResponse = piResponse?.asError;
if (errorResponse != null) throw errorResponse.piServerResultError;
if (response.statusCode != 200 || piResponse == null) throw ResponseError(response);

return piResponse.asSuccess!.resultValue.success;
return piResponse.asSuccess!.resultValue;
}

/* //////////////////////////////
Expand Down Expand Up @@ -284,7 +320,7 @@ class PiContainerApi implements TokenContainerApi {
return syncResult;
}

Future<Map<String, dynamic>?> _getContainerDict({
Future<Map<String, dynamic>> _getContainerDict({
required ContainerSyncResult syncResult,
required KeyPair encKeyPair,
}) async {
Expand Down
9 changes: 4 additions & 5 deletions lib/api/interfaces/container_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import 'package:http/http.dart';

import '../../model/api_results/pi_server_results/pi_server_result_value.dart';
import '../../model/container_policies.dart';
import '../../model/riverpod_states/token_state.dart';
import '../../model/token_container.dart';
import '../../model/tokens/token.dart';
import '../../utils/ecc_utils.dart';

abstract class TokenContainerApi {
Future<Response> finalizeContainer(TokenContainerUnfinalized container, EccUtils eccUtils);
Future<String> getTransferQrData(TokenContainerFinalized container);
Future<ContainerFinalizationResponse> finalizeContainer(TokenContainerUnfinalized container, EccUtils eccUtils);
Future<TransferQrData> getRolloverQrData(TokenContainerFinalized container);
Future<ContainerSyncUpdates?> sync(TokenContainerFinalized container, TokenState tokenState);
Future<bool> unregister(TokenContainerFinalized container);
Future<UnregisterContainerResult> unregister(TokenContainerFinalized container);
}

class ContainerSyncUpdates {
Expand Down
8 changes: 5 additions & 3 deletions lib/mains/main_netknights.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import 'package:easy_dynamic_theme/easy_dynamic_theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/localization_notifier.dart';

import '../../../../../../../model/riverpod_states/settings_state.dart';
import '../firebase_options/default_firebase_options.dart';
Expand Down Expand Up @@ -80,6 +81,8 @@ class PrivacyIDEAAuthenticator extends ConsumerWidget {
globalRef = ref;
return LayoutBuilder(builder: (context, constraints) {
WidgetsBinding.instance.addPostFrameCallback((_) {
final localizations = AppLocalizations.of(context);
if (localizations != null) ref.read(localizationNotifierProvider.notifier).update(localizations);
ref.read(appConstraintsNotifierProvider.notifier).update(constraints);
});
return MaterialApp(
Expand All @@ -88,15 +91,14 @@ class PrivacyIDEAAuthenticator extends ConsumerWidget {
overscroll: false,
),
debugShowCheckedModeBanner: true,
navigatorKey: globalNavigatorKey,

localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
locale: ref.watch(settingsProvider).whenOrNull(data: (data) => data.currentLocale) ?? SettingsState.localeDefault,
title: _customization.appName,
theme: _customization.generateLightTheme(),
darkTheme: _customization.generateDarkTheme(),
scaffoldMessengerKey: globalSnackbarKey, // <= this
scaffoldMessengerKey: globalSnackbarKey,
navigatorKey: globalNavigatorKey,
themeMode: EasyDynamicTheme.of(context).themeMode,
initialRoute: SplashScreen.routeName,
routes: {
Expand Down
105 changes: 76 additions & 29 deletions lib/model/api_results/pi_server_results/pi_server_result_value.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,20 @@ sealed class PiServerResultValue extends PiServerResult {
@override
bool get status => true;

static T fromJsonOfType<T extends PiServerResultValue>(Map<String, dynamic> json) {
Logger.debug('PiServerResultValue.fromJsonOfType<$T>');
static T uriMapOfType<T extends PiServerResultValue>(Map<String, dynamic> uriMap) {
Logger.debug('PiServerResultValue.uriMapOfType<$T>');
return switch (T) {
const (ContainerChallenge) => ContainerChallenge.fromJson(json) as T,
const (ContainerFinalizationResponse) => ContainerFinalizationResponse.fromJson(json) as T,
const (ContainerSyncResult) => ContainerSyncResult.fromJson(json) as T,
const (TransferQrData) => TransferQrData.fromJson(json) as T,
const (UnregisterContainerResultValue) => UnregisterContainerResultValue.fromJson(json) as T,
_ => throw UnimplementedError('PiServerResultValue.fromJsonOfType<$T>'),
const (ContainerChallenge) => ContainerChallenge.fromUriMap(uriMap) as T,
const (ContainerFinalizationResponse) => ContainerFinalizationResponse.fromUriMap(uriMap) as T,
const (ContainerSyncResult) => ContainerSyncResult.fromUriMap(uriMap) as T,
const (TransferQrData) => TransferQrData.fromUriMap(uriMap) as T,
const (UnregisterContainerResult) => UnregisterContainerResult.fromUriMap(uriMap) as T,
_ => throw UnimplementedError('PiServerResultValue.fromUriMapOfType<$T>'),
};
}

Map<String, dynamic> toUriMap();

const PiServerResultValue();
}

Expand All @@ -68,22 +70,31 @@ class ContainerChallenge extends PiServerResultValue {
required this.timeStamp,
});

factory ContainerChallenge.fromJson(Map<String, dynamic> json) {
factory ContainerChallenge.fromUriMap(Map<String, dynamic> uriMap) {
final map = validateMap(
map: json,
map: uriMap,
validators: {
KEY_ALGORITHM: const ObjectValidator<String>(),
NONCE: const ObjectValidator<String>(),
TIMESTAMP: const ObjectValidator<String>(),
},
name: 'ContainerChallenge#fromJson',
name: 'ContainerChallenge#fromUriMap',
);
return ContainerChallenge(
keyAlgorithm: map[KEY_ALGORITHM] as String,
nonce: map[NONCE] as String,
timeStamp: map[TIMESTAMP] as String,
);
}

@override
Map<String, dynamic> toUriMap() {
return {
KEY_ALGORITHM: keyAlgorithm,
NONCE: nonce,
TIMESTAMP: timeStamp,
};
}
}

class ContainerFinalizationResponse extends PiServerResultValue {
Expand All @@ -95,20 +106,28 @@ class ContainerFinalizationResponse extends PiServerResultValue {
required this.policies,
});

static ContainerFinalizationResponse fromJson(Map<String, dynamic> json) {
static ContainerFinalizationResponse fromUriMap(Map<String, dynamic> uriMap) {
final map = validateMap(
map: json,
map: uriMap,
validators: {
TokenContainer.SYNC_PUBLIC_SERVER_KEY: ObjectValidator<ECPublicKey>(transformer: (v) => const EccUtils().deserializeECPublicKey(v)),
TokenContainer.SYNC_POLICIES: ObjectValidator<ContainerPolicies>(transformer: (v) => ContainerPolicies.fromUriMap(v)),
},
name: 'ContainerFinalizationResponse#fromJson',
name: 'ContainerFinalizationResponse#fromUriMap',
);
return ContainerFinalizationResponse(
publicServerKey: map[TokenContainer.SYNC_PUBLIC_SERVER_KEY] as ECPublicKey,
policies: map[TokenContainer.SYNC_POLICIES] as ContainerPolicies,
);
}

@override
Map<String, dynamic> toUriMap() {
return {
TokenContainer.SYNC_PUBLIC_SERVER_KEY: const EccUtils().serializeECPublicKey(publicServerKey),
TokenContainer.SYNC_POLICIES: policies.toJson(),
};
}
}

class ContainerSyncResult extends PiServerResultValue {
Expand All @@ -130,18 +149,18 @@ class ContainerSyncResult extends PiServerResultValue {
required this.serverUrl,
});

static ContainerSyncResult fromJson(Map<String, dynamic> json) {
static ContainerSyncResult fromUriMap(Map<String, dynamic> uriMap) {
final map = validateMap(
map: json,
map: uriMap,
validators: {
TokenContainer.SYNC_DICT_SERVER: const ObjectValidator<String>(),
TokenContainer.SYNC_ENC_ALGORITHM: const ObjectValidator<String>(),
TokenContainer.SYNC_ENC_PARAMS: ObjectValidator<EncryptionParams>(transformer: (v) => EncryptionParams.fromParams(v)),
TokenContainer.SYNC_ENC_PARAMS: ObjectValidator<EncryptionParams>(transformer: (v) => EncryptionParams.fromUriMap(v)),
TokenContainer.SYNC_POLICIES: ObjectValidator<ContainerPolicies>(transformer: (v) => ContainerPolicies.fromUriMap(v)),
TokenContainer.SYNC_PUBLIC_SERVER_KEY: const ObjectValidator<String>(),
TokenContainer.SYNC_SERVER_URL: const ObjectValidator<String>(),
},
name: 'ContainerSyncResult#fromJson',
name: 'ContainerSyncResult#fromUriMap',
);
return ContainerSyncResult(
containerDictEncrypted: map[TokenContainer.SYNC_DICT_SERVER] as String,
Expand All @@ -152,46 +171,74 @@ class ContainerSyncResult extends PiServerResultValue {
serverUrl: map[TokenContainer.SYNC_SERVER_URL] as String,
);
}

@override
Map<String, dynamic> toUriMap() {
return {
TokenContainer.SYNC_DICT_SERVER: containerDictEncrypted,
TokenContainer.SYNC_ENC_ALGORITHM: encryptionAlgorithm,
TokenContainer.SYNC_ENC_PARAMS: encryptionParams.toUriMap(),
TokenContainer.SYNC_POLICIES: policies.toUriMap(),
TokenContainer.SYNC_PUBLIC_SERVER_KEY: publicServerKey,
TokenContainer.SYNC_SERVER_URL: serverUrl,
};
}
}

class TransferQrData extends PiServerResultValue {
final String description;
final String value;
TransferQrData(this.description, this.value);
const TransferQrData({required this.description, required this.value});

factory TransferQrData.fromJson(Map<String, dynamic> json) {
Logger.debug(jsonEncode(json));
factory TransferQrData.fromUriMap(Map<String, dynamic> uriMap) {
final map = validateMap<String>(
map: json['container_url'] as Map<String, dynamic>,
map: uriMap['container_url'] as Map<String, dynamic>,
validators: {
'description': const ObjectValidator<String>(),
'value': const ObjectValidator<String>(),
},
name: 'TransferQrData',
);
return TransferQrData(map['description'] as String, map['value'] as String);
return TransferQrData(description: map['description'] as String, value: map['value'] as String);
}

@override
Map<String, dynamic> toUriMap() {
return {
'container_url': {
'description': description,
'value': value,
}
};
}
}

class UnregisterContainerResultValue extends PiServerResultValue {
class UnregisterContainerResult extends PiServerResultValue {
static const String CONTAINER_UNREGISTER_SUCCESS = 'success';

final bool success;

const UnregisterContainerResultValue({
const UnregisterContainerResult({
required this.success,
});

factory UnregisterContainerResultValue.fromJson(Map<String, dynamic> json) {
factory UnregisterContainerResult.fromUriMap(Map<String, dynamic> uriMap) {
final map = validateMap(
map: json,
map: uriMap,
validators: {
CONTAINER_UNREGISTER_SUCCESS: const ObjectValidator<bool>(),
},
name: 'UnregisterContainerResultValue#fromJson',
name: 'UnregisterContainerResultValue#fromUriMap',
);
return UnregisterContainerResultValue(
return UnregisterContainerResult(
success: map[CONTAINER_UNREGISTER_SUCCESS] as bool,
);
}

@override
Map<String, dynamic> toUriMap() {
return {
CONTAINER_UNREGISTER_SUCCESS: success,
};
}
}
Loading

0 comments on commit f58e74d

Please sign in to comment.