diff --git a/src/main.zig b/src/main.zig index 9a3b622..e1b5cdf 100644 --- a/src/main.zig +++ b/src/main.zig @@ -62,6 +62,7 @@ const OtpAuthUrl = struct { name: []const u8, secretEncoded: []const u8, url: [] const Authenticator = struct { url: OtpAuthUrl, + /// algorithm based on https://www.rfc-editor.org/rfc/rfc6238 pub fn code(self: Authenticator, allocator: Allocator, timeFunc: *const fn () i64) ![]const u8 { if (self.url.name.len > 0) {} @@ -331,6 +332,54 @@ test "authenticator generate code with 10 digits and zero padding" { try std.testing.expectEqualStrings("0844221464", code); } +test "testcases from https://www.rfc-editor.org/rfc/rfc6238#appendix-A" { + const secretForSha1 = "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ"; // plain: "12345678901234567890" hex: "3132333435363738393031323334353637383930" + + try testTOTP(OtpAuthUrl{ .name = "", .secretEncoded = secretForSha1, .url = "", .period = 30, .digits = 8 }, _closure_return_59, "94287082"); + + try testTOTP(OtpAuthUrl{ .name = "", .secretEncoded = secretForSha1, .url = "", .period = 30, .digits = 8 }, _closure_return_1111111109, "07081804"); + + try testTOTP(OtpAuthUrl{ .name = "", .secretEncoded = secretForSha1, .url = "", .period = 30, .digits = 8 }, _closure_return_1111111111, "14050471"); + + try testTOTP(OtpAuthUrl{ .name = "", .secretEncoded = secretForSha1, .url = "", .period = 30, .digits = 8 }, _closure_return_1234567890, "89005924"); + + try testTOTP(OtpAuthUrl{ .name = "", .secretEncoded = secretForSha1, .url = "", .period = 30, .digits = 8 }, _closure_return_2000000000, "69279037"); + + try testTOTP(OtpAuthUrl{ .name = "", .secretEncoded = secretForSha1, .url = "", .period = 30, .digits = 8 }, _closure_return_20000000000, "65353130"); +} + +fn testTOTP(otpAuthUrl: OtpAuthUrl, timeFunc: *const fn () i64, expected: []const u8) !void { + const authenticator = Authenticator{ .url = otpAuthUrl }; + + const code = try authenticator.code(std.testing.allocator, timeFunc); + defer std.testing.allocator.free(code); + try std.testing.expectEqualStrings(expected, code); +} + fn _closure_return_1725695340() i64 { return 1725695340; } + +fn _closure_return_59() i64 { + return 59; +} + +fn _closure_return_1111111109() i64 { + return 1111111109; +} + +fn _closure_return_1111111111() i64 { + return 1111111111; +} + +fn _closure_return_1234567890() i64 { + return 1234567890; +} + +fn _closure_return_2000000000() i64 { + return 2000000000; +} + +fn _closure_return_20000000000() i64 { + return 20000000000; +}