| ... | ... | @@ -1,6 +1,7 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const extras = @import("extras"); |
| 3 | 3 | const url = @import("url"); |
| 4 | const nio = @import("nio"); |
| 4 | 5 | |
| 5 | 6 | pub fn totp(digits: comptime_int, Hash: type, epoch: u64, X: u64, K: *const [Hash.digest_length]u8, time_now_s: u64) [digits]u8 { |
| 6 | 7 | const T = (time_now_s - epoch) / X; |
| ... | ... | @@ -56,32 +57,32 @@ pub fn generateUrl(allocator: std.mem.Allocator, issuer: []const u8, account: [] |
| 56 | 57 | std.debug.assert(secret_raw.len <= algo.digest_length()); |
| 57 | 58 | std.debug.assert(digits == 6 or digits == 7 or digits == 8); |
| 58 | 59 | std.debug.assert(period == 15 or period == 30 or period == 60); |
| 59 | | var list: std.array_list.Managed(u8) = .init(allocator); |
| 60 | var list: nio.AllocatingWriter = .init(allocator); |
| 60 | 61 | errdefer list.deinit(); |
| 61 | | try list.appendSlice("otpauth://"); |
| 62 | | try list.appendSlice("totp/"); |
| 62 | try list.writeAll("otpauth://"); |
| 63 | try list.writeAll("totp/"); |
| 63 | 64 | try url.percentEncodeAL(&list, issuer, url.is_path_percent_char); |
| 64 | | try list.append(':'); |
| 65 | try list.writeAll(":"); |
| 65 | 66 | try url.percentEncodeAL(&list, account, url.is_path_percent_char); |
| 66 | | try list.appendSlice("?secret="); |
| 67 | try list.writeAll("?secret="); |
| 67 | 68 | try encodeBase32(&list, secret_raw); |
| 68 | | try list.appendSlice("&algorithm="); |
| 69 | | try list.appendSlice(@tagName(algo)); |
| 70 | | try list.appendSlice("&digits="); |
| 71 | | try list.writer().print("{d}", .{digits}); |
| 72 | | try list.appendSlice("&period="); |
| 73 | | try list.writer().print("{d}", .{period}); |
| 74 | | try list.appendSlice("&issuer="); |
| 69 | try list.writeAll("&algorithm="); |
| 70 | try list.writeAll(@tagName(algo)); |
| 71 | try list.writeAll("&digits="); |
| 72 | try list.print("{d}", .{digits}); |
| 73 | try list.writeAll("&period="); |
| 74 | try list.print("{d}", .{period}); |
| 75 | try list.writeAll("&issuer="); |
| 75 | 76 | try url.percentEncodeAL(&list, issuer, url.is_query_percent_char); |
| 76 | 77 | return list.toOwnedSlice(); |
| 77 | 78 | } |
| 78 | 79 | |
| 79 | 80 | // RFC3548 base32 |
| 80 | 81 | // input.len is gonna be 64 | 32 | 64 |
| 81 | | fn encodeBase32(list: *std.array_list.Managed(u8), input: []const u8) !void { |
| 82 | fn encodeBase32(list: *nio.AllocatingWriter, input: []const u8) !void { |
| 82 | 83 | const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; |
| 83 | 84 | var iter = BufBiterator.init(input); |
| 84 | | while (iter.nextInt(u5)) |idx| try list.append(alphabet[idx]); |
| 85 | while (iter.nextInt(u5)) |idx| try list.writeAll(alphabet[idx..][0..1]); |
| 85 | 86 | } |
| 86 | 87 | |
| 87 | 88 | const BufBiterator = struct { |