| ... | ... | @@ -234,3 +234,56 @@ pub fn random_string(len: usize) ![]const u8 { |
| 234 | 234 | } |
| 235 | 235 | return buf; |
| 236 | 236 | } |
| 237 | |
| 238 | pub fn parse_split(comptime T: type, delim: []const u8) type { |
| 239 | return struct { |
| 240 | const Self = @This(); |
| 241 | |
| 242 | id: T, |
| 243 | string: []const u8, |
| 244 | |
| 245 | pub fn do(input: []const u8) !Self { |
| 246 | const iter = &std.mem.split(input, delim); |
| 247 | return Self{ |
| 248 | .id = std.meta.stringToEnum(T, iter.next() orelse return error.IterEmpty) orelse return error.NoMemberFound, |
| 249 | .string = iter.rest(), |
| 250 | }; |
| 251 | } |
| 252 | }; |
| 253 | } |
| 254 | |
| 255 | pub const HashFn = enum { |
| 256 | blake3, |
| 257 | sha256, |
| 258 | sha512, |
| 259 | }; |
| 260 | |
| 261 | pub fn validate_hash(input: []const u8, file_path: []const u8) !bool { |
| 262 | const hash = parse_split(HashFn, "-").do(input) catch return false; |
| 263 | const file = try std.fs.cwd().openFile(file_path, .{}); |
| 264 | defer file.close(); |
| 265 | const data = try file.reader().readAllAlloc(gpa, mb); |
| 266 | return std.mem.eql(u8, hash.string, switch (hash.id) { |
| 267 | .blake3 => blk: { |
| 268 | const h = &std.crypto.hash.Blake3.init(.{}); |
| 269 | var out: [32]u8 = undefined; |
| 270 | h.update(data); |
| 271 | h.final(&out); |
| 272 | break :blk try std.fmt.allocPrint(gpa, "{x}", .{out}); |
| 273 | }, |
| 274 | .sha256 => blk: { |
| 275 | const h = &std.crypto.hash.sha2.Sha256.init(.{}); |
| 276 | var out: [32]u8 = undefined; |
| 277 | h.update(data); |
| 278 | h.final(&out); |
| 279 | break :blk try std.fmt.allocPrint(gpa, "{x}", .{out}); |
| 280 | }, |
| 281 | .sha512 => blk: { |
| 282 | const h = &std.crypto.hash.sha2.Sha512.init(.{}); |
| 283 | var out: [64]u8 = undefined; |
| 284 | h.update(data); |
| 285 | h.final(&out); |
| 286 | break :blk try std.fmt.allocPrint(gpa, "{x}", .{out}); |
| 287 | }, |
| 288 | }); |
| 289 | } |