Skip to content

Commit

Permalink
Moved the constant_identifiers to the corresponding token class.
Browse files Browse the repository at this point in the history
  • Loading branch information
frankmer committed Dec 6, 2024
1 parent 83d2d91 commit 1dd5861
Show file tree
Hide file tree
Showing 49 changed files with 882 additions and 813 deletions.
3 changes: 3 additions & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
analyzer:
errors:
constant_identifier_names: ignore
include: package:flutter_lints/flutter.yaml

linter:
Expand Down
18 changes: 9 additions & 9 deletions lib/api/impl/privacy_idea_container_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -225,7 +225,7 @@ class PiContainerApi implements TokenContainerApi {

Future<ContainerChallenge> _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) {
Expand Down Expand Up @@ -264,7 +264,7 @@ class PiContainerApi implements TokenContainerApi {
final body = <String, String>{
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);
Expand Down Expand Up @@ -358,7 +358,7 @@ class PiContainerApi implements TokenContainerApi {
final deleteSerials = <String>[];
final mergedTemplatesWithSerial = <TokenTemplate>[];
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!);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// ignore_for_file: constant_identifier_names

/*
* privacyIDEA Authenticator
*
Expand Down Expand Up @@ -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;
Expand All @@ -68,16 +72,16 @@ class ContainerChallenge extends PiServerResultValue {
final map = validateMap(
map: json,
validators: {
CONTAINER_CHAL_KEY_ALGORITHM: const ObjectValidator<String>(),
CONTAINER_CHAL_NONCE: const ObjectValidator<String>(),
CONTAINER_CHAL_TIMESTAMP: const ObjectValidator<String>(),
KEY_ALGORITHM: const ObjectValidator<String>(),
NONCE: const ObjectValidator<String>(),
TIMESTAMP: const ObjectValidator<String>(),
},
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,
);
}
}
Expand Down
6 changes: 1 addition & 5 deletions lib/model/container_policies.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// ignore_for_file: constant_identifier_names

/*
* privacyIDEA Authenticator
*
Expand Down Expand Up @@ -71,9 +69,7 @@ class ContainerPolicies with _$ContainerPolicies {
}
/**
*
* // ignore_for_file: constant_identifier_names
/*
* /*
* privacyIDEA Authenticator
*
* Author: Frank Merkel <[email protected]>
Expand Down
1 change: 0 additions & 1 deletion lib/model/enums/algorithms.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 0 additions & 1 deletion lib/model/enums/day_password_token_view_mode.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 0 additions & 2 deletions lib/model/enums/ec_key_algorithm.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// ignore_for_file: constant_identifier_names

/*
* privacyIDEA Authenticator
*
Expand Down
1 change: 0 additions & 1 deletion lib/model/enums/token_types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 0 additions & 2 deletions lib/model/exception_errors/pi_server_result_error.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// ignore_for_file: constant_identifier_names

/*
* privacyIDEA Authenticator
*
Expand Down
2 changes: 0 additions & 2 deletions lib/model/mixins/sortable_mixin.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// ignore_for_file: constant_identifier_names

/*
* privacyIDEA Authenticator
*
Expand Down
2 changes: 0 additions & 2 deletions lib/model/pi_server_response.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// ignore_for_file: constant_identifier_names

/*
* privacyIDEA Authenticator
*
Expand Down
63 changes: 36 additions & 27 deletions lib/model/push_request.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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;
Expand Down Expand Up @@ -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<String, dynamic> 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<String> or null.');
if (data[ANSWERS] is! String?) {
throw ArgumentError('Push request answers is ${data[ANSWERS].runtimeType}. Expected List<String> or null.');
}
Logger.debug('Push request data ($data) is valid.');
}
Expand Down
82 changes: 49 additions & 33 deletions lib/model/token_container.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// ignore_for_file: constant_identifier_names

/*
* privacyIDEA Authenticator
*
Expand All @@ -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';
Expand All @@ -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._();
Expand All @@ -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<String, dynamic> uriMap) {
uriMap = validateMap(
map: uriMap,
validators: {
CONTAINER_ISSUER: const ObjectValidator<String>(),
CONTAINER_NONCE: const ObjectValidator<String>(),
CONTAINER_TIMESTAMP: ObjectValidator<DateTime>(transformer: (v) => DateTime.parse(v)),
CONTAINER_FINALIZATION_URL: stringToUrivalidator,
CONTAINER_SERIAL: const ObjectValidator<String>(),
CONTAINER_EC_KEY_ALGORITHM: ObjectValidator<EcKeyAlgorithm>(transformer: (v) => EcKeyAlgorithm.values.byCurveName(v)),
CONTAINER_HASH_ALGORITHM: stringToAlgorithmsValidator,
CONTAINER_PASSPHRASE_QUESTION: const ObjectValidatorNullable<String>(),
CONTAINER_SSL_VERIFY: boolValidator,
CONTAINER_POLICIES: ObjectValidatorNullable<ContainerPolicies>(transformer: (value) => ContainerPolicies.fromUriMap(value)),
ISSUER: const ObjectValidator<String>(),
TTL: ObjectValidator<Duration>(transformer: (value) => Duration(minutes: value)),
NONCE: const ObjectValidator<String>(),
TIMESTAMP: ObjectValidator<DateTime>(transformer: (v) => DateTime.parse(v)),
FINALIZATION_URL: stringToUrivalidator,
SERIAL: const ObjectValidator<String>(),
EC_KEY_ALGORITHM: ObjectValidator<EcKeyAlgorithm>(transformer: (v) => EcKeyAlgorithm.values.byCurveName(v)),
HASH_ALGORITHM: stringToAlgorithmsValidator,
PASSPHRASE_QUESTION: const ObjectValidatorNullable<String>(),
SSL_VERIFY: boolValidator,
POLICIES: ObjectValidatorNullable<ContainerPolicies>(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,
Expand Down
Loading

0 comments on commit 1dd5861

Please sign in to comment.