Skip to content

Commit

Permalink
test: add a unit test to verify that the ttl is set to -1 (do not exp…
Browse files Browse the repository at this point in the history
…ire) if a ttl is not supplied to otp:put

refactor: rename isOTPValid to isPasscodeValid
  • Loading branch information
gkc committed May 24, 2024
1 parent 8e85f33 commit 0fdd619
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -270,14 +270,14 @@ abstract class AbstractVerbHandler implements VerbHandler {
///
/// Additionally, this function removes the OTP from the keystore to prevent
/// its reuse.
Future<bool> isOTPValid(String? otp) async {
if (otp == null) {
Future<bool> isPasscodeValid(String? passcode) async {
if (passcode == null) {
return false;
}
// 1. Check if user has configured an SPP(Semi-Permanent Pass-code).
// If SPP key is available, check if the otp sent is a valid pass code.
// If yes, return true, else check it is a valid OTP.
String passcodeKey = OtpVerbHandler.passcodeKey(otp, isSpp: true);
String passcodeKey = OtpVerbHandler.passcodeKey(passcode, isSpp: true);
if (!keyStore.isKeyExists(passcodeKey)) {
// if new SPPKey does not exist in keystore, check for SPP data against legacy SPP key
// New SPP key has __otp namespace, legacy key does NOT have any namespace
Expand All @@ -290,7 +290,7 @@ abstract class AbstractVerbHandler implements VerbHandler {
// (which is the actual SPP)
// By comparison, OTPs are stored with the key being ${OTP}.__otp@alice
// i.e. the OTP is part of the key, and the stored data is irrelevant
if (sppAtData?.data?.toLowerCase() == otp.toLowerCase()) {
if (sppAtData?.data?.toLowerCase() == passcode.toLowerCase()) {
if (SecondaryUtil.isActiveKey(sppAtData)) {
return true;
} else {
Expand All @@ -303,12 +303,12 @@ abstract class AbstractVerbHandler implements VerbHandler {
}

// 2. If not a valid SPP, then check against OTP keys
String otpKey = OtpVerbHandler.passcodeKey(otp, isSpp: false);
String otpKey = OtpVerbHandler.passcodeKey(passcode, isSpp: false);
if (!keyStore.isKeyExists(otpKey)) {
// if new OTPKey does not exist in keystore, check for OTP data against legacy OTPKey
// New OTP key has __otp namespace, legacy key does not have namespace
otpKey =
'private:${otp.toLowerCase()}${AtSecondaryServerImpl.getInstance().currentAtSign}';
'private:${passcode.toLowerCase()}${AtSecondaryServerImpl.getInstance().currentAtSign}';
}

AtData? otpAtData;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ class EnrollVerbHandler extends AbstractVerbHandler {
// OTP is sent only in enrollment request which is submitted on
// unauthenticated connection.
if (atConnection.metaData.isAuthenticated == false) {
var isValid = await isOTPValid(enrollParams.otp);
var isValid = await isPasscodeValid(enrollParams.otp);
if (!isValid) {
_lastInvalidOtpReceivedInMills =
DateTime.now().toUtc().millisecondsSinceEpoch;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class TestUpdateVerbHandler extends AbstractVerbHandler {
}

@override
Future<bool> isOTPValid(String? otp) {
Future<bool> isPasscodeValid(String? otp) {
// TODO: implement isOTPValid
throw UnimplementedError();
}
Expand Down
2 changes: 1 addition & 1 deletion packages/at_secondary_server/test/enroll_verb_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ void main() {
response, enrollmentRequestVerbParams, inboundConnection);
String enrollmentId = jsonDecode(response.data!)['enrollmentId'];
expect(enrollmentId, isNotNull);
expect(await enrollVerbHandler.isOTPValid(otp), false);
expect(await enrollVerbHandler.isPasscodeValid(otp), false);
});
tearDown(() async => await verbTestsTearDown());
});
Expand Down
55 changes: 37 additions & 18 deletions packages/at_secondary_server/test/otp_verb_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ void main() {
OtpVerbHandler otpVerbHandler = OtpVerbHandler(secondaryKeyStore);
await otpVerbHandler.processVerb(response, verbParams, inboundConnection);
String? otp = response.data;
expect(await otpVerbHandler.isOTPValid(otp), true);
expect(await otpVerbHandler.isPasscodeValid(otp), true);
});

test('A test to verify otp:get with TTL set expires after the TTL is met',
Expand All @@ -103,7 +103,7 @@ void main() {
await otpVerbHandler.processVerb(response, verbParams, inboundConnection);
String? otp = response.data;
await Future.delayed(Duration(seconds: 1));
expect(await otpVerbHandler.isOTPValid(otp), false);
expect(await otpVerbHandler.isPasscodeValid(otp), false);
});
tearDown(() async => await verbTestsTearDown());
});
Expand Down Expand Up @@ -142,7 +142,7 @@ void main() {
inboundConnection.metaData.isAuthenticated = true;
OtpVerbHandler otpVerbHandler = OtpVerbHandler(secondaryKeyStore);
await otpVerbHandler.processVerb(response, verbParams, inboundConnection);
expect(await otpVerbHandler.isOTPValid(response.data), true);
expect(await otpVerbHandler.isPasscodeValid(response.data), true);
});

test('A test to verify otp:validate returns invalid when OTP is expired',
Expand All @@ -155,7 +155,7 @@ void main() {
await otpVerbHandler.processVerb(response, verbParams, inboundConnection);
String? otp = response.data;
await Future.delayed(Duration(milliseconds: 2));
expect(await otpVerbHandler.isOTPValid(otp), false);
expect(await otpVerbHandler.isPasscodeValid(otp), false);
});

test('A test to verify default otp expiry not overwritten', () async {
Expand Down Expand Up @@ -183,7 +183,7 @@ void main() {
() async {
String otp = 'ABC123';
OtpVerbHandler otpVerbHandler = OtpVerbHandler(secondaryKeyStore);
expect(await otpVerbHandler.isOTPValid(otp), false);
expect(await otpVerbHandler.isPasscodeValid(otp), false);
});

test('A test to verify otp is removed from the keystore after use',
Expand All @@ -195,8 +195,8 @@ void main() {
OtpVerbHandler otpVerbHandler = OtpVerbHandler(secondaryKeyStore);
await otpVerbHandler.processVerb(response, verbParams, inboundConnection);
String? otp = response.data;
expect(await otpVerbHandler.isOTPValid(otp), true);
expect(await otpVerbHandler.isOTPValid(otp), false);
expect(await otpVerbHandler.isPasscodeValid(otp), true);
expect(await otpVerbHandler.isPasscodeValid(otp), false);
});

test('validate backwards compatability with legacy otp key', () async {
Expand All @@ -210,7 +210,7 @@ void main() {
await secondaryKeyStore.put(otpLegacyKey, value);

OtpVerbHandler otpVerbHandler = OtpVerbHandler(secondaryKeyStore);
expect(await otpVerbHandler.isOTPValid(testOtp), true);
expect(await otpVerbHandler.isPasscodeValid(testOtp), true);
});
tearDown(() async => await verbTestsTearDown());
});
Expand Down Expand Up @@ -240,10 +240,10 @@ void main() {
enrollmentId;
OtpVerbHandler otpVerbHandler = OtpVerbHandler(secondaryKeyStore);
await otpVerbHandler.processVerb(response, verbParams, inboundConnection);
expect(await otpVerbHandler.isOTPValid(passcode), true);
expect(await otpVerbHandler.isPasscodeValid(passcode), true);
// Adding expect again to ensure the Semi-permanent passcodes are not deleted
// after one time use.
expect(await otpVerbHandler.isOTPValid(passcode), true);
expect(await otpVerbHandler.isPasscodeValid(passcode), true);
});

test('set spp with a ttl, check isOTPValid before ttl expires', () async {
Expand All @@ -256,10 +256,11 @@ void main() {
enrollmentId;
OtpVerbHandler otpVerbHandler = OtpVerbHandler(secondaryKeyStore);
await otpVerbHandler.processVerb(response, verbParams, inboundConnection);
expect(await otpVerbHandler.isOTPValid(passcode), true);
expect(await otpVerbHandler.isPasscodeValid(passcode), true);
// Adding expect again to ensure the Semi-permanent passcodes are not deleted
// after one time use.
expect(await otpVerbHandler.isOTPValid(passcode), true);
await Future.delayed(Duration(milliseconds: 10));
expect(await otpVerbHandler.isPasscodeValid(passcode), true);
});

test('set spp with a ttl, check isOTPValid before and after ttl expires',
Expand All @@ -273,13 +274,31 @@ void main() {
enrollmentId;
OtpVerbHandler otpVerbHandler = OtpVerbHandler(secondaryKeyStore);
await otpVerbHandler.processVerb(response, verbParams, inboundConnection);
expect(await otpVerbHandler.isOTPValid(passcode), true);
expect(await otpVerbHandler.isPasscodeValid(passcode), true);
// Adding expect again to ensure the Semi-permanent passcodes are not deleted
// after one time use.
expect(await otpVerbHandler.isOTPValid(passcode), true);
expect(await otpVerbHandler.isPasscodeValid(passcode), true);

await Future.delayed(Duration(milliseconds: 51));
expect(await otpVerbHandler.isOTPValid(passcode), false);
expect(await otpVerbHandler.isPasscodeValid(passcode), false);
});

test('set spp without a ttl, verify its ttl has been set to -1', () async {
String passcode = 'SppWithoutTtl';
Response response = Response();
HashMap<String, String?> verbParams =
getVerbParam(VerbSyntax.otp, 'otp:put:$passcode');
inboundConnection.metaData.isAuthenticated = true;
(inboundConnection.metaData as InboundConnectionMetadata).enrollmentId =
enrollmentId;
OtpVerbHandler otpVerbHandler = OtpVerbHandler(secondaryKeyStore);
await otpVerbHandler.processVerb(response, verbParams, inboundConnection);
await Future.delayed(Duration(milliseconds: 2));
expect(await otpVerbHandler.isPasscodeValid(passcode), true);

String sppKey = OtpVerbHandler.passcodeKey(passcode, isSpp: true);
var atData = await secondaryKeyStore.get(sppKey);
expect(atData?.metaData?.ttl, -1);
});

test('A test to verify pass code can be updated', () async {
Expand All @@ -292,14 +311,14 @@ void main() {
enrollmentId;
OtpVerbHandler otpVerbHandler = OtpVerbHandler(secondaryKeyStore);
await otpVerbHandler.processVerb(response, verbParams, inboundConnection);
expect(await otpVerbHandler.isOTPValid(passcode), true);
expect(await otpVerbHandler.isPasscodeValid(passcode), true);
// Update the pass-code
passcode = 'xyz987';
response = Response();
verbParams = getVerbParam(VerbSyntax.otp, 'otp:put:$passcode');
otpVerbHandler = OtpVerbHandler(secondaryKeyStore);
await otpVerbHandler.processVerb(response, verbParams, inboundConnection);
expect(await otpVerbHandler.isOTPValid(passcode), true);
expect(await otpVerbHandler.isPasscodeValid(passcode), true);
});

test('validate backwards compatability with legacy ssp key', () async {
Expand All @@ -310,7 +329,7 @@ void main() {
await secondaryKeyStore.put(otpLegacyKey, value);

OtpVerbHandler otpVerbHandler = OtpVerbHandler(secondaryKeyStore);
expect(await otpVerbHandler.isOTPValid(testOtp), true);
expect(await otpVerbHandler.isPasscodeValid(testOtp), true);
});
tearDown(() async => await verbTestsTearDown());
});
Expand Down

0 comments on commit 0fdd619

Please sign in to comment.