add 'algorithm' to OtpAuthUrl

Currently the parameter is not evaluated.
This commit is contained in:
2024-09-09 14:47:22 +02:00
parent d0f5860a44
commit 0f5fd3f561

View File

@@ -76,7 +76,7 @@ const Args = struct {
config_location: []const u8, config_location: []const u8,
}; };
const OtpAuthUrl = struct { name: []const u8, secretEncoded: []const u8, url: []const u8, period: u32, digits: u4 }; const OtpAuthUrl = struct { name: []const u8, secretEncoded: []const u8, url: []const u8, period: u32, digits: u4, algorithm: []const u8 };
const Authenticator = struct { const Authenticator = struct {
url: OtpAuthUrl, url: OtpAuthUrl,
@@ -199,6 +199,7 @@ fn parseOtpAuthUrl(allocator: Allocator, url: []const u8) !OtpAuthUrl {
.url = url, .url = url,
.period = if (params.get("period") != null) try std.fmt.parseInt(u32, params.get("period").?, 10) else 30, .period = if (params.get("period") != null) try std.fmt.parseInt(u32, params.get("period").?, 10) else 30,
.digits = if (params.get("digits") != null) try std.fmt.parseInt(u4, params.get("digits").?, 10) else 6, .digits = if (params.get("digits") != null) try std.fmt.parseInt(u4, params.get("digits").?, 10) else 6,
.algorithm = if (params.get("algorithm") != null) params.get("algorithm").? else "SHA1",
}; };
} }
@@ -373,14 +374,14 @@ test "zero padding" {
} }
test "authenticator generate code with 6 digits" { test "authenticator generate code with 6 digits" {
const authenticator = Authenticator{ .url = OtpAuthUrl{ .name = "TestAuthenticator", .secretEncoded = "HJ5PX4IFQKD37HFNXLJYBAVD5G6NMMUOKUCDXJ4XTLUUBWSXRXEN5SR4MLAZA5M2", .url = "not needed", .period = 30, .digits = 6 } }; const authenticator = Authenticator{ .url = OtpAuthUrl{ .name = "TestAuthenticator", .secretEncoded = "HJ5PX4IFQKD37HFNXLJYBAVD5G6NMMUOKUCDXJ4XTLUUBWSXRXEN5SR4MLAZA5M2", .url = "not needed", .period = 30, .digits = 6, .algorithm = "SHA1" } };
const code = try authenticator.code(std.testing.allocator, _closure_return_1725695340); const code = try authenticator.code(std.testing.allocator, _closure_return_1725695340);
defer std.testing.allocator.free(code); defer std.testing.allocator.free(code);
try std.testing.expectEqualStrings("218139", code); try std.testing.expectEqualStrings("218139", code);
} }
test "authenticator generate code with 10 digits and zero padding" { test "authenticator generate code with 10 digits and zero padding" {
const authenticator = Authenticator{ .url = OtpAuthUrl{ .name = "TestAuthenticator", .secretEncoded = "HJ5PX4IFQKD37HFNXLJYBAVD5G6NMMUOKUCDXJ4XTLUUBWSXRXEN5SR4MLAZA5M2", .url = "not needed", .period = 60, .digits = 10 } }; const authenticator = Authenticator{ .url = OtpAuthUrl{ .name = "TestAuthenticator", .secretEncoded = "HJ5PX4IFQKD37HFNXLJYBAVD5G6NMMUOKUCDXJ4XTLUUBWSXRXEN5SR4MLAZA5M2", .url = "not needed", .period = 60, .digits = 10, .algorithm = "SHA1" } };
const code = try authenticator.code(std.testing.allocator, _closure_return_1725695340); const code = try authenticator.code(std.testing.allocator, _closure_return_1725695340);
defer std.testing.allocator.free(code); defer std.testing.allocator.free(code);
@@ -390,17 +391,17 @@ test "authenticator generate code with 10 digits and zero padding" {
test "testcases from https://www.rfc-editor.org/rfc/rfc6238#appendix-A" { test "testcases from https://www.rfc-editor.org/rfc/rfc6238#appendix-A" {
const secretForSha1 = "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ"; // plain: "12345678901234567890" hex: "3132333435363738393031323334353637383930" 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, .algorithm = "SHA1" }, _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, .algorithm = "SHA1" }, _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, .algorithm = "SHA1" }, _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, .algorithm = "SHA1" }, _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, .algorithm = "SHA1" }, _closure_return_2000000000, "69279037");
try testTOTP(OtpAuthUrl{ .name = "", .secretEncoded = secretForSha1, .url = "", .period = 30, .digits = 8 }, _closure_return_20000000000, "65353130"); try testTOTP(OtpAuthUrl{ .name = "", .secretEncoded = secretForSha1, .url = "", .period = 30, .digits = 8, .algorithm = "SHA1" }, _closure_return_20000000000, "65353130");
} }
fn testTOTP(otpAuthUrl: OtpAuthUrl, timeFunc: *const fn () i64, expected: []const u8) !void { fn testTOTP(otpAuthUrl: OtpAuthUrl, timeFunc: *const fn () i64, expected: []const u8) !void {
@@ -440,26 +441,26 @@ fn _closure_return_20000000000() i64 {
} }
test "secret is not Base32 - invalid padding" { test "secret is not Base32 - invalid padding" {
const authenticator = Authenticator{ .url = OtpAuthUrl{ .name = "", .secretEncoded = "H", .url = "", .period = 60, .digits = 6 } }; const authenticator = Authenticator{ .url = OtpAuthUrl{ .name = "", .secretEncoded = "H", .url = "", .period = 60, .digits = 6, .algorithm = "SHA1" } };
const actualError = authenticator.code(std.testing.allocator, _closure_return_1725695340); const actualError = authenticator.code(std.testing.allocator, _closure_return_1725695340);
try std.testing.expectError(Base32Error.InvalidPadding, actualError); try std.testing.expectError(Base32Error.InvalidPadding, actualError);
} }
test "secret is not Base32 - invalid padding, input has too many bytes" { test "secret is not Base32 - invalid padding, input has too many bytes" {
const authenticator = Authenticator{ .url = OtpAuthUrl{ .name = "", .secretEncoded = "HAX", .url = "", .period = 60, .digits = 6 } }; const authenticator = Authenticator{ .url = OtpAuthUrl{ .name = "", .secretEncoded = "HAX", .url = "", .period = 60, .digits = 6, .algorithm = "SHA1" } };
const actualError = authenticator.code(std.testing.allocator, _closure_return_1725695340); const actualError = authenticator.code(std.testing.allocator, _closure_return_1725695340);
try std.testing.expectError(Base32Error.InvalidPadding, actualError); try std.testing.expectError(Base32Error.InvalidPadding, actualError);
} }
test "secret is not Base32 - invalid padding, trailing bits are not 0" { test "secret is not Base32 - invalid padding, trailing bits are not 0" {
const authenticator = Authenticator{ .url = OtpAuthUrl{ .name = "", .secretEncoded = "HX", .url = "", .period = 60, .digits = 6 } }; const authenticator = Authenticator{ .url = OtpAuthUrl{ .name = "", .secretEncoded = "HX", .url = "", .period = 60, .digits = 6, .algorithm = "SHA1" } };
const actualError = authenticator.code(std.testing.allocator, _closure_return_1725695340); const actualError = authenticator.code(std.testing.allocator, _closure_return_1725695340);
try std.testing.expectError(Base32Error.InvalidPadding, actualError); try std.testing.expectError(Base32Error.InvalidPadding, actualError);
} }
test "secret is not Base32 - invalid character" { test "secret is not Base32 - invalid character" {
const authenticator = Authenticator{ .url = OtpAuthUrl{ .name = "", .secretEncoded = "0", .url = "", .period = 60, .digits = 6 } }; const authenticator = Authenticator{ .url = OtpAuthUrl{ .name = "", .secretEncoded = "0", .url = "", .period = 60, .digits = 6, .algorithm = "SHA1" } };
const actualError = authenticator.code(std.testing.allocator, _closure_return_1725695340); const actualError = authenticator.code(std.testing.allocator, _closure_return_1725695340);
try std.testing.expectError(Base32Error.InvalidCharacter, actualError); try std.testing.expectError(Base32Error.InvalidCharacter, actualError);