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); }); }