From 1dd58619e2e5ab938b7aa240a9dd3f8f852219b4 Mon Sep 17 00:00:00 2001 From: Frank Merkel <138444693+frankmer@users.noreply.github.com> Date: Fri, 6 Dec 2024 15:41:18 +0100 Subject: [PATCH] Moved the constant_identifiers to the corresponding token class. --- analysis_options.yaml | 3 + lib/api/impl/privacy_idea_container_api.dart | 18 +-- .../pi_server_result_value.dart | 20 ++- lib/model/container_policies.dart | 6 +- lib/model/enums/algorithms.dart | 1 - .../enums/day_password_token_view_mode.dart | 1 - lib/model/enums/ec_key_algorithm.dart | 2 - lib/model/enums/token_types.dart | 1 - .../pi_server_result_error.dart | 2 - lib/model/mixins/sortable_mixin.dart | 2 - lib/model/pi_server_response.dart | 2 - lib/model/push_request.dart | 63 ++++---- lib/model/token_container.dart | 82 ++++++---- lib/model/token_container.freezed.dart | 25 +++ lib/model/token_container.g.dart | 2 + lib/model/token_folder.dart | 2 - lib/model/token_template.dart | 15 +- lib/model/tokens/day_password_token.dart | 128 ++++++++-------- lib/model/tokens/hotp_token.dart | 104 ++++++------- lib/model/tokens/otp_token.dart | 57 ++++--- lib/model/tokens/push_token.dart | 142 ++++++++++-------- lib/model/tokens/steam_token.dart | 74 ++++----- lib/model/tokens/token.dart | 78 +++++++--- lib/model/tokens/totp_token.dart | 100 ++++++------ .../token_container_processor.dart | 2 - .../otp_auth_processor.dart | 49 +++--- .../aegis_import_file_processor.dart | 77 +++++----- ...thenticator_pro_import_file_processor.dart | 36 ++--- .../free_otp_plus_import_file_processor.dart | 37 ++--- .../two_fas_import_file_processor.dart | 37 ++--- .../GoogleAuthenticatorImport.pbserver.dart | 2 - lib/repo/secure_push_request_repository.dart | 1 - lib/repo/secure_token_repository.dart | 2 - lib/utils/firebase_utils.dart | 1 - lib/utils/globals.dart | 2 - lib/utils/identifiers.dart | 97 ------------ lib/utils/logger.dart | 1 - .../lib/identifiers.dart | 2 - .../lib/pi_authenticator_legacy.dart | 2 - test/unit_test/model/push_request_test.dart | 29 ++-- .../model/token/day_password_test.dart | 94 ++++++------ .../model/token/hotp_token_test.dart | 75 ++++----- .../model/token/push_token_test.dart | 20 +-- .../model/token/steam_token_test.dart | 25 +-- .../model/token/totp_token_test.dart | 91 +++++------ ...token_container_scheme_processor_test.dart | 68 +++++++++ .../free_otp_plus_qr_processor_test.dart | 2 +- .../otp_auth_processor_test.dart | 6 +- .../token_container_notifier_test.dart | 7 + 49 files changed, 882 insertions(+), 813 deletions(-) create mode 100644 test/unit_test/processors/scheme_processors/token_container_scheme_processor_test.dart diff --git a/analysis_options.yaml b/analysis_options.yaml index 3df1067df..5c6bc0fa3 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,3 +1,6 @@ +analyzer: + errors: + constant_identifier_names: ignore include: package:flutter_lints/flutter.yaml linter: diff --git a/lib/api/impl/privacy_idea_container_api.dart b/lib/api/impl/privacy_idea_container_api.dart index c1ce6c286..551f72d6b 100644 --- a/lib/api/impl/privacy_idea_container_api.dart +++ b/lib/api/impl/privacy_idea_container_api.dart @@ -96,7 +96,7 @@ class PiContainerApi implements TokenContainerApi { container: container, ); - final serverTokensWithSerial = serverTokensUpdate.where((element) => element[OTP_AUTH_SERIAL] != null).toList(); + final serverTokensWithSerial = serverTokensUpdate.where((element) => element[Token.SERIAL] != null).toList(); serverTokensWithSerial.forEach(serverTokensUpdate.remove); assert(serverTokensUpdate.isEmpty, 'Server token otps map should be empty after removing all tokens with serial and otps'); // Container tokens can be deleted if they are not in the server list @@ -146,7 +146,7 @@ class PiContainerApi implements TokenContainerApi { if (container.addDeviceInfos == true) CONTAINER_DEVICE_MODEL: InfoUtils.deviceModel, CONTAINER_CONTAINER_SERIAL: container.serial, CONTAINER_PUBLIC_CLIENT_KEY: container.publicClientKey, - CONTAINER_CHAL_SIGNATURE: signature, + ContainerChallenge.SIGNATURE: signature, }; return await _ioClient.doPost(url: container.registrationUrl, body: body, sslVerify: container.sslVerify); } @@ -171,8 +171,8 @@ class PiContainerApi implements TokenContainerApi { Logger.debug(signMessage); final body = { - 'scope': '$requestUrl', - CONTAINER_CHAL_SIGNATURE: container.signMessage(signMessage), + TokenContainer.SCOPE: '$requestUrl', + ContainerChallenge.SIGNATURE: container.signMessage(signMessage), }; final response = await _ioClient.doPost(url: requestUrl, body: body, sslVerify: container.sslVerify); @@ -205,8 +205,8 @@ class PiContainerApi implements TokenContainerApi { } final body = { - CONTAINER_SCOPE: unregisterUrl.toString(), - CONTAINER_CHAL_SIGNATURE: container.signMessage('${challenge.nonce}|${challenge.timeStamp}|${container.serial}|$unregisterUrl'), + TokenContainer.SCOPE: unregisterUrl.toString(), + ContainerChallenge.SIGNATURE: container.signMessage('${challenge.nonce}|${challenge.timeStamp}|${container.serial}|$unregisterUrl'), }; final response = await _ioClient.doPost(url: unregisterUrl, body: body, sslVerify: container.sslVerify); @@ -225,7 +225,7 @@ class PiContainerApi implements TokenContainerApi { Future _getChallenge(TokenContainerFinalized container, Uri requestUrl) async { final body = { - CONTAINER_SCOPE: requestUrl.toString(), + TokenContainer.SCOPE: requestUrl.toString(), }; final challengeResponse = await _ioClient.doPost(url: container.challengeUrl, body: body, sslVerify: container.sslVerify); if (challengeResponse.statusCode != 200) { @@ -264,7 +264,7 @@ class PiContainerApi implements TokenContainerApi { final body = { CONTAINER_SYNC_PUBLIC_CLIENT_KEY: publicKeyBase64, CONTAINER_SYNC_DICT_CLIENT: jsonEncode(containerDict), - CONTAINER_CHAL_SIGNATURE: signature, + ContainerChallenge.SIGNATURE: signature, }; final response = await _ioClient.doPost(url: container.syncUrl, body: body, sslVerify: container.sslVerify); @@ -358,7 +358,7 @@ class PiContainerApi implements TokenContainerApi { final deleteSerials = []; final mergedTemplatesWithSerial = []; for (var containerToken in containerTokenTemplates) { - final serverToken = serverTokensWithSerial.firstWhereOrNull((element) => element[OTP_AUTH_SERIAL] == containerToken.serial); + final serverToken = serverTokensWithSerial.firstWhereOrNull((element) => element[Token.SERIAL] == containerToken.serial); serverTokensWithSerial.remove(serverToken); if (serverToken == null) { deleteSerials.add(containerToken.serial!); diff --git a/lib/model/api_results/pi_server_results/pi_server_result_value.dart b/lib/model/api_results/pi_server_results/pi_server_result_value.dart index 2bd033f3a..94255e804 100644 --- a/lib/model/api_results/pi_server_results/pi_server_result_value.dart +++ b/lib/model/api_results/pi_server_results/pi_server_result_value.dart @@ -1,5 +1,3 @@ -// ignore_for_file: constant_identifier_names - /* * privacyIDEA Authenticator * @@ -52,6 +50,12 @@ sealed class PiServerResultValue extends PiServerResult { } class ContainerChallenge extends PiServerResultValue { +// Container challenge: + static const String KEY_ALGORITHM = 'enc_key_algorithm'; + static const String NONCE = 'nonce'; + static const String TIMESTAMP = 'time_stamp'; + static const String SIGNATURE = 'signature'; + final String keyAlgorithm; final String nonce; final String timeStamp; @@ -68,16 +72,16 @@ class ContainerChallenge extends PiServerResultValue { final map = validateMap( map: json, validators: { - CONTAINER_CHAL_KEY_ALGORITHM: const ObjectValidator(), - CONTAINER_CHAL_NONCE: const ObjectValidator(), - CONTAINER_CHAL_TIMESTAMP: const ObjectValidator(), + KEY_ALGORITHM: const ObjectValidator(), + NONCE: const ObjectValidator(), + TIMESTAMP: const ObjectValidator(), }, name: 'ContainerChallenge#fromJson', ); return ContainerChallenge( - keyAlgorithm: map[CONTAINER_CHAL_KEY_ALGORITHM] as String, - nonce: map[CONTAINER_CHAL_NONCE] as String, - timeStamp: map[CONTAINER_CHAL_TIMESTAMP] as String, + keyAlgorithm: map[KEY_ALGORITHM] as String, + nonce: map[NONCE] as String, + timeStamp: map[TIMESTAMP] as String, ); } } diff --git a/lib/model/container_policies.dart b/lib/model/container_policies.dart index 8506d61b3..3971ac8be 100644 --- a/lib/model/container_policies.dart +++ b/lib/model/container_policies.dart @@ -1,5 +1,3 @@ -// ignore_for_file: constant_identifier_names - /* * privacyIDEA Authenticator * @@ -71,9 +69,7 @@ class ContainerPolicies with _$ContainerPolicies { } /** * - * // ignore_for_file: constant_identifier_names - -/* + * /* * privacyIDEA Authenticator * * Author: Frank Merkel diff --git a/lib/model/enums/algorithms.dart b/lib/model/enums/algorithms.dart index 75600d217..6174ba599 100644 --- a/lib/model/enums/algorithms.dart +++ b/lib/model/enums/algorithms.dart @@ -17,7 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -// ignore_for_file: constant_identifier_names // Do not rename, remove or reorder values, they are used for serialization. Only add new values at the end. enum Algorithms { SHA1, diff --git a/lib/model/enums/day_password_token_view_mode.dart b/lib/model/enums/day_password_token_view_mode.dart index 0ea76ff3d..f49022299 100644 --- a/lib/model/enums/day_password_token_view_mode.dart +++ b/lib/model/enums/day_password_token_view_mode.dart @@ -17,7 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -// ignore_for_file: constant_identifier_names // Do not rename or remove values, they are used for serialization. Only add new values. enum DayPasswordTokenViewMode { VALIDFOR, diff --git a/lib/model/enums/ec_key_algorithm.dart b/lib/model/enums/ec_key_algorithm.dart index 92314af81..182cb7f67 100644 --- a/lib/model/enums/ec_key_algorithm.dart +++ b/lib/model/enums/ec_key_algorithm.dart @@ -1,5 +1,3 @@ -// ignore_for_file: constant_identifier_names - /* * privacyIDEA Authenticator * diff --git a/lib/model/enums/token_types.dart b/lib/model/enums/token_types.dart index fffd02762..0a8014d9c 100644 --- a/lib/model/enums/token_types.dart +++ b/lib/model/enums/token_types.dart @@ -17,7 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -// ignore_for_file: constant_identifier_names // Do not rename or remove values, they are used for serialization. Only add new values. enum TokenTypes { HOTP, diff --git a/lib/model/exception_errors/pi_server_result_error.dart b/lib/model/exception_errors/pi_server_result_error.dart index 746d91605..01e34470f 100644 --- a/lib/model/exception_errors/pi_server_result_error.dart +++ b/lib/model/exception_errors/pi_server_result_error.dart @@ -1,5 +1,3 @@ -// ignore_for_file: constant_identifier_names - /* * privacyIDEA Authenticator * diff --git a/lib/model/mixins/sortable_mixin.dart b/lib/model/mixins/sortable_mixin.dart index e5df7e8be..05f87e722 100644 --- a/lib/model/mixins/sortable_mixin.dart +++ b/lib/model/mixins/sortable_mixin.dart @@ -1,5 +1,3 @@ -// ignore_for_file: constant_identifier_names - /* * privacyIDEA Authenticator * diff --git a/lib/model/pi_server_response.dart b/lib/model/pi_server_response.dart index b7cf3d3cb..758a76d58 100644 --- a/lib/model/pi_server_response.dart +++ b/lib/model/pi_server_response.dart @@ -1,5 +1,3 @@ -// ignore_for_file: constant_identifier_names - /* * privacyIDEA Authenticator * diff --git a/lib/model/push_request.dart b/lib/model/push_request.dart index 82e8b18f5..9eec23bfe 100644 --- a/lib/model/push_request.dart +++ b/lib/model/push_request.dart @@ -23,7 +23,6 @@ import 'package:base32/base32.dart'; import 'package:json_annotation/json_annotation.dart'; import '../utils/globals.dart'; -import '../utils/identifiers.dart'; import '../utils/logger.dart'; import '../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../utils/rsa_utils.dart'; @@ -33,6 +32,16 @@ part 'push_request.g.dart'; @JsonSerializable() class PushRequest { +// Push request: + static const String NONCE = 'nonce'; // 1. + static const String URL = 'url'; // 2. + static const String SERIAL = 'serial'; // 3. + static const String QUESTION = 'question'; // 4. + static const String TITLE = 'title'; // 5. + static const String SSL_VERIFY = 'sslverify'; // 6. + static const String SIGNATURE = 'signature'; // 7. + static const String ANSWERS = 'require_presence'; // 8. + final String title; final String question; final int id; @@ -117,47 +126,47 @@ class PushRequest { Logger.error('Invalid push request data.', error: e, stackTrace: s); } return PushRequest( - title: data[PUSH_REQUEST_TITLE], - question: data[PUSH_REQUEST_QUESTION], - uri: Uri.parse(data[PUSH_REQUEST_URL]), - nonce: data[PUSH_REQUEST_NONCE], - id: data[PUSH_REQUEST_NONCE].hashCode, - sslVerify: data[PUSH_REQUEST_SSL_VERIFY] == '1', - serial: data[PUSH_REQUEST_SERIAL], + title: data[TITLE], + question: data[QUESTION], + uri: Uri.parse(data[URL]), + nonce: data[NONCE], + id: data[NONCE].hashCode, + sslVerify: data[SSL_VERIFY] == '1', + serial: data[SERIAL], expirationDate: DateTime.now().add(const Duration(minutes: 2)), - signature: data[PUSH_REQUEST_SIGNATURE], - possibleAnswers: data[PUSH_REQUEST_ANSWERS] != null ? (data[PUSH_REQUEST_ANSWERS] as String).split(',') : null, + signature: data[SIGNATURE], + possibleAnswers: data[ANSWERS] != null ? (data[ANSWERS] as String).split(',') : null, ); } /// Verify that the data is valid. /// Throws ArgumentError if data is invalid static void verifyData(Map data) { - if (data[PUSH_REQUEST_TITLE] is! String) { - throw ArgumentError('Push request title is ${data[PUSH_REQUEST_TITLE].runtimeType}. Expected String.'); + if (data[TITLE] is! String) { + throw ArgumentError('Push request title is ${data[TITLE].runtimeType}. Expected String.'); } - if (data[PUSH_REQUEST_QUESTION] is! String) { - throw ArgumentError('Push request question is ${data[PUSH_REQUEST_QUESTION].runtimeType}. Expected String.'); + if (data[QUESTION] is! String) { + throw ArgumentError('Push request question is ${data[QUESTION].runtimeType}. Expected String.'); } - if (data[PUSH_REQUEST_URL] is! String) { - throw ArgumentError('Push request url is ${data[PUSH_REQUEST_URL].runtimeType}. Expected String.'); - } else if (Uri.tryParse(data[PUSH_REQUEST_URL]) == null) { + if (data[URL] is! String) { + throw ArgumentError('Push request url is ${data[URL].runtimeType}. Expected String.'); + } else if (Uri.tryParse(data[URL]) == null) { throw ArgumentError('Push request url is a String but not a valid Uri.'); } - if (data[PUSH_REQUEST_NONCE] is! String) { - throw ArgumentError('Push request nonce is ${data[PUSH_REQUEST_NONCE].runtimeType}. Expected String.'); + if (data[NONCE] is! String) { + throw ArgumentError('Push request nonce is ${data[NONCE].runtimeType}. Expected String.'); } - if (data[PUSH_REQUEST_SSL_VERIFY] is! String) { - throw ArgumentError('Push request sslVerify is ${data[PUSH_REQUEST_SSL_VERIFY].runtimeType}. Expected String.'); + if (data[SSL_VERIFY] is! String) { + throw ArgumentError('Push request sslVerify is ${data[SSL_VERIFY].runtimeType}. Expected String.'); } - if (data[PUSH_REQUEST_SERIAL] is! String) { - throw ArgumentError('Push request serial is ${data[PUSH_REQUEST_SERIAL].runtimeType}. Expected String.'); + if (data[SERIAL] is! String) { + throw ArgumentError('Push request serial is ${data[SERIAL].runtimeType}. Expected String.'); } - if (data[PUSH_REQUEST_SIGNATURE] is! String) { - throw ArgumentError('Push request signature is ${data[PUSH_REQUEST_SIGNATURE].runtimeType}. Expected String.'); + if (data[SIGNATURE] is! String) { + throw ArgumentError('Push request signature is ${data[SIGNATURE].runtimeType}. Expected String.'); } - if (data[PUSH_REQUEST_ANSWERS] is! String?) { - throw ArgumentError('Push request answers is ${data[PUSH_REQUEST_ANSWERS].runtimeType}. Expected List or null.'); + if (data[ANSWERS] is! String?) { + throw ArgumentError('Push request answers is ${data[ANSWERS].runtimeType}. Expected List or null.'); } Logger.debug('Push request data ($data) is valid.'); } diff --git a/lib/model/token_container.dart b/lib/model/token_container.dart index 2605afd11..b0a351f4e 100644 --- a/lib/model/token_container.dart +++ b/lib/model/token_container.dart @@ -1,5 +1,3 @@ -// ignore_for_file: constant_identifier_names - /* * privacyIDEA Authenticator * @@ -26,7 +24,6 @@ import 'package:freezed_annotation/freezed_annotation.dart'; import '../../../../../../../model/enums/algorithms.dart'; import '../../../../../../../model/extensions/enums/ec_key_algorithm_extension.dart'; import '../../../../../../../model/tokens/token.dart'; -import '../../../../../../../utils/identifiers.dart'; import '../utils/ecc_utils.dart'; import '../utils/logger.dart'; import '../utils/object_validator.dart'; @@ -42,7 +39,21 @@ part 'token_container.g.dart'; @Freezed(toStringOverride: false, addImplicitFinal: true, toJson: true, fromJson: true) class TokenContainer with _$TokenContainer { - static const SERIAL = 'serial'; +// Container registration: + static const String ISSUER = 'issuer'; + static const String TTL = 'ttl'; + static const String NONCE = 'nonce'; + static const String TIMESTAMP = 'time'; + static const String FINALIZATION_URL = 'url'; + static const String EC_KEY_ALGORITHM = 'key_algorithm'; + static const String SERIAL = 'serial'; + static const String HASH_ALGORITHM = 'hash_algorithm'; + static const String PASSPHRASE_QUESTION = 'passphrase'; + static const String SSL_VERIFY = 'ssl_verify'; + static const String SERVER_URL = 'container_sync_url'; + static const String SCOPE = 'scope'; + static const String POLICIES = 'info'; + static const eccUtils = EccUtils(); const TokenContainer._(); @@ -53,48 +64,53 @@ class TokenContainer with _$TokenContainer { Uri get transferUrl => serverUrl.replace(path: '/container/$serial/rollover'); Uri get unregisterUrl => serverUrl.replace(path: '/container/register/$serial/terminate/client'); - // example: pia://container/SMPH00134123 - // ?issuer=privacyIDEA - // &nonce=887197025f5fa59b50f33c15196eb97ee651a5d1 - // &time=2024-08-21T07%3A43%3A07.086670%2B00%3A00 - // &url=http://127.0.0.1:5000/container/register/initialize - // &serial=SMPH00134123 - // &key_algorithm=secp384r1 - // &hash_algorithm=SHA256 - // &passphrase=Enter%20your%20passphrase + // example: "pia://container/SMPH00067A2F" + // "?issuer=privacyIDEA" + // "&ttl=10" + // "&nonce=b33d3a11c8d1b45f19640035e27944ccf0b2383d" + // "&time=2024-12-06T11%3A14%3A26.885409%2B00%3A00" + // "&url=http://192.168.0.230:5000/" + // "&serial=SMPH00067A2F" + // "&key_algorithm=secp384r1" + // "&hash_algorithm=SHA256" + // "&ssl_verify=False" + // "&passphrase=Enter%20your%20password" factory TokenContainer.fromUriMap(Map uriMap) { uriMap = validateMap( map: uriMap, validators: { - CONTAINER_ISSUER: const ObjectValidator(), - CONTAINER_NONCE: const ObjectValidator(), - CONTAINER_TIMESTAMP: ObjectValidator(transformer: (v) => DateTime.parse(v)), - CONTAINER_FINALIZATION_URL: stringToUrivalidator, - CONTAINER_SERIAL: const ObjectValidator(), - CONTAINER_EC_KEY_ALGORITHM: ObjectValidator(transformer: (v) => EcKeyAlgorithm.values.byCurveName(v)), - CONTAINER_HASH_ALGORITHM: stringToAlgorithmsValidator, - CONTAINER_PASSPHRASE_QUESTION: const ObjectValidatorNullable(), - CONTAINER_SSL_VERIFY: boolValidator, - CONTAINER_POLICIES: ObjectValidatorNullable(transformer: (value) => ContainerPolicies.fromUriMap(value)), + ISSUER: const ObjectValidator(), + TTL: ObjectValidator(transformer: (value) => Duration(minutes: value)), + NONCE: const ObjectValidator(), + TIMESTAMP: ObjectValidator(transformer: (v) => DateTime.parse(v)), + FINALIZATION_URL: stringToUrivalidator, + SERIAL: const ObjectValidator(), + EC_KEY_ALGORITHM: ObjectValidator(transformer: (v) => EcKeyAlgorithm.values.byCurveName(v)), + HASH_ALGORITHM: stringToAlgorithmsValidator, + PASSPHRASE_QUESTION: const ObjectValidatorNullable(), + SSL_VERIFY: boolValidator, + POLICIES: ObjectValidatorNullable(transformer: (value) => ContainerPolicies.fromUriMap(value)), }, name: 'Container', ); return TokenContainer.unfinalized( - issuer: uriMap[CONTAINER_ISSUER], - nonce: uriMap[CONTAINER_NONCE], - timestamp: uriMap[CONTAINER_TIMESTAMP], - serverUrl: uriMap[CONTAINER_FINALIZATION_URL], - serial: uriMap[CONTAINER_SERIAL], - ecKeyAlgorithm: uriMap[CONTAINER_EC_KEY_ALGORITHM], - hashAlgorithm: uriMap[CONTAINER_HASH_ALGORITHM], - sslVerify: uriMap[CONTAINER_SSL_VERIFY], - passphraseQuestion: uriMap[CONTAINER_PASSPHRASE_QUESTION], - policies: uriMap[CONTAINER_POLICIES] ?? ContainerPolicies.defaultSetting, + issuer: uriMap[ISSUER], + ttl: uriMap[TTL], + nonce: uriMap[NONCE], + timestamp: uriMap[TIMESTAMP], + serverUrl: uriMap[FINALIZATION_URL], + serial: uriMap[SERIAL], + ecKeyAlgorithm: uriMap[EC_KEY_ALGORITHM], + hashAlgorithm: uriMap[HASH_ALGORITHM], + sslVerify: uriMap[SSL_VERIFY], + passphraseQuestion: uriMap[PASSPHRASE_QUESTION], + policies: uriMap[POLICIES] ?? ContainerPolicies.defaultSetting, ); } const factory TokenContainer.unfinalized({ required String issuer, + required Duration ttl, required String nonce, required DateTime timestamp, required Uri serverUrl, diff --git a/lib/model/token_container.freezed.dart b/lib/model/token_container.freezed.dart index 5947847ff..f074b0bc7 100644 --- a/lib/model/token_container.freezed.dart +++ b/lib/model/token_container.freezed.dart @@ -48,6 +48,7 @@ mixin _$TokenContainer { TResult when({ required TResult Function( String issuer, + Duration ttl, String nonce, DateTime timestamp, Uri serverUrl, @@ -88,6 +89,7 @@ mixin _$TokenContainer { TResult? whenOrNull({ TResult? Function( String issuer, + Duration ttl, String nonce, DateTime timestamp, Uri serverUrl, @@ -128,6 +130,7 @@ mixin _$TokenContainer { TResult maybeWhen({ TResult Function( String issuer, + Duration ttl, String nonce, DateTime timestamp, Uri serverUrl, @@ -338,6 +341,7 @@ abstract class _$$TokenContainerUnfinalizedImplCopyWith<$Res> @useResult $Res call( {String issuer, + Duration ttl, String nonce, DateTime timestamp, Uri serverUrl, @@ -373,6 +377,7 @@ class __$$TokenContainerUnfinalizedImplCopyWithImpl<$Res> @override $Res call({ Object? issuer = null, + Object? ttl = null, Object? nonce = null, Object? timestamp = null, Object? serverUrl = null, @@ -394,6 +399,10 @@ class __$$TokenContainerUnfinalizedImplCopyWithImpl<$Res> ? _value.issuer : issuer // ignore: cast_nullable_to_non_nullable as String, + ttl: null == ttl + ? _value.ttl + : ttl // ignore: cast_nullable_to_non_nullable + as Duration, nonce: null == nonce ? _value.nonce : nonce // ignore: cast_nullable_to_non_nullable @@ -463,6 +472,7 @@ class __$$TokenContainerUnfinalizedImplCopyWithImpl<$Res> class _$TokenContainerUnfinalizedImpl extends TokenContainerUnfinalized { const _$TokenContainerUnfinalizedImpl( {required this.issuer, + required this.ttl, required this.nonce, required this.timestamp, required this.serverUrl, @@ -488,6 +498,8 @@ class _$TokenContainerUnfinalizedImpl extends TokenContainerUnfinalized { @override final String issuer; @override + final Duration ttl; + @override final String nonce; @override final DateTime timestamp; @@ -530,6 +542,7 @@ class _$TokenContainerUnfinalizedImpl extends TokenContainerUnfinalized { (other.runtimeType == runtimeType && other is _$TokenContainerUnfinalizedImpl && (identical(other.issuer, issuer) || other.issuer == issuer) && + (identical(other.ttl, ttl) || other.ttl == ttl) && (identical(other.nonce, nonce) || other.nonce == nonce) && (identical(other.timestamp, timestamp) || other.timestamp == timestamp) && @@ -565,6 +578,7 @@ class _$TokenContainerUnfinalizedImpl extends TokenContainerUnfinalized { int get hashCode => Object.hash( runtimeType, issuer, + ttl, nonce, timestamp, serverUrl, @@ -595,6 +609,7 @@ class _$TokenContainerUnfinalizedImpl extends TokenContainerUnfinalized { TResult when({ required TResult Function( String issuer, + Duration ttl, String nonce, DateTime timestamp, Uri serverUrl, @@ -632,6 +647,7 @@ class _$TokenContainerUnfinalizedImpl extends TokenContainerUnfinalized { }) { return unfinalized( issuer, + ttl, nonce, timestamp, serverUrl, @@ -654,6 +670,7 @@ class _$TokenContainerUnfinalizedImpl extends TokenContainerUnfinalized { TResult? whenOrNull({ TResult? Function( String issuer, + Duration ttl, String nonce, DateTime timestamp, Uri serverUrl, @@ -691,6 +708,7 @@ class _$TokenContainerUnfinalizedImpl extends TokenContainerUnfinalized { }) { return unfinalized?.call( issuer, + ttl, nonce, timestamp, serverUrl, @@ -713,6 +731,7 @@ class _$TokenContainerUnfinalizedImpl extends TokenContainerUnfinalized { TResult maybeWhen({ TResult Function( String issuer, + Duration ttl, String nonce, DateTime timestamp, Uri serverUrl, @@ -752,6 +771,7 @@ class _$TokenContainerUnfinalizedImpl extends TokenContainerUnfinalized { if (unfinalized != null) { return unfinalized( issuer, + ttl, nonce, timestamp, serverUrl, @@ -813,6 +833,7 @@ class _$TokenContainerUnfinalizedImpl extends TokenContainerUnfinalized { abstract class TokenContainerUnfinalized extends TokenContainer { const factory TokenContainerUnfinalized( {required final String issuer, + required final Duration ttl, required final String nonce, required final DateTime timestamp, required final Uri serverUrl, @@ -835,6 +856,7 @@ abstract class TokenContainerUnfinalized extends TokenContainer { @override String get issuer; + Duration get ttl; @override String get nonce; @override @@ -1142,6 +1164,7 @@ class _$TokenContainerFinalizedImpl extends TokenContainerFinalized { TResult when({ required TResult Function( String issuer, + Duration ttl, String nonce, DateTime timestamp, Uri serverUrl, @@ -1201,6 +1224,7 @@ class _$TokenContainerFinalizedImpl extends TokenContainerFinalized { TResult? whenOrNull({ TResult? Function( String issuer, + Duration ttl, String nonce, DateTime timestamp, Uri serverUrl, @@ -1260,6 +1284,7 @@ class _$TokenContainerFinalizedImpl extends TokenContainerFinalized { TResult maybeWhen({ TResult Function( String issuer, + Duration ttl, String nonce, DateTime timestamp, Uri serverUrl, diff --git a/lib/model/token_container.g.dart b/lib/model/token_container.g.dart index e679d0336..f103d291e 100644 --- a/lib/model/token_container.g.dart +++ b/lib/model/token_container.g.dart @@ -10,6 +10,7 @@ _$TokenContainerUnfinalizedImpl _$$TokenContainerUnfinalizedImplFromJson( Map json) => _$TokenContainerUnfinalizedImpl( issuer: json['issuer'] as String, + ttl: Duration(microseconds: (json['ttl'] as num).toInt()), nonce: json['nonce'] as String, timestamp: DateTime.parse(json['timestamp'] as String), serverUrl: Uri.parse(json['serverUrl'] as String), @@ -38,6 +39,7 @@ Map _$$TokenContainerUnfinalizedImplToJson( _$TokenContainerUnfinalizedImpl instance) => { 'issuer': instance.issuer, + 'ttl': instance.ttl.inMicroseconds, 'nonce': instance.nonce, 'timestamp': instance.timestamp.toIso8601String(), 'serverUrl': instance.serverUrl.toString(), diff --git a/lib/model/token_folder.dart b/lib/model/token_folder.dart index 3e2d65c28..3c4dfbd0d 100644 --- a/lib/model/token_folder.dart +++ b/lib/model/token_folder.dart @@ -1,5 +1,3 @@ -// ignore_for_file: constant_identifier_names - /* * privacyIDEA Authenticator * diff --git a/lib/model/token_template.dart b/lib/model/token_template.dart index 2e70071c4..6500b6a3d 100644 --- a/lib/model/token_template.dart +++ b/lib/model/token_template.dart @@ -27,7 +27,6 @@ import 'package:freezed_annotation/freezed_annotation.dart'; import '../../../../../../../model/enums/token_origin_source_type.dart'; import '../../../../../../../model/token_container.dart'; import '../../../../../../../model/tokens/otp_token.dart'; -import '../../../../../../../utils/identifiers.dart'; import '../utils/object_validator.dart'; import 'token_import/token_origin_data.dart'; import 'tokens/token.dart'; @@ -58,26 +57,26 @@ class TokenTemplate with _$TokenTemplate { List get values => otpAuthMap.values.toList(); String? get serial => validateOptional( - value: otpAuthMap[OTP_AUTH_SERIAL], + value: otpAuthMap[Token.SERIAL], validator: const ObjectValidatorNullable(), - name: OTP_AUTH_SERIAL, + name: Token.SERIAL, ); String? get type => validateOptional( - value: otpAuthMap[OTP_AUTH_TYPE], + value: otpAuthMap[Token.TYPE], validator: const ObjectValidatorNullable(), - name: OTP_AUTH_TYPE, + name: Token.TYPE, ); List? get otpValues => this is _TokenTemplateWithOtps ? (this as _TokenTemplateWithOtps).otps : null; String? get containerSerial => validateOptional( - value: otpAuthMap[CONTAINER_SERIAL], + value: otpAuthMap[TokenContainer.SERIAL], validator: const ObjectValidatorNullable(), - name: CONTAINER_SERIAL, + name: TokenContainer.SERIAL, ); - Map get otpAuthMapSafeToSend => Map.from(otpAuthMap)..remove(OTP_AUTH_SECRET_BASE32); + Map get otpAuthMapSafeToSend => Map.from(otpAuthMap)..remove(OTPToken.SECRET_BASE32); @override operator ==(Object other) { diff --git a/lib/model/tokens/day_password_token.dart b/lib/model/tokens/day_password_token.dart index b84d44a9d..2dab0d005 100644 --- a/lib/model/tokens/day_password_token.dart +++ b/lib/model/tokens/day_password_token.dart @@ -20,9 +20,9 @@ import 'package:flutter/material.dart'; import 'package:json_annotation/json_annotation.dart'; +import 'package:privacyidea_authenticator/model/tokens/totp_token.dart'; import 'package:uuid/uuid.dart'; -import '../../utils/identifiers.dart'; import '../../utils/object_validator.dart'; import '../enums/algorithms.dart'; import '../enums/day_password_token_view_mode.dart'; @@ -158,29 +158,29 @@ class DayPasswordToken extends OTPToken { final uriMap = validateMap( map: template.otpAuthMap, validators: { - OTP_AUTH_LABEL: const ObjectValidatorNullable(), - OTP_AUTH_ISSUER: const ObjectValidatorNullable(), - OTP_AUTH_SERIAL: const ObjectValidatorNullable(), - OTP_AUTH_ALGORITHM: stringToAlgorithmsValidatorNullable, - OTP_AUTH_DIGITS: intValidatorNullable, - OTP_AUTH_SECRET_BASE32: base32SecretValidatorNullable, - OTP_AUTH_PERIOD_SECONDS: stringSecondsToDurationValidatorNullable, - OTP_AUTH_IMAGE: const ObjectValidatorNullable(), - OTP_AUTH_PIN: boolValidatorNullable, + Token.LABEL: const ObjectValidatorNullable(), + Token.ISSUER: const ObjectValidatorNullable(), + Token.SERIAL: const ObjectValidatorNullable(), + Token.IMAGE: const ObjectValidatorNullable(), + Token.PIN: boolValidatorNullable, + OTPToken.ALGORITHM: stringToAlgorithmsValidatorNullable, + OTPToken.DIGITS: intValidatorNullable, + OTPToken.SECRET_BASE32: base32SecretValidatorNullable, + TOTPToken.PERIOD_SECONDS: stringSecondsToDurationValidatorNullable, }, name: 'DayPasswordToken', ); return copyWith( - label: uriMap[OTP_AUTH_LABEL] as String?, - issuer: uriMap[OTP_AUTH_ISSUER] as String?, - serial: uriMap[OTP_AUTH_SERIAL] as String?, - algorithm: uriMap[OTP_AUTH_ALGORITHM] as Algorithms?, - digits: uriMap[OTP_AUTH_DIGITS] as int?, - secret: uriMap[OTP_AUTH_SECRET_BASE32] as String?, - period: uriMap[OTP_AUTH_PERIOD_SECONDS] as Duration?, - tokenImage: uriMap[OTP_AUTH_IMAGE] as String?, - pin: uriMap[OTP_AUTH_PIN] as bool?, - isLocked: uriMap[OTP_AUTH_PIN] as bool?, + label: uriMap[Token.LABEL] as String?, + issuer: uriMap[Token.ISSUER] as String?, + serial: uriMap[Token.SERIAL] as String?, + tokenImage: uriMap[Token.IMAGE] as String?, + pin: uriMap[Token.PIN] as bool?, + isLocked: uriMap[Token.PIN] as bool?, + algorithm: uriMap[OTPToken.ALGORITHM] as Algorithms?, + digits: uriMap[OTPToken.DIGITS] as int?, + secret: uriMap[OTPToken.SECRET_BASE32] as String?, + period: uriMap[TOTPToken.PERIOD_SECONDS] as Duration?, ); } @@ -188,30 +188,26 @@ class DayPasswordToken extends OTPToken { uriMap = validateMap( map: uriMap, validators: { - OTP_AUTH_LABEL: const ObjectValidator(defaultValue: ''), - OTP_AUTH_ISSUER: const ObjectValidator(defaultValue: ''), - OTP_AUTH_SERIAL: const ObjectValidatorNullable(), - OTP_AUTH_ALGORITHM: stringToAlgorithmsValidator.withDefault(Algorithms.SHA1), - OTP_AUTH_DIGITS: otpAuthDigitsValidatorNullable, - OTP_AUTH_SECRET_BASE32: base32Secretvalidator, - OTP_AUTH_PERIOD_SECONDS: stringSecondsToDurationValidator.withDefault(const Duration(hours: 24)), - OTP_AUTH_IMAGE: const ObjectValidatorNullable(), - OTP_AUTH_PIN: boolValidatorNullable, + Token.LABEL: const ObjectValidator(defaultValue: ''), + Token.ISSUER: const ObjectValidator(defaultValue: ''), + Token.SERIAL: const ObjectValidatorNullable(), + Token.IMAGE: const ObjectValidatorNullable(), + Token.PIN: boolValidatorNullable, + OTPToken.ALGORITHM: stringToAlgorithmsValidator.withDefault(Algorithms.SHA1), + OTPToken.DIGITS: otpAuthDigitsValidatorNullable, + OTPToken.SECRET_BASE32: base32Secretvalidator, + TOTPToken.PERIOD_SECONDS: stringSecondsToDurationValidator.withDefault(const Duration(hours: 24)), }, name: 'DayPasswordToken', ); final validatedAdditionalData = Token.validateAdditionalData(additionalData); return DayPasswordToken( - label: uriMap[OTP_AUTH_LABEL], - issuer: uriMap[OTP_AUTH_ISSUER], - serial: uriMap[OTP_AUTH_SERIAL], - algorithm: uriMap[OTP_AUTH_ALGORITHM], - digits: uriMap[OTP_AUTH_DIGITS], - secret: uriMap[OTP_AUTH_SECRET_BASE32], - period: uriMap[OTP_AUTH_PERIOD_SECONDS], - tokenImage: uriMap[OTP_AUTH_IMAGE], - pin: uriMap[OTP_AUTH_PIN], - isLocked: uriMap[OTP_AUTH_PIN], + label: uriMap[Token.LABEL], + issuer: uriMap[Token.ISSUER], + serial: uriMap[Token.SERIAL], + tokenImage: uriMap[Token.IMAGE], + pin: uriMap[Token.PIN], + isLocked: uriMap[Token.PIN], id: validatedAdditionalData[Token.ID] ?? const Uuid().v4(), containerSerial: validatedAdditionalData[Token.CONTAINER_SERIAL], checkedContainer: validatedAdditionalData[Token.CHECKED_CONTAINERS] ?? [], @@ -219,41 +215,45 @@ class DayPasswordToken extends OTPToken { folderId: validatedAdditionalData[Token.FOLDER_ID], origin: validatedAdditionalData[Token.ORIGIN], isHidden: validatedAdditionalData[Token.HIDDEN], + algorithm: uriMap[OTPToken.ALGORITHM], + digits: uriMap[OTPToken.DIGITS], + secret: uriMap[OTPToken.SECRET_BASE32], + period: uriMap[TOTPToken.PERIOD_SECONDS], ); } /// This is used to create a map that typically was created from a uri. /// ```dart - /// -------------------------- [Token] -------------------------------- - /// | OTP_AUTH_SERIAL: serial, (optional) | - /// | OTP_AUTH_LABEL: label, | - /// | OTP_AUTH_ISSUER: issuer, | - /// | CONTAINER_SERIAL: containerSerial, (optional) | - /// | CHECKED_CONTAINERS: checkedContainer, | - /// | TOKEN_ID: id, | - /// | OTP_AUTH_TYPE: type, | - /// | OTP_AUTH_IMAGE: tokenImage, (optional) | - /// | SORTABLE_INDEX: sortIndex, (optional) | - /// | FOLDER_ID: folderId, (optional) | - /// | TOKEN_ORIGIN: origin, (optional) | - /// | OTP_AUTH_PIN: pin, | - /// | TOKEN_HIDDEN: isHidden, | - /// ------------------------------------------------------------------- - /// ------------------------- [OTPToken] ------------------------------ - /// | OTP_AUTH_ALGORITHM: algorithm, | - /// | OTP_AUTH_DIGITS: digits, | - /// | OTP_AUTH_SECRET_BASE32: secret, | - /// | OTP_AUTH_OTP_VALUES: [otpValue, nextValue], (if serial is null) | - /// ------------------------------------------------------------------- - /// -------------------- [DayPasswordToken] --------------------------- - /// | OTP_AUTH_PERIOD: period, | - /// ------------------------------------------------------------------- + /// ------------------------- [Token] -------------------------------- + /// | Token.SERIAL: serial, (optional) | + /// | Token.LABEL: label, | + /// | Token.ISSUER: issuer, | + /// | CONTAINER_SERIAL: containerSerial, (optional) | + /// | CHECKED_CONTAINERS: checkedContainer, | + /// | TOKEN_ID: id, | + /// | Token.TYPE: type, | + /// | Token.IMAGE: tokenImage, (optional) | + /// | SORTABLE_INDEX: sortIndex, (optional) | + /// | FOLDER_ID: folderId, (optional) | + /// | TOKEN_ORIGIN: origin, (optional) | + /// | Token.PIN: pin, | + /// | TOKEN_HIDDEN: isHidden, | + /// ------------------------------------------------------------------ + /// ------------------------ [OTPToken] ------------------------------ + /// | OTPToken.ALGORITHM: algorithm, | + /// | OTPToken.DIGITS: digits, | + /// | OTPToken.SECRET_BASE32: secret, | + /// | OTPToken.OTP_VALUES: [otpValue, nextValue], (if serial is null) | + /// ------------------------------------------------------------------ + /// ------------------- [DayPasswordToken] --------------------------- + /// | TOTPToken.PERIOD_SECONDS: period, | + /// ------------------------------------------------------------------ /// ``` @override Map toOtpAuthMap() { return super.toOtpAuthMap() ..addAll({ - OTP_AUTH_PERIOD_SECONDS: period.inSeconds.toString(), + TOTPToken.PERIOD_SECONDS: period.inSeconds.toString(), }); } diff --git a/lib/model/tokens/hotp_token.dart b/lib/model/tokens/hotp_token.dart index f018873a1..7f7aa175f 100644 --- a/lib/model/tokens/hotp_token.dart +++ b/lib/model/tokens/hotp_token.dart @@ -21,7 +21,6 @@ import 'package:json_annotation/json_annotation.dart'; import 'package:uuid/uuid.dart'; -import '../../utils/identifiers.dart'; import '../../utils/object_validator.dart'; import '../enums/algorithms.dart'; import '../enums/token_types.dart'; @@ -35,6 +34,9 @@ part 'hotp_token.g.dart'; @JsonSerializable() class HOTPToken extends OTPToken { + /// [String]/[int] (optional) default = '0' + static const String COUNTER = 'counter'; + static String get tokenType => TokenTypes.HOTP.name; final int counter; // this value is used to calculate the current otp value @@ -137,29 +139,29 @@ class HOTPToken extends OTPToken { final uriMap = validateMap( map: template.otpAuthMap, validators: { - OTP_AUTH_LABEL: const ObjectValidatorNullable(), - OTP_AUTH_ISSUER: const ObjectValidatorNullable(), - OTP_AUTH_SERIAL: const ObjectValidatorNullable(), - OTP_AUTH_ALGORITHM: stringToAlgorithmsValidatorNullable, - OTP_AUTH_DIGITS: intValidatorNullable, - OTP_AUTH_SECRET_BASE32: base32SecretValidatorNullable, - OTP_AUTH_COUNTER: otpAuthCounterValidator, - OTP_AUTH_IMAGE: const ObjectValidatorNullable(), - OTP_AUTH_PIN: boolValidatorNullable, + Token.LABEL: const ObjectValidatorNullable(), + Token.ISSUER: const ObjectValidatorNullable(), + Token.SERIAL: const ObjectValidatorNullable(), + Token.IMAGE: const ObjectValidatorNullable(), + Token.PIN: boolValidatorNullable, + OTPToken.ALGORITHM: stringToAlgorithmsValidatorNullable, + OTPToken.DIGITS: intValidatorNullable, + OTPToken.SECRET_BASE32: base32SecretValidatorNullable, + COUNTER: otpAuthCounterValidator, }, name: 'HOTPToken', ); return copyWith( - label: uriMap[OTP_AUTH_LABEL] as String?, - issuer: uriMap[OTP_AUTH_ISSUER] as String?, - serial: uriMap[OTP_AUTH_SERIAL] as String?, - algorithm: uriMap[OTP_AUTH_ALGORITHM] as Algorithms?, - digits: uriMap[OTP_AUTH_DIGITS] as int?, - secret: uriMap[OTP_AUTH_SECRET_BASE32] as String?, - counter: uriMap[OTP_AUTH_COUNTER] as int?, - tokenImage: uriMap[OTP_AUTH_IMAGE] as String?, - pin: uriMap[OTP_AUTH_PIN] as bool?, - isLocked: uriMap[OTP_AUTH_PIN] as bool?, + label: uriMap[Token.LABEL] as String?, + issuer: uriMap[Token.ISSUER] as String?, + serial: uriMap[Token.SERIAL] as String?, + tokenImage: uriMap[Token.IMAGE] as String?, + pin: uriMap[Token.PIN] as bool?, + isLocked: uriMap[Token.PIN] as bool?, + algorithm: uriMap[OTPToken.ALGORITHM] as Algorithms?, + digits: uriMap[OTPToken.DIGITS] as int?, + secret: uriMap[OTPToken.SECRET_BASE32] as String?, + counter: uriMap[COUNTER] as int?, ); } @@ -167,30 +169,26 @@ class HOTPToken extends OTPToken { final validatedMap = validateMap( map: otpAuthMap, validators: { - OTP_AUTH_LABEL: const ObjectValidator(defaultValue: ''), - OTP_AUTH_ISSUER: const ObjectValidator(defaultValue: ''), - OTP_AUTH_SERIAL: const ObjectValidatorNullable(), - OTP_AUTH_ALGORITHM: stringToAlgorithmsValidator.withDefault(Algorithms.SHA1), - OTP_AUTH_DIGITS: otpAuthDigitsValidatorNullable, - OTP_AUTH_SECRET_BASE32: base32Secretvalidator, - OTP_AUTH_COUNTER: otpAuthCounterValidator, - OTP_AUTH_IMAGE: const ObjectValidatorNullable(), - OTP_AUTH_PIN: boolValidatorNullable, + Token.LABEL: const ObjectValidator(defaultValue: ''), + Token.ISSUER: const ObjectValidator(defaultValue: ''), + Token.SERIAL: const ObjectValidatorNullable(), + Token.IMAGE: const ObjectValidatorNullable(), + Token.PIN: boolValidatorNullable, + OTPToken.ALGORITHM: stringToAlgorithmsValidator.withDefault(Algorithms.SHA1), + OTPToken.DIGITS: otpAuthDigitsValidatorNullable, + OTPToken.SECRET_BASE32: base32Secretvalidator, + COUNTER: otpAuthCounterValidator, }, name: 'HOTPToken#otpAuthMap', ); final validatedAdditionalData = Token.validateAdditionalData(additionalData); return HOTPToken( - label: validatedMap[OTP_AUTH_LABEL] as String, - issuer: validatedMap[OTP_AUTH_ISSUER] as String, - serial: validatedMap[OTP_AUTH_SERIAL] as String?, - algorithm: validatedMap[OTP_AUTH_ALGORITHM] as Algorithms, - digits: validatedMap[OTP_AUTH_DIGITS] as int, - secret: validatedMap[OTP_AUTH_SECRET_BASE32] as String, - counter: validatedMap[OTP_AUTH_COUNTER] as int, - tokenImage: validatedMap[OTP_AUTH_IMAGE] as String?, - pin: validatedMap[OTP_AUTH_PIN] as bool?, - isLocked: validatedMap[OTP_AUTH_PIN] as bool?, + label: validatedMap[Token.LABEL] as String, + issuer: validatedMap[Token.ISSUER] as String, + serial: validatedMap[Token.SERIAL] as String?, + tokenImage: validatedMap[Token.IMAGE] as String?, + pin: validatedMap[Token.PIN] as bool?, + isLocked: validatedMap[Token.PIN] as bool?, containerSerial: validatedAdditionalData[Token.CONTAINER_SERIAL], id: validatedAdditionalData[Token.ID] ?? const Uuid().v4(), origin: validatedAdditionalData[Token.ORIGIN], @@ -198,41 +196,45 @@ class HOTPToken extends OTPToken { checkedContainer: validatedAdditionalData[Token.CHECKED_CONTAINERS] ?? [], folderId: validatedAdditionalData[Token.FOLDER_ID], sortIndex: validatedAdditionalData[Token.SORT_INDEX], + algorithm: validatedMap[OTPToken.ALGORITHM] as Algorithms, + digits: validatedMap[OTPToken.DIGITS] as int, + secret: validatedMap[OTPToken.SECRET_BASE32] as String, + counter: validatedMap[COUNTER] as int, ); } /// This is used to create a map that typically was created from a uri. /// ```dart /// -------------------------- [Token] -------------------------------- - /// | OTP_AUTH_SERIAL: serial, (optional) | - /// | OTP_AUTH_LABEL: label, | - /// | OTP_AUTH_ISSUER: issuer, | + /// | Token.SERIAL: serial, (optional) | + /// | Token.LABEL: label, | + /// | Token.ISSUER: issuer, | /// | CONTAINER_SERIAL: containerSerial, (optional) | /// | CHECKED_CONTAINERS: checkedContainer, | /// | TOKEN_ID: id, | - /// | OTP_AUTH_TYPE: type, | - /// | OTP_AUTH_IMAGE: tokenImage, (optional) | + /// | Token.TYPE: type, | + /// | Token.IMAGE: tokenImage, (optional) | /// | SORTABLE_INDEX: sortIndex, (optional) | /// | FOLDER_ID: folderId, (optional) | /// | TOKEN_ORIGIN: origin, (optional) | - /// | OTP_AUTH_PIN: pin, | + /// | Token.PIN: pin, | /// | TOKEN_HIDDEN: isHidden, | /// ------------------------------------------------------------------- /// ------------------------- [OTPToken] ------------------------------ - /// | OTP_AUTH_ALGORITHM: algorithm, | - /// | OTP_AUTH_DIGITS: digits, | - /// | OTP_AUTH_SECRET_BASE32: secret, | - /// | OTP_AUTH_OTP_VALUES: [otpValue, nextValue], (if serial is null) | + /// | OTPToken.ALGORITHM: algorithm, | + /// | OTPToken.DIGITS: digits, | + /// | OTPToken.SECRET_BASE32: secret, | + /// | OTPToken.OTP_VALUES: [otpValue, nextValue], (if serial is null) | /// ------------------------------------------------------------------- /// ------------------------ [HOTPToken] ------------------------------ - /// | OTP_AUTH_COUNTER: counter, | + /// | COUNTER: counter, | /// ------------------------------------------------------------------- /// ``` @override Map toOtpAuthMap() { return super.toOtpAuthMap() ..addAll({ - OTP_AUTH_COUNTER: counter.toString(), + COUNTER: counter.toString(), }); } diff --git a/lib/model/tokens/otp_token.dart b/lib/model/tokens/otp_token.dart index 0fdd2dc68..19fd0bef9 100644 --- a/lib/model/tokens/otp_token.dart +++ b/lib/model/tokens/otp_token.dart @@ -28,6 +28,15 @@ import '../token_template.dart'; import 'token.dart'; abstract class OTPToken extends Token { + /// [String] (optional) default = 'SHA1' + static const String ALGORITHM = 'algorithm'; + + /// [String] (optional) default = '6' + static const String DIGITS = 'digits'; + + /// [String] (required) + static const String SECRET_BASE32 = 'secret'; + final Algorithms algorithm; // the hashing algorithm that is used to calculate the otp value final int digits; // the number of digits the otp value will have final String secret; // the secret based on which the otp value is calculated in base32 @@ -95,36 +104,36 @@ abstract class OTPToken extends Token { /// This is used to create a map that typically was created from a uri. /// ```dart - /// -------------------------- [Token] ------------------------------- - /// | OTP_AUTH_SERIAL: serial, (optional) | - /// | OTP_AUTH_LABEL: label, | - /// | OTP_AUTH_ISSUER: issuer, | - /// | CONTAINER_SERIAL: containerSerial, (optional) | - /// | CHECKED_CONTAINERS: checkedContainer, | - /// | TOKEN_ID: id, | - /// | OTP_AUTH_TYPE: type, | - /// | OTP_AUTH_IMAGE: tokenImage, (optional) | - /// | SORTABLE_INDEX: sortIndex, (optional) | - /// | FOLDER_ID: folderId, (optional) | - /// | TOKEN_ORIGIN: origin, (optional) | - /// | OTP_AUTH_PIN: pin, | - /// | TOKEN_HIDDEN: isHidden, | - /// ------------------------------------------------------------------- - /// ------------------------- [OTPToken] ------------------------------ - /// | OTP_AUTH_ALGORITHM: algorithm, | - /// | OTP_AUTH_DIGITS: digits, | - /// | OTP_AUTH_SECRET_BASE32: secret, | - /// | OTP_AUTH_OTP_VALUES: [otpValue, nextValue], (if serial is null) | - /// ------------------------------------------------------------------- + /// ------------------------- [Token] ------------------------------- + /// | Token.SERIAL: serial, (optional) | + /// | Token.LABEL: label, | + /// | Token.ISSUER: issuer, | + /// | Token.CONTAINER_SERIAL: containerSerial, (optional) | + /// | Token.CHECKED_CONTAINERS: checkedContainer, | + /// | Token.TOKEN_ID: id, | + /// | Token.TYPE: type, | + /// | Token.IMAGE: tokenImage, (optional) | + /// | Token.SORTABLE_INDEX: sortIndex, (optional) | + /// | Token.FOLDER_ID: folderId, (optional) | + /// | Token.TOKEN_ORIGIN: origin, (optional) | + /// | Token.PIN: pin, | + /// | Token.TOKEN_HIDDEN: isHidden, | + /// ----------------------------------------------------------------- + /// ------------------------- [OTPToken] ---------------------------- + /// | ALGORITHM: algorithm, | + /// | DIGITS: digits, | + /// | SECRET_BASE32: secret, | + /// | OTP_VALUES: [otpValue, nextValue], (if serial is null) | + /// ----------------------------------------------------------------- /// ``` @override Map toOtpAuthMap() { Logger.debug('$OTP_AUTH_OTP_VALUES ${jsonEncode([otpValue, nextValue])}'); return super.toOtpAuthMap() ..addAll({ - OTP_AUTH_ALGORITHM: algorithm.name, - OTP_AUTH_DIGITS: digits.toString(), - OTP_AUTH_SECRET_BASE32: secret, + ALGORITHM: algorithm.name, + DIGITS: digits.toString(), + SECRET_BASE32: secret, if (serial == null) OTP_AUTH_OTP_VALUES: [otpValue, nextValue], }); } diff --git a/lib/model/tokens/push_token.dart b/lib/model/tokens/push_token.dart index 4c0564167..4e32ae87e 100644 --- a/lib/model/tokens/push_token.dart +++ b/lib/model/tokens/push_token.dart @@ -1,5 +1,3 @@ -// ignore_for_file: constant_identifier_names - /* * privacyIDEA Authenticator * @@ -25,7 +23,6 @@ import 'package:uuid/uuid.dart'; import '../../../../../../../model/token_template.dart'; import '../../utils/custom_int_buffer.dart'; -import '../../utils/identifiers.dart'; import '../../utils/object_validator.dart'; import '../../utils/rsa_utils.dart'; import '../enums/push_token_rollout_state.dart'; @@ -41,6 +38,19 @@ part 'push_token.g.dart'; class PushToken extends Token { static RsaUtils rsaParser = const RsaUtils(); + /// [String] (required for PUSH) + static const String ROLLOUT_URL = 'url'; + static const String TTL_MINUTES = 'ttl'; + + /// [String] (optional) default = null + static const String ENROLLMENT_CREDENTIAL = 'enrollment_credential'; + + /// [String] '1' / '0' (optional) default = '1' + static const String SSL_VERIFY = 'sslverify'; + static const String SSL_VERIFY_VALUE_TRUE = '1'; + static const String SSL_VERIFY_VALUE_FALSE = '0'; + + static const String VERSION = 'v'; static const String EXPIRATION_DATE = 'expirationDate'; static const String ROLLOUT_STATE = 'rolloutState'; static const String IS_ROLLED_OUT = 'isRolledOut'; @@ -205,19 +215,19 @@ class PushToken extends Token { final validatedMap = validateMap( map: otpAuthMap, validators: { - OTP_AUTH_LABEL: const ObjectValidatorNullable(defaultValue: ''), - OTP_AUTH_ISSUER: const ObjectValidatorNullable(defaultValue: ''), - OTP_AUTH_SERIAL: const ObjectValidator(), - OTP_AUTH_PUSH_SSL_VERIFY: boolValidator.withDefault(true), - OTP_AUTH_PUSH_TTL_MINUTES: ObjectValidator( + Token.LABEL: const ObjectValidatorNullable(defaultValue: ''), + Token.ISSUER: const ObjectValidatorNullable(defaultValue: ''), + Token.SERIAL: const ObjectValidator(), + SSL_VERIFY: boolValidator.withDefault(true), + TTL_MINUTES: ObjectValidator( transformer: (v) => Duration(minutes: int.parse(v)), defaultValue: const Duration(minutes: 10), ), - OTP_AUTH_PUSH_ENROLLMENT_CREDENTIAL: const ObjectValidatorNullable(), - OTP_AUTH_PUSH_ROLLOUT_URL: stringToUrivalidator, - OTP_AUTH_IMAGE: stringToUriValidatorNullable, - OTP_AUTH_PIN: boolValidatorNullable, - OTP_AUTH_VERSION: const ObjectValidator(), + ENROLLMENT_CREDENTIAL: const ObjectValidatorNullable(), + ROLLOUT_URL: stringToUrivalidator, + Token.IMAGE: stringToUriValidatorNullable, + Token.PIN: boolValidatorNullable, + VERSION: const ObjectValidator(), }, name: 'PushToken', ); @@ -235,20 +245,20 @@ class PushToken extends Token { name: 'PushToken#additionalData', )); final expirationDate = validatedAdditionalData[EXPIRATION_DATE] as DateTime?; - return switch (validatedMap[OTP_AUTH_VERSION]) { + return switch (validatedMap[VERSION]) { '1' => PushToken( - label: validatedMap[OTP_AUTH_LABEL] as String, - issuer: validatedMap[OTP_AUTH_ISSUER] as String, - serial: validatedMap[OTP_AUTH_SERIAL] as String, - sslVerify: validatedMap[OTP_AUTH_PUSH_SSL_VERIFY] as bool, - expirationDate: expirationDate ?? DateTime.now().add(validatedMap[OTP_AUTH_PUSH_TTL_MINUTES] as Duration), + label: validatedMap[Token.LABEL] as String, + issuer: validatedMap[Token.ISSUER] as String, + serial: validatedMap[Token.SERIAL] as String, + sslVerify: validatedMap[SSL_VERIFY] as bool, + expirationDate: expirationDate ?? DateTime.now().add(validatedMap[TTL_MINUTES] as Duration), rolloutState: validatedAdditionalData[ROLLOUT_STATE], isRolledOut: validatedAdditionalData[IS_ROLLED_OUT], - enrollmentCredentials: validatedMap[OTP_AUTH_PUSH_ENROLLMENT_CREDENTIAL] as String?, - url: validatedMap[OTP_AUTH_PUSH_ROLLOUT_URL] as Uri, - tokenImage: validatedMap[OTP_AUTH_IMAGE] as String?, - pin: validatedMap[OTP_AUTH_PIN] as bool?, - isLocked: validatedMap[OTP_AUTH_PIN] as bool?, + enrollmentCredentials: validatedMap[ENROLLMENT_CREDENTIAL] as String?, + url: validatedMap[ROLLOUT_URL] as Uri, + tokenImage: validatedMap[Token.IMAGE] as String?, + pin: validatedMap[Token.PIN] as bool?, + isLocked: validatedMap[Token.PIN] as bool?, id: validatedAdditionalData[Token.ID] ?? const Uuid().v4(), origin: validatedAdditionalData[Token.ORIGIN], isHidden: validatedAdditionalData[Token.HIDDEN], @@ -261,8 +271,8 @@ class PushToken extends Token { ), _ => throw LocalizedArgumentError( localizedMessage: (localizations, value, name) => localizations.unsupported(value, name), - unlocalizedMessage: 'The piauth version [${validatedMap[OTP_AUTH_VERSION]}] is not supported by this version of the app.', - invalidValue: validatedMap[OTP_AUTH_VERSION].toString(), + unlocalizedMessage: 'The piauth version [${validatedMap[VERSION]}] is not supported by this version of the app.', + invalidValue: validatedMap[VERSION].toString(), name: 'piauth version', ), }; @@ -273,67 +283,67 @@ class PushToken extends Token { final uriMap = validateMap( map: template.otpAuthMap, validators: { - OTP_AUTH_LABEL: const ObjectValidatorNullable(), - OTP_AUTH_ISSUER: const ObjectValidatorNullable(), - OTP_AUTH_SERIAL: const ObjectValidatorNullable(), - OTP_AUTH_PUSH_SSL_VERIFY: boolValidatorNullable, - OTP_AUTH_PUSH_TTL_MINUTES: ObjectValidatorNullable( + Token.LABEL: const ObjectValidatorNullable(), + Token.ISSUER: const ObjectValidatorNullable(), + Token.SERIAL: const ObjectValidatorNullable(), + SSL_VERIFY: boolValidatorNullable, + TTL_MINUTES: ObjectValidatorNullable( transformer: (v) => Duration(minutes: int.parse(v)), ), - OTP_AUTH_PUSH_ENROLLMENT_CREDENTIAL: const ObjectValidatorNullable(), - OTP_AUTH_PUSH_ROLLOUT_URL: stringToUriValidatorNullable, - OTP_AUTH_IMAGE: stringToUriValidatorNullable, - OTP_AUTH_PIN: boolValidator, - OTP_AUTH_VERSION: intValidatorNullable, + ENROLLMENT_CREDENTIAL: const ObjectValidatorNullable(), + ROLLOUT_URL: stringToUriValidatorNullable, + Token.IMAGE: stringToUriValidatorNullable, + Token.PIN: boolValidator, + VERSION: intValidatorNullable, }, name: 'PushToken', ); return copyWith( - label: uriMap[OTP_AUTH_LABEL] as String?, - issuer: uriMap[OTP_AUTH_ISSUER] as String?, - serial: uriMap[OTP_AUTH_SERIAL] as String?, - sslVerify: uriMap[OTP_AUTH_PUSH_SSL_VERIFY] as bool?, - expirationDate: uriMap[OTP_AUTH_PUSH_TTL_MINUTES] != null ? DateTime.now().add(uriMap[OTP_AUTH_PUSH_TTL_MINUTES] as Duration) : expirationDate, - enrollmentCredentials: uriMap[OTP_AUTH_PUSH_ENROLLMENT_CREDENTIAL] as String?, - url: uriMap[OTP_AUTH_PUSH_ROLLOUT_URL] as Uri?, - tokenImage: uriMap[OTP_AUTH_IMAGE] as String?, - pin: uriMap[OTP_AUTH_PIN] as bool?, - isLocked: uriMap[OTP_AUTH_PIN] as bool?, + label: uriMap[Token.LABEL] as String?, + issuer: uriMap[Token.ISSUER] as String?, + serial: uriMap[Token.SERIAL] as String?, + sslVerify: uriMap[SSL_VERIFY] as bool?, + expirationDate: uriMap[TTL_MINUTES] != null ? DateTime.now().add(uriMap[TTL_MINUTES] as Duration) : expirationDate, + enrollmentCredentials: uriMap[ENROLLMENT_CREDENTIAL] as String?, + url: uriMap[ROLLOUT_URL] as Uri?, + tokenImage: uriMap[Token.IMAGE] as String?, + pin: uriMap[Token.PIN] as bool?, + isLocked: uriMap[Token.PIN] as bool?, ); } /// This is used to create a map that typically was created from a uri. /// ```dart /// ---------------------------- [Token] ---------------------------- - /// | OTP_AUTH_SERIAL: serial, (optional) | - /// | OTP_AUTH_TYPE: type, | - /// | OTP_AUTH_LABEL: label, | - /// | OTP_AUTH_ISSUER: issuer, | - /// | OTP_AUTH_PIN: pin, | - /// | OTP_AUTH_IMAGE: tokenImage, (optional) | + /// | Token.SERIAL: serial, (optional) | + /// | Token.TYPE: type, | + /// | Token.LABEL: label, | + /// | Token.ISSUER: issuer, | + /// | Token.PIN: pin, | + /// | Token.IMAGE: tokenImage, (optional) | /// ------------------------------------------------------------------ /// -------------------------- [PushToken] --------------------------- - /// | OTP_AUTH_SSL_VERIFY: sslVerify, | - /// | OTP_AUTH_ROLLOUT_TTL_MINUTES: expirationDate, (optional) | - /// | OTP_AUTH_ENROLLMENT_CREDENTIAL: enrollmentCredentials, (optional)| - /// | OTP_AUTH_ROLLOUT_URL: url, (optional) | - /// | OTP_AUTH_IMAGE: tokenImage, (optional) | - /// | OTP_AUTH_PIN: pin, | - /// | OTP_AUTH_VERSION: 1, | + /// | Token.SSL_VERIFY: sslVerify, | + /// | Token.ROLLOUT_TTL_MINUTES: expirationDate, (optional) | + /// | Token.ENROLLMENT_CREDENTIAL: enrollmentCredentials, (optional) | + /// | Token.ROLLOUT_URL: url, (optional) | + /// | Token.IMAGE: tokenImage, (optional) | + /// | Token.PIN: pin, | + /// | Token.VERSION: 1, | /// ------------------------------------------------------------------ /// ``` @override Map toOtpAuthMap() { return super.toOtpAuthMap() ..addAll({ - OTP_AUTH_PUSH_SSL_VERIFY: sslVerify ? OTP_AUTH_PUSH_SSL_VERIFY_TRUE : OTP_AUTH_PUSH_SSL_VERIFY_FALSE, - if (expirationDate != null) OTP_AUTH_PUSH_TTL_MINUTES: expirationDate!.difference(DateTime.now()).inMinutes.toString(), - if (enrollmentCredentials != null) OTP_AUTH_PUSH_ENROLLMENT_CREDENTIAL: enrollmentCredentials!, - if (url != null) OTP_AUTH_PUSH_ROLLOUT_URL: url.toString(), - if (tokenImage != null) OTP_AUTH_IMAGE: tokenImage!, - OTP_AUTH_PIN: pin ? OTP_AUTH_PIN_TRUE : OTP_AUTH_PIN_FALSE, - OTP_AUTH_VERSION: '1', + SSL_VERIFY: sslVerify ? SSL_VERIFY_VALUE_TRUE : SSL_VERIFY_VALUE_FALSE, + if (expirationDate != null) TTL_MINUTES: expirationDate!.difference(DateTime.now()).inMinutes.toString(), + if (enrollmentCredentials != null) ENROLLMENT_CREDENTIAL: enrollmentCredentials!, + if (url != null) ROLLOUT_URL: url.toString(), + if (tokenImage != null) Token.IMAGE: tokenImage!, + Token.PIN: pin ? Token.PIN_VALUE_TRUE : Token.PIN_VALUE_FALSE, + VERSION: '1', }); } diff --git a/lib/model/tokens/steam_token.dart b/lib/model/tokens/steam_token.dart index d6214dc85..d2855b847 100644 --- a/lib/model/tokens/steam_token.dart +++ b/lib/model/tokens/steam_token.dart @@ -23,12 +23,12 @@ import 'package:json_annotation/json_annotation.dart'; import 'package:uuid/uuid.dart'; import '../../../../../../../model/token_template.dart'; -import '../../utils/identifiers.dart'; import '../../utils/object_validator.dart'; import '../enums/algorithms.dart'; import '../enums/token_types.dart'; import '../extensions/int_extension.dart'; import '../token_import/token_origin_data.dart'; +import 'otp_token.dart'; import 'token.dart'; import 'totp_token.dart'; @@ -36,6 +36,8 @@ part 'steam_token.g.dart'; @JsonSerializable() class SteamToken extends TOTPToken { + static const STEAM_ISSUER = 'Steam'; + @override bool get isPrivacyIdeaToken => false; static String get tokenType => TokenTypes.STEAM.name; @@ -141,23 +143,23 @@ class SteamToken extends TOTPToken { final uriMap = validateMap( map: template.otpAuthMap, validators: { - OTP_AUTH_LABEL: const ObjectValidatorNullable(), - OTP_AUTH_ISSUER: const ObjectValidatorNullable(), - OTP_AUTH_SERIAL: const ObjectValidatorNullable(), - OTP_AUTH_SECRET_BASE32: base32SecretValidatorNullable, - OTP_AUTH_IMAGE: const ObjectValidatorNullable(), - OTP_AUTH_PIN: boolValidatorNullable, + Token.LABEL: const ObjectValidatorNullable(), + Token.ISSUER: const ObjectValidatorNullable(), + Token.SERIAL: const ObjectValidatorNullable(), + OTPToken.SECRET_BASE32: base32SecretValidatorNullable, + Token.IMAGE: const ObjectValidatorNullable(), + Token.PIN: boolValidatorNullable, }, name: 'SteamToken', ); return copyWith( - label: uriMap[OTP_AUTH_LABEL] as String?, - issuer: uriMap[OTP_AUTH_ISSUER] as String?, - serial: uriMap[OTP_AUTH_SERIAL] as String?, - secret: uriMap[OTP_AUTH_SECRET_BASE32] as String?, - tokenImage: uriMap[OTP_AUTH_IMAGE] as String?, - pin: uriMap[OTP_AUTH_PIN] as bool?, - isLocked: uriMap[OTP_AUTH_PIN] as bool?, + label: uriMap[Token.LABEL] as String?, + issuer: uriMap[Token.ISSUER] as String?, + serial: uriMap[Token.SERIAL] as String?, + secret: uriMap[OTPToken.SECRET_BASE32] as String?, + tokenImage: uriMap[Token.IMAGE] as String?, + pin: uriMap[Token.PIN] as bool?, + isLocked: uriMap[Token.PIN] as bool?, ); } @@ -165,24 +167,24 @@ class SteamToken extends TOTPToken { uriMap = validateMap( map: uriMap, validators: { - OTP_AUTH_LABEL: const ObjectValidator(defaultValue: ''), - OTP_AUTH_ISSUER: const ObjectValidator(defaultValue: ''), - OTP_AUTH_SERIAL: const ObjectValidatorNullable(), - OTP_AUTH_SECRET_BASE32: base32Secretvalidator, - OTP_AUTH_IMAGE: const ObjectValidatorNullable(), - OTP_AUTH_PIN: boolValidatorNullable, + Token.LABEL: const ObjectValidator(defaultValue: ''), + Token.ISSUER: const ObjectValidator(defaultValue: ''), + Token.SERIAL: const ObjectValidatorNullable(), + OTPToken.SECRET_BASE32: base32Secretvalidator, + Token.IMAGE: const ObjectValidatorNullable(), + Token.PIN: boolValidatorNullable, }, name: 'SteamToken#otpAuthMap', ); final validatedAdditionalData = Token.validateAdditionalData(additionalData); return SteamToken( - label: uriMap[OTP_AUTH_LABEL], - issuer: uriMap[OTP_AUTH_ISSUER], - serial: uriMap[OTP_AUTH_SERIAL], - secret: uriMap[OTP_AUTH_SECRET_BASE32], - tokenImage: uriMap[OTP_AUTH_IMAGE], - pin: uriMap[OTP_AUTH_PIN], - isLocked: uriMap[OTP_AUTH_PIN], + label: uriMap[Token.LABEL], + issuer: uriMap[Token.ISSUER], + serial: uriMap[Token.SERIAL], + secret: uriMap[OTPToken.SECRET_BASE32], + tokenImage: uriMap[Token.IMAGE], + pin: uriMap[Token.PIN], + isLocked: uriMap[Token.PIN], id: validatedAdditionalData[Token.ID] ?? const Uuid().v4(), containerSerial: validatedAdditionalData[Token.CONTAINER_SERIAL], checkedContainer: validatedAdditionalData[Token.CHECKED_CONTAINERS] ?? [], @@ -196,19 +198,19 @@ class SteamToken extends TOTPToken { /// This is used to create a map that typically was created from a uri. /// ```dart /// ------------------------- [Token] ------------------------- - /// | OTP_AUTH_SERIAL: serial, (optional) | - /// | OTP_AUTH_TYPE: type, | - /// | OTP_AUTH_LABEL: label, | - /// | OTP_AUTH_ISSUER: issuer, | - /// | OTP_AUTH_PIN: pin, | - /// | OTP_AUTH_IMAGE: tokenImage, (optional) | + /// | Token.SERIAL: serial, (optional) | + /// | Token.TYPE: type, | + /// | Token.LABEL: label, | + /// | Token.ISSUER: issuer, | + /// | Token.PIN: pin, | + /// | Token.IMAGE: tokenImage, (optional) | /// ----------------------------------------------------------- /// ----------------------- [OTPToken] ------------------------ - /// | OTP_AUTH_ALGORITHM: algorithm, | - /// | OTP_AUTH_DIGITS: digits, | + /// | OTPToken.ALGORITHM: algorithm, | + /// | OTPToken.DIGITS: digits, | /// ----------------------------------------------------------- /// ----------------------- [HOTPToken] ----------------------- - /// | OTP_AUTH_COUNTER: period, | + /// | HOTPToken.COUNTER: period, | /// ----------------------------------------------------------- /// ----------------------- [SteamToken] ---------------------- /// | /*No additional fields*/ | diff --git a/lib/model/tokens/token.dart b/lib/model/tokens/token.dart index b75bd346d..08eb92eb4 100644 --- a/lib/model/tokens/token.dart +++ b/lib/model/tokens/token.dart @@ -1,5 +1,3 @@ -// ignore_for_file: constant_identifier_names - /* * privacyIDEA Authenticator * @@ -22,7 +20,6 @@ import 'package:flutter/material.dart'; import '../../../../../../../model/token_container.dart'; -import '../../utils/identifiers.dart'; import '../../utils/object_validator.dart'; import '../enums/token_types.dart'; import '../extensions/enum_extension.dart'; @@ -37,13 +34,46 @@ import 'totp_token.dart'; @immutable abstract class Token with SortableMixin { - static const CONTAINER_SERIAL = 'containerSerial'; - static const ID = 'id'; - static const ORIGIN = 'origin'; - static const HIDDEN = 'hidden'; - static const CHECKED_CONTAINERS = 'checkedContainer'; - static const FOLDER_ID = 'folderId'; - static const SORT_INDEX = SortableMixin.SORT_INDEX; + /// [String] (optional) default = 'False' + static const String PIN_VALUE_TRUE = 'True'; + static const String PIN_VALUE_FALSE = 'False'; + + /// [String] (optional) default = '' + static const String IMAGE = 'image'; + + // Default data keys + static const String TYPE = 'type'; + + /// [String] (optional) default = '' + static const String LABEL = 'label'; + + /// [String] (optional) default = '' + static const String ISSUER = 'issuer'; + + /// [String] 'True' / 'False' (optional) default = 'False' + static const String PIN = 'pin'; + + /// [String] (optional) default = null + static const String SERIAL = 'serial'; + + // Additional data keys + static const String CONTAINER_SERIAL = 'containerSerial'; + static const String ID = 'id'; + static const String ORIGIN = 'origin'; + static const String HIDDEN = 'hidden'; + static const String CHECKED_CONTAINERS = 'checkedContainer'; + static const String FOLDER_ID = 'folderId'; + static const String SORT_INDEX = SortableMixin.SORT_INDEX; + + // otp auth 2step + /// [String] (required for 2step) + static const String TWO_STEP_SALT_LENTH = '2step_salt'; + + /// [String] (required for 2step) + static const String TWO_STEP_OUTPUT_LENTH = '2step_output'; + + /// [String] (required for 2step) + static const String TWO_STEP_ITERATIONS = '2step_difficulty'; bool? get isPrivacyIdeaToken => origin?.isPrivacyIdeaToken; final String tokenVersion = 'v1.0.0'; // The version of this token, this is used for serialization. @@ -67,7 +97,7 @@ abstract class Token with SortableMixin { /// Creates a token from a json map. factory Token.fromJson(Map json) { - String? type = json['type']; + String? type = json[TYPE]; if (type == null) throw ArgumentError.value(json, 'Token#fromJson', 'Token type is not defined in the json'); if (TokenTypes.HOTP.isName(type, caseSensitive: false)) return HOTPToken.fromJson(json); if (TokenTypes.TOTP.isName(type, caseSensitive: false)) return TOTPToken.fromJson(json); @@ -79,7 +109,7 @@ abstract class Token with SortableMixin { /// Creates a token from a uri map. factory Token.fromOtpAuthMap(Map otpAuthMap, {Map additionalData = const {}}) { - String? type = otpAuthMap[OTP_AUTH_TYPE]; + String? type = otpAuthMap[TYPE]; if (type == null) throw ArgumentError.value(otpAuthMap, 'Token#fromUriMap', 'Token type is not defined in the uri map'); if (TokenTypes.HOTP.isName(type, caseSensitive: false)) return HOTPToken.fromOtpAuthMap(otpAuthMap, additionalData: additionalData); if (TokenTypes.TOTP.isName(type, caseSensitive: false)) return TOTPToken.fromOtpAuthMap(otpAuthMap, additionalData: additionalData); @@ -181,23 +211,23 @@ abstract class Token with SortableMixin { /// This is used to create a map that typically was created from a uri. /// ```dart /// ------------------------- [Token] ------------------------- - /// | OTP_AUTH_SERIAL: serial, (optional) | - /// | OTP_AUTH_TYPE: type, | - /// | OTP_AUTH_LABEL: label, | - /// | OTP_AUTH_ISSUER: issuer, | - /// | OTP_AUTH_PIN: pin, | - /// | OTP_AUTH_IMAGE: tokenImage, (optional) | + /// | SERIAL: serial, (optional) | + /// | TYPE: type, | + /// | LABEL: label, | + /// | ISSUER: issuer, | + /// | PIN: pin, | + /// | IMAGE: tokenImage, (optional) | /// ----------------------------------------------------------- /// /// ``` Map toOtpAuthMap() { return { - if (serial != null) OTP_AUTH_SERIAL: serial!, - OTP_AUTH_TYPE: type, - OTP_AUTH_LABEL: label, - OTP_AUTH_ISSUER: issuer, - OTP_AUTH_PIN: pin ? OTP_AUTH_PIN_TRUE : OTP_AUTH_PIN_FALSE, - if (tokenImage != null) OTP_AUTH_IMAGE: tokenImage!, + if (serial != null) SERIAL: serial!, + TYPE: type, + LABEL: label, + ISSUER: issuer, + PIN: pin ? PIN_VALUE_TRUE : PIN_VALUE_FALSE, + if (tokenImage != null) IMAGE: tokenImage!, }; } diff --git a/lib/model/tokens/totp_token.dart b/lib/model/tokens/totp_token.dart index 651e52bd9..36da91170 100644 --- a/lib/model/tokens/totp_token.dart +++ b/lib/model/tokens/totp_token.dart @@ -21,7 +21,6 @@ import 'package:json_annotation/json_annotation.dart'; import 'package:uuid/uuid.dart'; -import '../../utils/identifiers.dart'; import '../../utils/logger.dart'; import '../../utils/object_validator.dart'; import '../enums/algorithms.dart'; @@ -36,6 +35,9 @@ part 'totp_token.g.dart'; @JsonSerializable() class TOTPToken extends OTPToken { + /// [String] (optional) default = '30' + static const String PERIOD_SECONDS = 'period'; + static String get tokenType => TokenTypes.TOTP.name; // this value is used to calculate the current 'counter' of this token // based on the UNIX systemtime), the counter is used to calculate the @@ -137,29 +139,29 @@ class TOTPToken extends OTPToken { final uriMap = validateMap( map: template.otpAuthMap, validators: { - OTP_AUTH_LABEL: const ObjectValidatorNullable(), - OTP_AUTH_ISSUER: const ObjectValidatorNullable(), - OTP_AUTH_SERIAL: const ObjectValidatorNullable(), - OTP_AUTH_ALGORITHM: stringToAlgorithmsValidatorNullable, - OTP_AUTH_DIGITS: intValidatorNullable, - OTP_AUTH_SECRET_BASE32: base32SecretValidatorNullable, - OTP_AUTH_PERIOD_SECONDS: intValidatorNullable, - OTP_AUTH_IMAGE: const ObjectValidatorNullable(), - OTP_AUTH_PIN: boolValidatorNullable, + Token.LABEL: const ObjectValidatorNullable(), + Token.ISSUER: const ObjectValidatorNullable(), + Token.SERIAL: const ObjectValidatorNullable(), + Token.IMAGE: const ObjectValidatorNullable(), + Token.PIN: boolValidatorNullable, + OTPToken.ALGORITHM: stringToAlgorithmsValidatorNullable, + OTPToken.DIGITS: intValidatorNullable, + OTPToken.SECRET_BASE32: base32SecretValidatorNullable, + PERIOD_SECONDS: intValidatorNullable, }, name: 'TOTPToken', ); return copyWith( - label: uriMap[OTP_AUTH_LABEL] as String?, - issuer: uriMap[OTP_AUTH_ISSUER] as String?, - serial: uriMap[OTP_AUTH_SERIAL] as String?, - algorithm: uriMap[OTP_AUTH_ALGORITHM] as Algorithms?, - digits: uriMap[OTP_AUTH_DIGITS] as int?, - secret: uriMap[OTP_AUTH_SECRET_BASE32] as String?, - period: uriMap[OTP_AUTH_PERIOD_SECONDS] as int?, - tokenImage: uriMap[OTP_AUTH_IMAGE] as String?, - pin: uriMap[OTP_AUTH_PIN] as bool?, - isLocked: uriMap[OTP_AUTH_PIN] as bool?, + label: uriMap[Token.LABEL] as String?, + issuer: uriMap[Token.ISSUER] as String?, + serial: uriMap[Token.SERIAL] as String?, + tokenImage: uriMap[Token.IMAGE] as String?, + pin: uriMap[Token.PIN] as bool?, + isLocked: uriMap[Token.PIN] as bool?, + algorithm: uriMap[OTPToken.ALGORITHM] as Algorithms?, + digits: uriMap[OTPToken.DIGITS] as int?, + secret: uriMap[OTPToken.SECRET_BASE32] as String?, + period: uriMap[PERIOD_SECONDS] as int?, ); } @@ -172,30 +174,26 @@ class TOTPToken extends OTPToken { final validatedMap = validateMap( map: otpAuthMap, validators: { - OTP_AUTH_LABEL: const ObjectValidator(defaultValue: ''), - OTP_AUTH_ISSUER: const ObjectValidator(defaultValue: ''), - OTP_AUTH_SERIAL: const ObjectValidatorNullable(), - OTP_AUTH_ALGORITHM: stringToAlgorithmsValidator.withDefault(Algorithms.SHA1), - OTP_AUTH_DIGITS: otpAuthDigitsValidator, - OTP_AUTH_SECRET_BASE32: base32Secretvalidator, - OTP_AUTH_PERIOD_SECONDS: otpAuthPeriodSecondsValidator, - OTP_AUTH_IMAGE: const ObjectValidatorNullable(), - OTP_AUTH_PIN: boolValidatorNullable, + Token.LABEL: const ObjectValidator(defaultValue: ''), + Token.ISSUER: const ObjectValidator(defaultValue: ''), + Token.SERIAL: const ObjectValidatorNullable(), + Token.IMAGE: const ObjectValidatorNullable(), + Token.PIN: boolValidatorNullable, + OTPToken.ALGORITHM: stringToAlgorithmsValidator.withDefault(Algorithms.SHA1), + OTPToken.DIGITS: otpAuthDigitsValidator, + OTPToken.SECRET_BASE32: base32Secretvalidator, + PERIOD_SECONDS: otpAuthPeriodSecondsValidator, }, name: 'TOTPToken#otpAuthMap', ); final validatedAdditionalData = Token.validateAdditionalData(additionalData); return TOTPToken( - label: validatedMap[OTP_AUTH_LABEL] as String, - issuer: validatedMap[OTP_AUTH_ISSUER] as String, - serial: validatedMap[OTP_AUTH_SERIAL] as String?, - algorithm: validatedMap[OTP_AUTH_ALGORITHM] as Algorithms, - digits: validatedMap[OTP_AUTH_DIGITS] as int, - secret: validatedMap[OTP_AUTH_SECRET_BASE32] as String, - period: validatedMap[OTP_AUTH_PERIOD_SECONDS] as int, - tokenImage: validatedMap[OTP_AUTH_IMAGE] as String?, - pin: validatedMap[OTP_AUTH_PIN] as bool?, - isLocked: validatedMap[OTP_AUTH_PIN] as bool?, + label: validatedMap[Token.LABEL] as String, + issuer: validatedMap[Token.ISSUER] as String, + serial: validatedMap[Token.SERIAL] as String?, + tokenImage: validatedMap[Token.IMAGE] as String?, + pin: validatedMap[Token.PIN] as bool?, + isLocked: validatedMap[Token.PIN] as bool?, id: validatedAdditionalData[Token.ID] ?? const Uuid().v4(), containerSerial: validatedAdditionalData[Token.CONTAINER_SERIAL], checkedContainer: validatedAdditionalData[Token.CHECKED_CONTAINERS] ?? [], @@ -203,32 +201,36 @@ class TOTPToken extends OTPToken { folderId: validatedAdditionalData[Token.FOLDER_ID], origin: validatedAdditionalData[Token.ORIGIN], isHidden: validatedAdditionalData[Token.HIDDEN], + algorithm: validatedMap[OTPToken.ALGORITHM] as Algorithms, + digits: validatedMap[OTPToken.DIGITS] as int, + secret: validatedMap[OTPToken.SECRET_BASE32] as String, + period: validatedMap[PERIOD_SECONDS] as int, ); } /// This is used to create a map that typically was created from a uri. /// ```dart /// ------------------------- [Token] ------------------------- - /// | OTP_AUTH_SERIAL: serial, (optional) | - /// | OTP_AUTH_TYPE: type, | - /// | OTP_AUTH_LABEL: label, | - /// | OTP_AUTH_ISSUER: issuer, | - /// | OTP_AUTH_PIN: pin, | - /// | OTP_AUTH_IMAGE: tokenImage, (optional) | + /// | Token.SERIAL: serial, (optional) | + /// | Token.TYPE: type, | + /// | Token.LABEL: label, | + /// | Token.ISSUER: issuer, | + /// | Token.PIN: pin, | + /// | Token.IMAGE: tokenImage, (optional) | /// ----------------------------------------------------------- /// ----------------------- [OTPToken] ------------------------ - /// | OTP_AUTH_ALGORITHM: algorithm, | - /// | OTP_AUTH_DIGITS: digits, | + /// | OTPToken.ALGORITHM: algorithm, | + /// | OTPToken.DIGITS: digits, | /// ----------------------------------------------------------- /// ----------------------- [HOTPToken] ----------------------- - /// | OTP_AUTH_COUNTER: period, | + /// | PERIOD_SECONDS: period, | /// ----------------------------------------------------------- /// ``` @override Map toOtpAuthMap() { return super.toOtpAuthMap() ..addAll({ - OTP_AUTH_COUNTER: period.toString(), + PERIOD_SECONDS: period.toString(), }); } diff --git a/lib/processors/scheme_processors/token_container_processor.dart b/lib/processors/scheme_processors/token_container_processor.dart index d4f4cb365..8d0b4b190 100644 --- a/lib/processors/scheme_processors/token_container_processor.dart +++ b/lib/processors/scheme_processors/token_container_processor.dart @@ -1,5 +1,3 @@ -// ignore_for_file: constant_identifier_names - /* * privacyIDEA Authenticator * diff --git a/lib/processors/scheme_processors/token_import_scheme_processors/otp_auth_processor.dart b/lib/processors/scheme_processors/token_import_scheme_processors/otp_auth_processor.dart index 87d23da08..db6f3700e 100644 --- a/lib/processors/scheme_processors/token_import_scheme_processors/otp_auth_processor.dart +++ b/lib/processors/scheme_processors/token_import_scheme_processors/otp_auth_processor.dart @@ -26,6 +26,7 @@ import '../../../model/extensions/enums/encodings_extension.dart'; import '../../../model/extensions/enums/token_origin_source_type.dart'; import '../../../model/processor_result.dart'; import '../../../model/token_import/token_origin_data.dart'; +import '../../../model/tokens/otp_token.dart'; import '../../../model/tokens/token.dart'; import '../../../utils/identifiers.dart'; import '../../../utils/logger.dart'; @@ -58,9 +59,9 @@ class OtpAuthProcessor extends TokenImportSchemeProcessor { Map queryParameters = {...uri.queryParameters}; final (label, issuer) = _parseLabelAndIssuer(uri); - queryParameters[OTP_AUTH_LABEL] = label; - queryParameters[OTP_AUTH_ISSUER] = issuer; - queryParameters[OTP_AUTH_TYPE] = _parseTokenType(uri); + queryParameters[Token.LABEL] = label; + queryParameters[Token.ISSUER] = issuer; + queryParameters[Token.TYPE] = _parseTokenType(uri); queryParameters = _secretAddPadding(queryParameters); _logInfo(uri); @@ -76,7 +77,7 @@ class OtpAuthProcessor extends TokenImportSchemeProcessor { ]; } // Update the secret with the two step secret. - queryParameters[OTP_AUTH_SECRET_BASE32] = twoStepSecretString; + queryParameters[OTPToken.SECRET_BASE32] = twoStepSecretString; } try { return [ @@ -150,9 +151,9 @@ TokenOriginData _parseCreatorToOrigin(Uri uri) { String _parseIssuer(Uri uri) { final param = validate( - value: uri.queryParameters[OTP_AUTH_ISSUER], + value: uri.queryParameters[Token.ISSUER], validator: const ObjectValidator(defaultValue: ''), - name: OTP_AUTH_ISSUER, + name: Token.ISSUER, ); try { return Uri.decodeFull(param); @@ -163,9 +164,9 @@ String _parseIssuer(Uri uri) { bool _is2StepURI(Uri uri) { final queryParameters = uri.queryParameters; - return queryParameters[OTP_AUTH_2STEP_SALT_LENTH] != null || - queryParameters[OTP_AUTH_2STEP_OUTPUT_LENTH] != null || - queryParameters[OTP_AUTH_2STEP_ITERATIONS] != null; + return queryParameters[Token.TWO_STEP_SALT_LENTH] != null || + queryParameters[Token.TWO_STEP_OUTPUT_LENTH] != null || + queryParameters[Token.TWO_STEP_ITERATIONS] != null; } /// This method parses the 2 step secret from the uri. @@ -179,22 +180,22 @@ Future? _parse2StepSecret(Uri uri) { validateMap( map: queryParameters, validators: { - OTP_AUTH_SECRET_BASE32: ObjectValidator(transformer: (v) => Encodings.base32.decode(v)), - OTP_AUTH_2STEP_SALT_LENTH: intValidator, - OTP_AUTH_2STEP_OUTPUT_LENTH: intValidator, - OTP_AUTH_2STEP_ITERATIONS: intValidator, + OTPToken.SECRET_BASE32: ObjectValidator(transformer: (v) => Encodings.base32.decode(v)), + Token.TWO_STEP_SALT_LENTH: intValidator, + Token.TWO_STEP_OUTPUT_LENTH: intValidator, + Token.TWO_STEP_ITERATIONS: intValidator, }, name: '2StepSecret', ); - final secret = Encodings.base32.decode(queryParameters[OTP_AUTH_SECRET_BASE32]!); + final secret = Encodings.base32.decode(queryParameters[OTPToken.SECRET_BASE32]!); // Calculate the whole secret. final twoStepSecret = showAsyncDialog( barrierDismissible: false, builder: (context) => GenerateTwoStepDialog( - iterations: int.parse(queryParameters[OTP_AUTH_2STEP_ITERATIONS]!), - keyLength: int.parse(queryParameters[OTP_AUTH_2STEP_OUTPUT_LENTH]!), - saltLength: int.parse(queryParameters[OTP_AUTH_2STEP_SALT_LENTH]!), + iterations: int.parse(queryParameters[Token.TWO_STEP_ITERATIONS]!), + keyLength: int.parse(queryParameters[Token.TWO_STEP_OUTPUT_LENTH]!), + saltLength: int.parse(queryParameters[Token.TWO_STEP_SALT_LENTH]!), password: secret, ), ); @@ -224,20 +225,20 @@ void _logInfo(Uri uri) { // According to https://github.com/google/google-authenticator/wiki/Key-Uri-Format, // the padding can be omitted, but the libraries for base32 do not allow this. Map _secretAddPadding(Map queryParameters) { - if (queryParameters[OTP_AUTH_SECRET_BASE32] == null) return queryParameters; - final secret = queryParameters[OTP_AUTH_SECRET_BASE32]!; - return {...queryParameters}..addAll({OTP_AUTH_SECRET_BASE32: '$secret${secret.length % 2 == 1 ? '=' : ''}'}); + if (queryParameters[OTPToken.SECRET_BASE32] == null) return queryParameters; + final secret = queryParameters[OTPToken.SECRET_BASE32]!; + return {...queryParameters}..addAll({OTPToken.SECRET_BASE32: '$secret${secret.length % 2 == 1 ? '=' : ''}'}); } String _parseTokenType(Uri uri) { if (_parseIssuer(uri) == "Steam") return TokenTypes.STEAM.name; Logger.debug('Token type host: ${uri.host}'); - Logger.debug('Token type queryParameters: ${uri.queryParameters[OTP_AUTH_TYPE]}'); - final value = uri.queryParameters[OTP_AUTH_TYPE] ?? uri.host; + Logger.debug('Token type queryParameters: ${uri.queryParameters[Token.TYPE]}'); + final value = uri.queryParameters[Token.TYPE] ?? uri.host; Logger.debug('Token type value: $value'); return validate( - value: uri.queryParameters[OTP_AUTH_TYPE] ?? uri.host, + value: uri.queryParameters[Token.TYPE] ?? uri.host, validator: ObjectValidator(defaultValue: uri.host), - name: OTP_AUTH_TYPE, + name: Token.TYPE, ); } diff --git a/lib/processors/token_import_file_processor/aegis_import_file_processor.dart b/lib/processors/token_import_file_processor/aegis_import_file_processor.dart index d49b886a6..ca7b6322d 100644 --- a/lib/processors/token_import_file_processor/aegis_import_file_processor.dart +++ b/lib/processors/token_import_file_processor/aegis_import_file_processor.dart @@ -17,7 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -// ignore_for_file: constant_identifier_names import 'dart:convert'; import 'dart:isolate'; @@ -36,9 +35,11 @@ import '../../model/exception_errors/localized_exception.dart'; import '../../model/extensions/enums/encodings_extension.dart'; import '../../model/extensions/enums/token_origin_source_type.dart'; import '../../model/processor_result.dart'; +import '../../model/tokens/hotp_token.dart'; +import '../../model/tokens/otp_token.dart'; import '../../model/tokens/token.dart'; +import '../../model/tokens/totp_token.dart'; import '../../utils/globals.dart'; -import '../../utils/identifiers.dart'; import '../../utils/logger.dart'; import '../../utils/object_validator.dart'; import '../../utils/token_import_origins.dart'; @@ -190,26 +191,26 @@ class AegisImportFileProcessor extends TokenImportFileProcessor { Map info = entry[AEGIS_ENTRY_INFO]; final otpAuthMap = validateMap( map: { - OTP_AUTH_TYPE: entry[AEGIS_ENTRY_TYPE], - OTP_AUTH_LABEL: entry[AEGIS_ENTRY_LABEL], - OTP_AUTH_ISSUER: entry[AEGIS_ENTRY_ISSUER], - OTP_AUTH_SECRET_BASE32: entry[AEGIS_INFO_SECRET], - OTP_AUTH_ALGORITHM: info[AEGIS_INFO_ALGORITHM], - OTP_AUTH_DIGITS: info[AEGIS_INFO_DIGITS], - OTP_AUTH_PERIOD_SECONDS: info[AEGIS_INFO_PERIOD], - OTP_AUTH_COUNTER: info[AEGIS_INFO_COUNTER], - OTP_AUTH_PIN: info[AEGIS_INFO_PIN], + Token.TYPE: entry[AEGIS_ENTRY_TYPE], + Token.LABEL: entry[AEGIS_ENTRY_LABEL], + Token.ISSUER: entry[AEGIS_ENTRY_ISSUER], + Token.PIN: info[AEGIS_INFO_PIN], + OTPToken.SECRET_BASE32: entry[AEGIS_INFO_SECRET], + OTPToken.ALGORITHM: info[AEGIS_INFO_ALGORITHM], + OTPToken.DIGITS: info[AEGIS_INFO_DIGITS], + TOTPToken.PERIOD_SECONDS: info[AEGIS_INFO_PERIOD], + HOTPToken.COUNTER: info[AEGIS_INFO_COUNTER], }, validators: { - OTP_AUTH_TYPE: const ObjectValidator(), - OTP_AUTH_LABEL: const ObjectValidator(defaultValue: ''), - OTP_AUTH_ISSUER: const ObjectValidator(defaultValue: ''), - OTP_AUTH_SECRET_BASE32: ObjectValidator(transformer: (v) => Encodings.none.encodeStringTo(Encodings.base32, info[AEGIS_INFO_SECRET])), - OTP_AUTH_ALGORITHM: const ObjectValidatorNullable(), - OTP_AUTH_DIGITS: ObjectValidatorNullable(transformer: (v) => (v as int).toString()), - OTP_AUTH_PERIOD_SECONDS: ObjectValidatorNullable(transformer: (v) => (v as int).toString()), - OTP_AUTH_COUNTER: ObjectValidatorNullable(transformer: (v) => (v as int).toString()), - OTP_AUTH_PIN: const ObjectValidatorNullable(), + Token.TYPE: const ObjectValidator(), + Token.LABEL: const ObjectValidator(defaultValue: ''), + Token.ISSUER: const ObjectValidator(defaultValue: ''), + Token.PIN: const ObjectValidatorNullable(), + OTPToken.SECRET_BASE32: ObjectValidator(transformer: (v) => Encodings.none.encodeStringTo(Encodings.base32, info[AEGIS_INFO_SECRET])), + OTPToken.ALGORITHM: const ObjectValidatorNullable(), + OTPToken.DIGITS: ObjectValidatorNullable(transformer: (v) => (v as int).toString()), + TOTPToken.PERIOD_SECONDS: ObjectValidatorNullable(transformer: (v) => (v as int).toString()), + HOTPToken.COUNTER: ObjectValidatorNullable(transformer: (v) => (v as int).toString()), }, name: 'aegisV2Entry', ); @@ -250,26 +251,26 @@ class AegisImportFileProcessor extends TokenImportFileProcessor { Map info = entry[AEGIS_ENTRY_INFO]; final otpAuthMap = validateMap( map: { - OTP_AUTH_TYPE: entry[AEGIS_ENTRY_TYPE], - OTP_AUTH_LABEL: entry[AEGIS_ENTRY_LABEL], - OTP_AUTH_ISSUER: entry[AEGIS_ENTRY_ISSUER], - OTP_AUTH_SECRET_BASE32: info[AEGIS_INFO_SECRET], - OTP_AUTH_ALGORITHM: info[AEGIS_INFO_ALGORITHM], - OTP_AUTH_DIGITS: info[AEGIS_INFO_DIGITS], - OTP_AUTH_PERIOD_SECONDS: info[AEGIS_INFO_PERIOD], - OTP_AUTH_COUNTER: info[AEGIS_INFO_COUNTER], - OTP_AUTH_PIN: info[AEGIS_INFO_PIN], + Token.TYPE: entry[AEGIS_ENTRY_TYPE], + Token.LABEL: entry[AEGIS_ENTRY_LABEL], + Token.ISSUER: entry[AEGIS_ENTRY_ISSUER], + OTPToken.SECRET_BASE32: info[AEGIS_INFO_SECRET], + OTPToken.ALGORITHM: info[AEGIS_INFO_ALGORITHM], + OTPToken.DIGITS: info[AEGIS_INFO_DIGITS], + TOTPToken.PERIOD_SECONDS: info[AEGIS_INFO_PERIOD], + HOTPToken.COUNTER: info[AEGIS_INFO_COUNTER], + Token.PIN: info[AEGIS_INFO_PIN], }, validators: { - OTP_AUTH_TYPE: const ObjectValidator(), - OTP_AUTH_LABEL: const ObjectValidator(defaultValue: ''), - OTP_AUTH_ISSUER: const ObjectValidator(defaultValue: ''), - OTP_AUTH_SECRET_BASE32: ObjectValidator(transformer: (v) => Encodings.base32.encodeStringTo(Encodings.base32, v)), - OTP_AUTH_ALGORITHM: const ObjectValidatorNullable(), - OTP_AUTH_DIGITS: intToStringValidatorNullable, - OTP_AUTH_PERIOD_SECONDS: intToStringValidatorNullable, - OTP_AUTH_COUNTER: intToStringValidatorNullable, - OTP_AUTH_PIN: const ObjectValidatorNullable(), + Token.TYPE: const ObjectValidator(), + Token.LABEL: const ObjectValidator(defaultValue: ''), + Token.ISSUER: const ObjectValidator(defaultValue: ''), + OTPToken.SECRET_BASE32: ObjectValidator(transformer: (v) => Encodings.base32.encodeStringTo(Encodings.base32, v)), + OTPToken.ALGORITHM: const ObjectValidatorNullable(), + OTPToken.DIGITS: intToStringValidatorNullable, + TOTPToken.PERIOD_SECONDS: intToStringValidatorNullable, + HOTPToken.COUNTER: intToStringValidatorNullable, + Token.PIN: const ObjectValidatorNullable(), }, name: 'aegisV3Entry', ); diff --git a/lib/processors/token_import_file_processor/authenticator_pro_import_file_processor.dart b/lib/processors/token_import_file_processor/authenticator_pro_import_file_processor.dart index a61f4878c..84a9a1107 100644 --- a/lib/processors/token_import_file_processor/authenticator_pro_import_file_processor.dart +++ b/lib/processors/token_import_file_processor/authenticator_pro_import_file_processor.dart @@ -32,12 +32,14 @@ import '../../model/enums/token_types.dart'; import '../../model/exception_errors/localized_exception.dart'; import '../../model/extensions/enums/token_origin_source_type.dart'; import '../../model/processor_result.dart'; +import '../../model/tokens/hotp_token.dart'; +import '../../model/tokens/otp_token.dart'; import '../../model/tokens/token.dart'; +import '../../model/tokens/totp_token.dart'; import '../../processors/scheme_processors/token_import_scheme_processors/otp_auth_processor.dart'; import '../../processors/token_import_file_processor/two_fas_import_file_processor.dart'; import '../../utils/encryption/aes_encrypted.dart'; import '../../utils/globals.dart'; -import '../../utils/identifiers.dart'; import '../../utils/logger.dart'; import '../../utils/object_validator.dart'; import '../../utils/token_import_origins.dart'; @@ -321,24 +323,24 @@ class AuthenticatorProImportFileProcessor extends TokenImportFileProcessor { final otpAuthMap = validateMap( map: { - OTP_AUTH_TYPE: tokenType, - OTP_AUTH_ISSUER: tokenMap[_AUTHENTICATOR_PRO_ISSUER], - OTP_AUTH_LABEL: tokenMap[_AUTHENTICATOR_PRO_LABEL], - OTP_AUTH_SECRET_BASE32: tokenMap[_AUTHENTICATOR_PRO_SECRET], - OTP_AUTH_DIGITS: tokenMap[_AUTHENTICATOR_PRO_DIGITS], - OTP_AUTH_PERIOD_SECONDS: tokenMap[_AUTHENTICATOR_PRO_PERIOD], - OTP_AUTH_ALGORITHM: tokenMap[_AUTHENTICATOR_PRO_ALGORITHM], - OTP_AUTH_COUNTER: tokenMap[_AUTHENTICATOR_PRO_COUNTER], + Token.TYPE: tokenType, + Token.ISSUER: tokenMap[_AUTHENTICATOR_PRO_ISSUER], + Token.LABEL: tokenMap[_AUTHENTICATOR_PRO_LABEL], + OTPToken.SECRET_BASE32: tokenMap[_AUTHENTICATOR_PRO_SECRET], + OTPToken.DIGITS: tokenMap[_AUTHENTICATOR_PRO_DIGITS], + OTPToken.ALGORITHM: tokenMap[_AUTHENTICATOR_PRO_ALGORITHM], + TOTPToken.PERIOD_SECONDS: tokenMap[_AUTHENTICATOR_PRO_PERIOD], + HOTPToken.COUNTER: tokenMap[_AUTHENTICATOR_PRO_COUNTER], }, validators: { - OTP_AUTH_TYPE: const ObjectValidator(), - OTP_AUTH_ISSUER: const ObjectValidator(), - OTP_AUTH_LABEL: const ObjectValidator(), - OTP_AUTH_SECRET_BASE32: const ObjectValidator(), - OTP_AUTH_DIGITS: intToStringValidator, - OTP_AUTH_PERIOD_SECONDS: intToStringValidator, - OTP_AUTH_ALGORITHM: ObjectValidator(transformer: (value) => algorithmMap[value]!), - OTP_AUTH_COUNTER: intToStringValidator, + Token.TYPE: const ObjectValidator(), + Token.ISSUER: const ObjectValidator(), + Token.LABEL: const ObjectValidator(), + OTPToken.SECRET_BASE32: const ObjectValidator(), + OTPToken.DIGITS: intToStringValidator, + TOTPToken.PERIOD_SECONDS: intToStringValidator, + HOTPToken.COUNTER: intToStringValidator, + OTPToken.ALGORITHM: ObjectValidator(transformer: (value) => algorithmMap[value]!), }, name: 'AuthenticatorProToken', ); diff --git a/lib/processors/token_import_file_processor/free_otp_plus_import_file_processor.dart b/lib/processors/token_import_file_processor/free_otp_plus_import_file_processor.dart index fa1c8f929..161c7097f 100644 --- a/lib/processors/token_import_file_processor/free_otp_plus_import_file_processor.dart +++ b/lib/processors/token_import_file_processor/free_otp_plus_import_file_processor.dart @@ -17,7 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -// ignore_for_file: constant_identifier_names import 'dart:convert'; import 'dart:typed_data'; @@ -31,9 +30,11 @@ import '../../model/enums/token_origin_source_type.dart'; import '../../model/exception_errors/localized_exception.dart'; import '../../model/extensions/enums/token_origin_source_type.dart'; import '../../model/processor_result.dart'; +import '../../model/tokens/hotp_token.dart'; +import '../../model/tokens/otp_token.dart'; import '../../model/tokens/token.dart'; +import '../../model/tokens/totp_token.dart'; import '../../utils/globals.dart'; -import '../../utils/identifiers.dart'; import '../../utils/logger.dart'; import '../../utils/object_validator.dart'; import '../../utils/token_import_origins.dart'; @@ -157,25 +158,25 @@ class FreeOtpPlusImportFileProcessor extends TokenImportFileProcessor { name: 'FreeOtpPlusToken', map: { /// Steam is a special case, its hardcoded in the original app. - OTP_AUTH_TYPE: tokenJson[_FREE_OTP_PLUS_ISSUER] == _steamTokenIssuer ? _steamTokenType : tokenJson[_FREE_OTP_PLUS_TYPE], - OTP_AUTH_LABEL: tokenJson[_FREE_OTP_PLUS_LABEL], - OTP_AUTH_SECRET_BASE32: tokenJson[_FREE_OTP_PLUS_SECRET], - OTP_AUTH_ISSUER: tokenJson[_FREE_OTP_PLUS_ISSUER], - OTP_AUTH_ALGORITHM: tokenJson[_FREE_OTP_PLUS_ALGORITHM], - OTP_AUTH_DIGITS: tokenJson[_FREE_OTP_PLUS_DIGITS], - OTP_AUTH_COUNTER: tokenJson[_FREE_OTP_PLUS_COUNTER], - OTP_AUTH_PERIOD_SECONDS: tokenJson[_FREE_OTP_PLUS_PERIOD], + Token.TYPE: tokenJson[_FREE_OTP_PLUS_ISSUER] == _steamTokenIssuer ? _steamTokenType : tokenJson[_FREE_OTP_PLUS_TYPE], + Token.LABEL: tokenJson[_FREE_OTP_PLUS_LABEL], + Token.ISSUER: tokenJson[_FREE_OTP_PLUS_ISSUER], + OTPToken.SECRET_BASE32: tokenJson[_FREE_OTP_PLUS_SECRET], + OTPToken.ALGORITHM: tokenJson[_FREE_OTP_PLUS_ALGORITHM], + OTPToken.DIGITS: tokenJson[_FREE_OTP_PLUS_DIGITS], + HOTPToken.COUNTER: tokenJson[_FREE_OTP_PLUS_COUNTER], + TOTPToken.PERIOD_SECONDS: tokenJson[_FREE_OTP_PLUS_PERIOD], }, validators: { - OTP_AUTH_TYPE: const ObjectValidator(), - OTP_AUTH_LABEL: const ObjectValidator(), - OTP_AUTH_SECRET_BASE32: ObjectValidator(transformer: (value) => Encodings.base32.encode(Uint8List.fromList((value as List).cast()))), - OTP_AUTH_ISSUER: const ObjectValidator(), - OTP_AUTH_ALGORITHM: const ObjectValidator(), - OTP_AUTH_DIGITS: intToStringValidator, + Token.TYPE: const ObjectValidator(), + Token.LABEL: const ObjectValidator(), + Token.ISSUER: const ObjectValidator(), + OTPToken.SECRET_BASE32: ObjectValidator(transformer: (value) => Encodings.base32.encode(Uint8List.fromList((value as List).cast()))), + OTPToken.ALGORITHM: const ObjectValidator(), + OTPToken.DIGITS: intToStringValidator, // FreeOTP+ saves the counter 1 less than the actual value - OTP_AUTH_COUNTER: ObjectValidatorNullable(transformer: (value) => ((value as int) + 1).toString()), - OTP_AUTH_PERIOD_SECONDS: intToStringValidatorNullable, + HOTPToken.COUNTER: ObjectValidatorNullable(transformer: (value) => ((value as int) + 1).toString()), + TOTPToken.PERIOD_SECONDS: intToStringValidatorNullable, }, ); } diff --git a/lib/processors/token_import_file_processor/two_fas_import_file_processor.dart b/lib/processors/token_import_file_processor/two_fas_import_file_processor.dart index 1ee4f4f6b..4a8867a3c 100644 --- a/lib/processors/token_import_file_processor/two_fas_import_file_processor.dart +++ b/lib/processors/token_import_file_processor/two_fas_import_file_processor.dart @@ -17,7 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -// ignore_for_file: constant_identifier_names import 'dart:convert'; @@ -29,10 +28,12 @@ import '../../model/enums/token_origin_source_type.dart'; import '../../model/exception_errors/localized_exception.dart'; import '../../model/extensions/enums/token_origin_source_type.dart'; import '../../model/processor_result.dart'; +import '../../model/tokens/hotp_token.dart'; +import '../../model/tokens/otp_token.dart'; import '../../model/tokens/token.dart'; +import '../../model/tokens/totp_token.dart'; import '../../utils/encryption/aes_encrypted.dart'; import '../../utils/globals.dart'; -import '../../utils/identifiers.dart'; import '../../utils/logger.dart'; import '../../utils/object_validator.dart'; import '../../utils/token_import_origins.dart'; @@ -175,24 +176,24 @@ class TwoFasAuthenticatorImportFileProcessor extends TokenImportFileProcessor { Map twoFasOTP = twoFasToken[TWOFAS_OTP]; return validateMap( map: { - OTP_AUTH_ISSUER: twoFasToken[TWOFAS_ISSUER], - OTP_AUTH_SECRET_BASE32: twoFasToken[TWOFAS_SECRET], - OTP_AUTH_TYPE: twoFasOTP[TWOFAS_TYPE], - OTP_AUTH_LABEL: twoFasOTP[TWOFAS_LABEL], - OTP_AUTH_ALGORITHM: twoFasOTP[TWOFAS_ALGORITHM], - OTP_AUTH_DIGITS: twoFasOTP[TWOFAS_DIGITS], - OTP_AUTH_PERIOD_SECONDS: twoFasOTP[TWOFAS_PERIOD], - OTP_AUTH_COUNTER: twoFasOTP[TWOFAS_COUNTER], + Token.ISSUER: twoFasToken[TWOFAS_ISSUER], + Token.TYPE: twoFasOTP[TWOFAS_TYPE], + Token.LABEL: twoFasOTP[TWOFAS_LABEL], + OTPToken.SECRET_BASE32: twoFasToken[TWOFAS_SECRET], + OTPToken.ALGORITHM: twoFasOTP[TWOFAS_ALGORITHM], + OTPToken.DIGITS: twoFasOTP[TWOFAS_DIGITS], + TOTPToken.PERIOD_SECONDS: twoFasOTP[TWOFAS_PERIOD], + HOTPToken.COUNTER: twoFasOTP[TWOFAS_COUNTER], }, validators: { - OTP_AUTH_TYPE: const ObjectValidator(), - OTP_AUTH_ISSUER: const ObjectValidatorNullable(), - OTP_AUTH_LABEL: const ObjectValidatorNullable(), - OTP_AUTH_SECRET_BASE32: const ObjectValidator(), - OTP_AUTH_ALGORITHM: const ObjectValidatorNullable(), - OTP_AUTH_DIGITS: intToStringValidatorNullable, - OTP_AUTH_PERIOD_SECONDS: intToStringValidatorNullable, - OTP_AUTH_COUNTER: intToStringValidatorNullable, + Token.TYPE: const ObjectValidator(), + Token.ISSUER: const ObjectValidatorNullable(), + Token.LABEL: const ObjectValidatorNullable(), + OTPToken.SECRET_BASE32: const ObjectValidator(), + OTPToken.ALGORITHM: const ObjectValidatorNullable(), + OTPToken.DIGITS: intToStringValidatorNullable, + TOTPToken.PERIOD_SECONDS: intToStringValidatorNullable, + HOTPToken.COUNTER: intToStringValidatorNullable, }, name: '2FAS token', ); diff --git a/lib/proto/generated/GoogleAuthenticatorImport.pbserver.dart b/lib/proto/generated/GoogleAuthenticatorImport.pbserver.dart index 6a01da06b..14d014a28 100644 --- a/lib/proto/generated/GoogleAuthenticatorImport.pbserver.dart +++ b/lib/proto/generated/GoogleAuthenticatorImport.pbserver.dart @@ -5,10 +5,8 @@ // @dart = 2.12 // ignore_for_file: annotate_overrides, camel_case_types, comment_references -// ignore_for_file: constant_identifier_names // ignore_for_file: deprecated_member_use_from_same_package, library_prefixes // ignore_for_file: non_constant_identifier_names, prefer_final_fields // ignore_for_file: unnecessary_import, unnecessary_this, unused_import export 'GoogleAuthenticatorImport.pb.dart'; - diff --git a/lib/repo/secure_push_request_repository.dart b/lib/repo/secure_push_request_repository.dart index a3b6ae209..9fabf10cf 100644 --- a/lib/repo/secure_push_request_repository.dart +++ b/lib/repo/secure_push_request_repository.dart @@ -17,7 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -// ignore_for_file: constant_identifier_names import 'dart:convert'; diff --git a/lib/repo/secure_token_repository.dart b/lib/repo/secure_token_repository.dart index c8ed17f46..3b0f51b16 100644 --- a/lib/repo/secure_token_repository.dart +++ b/lib/repo/secure_token_repository.dart @@ -1,5 +1,3 @@ -// ignore_for_file: constant_identifier_names - /* privacyIDEA Authenticator diff --git a/lib/utils/firebase_utils.dart b/lib/utils/firebase_utils.dart index 8cefba6e7..b9883c326 100644 --- a/lib/utils/firebase_utils.dart +++ b/lib/utils/firebase_utils.dart @@ -17,7 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -// ignore_for_file: constant_identifier_names import 'dart:io'; diff --git a/lib/utils/globals.dart b/lib/utils/globals.dart index 5852df842..213266d78 100644 --- a/lib/utils/globals.dart +++ b/lib/utils/globals.dart @@ -1,5 +1,3 @@ -// ignore_for_file: constant_identifier_names - /* privacyIDEA Authenticator diff --git a/lib/utils/identifiers.dart b/lib/utils/identifiers.dart index 14345870c..58b384e49 100644 --- a/lib/utils/identifiers.dart +++ b/lib/utils/identifiers.dart @@ -1,5 +1,3 @@ -// ignore_for_file: constant_identifier_names - /* privacyIDEA Authenticator @@ -21,111 +19,17 @@ */ // otp auth -const OTP_AUTH_VERSION = 'v'; const OTP_AUTH_CREATOR = 'creator'; -const OTP_AUTH_TYPE = 'type'; - -/// [String] (optional) default = null -const OTP_AUTH_SERIAL = 'serial'; - -/// [String] (required) -const OTP_AUTH_SECRET_BASE32 = 'secret'; - -/// [String]/[int] (optional) default = '0' -const OTP_AUTH_COUNTER = 'counter'; - -/// [String] (optional) default = '30' -const OTP_AUTH_PERIOD_SECONDS = 'period'; - -/// [String] (optional) default = 'SHA1' -const OTP_AUTH_ALGORITHM = 'algorithm'; - -/// [String] (optional) default = '6' -const OTP_AUTH_DIGITS = 'digits'; - -/// [String] (optional) default = '' -const OTP_AUTH_LABEL = 'label'; - -/// [String] (optional) default = '' -const OTP_AUTH_ISSUER = 'issuer'; - -/// [String] 'True' / 'False' (optional) default = 'False' -const OTP_AUTH_PIN = 'pin'; - -/// [String] (optional) default = 'False' -const OTP_AUTH_PIN_TRUE = 'True'; -const OTP_AUTH_PIN_FALSE = 'False'; - -/// [String] (optional) default = '' -const OTP_AUTH_IMAGE = 'image'; - -// OTP auth push - -/// [String] (required for PUSH) -const OTP_AUTH_PUSH_ROLLOUT_URL = 'url'; -const OTP_AUTH_PUSH_TTL_MINUTES = 'ttl'; - -/// [String] (optional) default = null -const OTP_AUTH_PUSH_ENROLLMENT_CREDENTIAL = 'enrollment_credential'; - -/// [String] '1' / '0' (optional) default = '1' -const OTP_AUTH_PUSH_SSL_VERIFY = 'sslverify'; -const OTP_AUTH_PUSH_SSL_VERIFY_TRUE = '1'; -const OTP_AUTH_PUSH_SSL_VERIFY_FALSE = '0'; - -// otp auth 2step - -/// [String] (required for 2step) -const OTP_AUTH_2STEP_SALT_LENTH = '2step_salt'; - -/// [String] (required for 2step) -const OTP_AUTH_2STEP_OUTPUT_LENTH = '2step_output'; - -/// [String] (required for 2step) -const OTP_AUTH_2STEP_ITERATIONS = '2step_difficulty'; // Container otp sync - const OTP_AUTH_OTP_VALUES = 'otp'; -const OTP_AUTH_STEAM_ISSUER = 'Steam'; - // Crypto stuff: const String SIGNING_ALGORITHM = 'SHA-256/RSA'; // Custom error identifiers const String FIREBASE_TOKEN_ERROR_CODE = 'FIREBASE_TOKEN_ERROR_CODE'; -// Push request: -const String PUSH_REQUEST_NONCE = 'nonce'; // 1. -const String PUSH_REQUEST_URL = 'url'; // 2. -const String PUSH_REQUEST_SERIAL = 'serial'; // 3. -const String PUSH_REQUEST_QUESTION = 'question'; // 4. -const String PUSH_REQUEST_TITLE = 'title'; // 5. -const String PUSH_REQUEST_SSL_VERIFY = 'sslverify'; // 6. -const String PUSH_REQUEST_SIGNATURE = 'signature'; // 7. -const String PUSH_REQUEST_ANSWERS = 'require_presence'; // 8. - -// Container challenge: -const String CONTAINER_CHAL_KEY_ALGORITHM = 'enc_key_algorithm'; -const String CONTAINER_CHAL_NONCE = 'nonce'; -const String CONTAINER_CHAL_TIMESTAMP = 'time_stamp'; -const String CONTAINER_CHAL_SIGNATURE = 'signature'; - -// Container registration: -const String CONTAINER_ISSUER = 'issuer'; -const String CONTAINER_NONCE = 'nonce'; -const String CONTAINER_TIMESTAMP = 'time'; -const String CONTAINER_FINALIZATION_URL = 'url'; -const String CONTAINER_EC_KEY_ALGORITHM = 'key_algorithm'; -const String CONTAINER_SERIAL = 'serial'; -const String CONTAINER_HASH_ALGORITHM = 'hash_algorithm'; -const String CONTAINER_PASSPHRASE_QUESTION = 'passphrase'; -const String CONTAINER_SSL_VERIFY = 'ssl_verify'; -const String CONTAINER_SERVER_URL = 'container_sync_url'; -const String CONTAINER_SCOPE = 'scope'; -const String CONTAINER_POLICIES = 'info'; - // Container finalization: const String CONTAINER_CONTAINER_SERIAL = 'container_serial'; const String CONTAINER_PUBLIC_CLIENT_KEY = 'public_client_key'; @@ -133,7 +37,6 @@ const String CONTAINER_DEVICE_BRAND = 'device_brand'; const String CONTAINER_DEVICE_MODEL = 'device_model'; // Container sync: - const String CONTAINER_SYNC_PUBLIC_CLIENT_KEY = 'public_enc_key_client'; const String CONTAINER_SYNC_DICT_SERVER = 'container_dict_server'; const String CONTAINER_SYNC_DICT_CLIENT = 'container_dict_client'; diff --git a/lib/utils/logger.dart b/lib/utils/logger.dart index e4bcf66e3..696c6f771 100644 --- a/lib/utils/logger.dart +++ b/lib/utils/logger.dart @@ -17,7 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -// ignore_for_file: constant_identifier_names import 'dart:async'; import 'dart:developer'; diff --git a/local_plugins/pi-authenticator-legacy/lib/identifiers.dart b/local_plugins/pi-authenticator-legacy/lib/identifiers.dart index bc4cb952c..2344075f1 100644 --- a/local_plugins/pi-authenticator-legacy/lib/identifiers.dart +++ b/local_plugins/pi-authenticator-legacy/lib/identifiers.dart @@ -1,5 +1,3 @@ -// ignore_for_file: constant_identifier_names - /* privacyIDEA Authenticator diff --git a/local_plugins/pi-authenticator-legacy/lib/pi_authenticator_legacy.dart b/local_plugins/pi-authenticator-legacy/lib/pi_authenticator_legacy.dart index b094163e0..54ad3f250 100644 --- a/local_plugins/pi-authenticator-legacy/lib/pi_authenticator_legacy.dart +++ b/local_plugins/pi-authenticator-legacy/lib/pi_authenticator_legacy.dart @@ -1,5 +1,3 @@ -// ignore_for_file: constant_identifier_names - /* privacyIDEA Authenticator diff --git a/test/unit_test/model/push_request_test.dart b/test/unit_test/model/push_request_test.dart index e9862c056..8beb57adc 100644 --- a/test/unit_test/model/push_request_test.dart +++ b/test/unit_test/model/push_request_test.dart @@ -1,7 +1,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:privacyidea_authenticator/model/push_request.dart'; import 'package:privacyidea_authenticator/model/tokens/push_token.dart'; -import 'package:privacyidea_authenticator/utils/identifiers.dart'; void main() { _testPushRequest(); @@ -73,13 +72,13 @@ void _testPushRequest() { test('fromMessageData', () { // Arrange final data = { - PUSH_REQUEST_TITLE: 'title', - PUSH_REQUEST_QUESTION: 'question', - PUSH_REQUEST_URL: 'https://example.com', - PUSH_REQUEST_NONCE: 'nonce', - PUSH_REQUEST_SSL_VERIFY: '1', - PUSH_REQUEST_SERIAL: 'serial', - PUSH_REQUEST_SIGNATURE: 'signature', + PushRequest.TITLE: 'title', + PushRequest.QUESTION: 'question', + PushRequest.URL: 'https://example.com', + PushRequest.NONCE: 'nonce', + PushRequest.SSL_VERIFY: '1', + PushRequest.SERIAL: 'serial', + PushRequest.SIGNATURE: 'signature', }; // Act final request = PushRequest.fromMessageData(data); @@ -157,13 +156,13 @@ void _testPushRequest() { test('verifyData', () { // Arrange final data = { - PUSH_REQUEST_TITLE: 'title', - PUSH_REQUEST_QUESTION: 'question', - PUSH_REQUEST_URL: 'https://example.com', - PUSH_REQUEST_NONCE: 'nonce', - PUSH_REQUEST_SSL_VERIFY: '1', - PUSH_REQUEST_SERIAL: 'serial', - PUSH_REQUEST_SIGNATURE: 'signature', + PushRequest.TITLE: 'title', + PushRequest.QUESTION: 'question', + PushRequest.URL: 'https://example.com', + PushRequest.NONCE: 'nonce', + PushRequest.SSL_VERIFY: '1', + PushRequest.SERIAL: 'serial', + PushRequest.SIGNATURE: 'signature', }; // Assert expect(() => PushRequest.verifyData(data), returnsNormally); diff --git a/test/unit_test/model/token/day_password_test.dart b/test/unit_test/model/token/day_password_test.dart index 917639933..af23d3fa7 100644 --- a/test/unit_test/model/token/day_password_test.dart +++ b/test/unit_test/model/token/day_password_test.dart @@ -7,6 +7,8 @@ import 'package:privacyidea_authenticator/model/enums/encodings.dart'; import 'package:privacyidea_authenticator/model/extensions/enums/encodings_extension.dart'; import 'package:privacyidea_authenticator/model/tokens/day_password_token.dart'; import 'package:privacyidea_authenticator/model/tokens/hotp_token.dart'; +import 'package:privacyidea_authenticator/model/tokens/otp_token.dart'; +import 'package:privacyidea_authenticator/model/tokens/token.dart'; import 'package:privacyidea_authenticator/utils/identifiers.dart'; void main() { @@ -77,15 +79,15 @@ void _testDayPasswordToken() { group('fromUriMap', () { test('with full map', () { final uriMap = { - OTP_AUTH_PERIOD_SECONDS: '30', - OTP_AUTH_LABEL: 'label', - OTP_AUTH_ISSUER: 'issuer', - OTP_AUTH_ALGORITHM: 'SHA1', - OTP_AUTH_DIGITS: '6', - OTP_AUTH_SECRET_BASE32: Encodings.base32.encode(utf8.encode('secret')), - OTP_AUTH_TYPE: 'DAYPASSWORD', - OTP_AUTH_PIN: 'False', - OTP_AUTH_IMAGE: 'example.png', + TOTPToken.PERIOD_SECONDS: '30', + Token.LABEL: 'label', + Token.ISSUER: 'issuer', + OTPToken.ALGORITHM: 'SHA1', + OTPToken.DIGITS: '6', + OTPToken.SECRET_BASE32: Encodings.base32.encode(utf8.encode('secret')), + Token.TYPE: 'DAYPASSWORD', + Token.PIN: Token.PIN_VALUE_FALSE, + Token.IMAGE: 'example.png', }; final totpFromUriMap = DayPasswordToken.fromOtpAuthMap(uriMap); expect(totpFromUriMap.period, const Duration(seconds: 30)); @@ -100,70 +102,70 @@ void _testDayPasswordToken() { }); test('with missing secret', () { final uriMap = { - OTP_AUTH_PERIOD_SECONDS: 30, - OTP_AUTH_LABEL: 'label', - OTP_AUTH_ISSUER: 'issuer', - OTP_AUTH_ALGORITHM: 'SHA1', - OTP_AUTH_DIGITS: 6, - OTP_AUTH_TYPE: 'DAYPASSWORD', - OTP_AUTH_PIN: 'False', - OTP_AUTH_IMAGE: 'example.png', + TOTPToken.PERIOD_SECONDS: 30, + Token.LABEL: 'label', + Token.ISSUER: 'issuer', + OTPToken.ALGORITHM: 'SHA1', + OTPToken.DIGITS: 6, + Token.TYPE: 'DAYPASSWORD', + Token.PIN: Token.PIN_VALUE_FALSE, + Token.IMAGE: 'example.png', }; expect(() => DayPasswordToken.fromOtpAuthMap(uriMap), throwsA(isA())); }); test('with zero period', () { final uriMap = { - OTP_AUTH_PERIOD_SECONDS: '0', - OTP_AUTH_LABEL: 'label', - OTP_AUTH_ISSUER: 'issuer', - OTP_AUTH_ALGORITHM: 'SHA1', - OTP_AUTH_DIGITS: '6', - OTP_AUTH_SECRET_BASE32: Encodings.base32.encode(utf8.encode('secret')), - OTP_AUTH_TYPE: 'DAYPASSWORD', - OTP_AUTH_PIN: 'False', - OTP_AUTH_IMAGE: 'example.png', + TOTPToken.PERIOD_SECONDS: '0', + Token.LABEL: 'label', + Token.ISSUER: 'issuer', + OTPToken.ALGORITHM: 'SHA1', + OTPToken.DIGITS: '6', + OTPToken.SECRET_BASE32: Encodings.base32.encode(utf8.encode('secret')), + Token.TYPE: 'DAYPASSWORD', + Token.PIN: Token.PIN_VALUE_FALSE, + Token.IMAGE: 'example.png', }; expect(() => DayPasswordToken.fromOtpAuthMap(uriMap), throwsA(isA())); var errorContainsPeriod = false; try { DayPasswordToken.fromOtpAuthMap(uriMap); } catch (e) { - errorContainsPeriod = e.toString().contains(OTP_AUTH_PERIOD_SECONDS); + errorContainsPeriod = e.toString().contains(TOTPToken.PERIOD_SECONDS); } expect(errorContainsPeriod, true); }); test('with zero digits', () { final uriMap = { - OTP_AUTH_PERIOD_SECONDS: '30', - OTP_AUTH_LABEL: 'label', - OTP_AUTH_ISSUER: 'issuer', - OTP_AUTH_ALGORITHM: 'SHA1', - OTP_AUTH_DIGITS: '0', - OTP_AUTH_SECRET_BASE32: Encodings.base32.encode(utf8.encode('secret')), - OTP_AUTH_TYPE: 'DAYPASSWORD', - OTP_AUTH_PIN: 'False', - OTP_AUTH_IMAGE: 'example.png', + TOTPToken.PERIOD_SECONDS: '30', + Token.LABEL: 'label', + Token.ISSUER: 'issuer', + OTPToken.ALGORITHM: 'SHA1', + OTPToken.DIGITS: '0', + OTPToken.SECRET_BASE32: Encodings.base32.encode(utf8.encode('secret')), + Token.TYPE: 'DAYPASSWORD', + Token.PIN: Token.PIN_VALUE_FALSE, + Token.IMAGE: 'example.png', }; expect(() => DayPasswordToken.fromOtpAuthMap(uriMap), throwsA(isA())); var errorContainsDigits = false; try { DayPasswordToken.fromOtpAuthMap(uriMap); } catch (e) { - errorContainsDigits = e.toString().contains(OTP_AUTH_DIGITS); + errorContainsDigits = e.toString().contains(OTPToken.DIGITS); } expect(errorContainsDigits, true); }); test('with lowercase algorithm', () { final uriMap = { - OTP_AUTH_PERIOD_SECONDS: '30', - OTP_AUTH_LABEL: 'label', - OTP_AUTH_ISSUER: 'issuer', - OTP_AUTH_ALGORITHM: 'sha1', - OTP_AUTH_DIGITS: '6', - OTP_AUTH_SECRET_BASE32: Encodings.base32.encode(utf8.encode('secret')), - OTP_AUTH_TYPE: 'DAYPASSWORD', - OTP_AUTH_PIN: 'False', - OTP_AUTH_IMAGE: 'example.png', + TOTPToken.PERIOD_SECONDS: '30', + Token.LABEL: 'label', + Token.ISSUER: 'issuer', + OTPToken.ALGORITHM: 'sha1', + OTPToken.DIGITS: '6', + OTPToken.SECRET_BASE32: Encodings.base32.encode(utf8.encode('secret')), + Token.TYPE: 'DAYPASSWORD', + Token.PIN: Token.PIN_VALUE_FALSE, + Token.IMAGE: 'example.png', }; final totpFromUriMap = DayPasswordToken.fromOtpAuthMap(uriMap); expect(totpFromUriMap.algorithm, Algorithms.SHA1); diff --git a/test/unit_test/model/token/hotp_token_test.dart b/test/unit_test/model/token/hotp_token_test.dart index 76c0b9a53..2f0597945 100644 --- a/test/unit_test/model/token/hotp_token_test.dart +++ b/test/unit_test/model/token/hotp_token_test.dart @@ -5,7 +5,8 @@ import 'package:privacyidea_authenticator/model/enums/algorithms.dart'; import 'package:privacyidea_authenticator/model/enums/encodings.dart'; import 'package:privacyidea_authenticator/model/extensions/enums/encodings_extension.dart'; import 'package:privacyidea_authenticator/model/tokens/hotp_token.dart'; -import 'package:privacyidea_authenticator/utils/identifiers.dart'; +import 'package:privacyidea_authenticator/model/tokens/otp_token.dart'; +import 'package:privacyidea_authenticator/model/tokens/token.dart'; void main() { _testHotpToken(); @@ -79,15 +80,15 @@ void _testHotpToken() { group('fromUriMap', () { test('with full map', () { final uriMap = { - OTP_AUTH_COUNTER: '10', - OTP_AUTH_LABEL: 'label', - OTP_AUTH_ISSUER: 'issuer', - OTP_AUTH_ALGORITHM: 'SHA1', - OTP_AUTH_SECRET_BASE32: Encodings.base32.encode(utf8.encode('secret')), - OTP_AUTH_DIGITS: '6', - OTP_AUTH_TYPE: 'HOTP', - OTP_AUTH_PIN: 'True', - OTP_AUTH_IMAGE: 'example.png', + Token.LABEL: 'label', + Token.ISSUER: 'issuer', + Token.TYPE: 'HOTP', + Token.PIN: Token.PIN_VALUE_TRUE, + Token.IMAGE: 'example.png', + OTPToken.ALGORITHM: 'SHA1', + OTPToken.SECRET_BASE32: Encodings.base32.encode(utf8.encode('secret')), + OTPToken.DIGITS: '6', + HOTPToken.COUNTER: '10', }; final hotpFromUriMap = HOTPToken.fromOtpAuthMap(uriMap); expect(hotpFromUriMap.counter, 10); @@ -102,49 +103,49 @@ void _testHotpToken() { }); test('without secret', () { final uriMap = { - OTP_AUTH_COUNTER: '10', - OTP_AUTH_LABEL: 'label', - OTP_AUTH_ISSUER: 'issuer', - OTP_AUTH_ALGORITHM: 'SHA1', - OTP_AUTH_DIGITS: '6', - OTP_AUTH_TYPE: 'HOTP', - OTP_AUTH_PIN: 'True', - OTP_AUTH_IMAGE: 'example.png', + Token.LABEL: 'label', + Token.ISSUER: 'issuer', + Token.TYPE: 'HOTP', + Token.PIN: Token.PIN_VALUE_TRUE, + Token.IMAGE: 'example.png', + OTPToken.ALGORITHM: 'SHA1', + OTPToken.DIGITS: '6', + HOTPToken.COUNTER: '10', }; expect(() => HOTPToken.fromOtpAuthMap(uriMap), throwsArgumentError); }); test('digits is zero', () { final uriMap = { - OTP_AUTH_COUNTER: '10', - OTP_AUTH_LABEL: 'label', - OTP_AUTH_ISSUER: 'issuer', - OTP_AUTH_ALGORITHM: 'SHA1', - OTP_AUTH_SECRET_BASE32: Encodings.base32.encode(utf8.encode('secret')), - OTP_AUTH_DIGITS: '0', - OTP_AUTH_TYPE: 'HOTP', - OTP_AUTH_PIN: 'True', - OTP_AUTH_IMAGE: 'example.png', + Token.LABEL: 'label', + Token.ISSUER: 'issuer', + Token.TYPE: 'HOTP', + Token.PIN: Token.PIN_VALUE_TRUE, + Token.IMAGE: 'example.png', + OTPToken.ALGORITHM: 'SHA1', + OTPToken.SECRET_BASE32: Encodings.base32.encode(utf8.encode('secret')), + OTPToken.DIGITS: '0', + HOTPToken.COUNTER: '10', }; expect(() => HOTPToken.fromOtpAuthMap(uriMap), throwsArgumentError); bool errorContainsDigits = false; try { HOTPToken.fromOtpAuthMap(uriMap); } on ArgumentError catch (e) { - errorContainsDigits = e.toString().contains(OTP_AUTH_DIGITS); + errorContainsDigits = e.toString().contains(OTPToken.DIGITS); } expect(errorContainsDigits, true); }); test('with lowercase algorithm', () { final uriMap = { - OTP_AUTH_COUNTER: '10', - OTP_AUTH_LABEL: 'label', - OTP_AUTH_ISSUER: 'issuer', - OTP_AUTH_ALGORITHM: 'sha1', - OTP_AUTH_SECRET_BASE32: Encodings.base32.encode(utf8.encode('secret')), - OTP_AUTH_DIGITS: '6', - OTP_AUTH_TYPE: 'HOTP', - OTP_AUTH_PIN: 'True', - OTP_AUTH_IMAGE: 'example.png', + Token.LABEL: 'label', + Token.ISSUER: 'issuer', + Token.TYPE: 'HOTP', + Token.PIN: Token.PIN_VALUE_TRUE, + Token.IMAGE: 'example.png', + OTPToken.ALGORITHM: 'sha1', + OTPToken.SECRET_BASE32: Encodings.base32.encode(utf8.encode('secret')), + OTPToken.DIGITS: '6', + HOTPToken.COUNTER: '10', }; final hotpFromUriMap = HOTPToken.fromOtpAuthMap(uriMap); expect(hotpFromUriMap.counter, 10); diff --git a/test/unit_test/model/token/push_token_test.dart b/test/unit_test/model/token/push_token_test.dart index 1573bb8f9..360f1340a 100644 --- a/test/unit_test/model/token/push_token_test.dart +++ b/test/unit_test/model/token/push_token_test.dart @@ -1,7 +1,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:privacyidea_authenticator/model/enums/push_token_rollout_state.dart'; import 'package:privacyidea_authenticator/model/tokens/push_token.dart'; -import 'package:privacyidea_authenticator/utils/identifiers.dart'; +import 'package:privacyidea_authenticator/model/tokens/token.dart'; void main() { _testPushToken(); @@ -169,15 +169,15 @@ void _testPushToken() { group('fromUriMap', () { test('with full map', () { final uriMap = { - OTP_AUTH_TYPE: 'PIPUSH', - OTP_AUTH_LABEL: 'label', - OTP_AUTH_ISSUER: 'issuer', - OTP_AUTH_SERIAL: 'serial', - OTP_AUTH_PUSH_SSL_VERIFY: 'False', - OTP_AUTH_PUSH_ENROLLMENT_CREDENTIAL: 'enrollmentCredentials', - OTP_AUTH_PUSH_ROLLOUT_URL: 'http://www.example.com', - OTP_AUTH_PUSH_TTL_MINUTES: '10', - OTP_AUTH_VERSION: '1', + Token.TYPE: 'PIPUSH', + Token.LABEL: 'label', + Token.ISSUER: 'issuer', + Token.SERIAL: 'serial', + PushToken.SSL_VERIFY: 'False', + PushToken.ENROLLMENT_CREDENTIAL: 'enrollmentCredentials', + PushToken.ROLLOUT_URL: 'http://www.example.com', + PushToken.TTL_MINUTES: '10', + PushToken.VERSION: '1', }; final token = PushToken.fromOtpAuthMap(uriMap); expect(token.type, 'PIPUSH'); diff --git a/test/unit_test/model/token/steam_token_test.dart b/test/unit_test/model/token/steam_token_test.dart index f682fc0fb..f95431122 100644 --- a/test/unit_test/model/token/steam_token_test.dart +++ b/test/unit_test/model/token/steam_token_test.dart @@ -4,9 +4,10 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:privacyidea_authenticator/model/enums/algorithms.dart'; import 'package:privacyidea_authenticator/model/enums/encodings.dart'; import 'package:privacyidea_authenticator/model/extensions/enums/encodings_extension.dart'; +import 'package:privacyidea_authenticator/model/tokens/otp_token.dart'; import 'package:privacyidea_authenticator/model/tokens/steam_token.dart'; +import 'package:privacyidea_authenticator/model/tokens/token.dart'; import 'package:privacyidea_authenticator/model/tokens/totp_token.dart'; -import 'package:privacyidea_authenticator/utils/identifiers.dart'; void main() { _testSteamToken(); @@ -73,12 +74,12 @@ void _testSteamToken() { group('fromUriMap', () { test('with full map', () { final uriMap = { - OTP_AUTH_LABEL: 'label', - OTP_AUTH_ISSUER: 'issuer', - OTP_AUTH_SECRET_BASE32: Encodings.base32.encode(utf8.encode('secret')), - OTP_AUTH_TYPE: 'totp', - OTP_AUTH_PIN: 'False', - OTP_AUTH_IMAGE: 'example.png', + Token.LABEL: 'label', + Token.ISSUER: 'issuer', + Token.TYPE: 'totp', + Token.PIN: Token.PIN_VALUE_FALSE, + Token.IMAGE: 'example.png', + OTPToken.SECRET_BASE32: Encodings.base32.encode(utf8.encode('secret')), }; final totpFromUriMap = SteamToken.fromOtpAuthMap(uriMap); expect(totpFromUriMap.period, 30); @@ -93,11 +94,11 @@ void _testSteamToken() { }); test('with missing secret', () { final uriMap = { - OTP_AUTH_LABEL: 'label', - OTP_AUTH_ISSUER: 'issuer', - OTP_AUTH_TYPE: 'totp', - OTP_AUTH_PIN: 'False', - OTP_AUTH_IMAGE: 'example.png', + Token.LABEL: 'label', + Token.ISSUER: 'issuer', + Token.TYPE: 'totp', + Token.PIN: Token.PIN_VALUE_FALSE, + Token.IMAGE: 'example.png', }; expect(() => SteamToken.fromOtpAuthMap(uriMap), throwsA(isA())); }); diff --git a/test/unit_test/model/token/totp_token_test.dart b/test/unit_test/model/token/totp_token_test.dart index d52c368e6..74619e305 100644 --- a/test/unit_test/model/token/totp_token_test.dart +++ b/test/unit_test/model/token/totp_token_test.dart @@ -6,8 +6,9 @@ import 'package:privacyidea_authenticator/model/enums/algorithms.dart'; import 'package:privacyidea_authenticator/model/enums/encodings.dart'; import 'package:privacyidea_authenticator/model/extensions/enums/encodings_extension.dart'; import 'package:privacyidea_authenticator/model/tokens/hotp_token.dart'; +import 'package:privacyidea_authenticator/model/tokens/otp_token.dart'; +import 'package:privacyidea_authenticator/model/tokens/token.dart'; import 'package:privacyidea_authenticator/model/tokens/totp_token.dart'; -import 'package:privacyidea_authenticator/utils/identifiers.dart'; void main() { _testTotpToken(); @@ -76,15 +77,15 @@ void _testTotpToken() { group('fromUriMap', () { test('with full map', () { final uriMap = { - OTP_AUTH_PERIOD_SECONDS: '30', - OTP_AUTH_LABEL: 'label', - OTP_AUTH_ISSUER: 'issuer', - OTP_AUTH_ALGORITHM: 'SHA1', - OTP_AUTH_DIGITS: '6', - OTP_AUTH_SECRET_BASE32: Encodings.base32.encode(utf8.encode('secret')), - OTP_AUTH_TYPE: 'totp', - OTP_AUTH_PIN: 'False', - OTP_AUTH_IMAGE: 'example.png', + Token.LABEL: 'label', + Token.ISSUER: 'issuer', + Token.TYPE: 'totp', + Token.PIN: Token.PIN_VALUE_FALSE, + Token.IMAGE: 'example.png', + OTPToken.ALGORITHM: 'SHA1', + OTPToken.DIGITS: '6', + OTPToken.SECRET_BASE32: Encodings.base32.encode(utf8.encode('secret')), + TOTPToken.PERIOD_SECONDS: '30', }; final totpFromUriMap = TOTPToken.fromOtpAuthMap(uriMap); expect(totpFromUriMap.period, 30); @@ -99,56 +100,56 @@ void _testTotpToken() { }); test('with missing secret', () { final uriMap = { - OTP_AUTH_PERIOD_SECONDS: 30, - OTP_AUTH_LABEL: 'label', - OTP_AUTH_ISSUER: 'issuer', - OTP_AUTH_ALGORITHM: 'SHA1', - OTP_AUTH_DIGITS: 6, - OTP_AUTH_TYPE: 'totp', - OTP_AUTH_PIN: 'False', - OTP_AUTH_IMAGE: 'example.png', + Token.LABEL: 'label', + Token.ISSUER: 'issuer', + Token.TYPE: 'totp', + Token.PIN: Token.PIN_VALUE_FALSE, + Token.IMAGE: 'example.png', + OTPToken.ALGORITHM: 'SHA1', + OTPToken.DIGITS: 6, + TOTPToken.PERIOD_SECONDS: 30, }; expect(() => TOTPToken.fromOtpAuthMap(uriMap), throwsA(isA())); }); test('with zero period', () { final uriMap = { - OTP_AUTH_PERIOD_SECONDS: 0, - OTP_AUTH_LABEL: 'label', - OTP_AUTH_ISSUER: 'issuer', - OTP_AUTH_ALGORITHM: 'SHA1', - OTP_AUTH_DIGITS: 6, - OTP_AUTH_SECRET_BASE32: Uint8List.fromList(utf8.encode('secret')), - OTP_AUTH_TYPE: 'totp', - OTP_AUTH_PIN: 'False', - OTP_AUTH_IMAGE: 'example.png', + Token.LABEL: 'label', + Token.ISSUER: 'issuer', + Token.TYPE: 'totp', + Token.PIN: Token.PIN_VALUE_FALSE, + Token.IMAGE: 'example.png', + OTPToken.ALGORITHM: 'SHA1', + OTPToken.DIGITS: 6, + OTPToken.SECRET_BASE32: Uint8List.fromList(utf8.encode('secret')), + TOTPToken.PERIOD_SECONDS: 0, }; expect(() => TOTPToken.fromOtpAuthMap(uriMap), throwsA(isA())); }); test('with zero digits', () { final uriMap = { - OTP_AUTH_PERIOD_SECONDS: 30, - OTP_AUTH_LABEL: 'label', - OTP_AUTH_ISSUER: 'issuer', - OTP_AUTH_ALGORITHM: 'SHA1', - OTP_AUTH_DIGITS: 0, - OTP_AUTH_SECRET_BASE32: Uint8List.fromList(utf8.encode('secret')), - OTP_AUTH_TYPE: 'totp', - OTP_AUTH_PIN: 'False', - OTP_AUTH_IMAGE: 'example.png', + Token.LABEL: 'label', + Token.ISSUER: 'issuer', + Token.TYPE: 'totp', + Token.PIN: Token.PIN_VALUE_FALSE, + Token.IMAGE: 'example.png', + OTPToken.ALGORITHM: 'SHA1', + OTPToken.DIGITS: 0, + OTPToken.SECRET_BASE32: Uint8List.fromList(utf8.encode('secret')), + TOTPToken.PERIOD_SECONDS: 30, }; expect(() => TOTPToken.fromOtpAuthMap(uriMap), throwsA(isA())); }); test('with lowercase algorithm', () { final uriMap = { - OTP_AUTH_PERIOD_SECONDS: '30', - OTP_AUTH_LABEL: 'label', - OTP_AUTH_ISSUER: 'issuer', - OTP_AUTH_ALGORITHM: 'sha1', - OTP_AUTH_DIGITS: '6', - OTP_AUTH_SECRET_BASE32: Uint8List.fromList(utf8.encode('secret')), - OTP_AUTH_TYPE: 'totp', - OTP_AUTH_PIN: 'False', - OTP_AUTH_IMAGE: 'example.png', + Token.LABEL: 'label', + Token.ISSUER: 'issuer', + Token.TYPE: 'totp', + Token.PIN: Token.PIN_VALUE_FALSE, + Token.IMAGE: 'example.png', + OTPToken.ALGORITHM: 'sha1', + OTPToken.DIGITS: '6', + OTPToken.SECRET_BASE32: Uint8List.fromList(utf8.encode('secret')), + TOTPToken.PERIOD_SECONDS: '30', }; final totpFromUriMap = TOTPToken.fromOtpAuthMap(uriMap); expect(totpFromUriMap.algorithm, Algorithms.SHA1); diff --git a/test/unit_test/processors/scheme_processors/token_container_scheme_processor_test.dart b/test/unit_test/processors/scheme_processors/token_container_scheme_processor_test.dart new file mode 100644 index 000000000..9bbb0e0de --- /dev/null +++ b/test/unit_test/processors/scheme_processors/token_container_scheme_processor_test.dart @@ -0,0 +1,68 @@ +/* + * privacyIDEA Authenticator + * + * Author: Frank Merkel + * + * Copyright (c) 2024 NetKnights GmbH + * + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import 'package:flutter_test/flutter_test.dart'; +import 'package:privacyidea_authenticator/model/enums/algorithms.dart'; +import 'package:privacyidea_authenticator/model/enums/ec_key_algorithm.dart'; +import 'package:privacyidea_authenticator/model/token_container.dart'; +import 'package:privacyidea_authenticator/processors/scheme_processors/token_container_processor.dart'; + +final processor = TokenContainerProcessor(); + +void main() { + _testTokenContainerProcessor(); +} + +void _testTokenContainerProcessor() { + test('TokenContainerProcessor', () { + group('processUri', () { + test('valid uri', () async { + final uriString = "pia://container/SMPH00067A2F" + "?issuer=privacyIDEA" + "&ttl=10" + "&nonce=b33d3a11c8d1b45f19640035e27944ccf0b2383d" + "&time=2024-12-06T11%3A14%3A26.885409%2B00%3A00" + "&url=http://192.168.0.230:5000/" + "&serial=SMPH00067A2F" + "&key_algorithm=secp384r1" + "&hash_algorithm=SHA256" + "&ssl_verify=False" + "&passphrase=Enter%20your%20password"; + final uri = Uri.parse(uriString); + final result = await processor.processUri(uri); + expect(result?.length, 1); + expect(result![0].isSuccess, true); + expect(result[0].asSuccess, isNotNull); + final container = result[0].asSuccess!.resultData; + expect(container, isA()); + expect(container.issuer, "privacyIDEA"); + expect((container as TokenContainerUnfinalized).ttl, Duration(minutes: 10)); + expect(container.nonce, "b33d3a11c8d1b45f19640035e27944ccf0b2383d"); + expect(container.timestamp, DateTime.parse("2024-12-06T11:14:26.885409+00:00")); + expect(container.serverUrl, Uri.parse("http://192.168.0.230:5000/")); + expect(container.serial, "SMPH00067A2F"); + expect(container.ecKeyAlgorithm, EcKeyAlgorithm.secp384r1); + expect(container.hashAlgorithm, Algorithms.SHA256); + expect(container.sslVerify, false); + expect(container.passphraseQuestion, ""); + }); + }); + }); +} diff --git a/test/unit_test/processors/scheme_processors/token_import_scheme_processors/free_otp_plus_qr_processor_test.dart b/test/unit_test/processors/scheme_processors/token_import_scheme_processors/free_otp_plus_qr_processor_test.dart index 9c989e11c..f702c9c93 100644 --- a/test/unit_test/processors/scheme_processors/token_import_scheme_processors/free_otp_plus_qr_processor_test.dart +++ b/test/unit_test/processors/scheme_processors/token_import_scheme_processors/free_otp_plus_qr_processor_test.dart @@ -49,7 +49,7 @@ void _testFreeOtpPlusQrProcessor() { expect(result0, isA>()); final message = result0.asFailed!.message; final error = result0.asFailed!.error; - expect(message.toLowerCase().contains(OTP_AUTH_COUNTER) || error.toString().toLowerCase().contains(OTP_AUTH_COUNTER), isTrue); + expect(message.toLowerCase().contains(HOTPToken.COUNTER) || error.toString().toLowerCase().contains(HOTPToken.COUNTER), isTrue); }); }); } diff --git a/test/unit_test/processors/scheme_processors/token_import_scheme_processors/otp_auth_processor_test.dart b/test/unit_test/processors/scheme_processors/token_import_scheme_processors/otp_auth_processor_test.dart index 47bdd5f17..757dfb891 100644 --- a/test/unit_test/processors/scheme_processors/token_import_scheme_processors/otp_auth_processor_test.dart +++ b/test/unit_test/processors/scheme_processors/token_import_scheme_processors/otp_auth_processor_test.dart @@ -2,11 +2,11 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:privacyidea_authenticator/model/processor_result.dart'; import 'package:privacyidea_authenticator/model/tokens/day_password_token.dart'; import 'package:privacyidea_authenticator/model/tokens/hotp_token.dart'; +import 'package:privacyidea_authenticator/model/tokens/otp_token.dart'; import 'package:privacyidea_authenticator/model/tokens/push_token.dart'; import 'package:privacyidea_authenticator/model/tokens/totp_token.dart'; import 'package:privacyidea_authenticator/processors/scheme_processors/token_import_scheme_processors/otp_auth_processor.dart'; import 'package:privacyidea_authenticator/utils/customization/application_customization.dart'; -import 'package:privacyidea_authenticator/utils/identifiers.dart'; void main() { _testOtpAuthProcessor(); @@ -238,7 +238,7 @@ void _testOtpAuthProcessor() { expect(result0, isA()); final message = result0.asFailed!.message; final error = result0.asFailed!.error; - expect(message.toLowerCase().contains(OTP_AUTH_COUNTER) || error.toString().toLowerCase().contains(OTP_AUTH_COUNTER), isTrue); + expect(message.toLowerCase().contains(HOTPToken.COUNTER) || error.toString().toLowerCase().contains(HOTPToken.COUNTER), isTrue); }); test('processUri missing secret', () async { // Arrange @@ -253,7 +253,7 @@ void _testOtpAuthProcessor() { expect(result0, isA()); final message = result0.asFailed!.message; final error = result0.asFailed!.error; - expect(message.toLowerCase().contains(OTP_AUTH_SECRET_BASE32) || error.toString().toLowerCase().contains(OTP_AUTH_SECRET_BASE32), isTrue); + expect(message.toLowerCase().contains(OTPToken.SECRET_BASE32) || error.toString().toLowerCase().contains(OTPToken.SECRET_BASE32), isTrue); }); test('processUri issuer from path', () async { // Arrange diff --git a/test/unit_test/state_notifiers/token_container_notifier_test.dart b/test/unit_test/state_notifiers/token_container_notifier_test.dart index e17add85b..fa402ec73 100644 --- a/test/unit_test/state_notifiers/token_container_notifier_test.dart +++ b/test/unit_test/state_notifiers/token_container_notifier_test.dart @@ -35,6 +35,7 @@ TokenContainerState _buildUnfinalizedContainerState() => TokenContainerState( containerList: [ TokenContainerUnfinalized( issuer: 'issuer', + ttl: Duration(minutes: 10), nonce: 'nonce', timestamp: DateTime.now(), serverUrl: Uri.parse('https://example.com'), @@ -135,6 +136,7 @@ void _testTokenContainerNotifier() { await container.read(tokenContainerProvider.notifier).addContainer( TokenContainerUnfinalized( issuer: 'issuer2', + ttl: Duration(minutes: 10), nonce: 'nonce2', timestamp: DateTime.now().add(const Duration(days: 1)), serverUrl: Uri.parse('https://example.com'), @@ -188,6 +190,7 @@ void _testTokenContainerNotifier() { await container.read(tokenContainerProvider.notifier).addContainerList([ TokenContainerUnfinalized( issuer: 'issuer2', + ttl: Duration(minutes: 10), nonce: 'nonce2', timestamp: DateTime.now().add(const Duration(days: 1)), serverUrl: Uri.parse('https://example.com'), @@ -198,6 +201,7 @@ void _testTokenContainerNotifier() { ), TokenContainerUnfinalized( issuer: 'issuer3', + ttl: Duration(minutes: 10), nonce: 'nonce3', timestamp: DateTime.now().add(const Duration(days: 2)), serverUrl: Uri.parse('https://example.com'), @@ -268,6 +272,7 @@ void _testTokenContainerNotifier() { containerRepoState.containerList.first, TokenContainerUnfinalized( issuer: 'issuer2', + ttl: Duration(minutes: 10), nonce: 'nonce2', timestamp: DateTime.now().add(const Duration(days: 1)), serverUrl: Uri.parse('https://example.com'), @@ -381,6 +386,7 @@ void _testTokenContainerNotifier() { containerRepoState.containerList.first, TokenContainerUnfinalized( issuer: 'issuer2', + ttl: Duration(minutes: 10), nonce: 'nonce2', timestamp: DateTime.now().add(const Duration(days: 1)), serverUrl: Uri.parse('https://example.com'), @@ -391,6 +397,7 @@ void _testTokenContainerNotifier() { ), TokenContainerUnfinalized( issuer: 'issuer3', + ttl: Duration(minutes: 10), nonce: 'nonce3', timestamp: DateTime.now().add(const Duration(days: 2)), serverUrl: Uri.parse('https://example.com'),