|
|
@@ -0,0 +1,113 @@
|
|
|
+import 'package:test/test.dart';
|
|
|
+import 'package:pb_authenticator_totp/totp.dart';
|
|
|
+import 'package:pb_authenticator_totp/totp_algorithm.dart';
|
|
|
+import 'package:pb_authenticator_totp/otp_uri.dart';
|
|
|
+
|
|
|
+void main() {
|
|
|
+ // https://datatracker.ietf.org/doc/html/rfc4648#section-10
|
|
|
+ // https://stackoverflow.com/a/54263961
|
|
|
+ test('Base32', () {
|
|
|
+ expect(Base32.decode("MY======"), "f".codeUnits);
|
|
|
+ expect(Base32.decode("MZXQ===="), "fo".codeUnits);
|
|
|
+ expect(Base32.decode("MZXW6==="), "foo".codeUnits);
|
|
|
+ expect(Base32.decode("MZXW6YQ="), "foob".codeUnits);
|
|
|
+ expect(Base32.decode("MZXW6YTB"), "fooba".codeUnits);
|
|
|
+ expect(Base32.decode("MZXW6YTBOI======"), "foobar".codeUnits);
|
|
|
+ expect(Base32.isBase32("MZXW6YTBOI======"), true);
|
|
|
+ expect(Base32.decode("AE======"), "\x01".codeUnits);
|
|
|
+ expect(Base32.decode("AA======"), "\x00".codeUnits);
|
|
|
+ });
|
|
|
+
|
|
|
+ test('TOTP - Key URI 1', () {
|
|
|
+ var parsed = OtpUri.fromUri(
|
|
|
+ "otpauth://totp/Example:alice@example.com?secret=JBSWY3DPEHPK3PXP&issuer=Example");
|
|
|
+ expect(parsed.accountName, "alice@example.com");
|
|
|
+ expect(parsed.algorithm, OtpHashAlgorithm.sha1);
|
|
|
+ expect(parsed.digits, 6);
|
|
|
+ expect(parsed.issuer, "Example");
|
|
|
+ expect(parsed.period, 30);
|
|
|
+ expect(parsed.secret, "JBSWY3DPEHPK3PXP");
|
|
|
+ });
|
|
|
+
|
|
|
+ test('TOTP - Key URI Complete', () {
|
|
|
+ var parsed = OtpUri.fromUri(
|
|
|
+ "otpauth://totp/ACME%20Co:john.doe@email.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30");
|
|
|
+ expect(parsed.accountName, "john.doe@email.com");
|
|
|
+ expect(parsed.algorithm, OtpHashAlgorithm.sha1);
|
|
|
+ expect(parsed.digits, 6);
|
|
|
+ expect(parsed.issuer, "ACME Co");
|
|
|
+ expect(parsed.period, 30);
|
|
|
+ expect(parsed.secret, "HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ");
|
|
|
+ });
|
|
|
+
|
|
|
+ test('TOTP - Bad Key URI', () {
|
|
|
+ expect(
|
|
|
+ () => OtpUri.fromUri(
|
|
|
+ "otpauth://totp/Example:alice@example.com?secret=JBSWY3DPEHPK3PXP&issuer=Example&digits=12"),
|
|
|
+ throwsA(allOf(
|
|
|
+ isFormatException,
|
|
|
+ predicate((e) =>
|
|
|
+ e is FormatException && e.message == "Incorrect parameters"))));
|
|
|
+ });
|
|
|
+
|
|
|
+ test('TOTP - Bad Algorithm', () {
|
|
|
+ expect(
|
|
|
+ () => OtpUri.fromUri(
|
|
|
+ "otpauth://totp/Example:alice@example.com?secret=JBSWY3DPEHPK3PXP&issuer=Example&digits=12&algorithm=sha??"),
|
|
|
+ throwsA(allOf(
|
|
|
+ isFormatException,
|
|
|
+ predicate((e) =>
|
|
|
+ e is FormatException &&
|
|
|
+ e.message == "Unrecognised algorithm"))));
|
|
|
+ });
|
|
|
+
|
|
|
+ test('TOTP - 1542791843', () {
|
|
|
+ expect(Totp.generateCode(1542791843, "JBSWY3DPEHPK3PXP"), "092264");
|
|
|
+ });
|
|
|
+
|
|
|
+ test('TOTP - 59', () {
|
|
|
+ expect(Totp.generateCode(59, "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ", 8),
|
|
|
+ "94287082");
|
|
|
+ });
|
|
|
+
|
|
|
+ test('TOTP - 20000000000', () {
|
|
|
+ expect(
|
|
|
+ Totp.generateCode(20000000000, "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ", 8),
|
|
|
+ "65353130");
|
|
|
+ });
|
|
|
+
|
|
|
+ test('TOTP - Multiple', () {
|
|
|
+ expect(
|
|
|
+ Totp.generateCodes(
|
|
|
+ [59, 20000000000], "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ", 8),
|
|
|
+ ["94287082", "65353130"]);
|
|
|
+ });
|
|
|
+
|
|
|
+ test('TOTP Item attributes', () {
|
|
|
+ var secret = "A";
|
|
|
+ var digits = 8;
|
|
|
+ var period = 60;
|
|
|
+ var algorithm = OtpHashAlgorithm.sha256;
|
|
|
+ var issuer = "bar";
|
|
|
+ var accountName = "foo@bar";
|
|
|
+ var item = TotpItem(secret, digits, period, algorithm, issuer, accountName);
|
|
|
+ expect(item.secret, secret);
|
|
|
+ expect(item.digits, digits);
|
|
|
+ expect(item.period, period);
|
|
|
+ expect(item.algorithm, algorithm);
|
|
|
+ expect(item.issuer, issuer);
|
|
|
+ expect(item.accountName, accountName);
|
|
|
+ });
|
|
|
+
|
|
|
+ test('TOTP Item equality', () {
|
|
|
+ var item1 = TotpItem("A");
|
|
|
+ var item2 = TotpItem("A");
|
|
|
+ var item3 = TotpItem("B");
|
|
|
+ // Same object
|
|
|
+ expect(item1 == item1, true);
|
|
|
+ // Same secret (and other fields apart from id), so still equal
|
|
|
+ expect(item1 == item2, true);
|
|
|
+ // Secret changed
|
|
|
+ expect(item1 == item3, false);
|
|
|
+ });
|
|
|
+}
|