also looking at this
Harden encrypted mail storage, recovery, and forwarding
#8
50 files
+1701
-9001
Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.
| @@ -74,9 +74,11 @@ pub fn build(b: *std.Build) void { | ||
| 74 | 74 | // and embed an existing pre-rendered webmail_dist instead of failing the |
| 75 | 75 | // whole build on an unspawnable command. webmail_dist is gitignored, so |
| 76 | 76 | // whoever invokes such a build must pre-render it (the Docker CI job does). |
| 77 | const have_bun = (b.findProgram(&.{"bun"}, &.{}) catch null) != null; | |
| 77 | const have_bun = blk: { | |
| 78 | break :blk b.findProgram(.{ .names = &.{"bun"} }) != null; | |
| 79 | }; | |
| 78 | 80 | const have_webmail_pkg = blk: { |
| 79 | std.Io.Dir.cwd().access(b.graph.io, "../webmail", .{}) catch break :blk false; | |
| 81 | b.root.access(b.graph.io, "../webmail", .{}) catch break :blk false; | |
| 80 | 82 | break :blk true; |
| 81 | 83 | }; |
| 82 | 84 | if (have_bun and have_webmail_pkg) { |
| @@ -91,7 +93,7 @@ pub fn build(b: *std.Build) void { | ||
| 91 | 93 | // Run step: mail serve |
| 92 | 94 | const run_cmd = b.addRunArtifact(mail_exe); |
| 93 | 95 | run_cmd.step.dependOn(b.getInstallStep()); |
| 94 | if (b.args) |args| run_cmd.addArgs(args); | |
| 96 | run_cmd.addPassthruArgs(); | |
| 95 | 97 | |
| 96 | 98 | const run_step = b.step("run", "Run the mail CLI"); |
| 97 | 99 | run_step.dependOn(&run_cmd.step); |
| @@ -39,11 +39,8 @@ | ||
| 39 | 39 | .path = "vendor/zig-search-engine", |
| 40 | 40 | }, |
| 41 | 41 | .zig_cli = .{ |
| 42 | // Pin the last revision tested against Zig 0.16's unmanaged | |
| 43 | // ArrayList API. Later zig-cli commits target Zig 0.17-only | |
| 44 | // builtins/build APIs. | |
| 45 | .url = "git+https://github.com/zig-utils/zig-cli.git#b44ab9c372c18e73ada883afe9d0f9f9b2a6e80e", | |
| 46 | .hash = "zig_cli-0.1.1-18T51O3rAwBy6Q2GH6mEZGDrAGmx9-0RQfiIMpqYRGiN", | |
| 42 | .url = "git+https://github.com/zig-utils/zig-cli.git#d5b6d7cce234514e53073d566696cd2e69ef4836", | |
| 43 | .hash = "zig_cli-0.1.3-18T51LbtAwC1D5ymlw-xAeLSMooNBx2X2gDM4PawGb6c", | |
| 47 | 44 | }, |
| 48 | 45 | }, |
| 49 | 46 | .paths = .{ |
| @@ -263,9 +263,9 @@ pub const TLSARecord = struct { renamed throughout | ||
| 263 | 263 | /// Format the TLSA record as a DNS presentation string. |
| 264 | 264 | pub fn format(self: *const TLSARecord, allocator: std.mem.Allocator) ![]u8 { |
| 265 | 265 | return std.fmt.allocPrint(allocator, "{d} {d} {d} {s}", .{ |
| 266 | @intFromEnum(self.usage), | |
| 267 | @intFromEnum(self.selector), | |
| 268 | @intFromEnum(self.matching_type), | |
| 266 | @backingInt(self.usage), | |
| 267 | @backingInt(self.selector), | |
| 268 | @backingInt(self.matching_type), | |
| 269 | 269 | self.certificate_data, |
| 270 | 270 | }); |
| 271 | 271 | } |
| @@ -1512,7 +1512,7 @@ test "All TLSA usage values are covered" { | ||
| 1512 | 1512 | const parsed = TLSAUsage.fromInt(val); |
| 1513 | 1513 | try testing.expect(parsed != null); |
| 1514 | 1514 | try testing.expectEqual(exp, parsed.?); |
| 1515 | try testing.expectEqual(val, @intFromEnum(parsed.?)); | |
| 1515 | try testing.expectEqual(val, @backingInt(parsed.?)); | |
| 1516 | 1516 | } |
| 1517 | 1517 | } |
| 1518 | 1518 | |
| @@ -178,7 +178,7 @@ pub const DnsblChecker = struct { | ||
| 178 | 178 | defer if (result) |r| std.c.freeaddrinfo(r); |
| 179 | 179 | |
| 180 | 180 | // rc != 0 means the name did not resolve (NXDOMAIN etc.) => not listed. |
| 181 | if (@intFromEnum(rc) != 0) return false; | |
| 181 | if (@backingInt(rc) != 0) return false; | |
| 182 | 182 | |
| 183 | 183 | // Walk the result list and look for an A record in 127.0.0.0/8. |
| 184 | 184 | var node = result; |
| @@ -293,7 +293,7 @@ pub const ErrorHandler = struct { | ||
| 293 | 293 | } |
| 294 | 294 | |
| 295 | 295 | // Check severity |
| 296 | if (@intFromEnum(ctx.severity) < @intFromEnum(self.config.min_log_severity)) return; | |
| 296 | if (@backingInt(ctx.severity) < @backingInt(self.config.min_log_severity)) return; | |
| 297 | 297 | |
| 298 | 298 | // Log the error |
| 299 | 299 | if (self.config.log_all_errors) { |
| @@ -494,8 +494,8 @@ pub const ErrorMetrics = struct { renamed throughout | ||
| 494 | 494 | |
| 495 | 495 | pub fn record(self: *Self, ctx: ErrorContext) void { |
| 496 | 496 | _ = self.total_errors.fetchAdd(1, .monotonic); |
| 497 | _ = self.errors_by_category[@intFromEnum(ctx.category)].fetchAdd(1, .monotonic); | |
| 498 | _ = self.errors_by_severity[@intFromEnum(ctx.severity)].fetchAdd(1, .monotonic); | |
| 497 | _ = self.errors_by_category[@backingInt(ctx.category)].fetchAdd(1, .monotonic); | |
| 498 | _ = self.errors_by_severity[@backingInt(ctx.severity)].fetchAdd(1, .monotonic); | |
| 499 | 499 | self.last_error_time.store(ctx.timestamp, .monotonic); |
| 500 | 500 | |
| 501 | 501 | if (ctx.is_retryable) { |
| @@ -508,11 +508,11 @@ pub const ErrorMetrics = struct { renamed throughout | ||
| 508 | 508 | } |
| 509 | 509 | |
| 510 | 510 | pub fn getErrorsByCategory(self: *const Self, category: ErrorCategory) u64 { |
| 511 | return self.errors_by_category[@intFromEnum(category)].load(.monotonic); | |
| 511 | return self.errors_by_category[@backingInt(category)].load(.monotonic); | |
| 512 | 512 | } |
| 513 | 513 | |
| 514 | 514 | pub fn getErrorsBySeverity(self: *const Self, severity: ErrorSeverity) u64 { |
| 515 | return self.errors_by_severity[@intFromEnum(severity)].load(.monotonic); | |
| 515 | return self.errors_by_severity[@backingInt(severity)].load(.monotonic); | |
| 516 | 516 | } |
| 517 | 517 | |
| 518 | 518 | pub fn getCriticalErrors(self: *const Self) u64 { |
| @@ -63,7 +63,7 @@ pub const Dir = struct { | ||
| 63 | 63 | .CLOEXEC = true, |
| 64 | 64 | }, @as(std.c.mode_t, 0o644)); |
| 65 | 65 | if (fd < 0) { |
| 66 | const e: std.c.E = @enumFromInt(std.c._errno().*); | |
| 66 | const e: std.c.E = @fromBackingInt(@intCast(std.c._errno().*)); | |
| 67 | 67 | if (e == .EXIST) return error.PathAlreadyExists; |
| 68 | 68 | return error.SystemResources; |
| 69 | 69 | } |
| @@ -93,7 +93,7 @@ pub const Logger = struct { | ||
| 93 | 93 | } |
| 94 | 94 | |
| 95 | 95 | pub fn log(self: *Logger, level: LogLevel, comptime fmt: []const u8, args: anytype) void { |
| 96 | if (@intFromEnum(level) < @intFromEnum(self.min_level)) return; | |
| 96 | if (@backingInt(level) < @backingInt(self.min_level)) return; | |
| 97 | 97 | |
| 98 | 98 | const timestamp = time_compat.timestamp(); |
| 99 | 99 | var buf: [8192]u8 = undefined; |
| @@ -278,7 +278,7 @@ pub const Logger = struct { | ||
| 278 | 278 | }; |
| 279 | 279 | |
| 280 | 280 | pub fn logStructured(self: *Logger, slog: *StructuredLog) void { |
| 281 | if (@intFromEnum(slog.level) < @intFromEnum(self.min_level)) return; | |
| 281 | if (@backingInt(slog.level) < @backingInt(self.min_level)) return; | |
| 282 | 282 | |
| 283 | 283 | const timestamp = time_compat.timestamp(); |
| 284 | 284 | var log_buf: [8192]u8 = undefined; |
| @@ -127,8 +127,8 @@ pub const Server = struct { | ||
| 127 | 127 | if (address.family == .ipv4) { |
| 128 | 128 | const sockaddr = address.toSockaddrIn(); |
| 129 | 129 | if (std.c.bind(fd, @ptrCast(&sockaddr), @sizeOf(@TypeOf(sockaddr))) < 0) { |
| 130 | const e: posix.E = @enumFromInt(std.c._errno().*); | |
| 131 | std.log.err("bind() failed on port {d}: errno={d}", .{ address.port, @intFromEnum(e) }); | |
| 130 | const e: posix.E = @fromBackingInt(@intCast(std.c._errno().*)); | |
| 131 | std.log.err("bind() failed on port {d}: errno={d}", .{ address.port, @backingInt(e) }); | |
| 132 | 132 | return switch (e) { |
| 133 | 133 | .ADDRINUSE => error.AddressInUse, |
| 134 | 134 | .ADDRNOTAVAIL => error.AddressNotAvailable, |
| @@ -139,8 +139,8 @@ pub const Server = struct { | ||
| 139 | 139 | } else { |
| 140 | 140 | const sockaddr = address.toSockaddrIn6(); |
| 141 | 141 | if (std.c.bind(fd, @ptrCast(&sockaddr), @sizeOf(@TypeOf(sockaddr))) < 0) { |
| 142 | const e: posix.E = @enumFromInt(std.c._errno().*); | |
| 143 | std.log.err("bind() failed on port {d}: errno={d}", .{ address.port, @intFromEnum(e) }); | |
| 142 | const e: posix.E = @fromBackingInt(@intCast(std.c._errno().*)); | |
| 143 | std.log.err("bind() failed on port {d}: errno={d}", .{ address.port, @backingInt(e) }); | |
| 144 | 144 | return switch (e) { |
| 145 | 145 | .ADDRINUSE => error.AddressInUse, |
| 146 | 146 | .ADDRNOTAVAIL => error.AddressNotAvailable, |
| @@ -170,7 +170,7 @@ pub const Server = struct { | ||
| 170 | 170 | // Use raw syscall to avoid Zig 0.16 error type mismatch |
| 171 | 171 | const rc = std.c.accept(self.fd, &client_addr, &addr_len); |
| 172 | 172 | if (rc < 0) { |
| 173 | const err: posix.E = @enumFromInt(std.c._errno().*); | |
| 173 | const err: posix.E = @fromBackingInt(@intCast(std.c._errno().*)); | |
| 174 | 174 | return switch (err) { |
| 175 | 175 | .AGAIN => error.WouldBlock, |
| 176 | 176 | .INTR => error.OperationCancelled, |
| @@ -1026,7 +1026,7 @@ pub const CipherNegotiator = struct { | ||
| 1026 | 1026 | // Server preference: iterate server's list first |
| 1027 | 1027 | for (self.server_config.cipher_suites) |server_suite| { |
| 1028 | 1028 | for (client_suites) |client_suite| { |
| 1029 | if (@intFromEnum(server_suite) == client_suite) { | |
| 1029 | if (@backingInt(server_suite) == client_suite) { | |
| 1030 | 1030 | return server_suite; |
| 1031 | 1031 | } |
| 1032 | 1032 | } |
| @@ -1035,7 +1035,7 @@ pub const CipherNegotiator = struct { | ||
| 1035 | 1035 | // Client preference: iterate client's list first |
| 1036 | 1036 | for (client_suites) |client_suite| { |
| 1037 | 1037 | for (self.server_config.cipher_suites) |server_suite| { |
| 1038 | if (@intFromEnum(server_suite) == client_suite) { | |
| 1038 | if (@backingInt(server_suite) == client_suite) { | |
| 1039 | 1039 | return server_suite; |
| 1040 | 1040 | } |
| 1041 | 1041 | } |
| @@ -1051,7 +1051,7 @@ pub const CipherNegotiator = struct { | ||
| 1051 | 1051 | ) ?NamedGroup { |
| 1052 | 1052 | for (self.server_config.named_groups) |server_group| { |
| 1053 | 1053 | for (client_groups) |client_group| { |
| 1054 | if (@intFromEnum(server_group) == client_group) { | |
| 1054 | if (@backingInt(server_group) == client_group) { | |
| 1055 | 1055 | return server_group; |
| 1056 | 1056 | } |
| 1057 | 1057 | } |
| @@ -1072,7 +1072,7 @@ pub const CipherNegotiator = struct { | ||
| 1072 | 1072 | } |
| 1073 | 1073 | |
| 1074 | 1074 | for (client_schemes) |client_scheme| { |
| 1075 | if (@intFromEnum(server_scheme) == client_scheme) { | |
| 1075 | if (@backingInt(server_scheme) == client_scheme) { | |
| 1076 | 1076 | return server_scheme; |
| 1077 | 1077 | } |
| 1078 | 1078 | } |
| @@ -1294,7 +1294,7 @@ pub const ServerHelloBuilder = struct { | ||
| 1294 | 1294 | |
| 1295 | 1295 | // Named group (2 bytes) |
| 1296 | 1296 | var group_bytes: [2]u8 = undefined; |
| 1297 | std.mem.writeInt(u16, &group_bytes, @intFromEnum(group), .big); | |
| 1297 | std.mem.writeInt(u16, &group_bytes, @backingInt(group), .big); | |
| 1298 | 1298 | try data.appendSlice(self.allocator, &group_bytes); |
| 1299 | 1299 | |
| 1300 | 1300 | // Key exchange length (2 bytes) |
| @@ -1329,7 +1329,7 @@ pub const ServerHelloBuilder = struct { | ||
| 1329 | 1329 | |
| 1330 | 1330 | // Cipher suite (2 bytes) |
| 1331 | 1331 | var cipher_bytes: [2]u8 = undefined; |
| 1332 | std.mem.writeInt(u16, &cipher_bytes, @intFromEnum(self.cipher_suite), .big); | |
| 1332 | std.mem.writeInt(u16, &cipher_bytes, @backingInt(self.cipher_suite), .big); | |
| 1333 | 1333 | try output.appendSlice(self.allocator, &cipher_bytes); |
| 1334 | 1334 | |
| 1335 | 1335 | // Compression method (0 = null) |
| @@ -1344,7 +1344,7 @@ pub const ServerHelloBuilder = struct { | ||
| 1344 | 1344 | for (self.extensions.items) |ext| { |
| 1345 | 1345 | // Extension type (2 bytes) |
| 1346 | 1346 | var ext_type_bytes: [2]u8 = undefined; |
| 1347 | std.mem.writeInt(u16, &ext_type_bytes, @intFromEnum(ext.ext_type), .big); | |
| 1347 | std.mem.writeInt(u16, &ext_type_bytes, @backingInt(ext.ext_type), .big); | |
| 1348 | 1348 | try output.appendSlice(self.allocator, &ext_type_bytes); |
| 1349 | 1349 | |
| 1350 | 1350 | // Extension data length (2 bytes) |
| @@ -1452,8 +1452,8 @@ pub const TlsAlert = struct { | ||
| 1452 | 1452 | return .{ |
| 1453 | 1453 | 21, // Alert content type |
| 1454 | 1454 | 0x03, 0x03, // Version (TLS 1.2 for compatibility) |
| 1455 | 0x00, 0x02, // Length | |
| 1456 | @intFromEnum(self.level), @intFromEnum(self.description), | |
| 1455 | 0x00, 0x02, // Length | |
| 1456 | @backingInt(self.level), @backingInt(self.description), | |
| 1457 | 1457 | }; |
| 1458 | 1458 | } |
| 1459 | 1459 | |
| @@ -1706,9 +1706,9 @@ test "cipher negotiation server preference" { renamed throughout | ||
| 1706 | 1706 | |
| 1707 | 1707 | // Client offers TLS 1.2 ciphers first, then TLS 1.3 |
| 1708 | 1708 | const client_suites = [_]u16{ |
| 1709 | @intFromEnum(CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256), | |
| 1710 | @intFromEnum(CipherSuite.TLS_AES_128_GCM_SHA256), | |
| 1711 | @intFromEnum(CipherSuite.TLS_AES_256_GCM_SHA384), | |
| 1709 | @backingInt(CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256), | |
| 1710 | @backingInt(CipherSuite.TLS_AES_128_GCM_SHA256), | |
| 1711 | @backingInt(CipherSuite.TLS_AES_256_GCM_SHA384), | |
| 1712 | 1712 | }; |
| 1713 | 1713 | |
| 1714 | 1714 | // Server prefers TLS_AES_256_GCM_SHA384 (first in server list) |
| @@ -1744,8 +1744,8 @@ test "named group negotiation" { renamed throughout | ||
| 1744 | 1744 | var negotiator = CipherNegotiator.init(testing.allocator, .{}); |
| 1745 | 1745 | |
| 1746 | 1746 | const client_groups = [_]u16{ |
| 1747 | @intFromEnum(NamedGroup.secp256r1), | |
| 1748 | @intFromEnum(NamedGroup.x25519), | |
| 1747 | @backingInt(NamedGroup.secp256r1), | |
| 1748 | @backingInt(NamedGroup.x25519), | |
| 1749 | 1749 | }; |
| 1750 | 1750 | |
| 1751 | 1751 | // Server prefers x25519 |
| @@ -1761,17 +1761,17 @@ test "full negotiation" { renamed throughout | ||
| 1761 | 1761 | |
| 1762 | 1762 | const client_hello = ClientHelloParams{ |
| 1763 | 1763 | .cipher_suites = &[_]u16{ |
| 1764 | @intFromEnum(CipherSuite.TLS_AES_128_GCM_SHA256), | |
| 1765 | @intFromEnum(CipherSuite.TLS_AES_256_GCM_SHA384), | |
| 1764 | @backingInt(CipherSuite.TLS_AES_128_GCM_SHA256), | |
| 1765 | @backingInt(CipherSuite.TLS_AES_256_GCM_SHA384), | |
| 1766 | 1766 | }, |
| 1767 | 1767 | .supported_versions = &[_]u16{ 0x0304, 0x0303 }, |
| 1768 | 1768 | .named_groups = &[_]u16{ |
| 1769 | @intFromEnum(NamedGroup.x25519), | |
| 1770 | @intFromEnum(NamedGroup.secp256r1), | |
| 1769 | @backingInt(NamedGroup.x25519), | |
| 1770 | @backingInt(NamedGroup.secp256r1), | |
| 1771 | 1771 | }, |
| 1772 | 1772 | .signature_algorithms = &[_]u16{ |
| 1773 | @intFromEnum(SignatureScheme.ecdsa_secp256r1_sha256), | |
| 1774 | @intFromEnum(SignatureScheme.rsa_pss_rsae_sha256), | |
| 1773 | @backingInt(SignatureScheme.ecdsa_secp256r1_sha256), | |
| 1774 | @backingInt(SignatureScheme.rsa_pss_rsae_sha256), | |
| 1775 | 1775 | }, |
| 1776 | 1776 | .server_name = "mail.example.com", |
| 1777 | 1777 | }; |
| @@ -309,7 +309,7 @@ fn deliverOnce( | ||
| 309 | 309 | |
| 310 | 310 | var result: ?*std.c.addrinfo = null; |
| 311 | 311 | const gai_ret = std.c.getaddrinfo(mx_host_z.ptr, "25", &hints, &result); |
| 312 | if (@intFromEnum(gai_ret) != 0 or result == null) { | |
| 312 | if (@backingInt(gai_ret) != 0 or result == null) { | |
| 313 | 313 | std.log.err("Failed to resolve MX host {s}", .{mx_host}); |
| 314 | 314 | return error.MxResolutionFailed; |
| 315 | 315 | } |
| @@ -144,7 +144,7 @@ pub const ClusterNetwork = struct { | ||
| 144 | 144 | try std.json.stringify(message, .{}, body.writer()); |
| 145 | 145 | |
| 146 | 146 | // Write message type (1 byte) |
| 147 | const type_byte = [1]u8{@intFromEnum(msg_type)}; | |
| 147 | const type_byte = [1]u8{@backingInt(msg_type)}; | |
| 148 | 148 | _ = try stream.write(&type_byte); |
| 149 | 149 | |
| 150 | 150 | // Write message length (4 bytes, big-endian) |
| @@ -350,7 +350,7 @@ pub const MultiRegionManager = struct { | ||
| 350 | 350 | // Serialize event |
| 351 | 351 | try batch.writer().print("{d}:{d}:{s}\n", .{ |
| 352 | 352 | event.id, |
| 353 | @intFromEnum(event.event_type), | |
| 353 | @backingInt(event.event_type), | |
| 354 | 354 | event.payload, |
| 355 | 355 | }); |
| 356 | 356 | } |
| @@ -502,7 +502,7 @@ pub const AlertManager = struct { | ||
| 502 | 502 | }; |
| 503 | 503 | |
| 504 | 504 | // Check severity threshold |
| 505 | return @intFromEnum(alert.severity) >= @intFromEnum(min_severity); | |
| 505 | return @backingInt(alert.severity) >= @backingInt(min_severity); | |
| 506 | 506 | } |
| 507 | 507 | |
| 508 | 508 | fn sendToChannel(self: *AlertManager, channel: AlertChannel, alert: Alert) !void { |
| @@ -702,8 +702,8 @@ test "add slack channel" { | ||
| 702 | 702 | test "severity comparison" { |
| 703 | 703 | const testing = std.testing; |
| 704 | 704 | |
| 705 | try testing.expect(@intFromEnum(Severity.critical) > @intFromEnum(Severity.warning)); | |
| 706 | try testing.expect(@intFromEnum(Severity.warning) > @intFromEnum(Severity.info)); | |
| 705 | try testing.expect(@backingInt(Severity.critical) > @backingInt(Severity.warning)); | |
| 706 | try testing.expect(@backingInt(Severity.warning) > @backingInt(Severity.info)); | |
| 707 | 707 | } |
| 708 | 708 | |
| 709 | 709 | test "default rules creation" { |
| @@ -735,7 +735,7 @@ test "Protocol version parsing" { | ||
| 735 | 735 | test "Folder types" { |
| 736 | 736 | const testing = std.testing; |
| 737 | 737 | |
| 738 | try testing.expectEqual(@as(u8, 2), @intFromEnum(FolderType.default_inbox)); | |
| 739 | try testing.expectEqual(@as(u8, 8), @intFromEnum(FolderType.default_calendar)); | |
| 740 | try testing.expectEqual(@as(u8, 9), @intFromEnum(FolderType.default_contacts)); | |
| 738 | try testing.expectEqual(@as(u8, 2), @backingInt(FolderType.default_inbox)); | |
| 739 | try testing.expectEqual(@as(u8, 8), @backingInt(FolderType.default_calendar)); | |
| 740 | try testing.expectEqual(@as(u8, 9), @backingInt(FolderType.default_contacts)); | |
| 741 | 741 | } |
| @@ -856,7 +856,7 @@ fn civilFromEpoch(epoch: i64) Civil { | ||
| 856 | 856 | const ds = es.getDaySeconds(); |
| 857 | 857 | return .{ |
| 858 | 858 | .year = year_day.year, |
| 859 | .month = @intFromEnum(month_day.month), | |
| 859 | .month = @backingInt(month_day.month), | |
| 860 | 860 | .day = @as(u8, month_day.day_index) + 1, |
| 861 | 861 | .hour = ds.getHoursIntoDay(), |
| 862 | 862 | .minute = ds.getMinutesIntoHour(), |
| @@ -757,7 +757,7 @@ fn ewsDate(a: std.mem.Allocator, epoch: i64) []const u8 { | ||
| 757 | 757 | const md = yd.calculateMonthDay(); |
| 758 | 758 | const ds = es.getDaySeconds(); |
| 759 | 759 | return std.fmt.allocPrint(a, "{d:0>4}-{d:0>2}-{d:0>2}T{d:0>2}:{d:0>2}:{d:0>2}Z", .{ |
| 760 | yd.year, @intFromEnum(md.month), @as(u32, md.day_index) + 1, | |
| 760 | yd.year, @backingInt(md.month), @as(u32, md.day_index) + 1, | |
| 761 | 761 | ds.getHoursIntoDay(), ds.getMinutesIntoHour(), ds.getSecondsIntoMinute(), |
| 762 | 762 | }) catch "1970-01-01T00:00:00Z"; |
| 763 | 763 | } |
| @@ -945,7 +945,7 @@ fn rfc2822Date(a: std.mem.Allocator, epoch: i64) []const u8 { | ||
| 945 | 945 | const wdays = [_][]const u8{ "Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed" }; |
| 946 | 946 | const months = [_][]const u8{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; |
| 947 | 947 | const wd = wdays[@intCast(ed.day % 7)]; |
| 948 | const mon = months[@intFromEnum(md.month) - 1]; | |
| 948 | const mon = months[@backingInt(md.month) - 1]; | |
| 949 | 949 | return std.fmt.allocPrint(a, "{s}, {d:0>2} {s} {d} {d:0>2}:{d:0>2}:{d:0>2} +0000", .{ |
| 950 | 950 | wd, @as(u32, md.day_index) + 1, mon, yd.year, |
| 951 | 951 | ds.getHoursIntoDay(), ds.getMinutesIntoHour(), ds.getSecondsIntoMinute(), |
| @@ -904,7 +904,7 @@ test "command parsing - unknown returns null" { | ||
| 904 | 904 | |
| 905 | 905 | test "command toString round-trips" { |
| 906 | 906 | inline for (@typeInfo(ManageSieveCommand).@"enum".field_values) |value| { |
| 907 | const c: ManageSieveCommand = @enumFromInt(value); | |
| 907 | const c: ManageSieveCommand = @fromBackingInt(@intCast(value)); | |
| 908 | 908 | try std.testing.expectEqual(c, ManageSieveCommand.fromString(c.toString()).?); |
| 909 | 909 | } |
| 910 | 910 | } |
| @@ -69,7 +69,7 @@ pub const MilterCommand = enum(u8) { | ||
| 69 | 69 | /// Convert a raw byte to a MilterCommand, returning null if unrecognized. |
| 70 | 70 | pub fn fromByte(byte: u8) ?MilterCommand { |
| 71 | 71 | inline for (@typeInfo(MilterCommand).@"enum".field_values) |value| { |
| 72 | if (byte == value) return @enumFromInt(value); | |
| 72 | if (byte == value) return @fromBackingInt(@intCast(value)); | |
| 73 | 73 | } |
| 74 | 74 | return null; |
| 75 | 75 | } |
| @@ -142,7 +142,7 @@ pub const MilterResponse = enum(u8) { | ||
| 142 | 142 | /// Convert a raw byte to a MilterResponse, returning null if unrecognized. |
| 143 | 143 | pub fn fromByte(byte: u8) ?MilterResponse { |
| 144 | 144 | inline for (@typeInfo(MilterResponse).@"enum".field_values) |value| { |
| 145 | if (byte == value) return @enumFromInt(value); | |
| 145 | if (byte == value) return @fromBackingInt(@intCast(value)); | |
| 146 | 146 | } |
| 147 | 147 | return null; |
| 148 | 148 | } |
| @@ -371,7 +371,7 @@ pub const MilterFamily = enum(u8) { | ||
| 371 | 371 | |
| 372 | 372 | pub fn fromByte(byte: u8) ?MilterFamily { |
| 373 | 373 | inline for (@typeInfo(MilterFamily).@"enum".field_values) |value| { |
| 374 | if (byte == value) return @enumFromInt(value); | |
| 374 | if (byte == value) return @fromBackingInt(@intCast(value)); | |
| 375 | 375 | } |
| 376 | 376 | return null; |
| 377 | 377 | } |
| @@ -477,7 +477,7 @@ pub const MilterPacket = struct { | ||
| 477 | 477 | /// Convenience: create a command-only packet with no data. |
| 478 | 478 | pub fn commandOnly(cmd: MilterCommand) MilterPacket { |
| 479 | 479 | return .{ |
| 480 | .command = @intFromEnum(cmd), | |
| 480 | .command = @backingInt(cmd), | |
| 481 | 481 | .data = &[_]u8{}, |
| 482 | 482 | }; |
| 483 | 483 | } |
| @@ -784,14 +784,14 @@ pub const MilterClient = struct { renamed throughout | ||
| 784 | 784 | std.mem.writeInt(u32, payload[8..12], offered_protocol.toNetworkU32(), .big); |
| 785 | 785 | |
| 786 | 786 | try self.sendPacket(.{ |
| 787 | .command = @intFromEnum(MilterCommand.option_negotiation), | |
| 787 | .command = @backingInt(MilterCommand.option_negotiation), | |
| 788 | 788 | .data = &payload, |
| 789 | 789 | }); |
| 790 | 790 | |
| 791 | 791 | // Read the SMFIR_OPTNEG response. |
| 792 | 792 | const pkt = try self.readPacket(); |
| 793 | 793 | |
| 794 | if (pkt.command != @intFromEnum(MilterResponse.option_negotiation)) { | |
| 794 | if (pkt.command != @backingInt(MilterResponse.option_negotiation)) { | |
| 795 | 795 | return error.UnexpectedResponse; |
| 796 | 796 | } |
| 797 | 797 | if (pkt.data.len < 12) { |
| @@ -837,7 +837,7 @@ pub const MilterClient = struct { | ||
| 837 | 837 | offset += hostname.len; |
| 838 | 838 | buf[offset] = 0; |
| 839 | 839 | offset += 1; |
| 840 | buf[offset] = @intFromEnum(family); | |
| 840 | buf[offset] = @backingInt(family); | |
| 841 | 841 | offset += 1; |
| 842 | 842 | std.mem.writeInt(u16, buf[offset..][0..2], port, .big); |
| 843 | 843 | offset += 2; |
| @@ -846,7 +846,7 @@ pub const MilterClient = struct { | ||
| 846 | 846 | buf[offset] = 0; |
| 847 | 847 | |
| 848 | 848 | try self.sendPacket(.{ |
| 849 | .command = @intFromEnum(MilterCommand.connect), | |
| 849 | .command = @backingInt(MilterCommand.connect), | |
| 850 | 850 | .data = buf, |
| 851 | 851 | }); |
| 852 | 852 | |
| @@ -862,7 +862,7 @@ pub const MilterClient = struct { | ||
| 862 | 862 | buf[hostname.len] = 0; |
| 863 | 863 | |
| 864 | 864 | try self.sendPacket(.{ |
| 865 | .command = @intFromEnum(MilterCommand.helo), | |
| 865 | .command = @backingInt(MilterCommand.helo), | |
| 866 | 866 | .data = buf, |
| 867 | 867 | }); |
| 868 | 868 | |
| @@ -891,7 +891,7 @@ pub const MilterClient = struct { | ||
| 891 | 891 | } |
| 892 | 892 | |
| 893 | 893 | try self.sendPacket(.{ |
| 894 | .command = @intFromEnum(MilterCommand.mail_from), | |
| 894 | .command = @backingInt(MilterCommand.mail_from), | |
| 895 | 895 | .data = payload.items, |
| 896 | 896 | }); |
| 897 | 897 | |
| @@ -919,7 +919,7 @@ pub const MilterClient = struct { | ||
| 919 | 919 | } |
| 920 | 920 | |
| 921 | 921 | try self.sendPacket(.{ |
| 922 | .command = @intFromEnum(MilterCommand.rcpt_to), | |
| 922 | .command = @backingInt(MilterCommand.rcpt_to), | |
| 923 | 923 | .data = payload.items, |
| 924 | 924 | }); |
| 925 | 925 | |
| @@ -942,7 +942,7 @@ pub const MilterClient = struct { | ||
| 942 | 942 | buf[name.len + 1 + value.len] = 0; |
| 943 | 943 | |
| 944 | 944 | try self.sendPacket(.{ |
| 945 | .command = @intFromEnum(MilterCommand.header), | |
| 945 | .command = @backingInt(MilterCommand.header), | |
| 946 | 946 | .data = buf, |
| 947 | 947 | }); |
| 948 | 948 | |
| @@ -963,7 +963,7 @@ pub const MilterClient = struct { | ||
| 963 | 963 | if (chunk.len > MILTER_CHUNK_SIZE) return error.ChunkTooLarge; |
| 964 | 964 | |
| 965 | 965 | try self.sendPacket(.{ |
| 966 | .command = @intFromEnum(MilterCommand.body), | |
| 966 | .command = @backingInt(MilterCommand.body), | |
| 967 | 967 | .data = chunk, |
| 968 | 968 | }); |
| 969 | 969 | |
| @@ -1029,7 +1029,7 @@ pub const MilterClient = struct { | ||
| 1029 | 1029 | var payload: std.ArrayList(u8) = .empty; |
| 1030 | 1030 | defer payload.deinit(self.allocator); |
| 1031 | 1031 | |
| 1032 | try payload.append(self.allocator, @intFromEnum(cmd_code)); | |
| 1032 | try payload.append(self.allocator, @backingInt(cmd_code)); | |
| 1033 | 1033 | |
| 1034 | 1034 | for (macros) |pair| { |
| 1035 | 1035 | try payload.appendSlice(self.allocator, pair[0]); |
| @@ -1039,7 +1039,7 @@ pub const MilterClient = struct { | ||
| 1039 | 1039 | } |
| 1040 | 1040 | |
| 1041 | 1041 | try self.sendPacket(.{ |
| 1042 | .command = @intFromEnum(MilterCommand.macro), | |
| 1042 | .command = @backingInt(MilterCommand.macro), | |
| 1043 | 1043 | .data = payload.items, |
| 1044 | 1044 | }); |
| 1045 | 1045 | // Macros do not expect a response. |
| @@ -1788,21 +1788,21 @@ pub const MilterManagerStats = struct { renamed throughout | ||
| 1788 | 1788 | test "MilterCommand byte values" { |
| 1789 | 1789 | const testing = std.testing; |
| 1790 | 1790 | |
| 1791 | try testing.expectEqual(@as(u8, 'A'), @intFromEnum(MilterCommand.abort)); | |
| 1792 | try testing.expectEqual(@as(u8, 'B'), @intFromEnum(MilterCommand.body)); | |
| 1793 | try testing.expectEqual(@as(u8, 'C'), @intFromEnum(MilterCommand.connect)); | |
| 1794 | try testing.expectEqual(@as(u8, 'D'), @intFromEnum(MilterCommand.macro)); | |
| 1795 | try testing.expectEqual(@as(u8, 'E'), @intFromEnum(MilterCommand.end_of_body)); | |
| 1796 | try testing.expectEqual(@as(u8, 'H'), @intFromEnum(MilterCommand.helo)); | |
| 1797 | try testing.expectEqual(@as(u8, 'L'), @intFromEnum(MilterCommand.header)); | |
| 1798 | try testing.expectEqual(@as(u8, 'N'), @intFromEnum(MilterCommand.end_of_headers)); | |
| 1799 | try testing.expectEqual(@as(u8, 'M'), @intFromEnum(MilterCommand.mail_from)); | |
| 1800 | try testing.expectEqual(@as(u8, 'O'), @intFromEnum(MilterCommand.option_negotiation)); | |
| 1801 | try testing.expectEqual(@as(u8, 'Q'), @intFromEnum(MilterCommand.quit)); | |
| 1802 | try testing.expectEqual(@as(u8, 'R'), @intFromEnum(MilterCommand.rcpt_to)); | |
| 1803 | try testing.expectEqual(@as(u8, 'T'), @intFromEnum(MilterCommand.data)); | |
| 1804 | try testing.expectEqual(@as(u8, 'K'), @intFromEnum(MilterCommand.quit_new_connection)); | |
| 1805 | try testing.expectEqual(@as(u8, 'U'), @intFromEnum(MilterCommand.unknown)); | |
| 1791 | try testing.expectEqual(@as(u8, 'A'), @backingInt(MilterCommand.abort)); | |
| 1792 | try testing.expectEqual(@as(u8, 'B'), @backingInt(MilterCommand.body)); | |
| 1793 | try testing.expectEqual(@as(u8, 'C'), @backingInt(MilterCommand.connect)); | |
| 1794 | try testing.expectEqual(@as(u8, 'D'), @backingInt(MilterCommand.macro)); | |
| 1795 | try testing.expectEqual(@as(u8, 'E'), @backingInt(MilterCommand.end_of_body)); | |
| 1796 | try testing.expectEqual(@as(u8, 'H'), @backingInt(MilterCommand.helo)); | |
| 1797 | try testing.expectEqual(@as(u8, 'L'), @backingInt(MilterCommand.header)); | |
| 1798 | try testing.expectEqual(@as(u8, 'N'), @backingInt(MilterCommand.end_of_headers)); | |
| 1799 | try testing.expectEqual(@as(u8, 'M'), @backingInt(MilterCommand.mail_from)); | |
| 1800 | try testing.expectEqual(@as(u8, 'O'), @backingInt(MilterCommand.option_negotiation)); | |
| 1801 | try testing.expectEqual(@as(u8, 'Q'), @backingInt(MilterCommand.quit)); | |
| 1802 | try testing.expectEqual(@as(u8, 'R'), @backingInt(MilterCommand.rcpt_to)); | |
| 1803 | try testing.expectEqual(@as(u8, 'T'), @backingInt(MilterCommand.data)); | |
| 1804 | try testing.expectEqual(@as(u8, 'K'), @backingInt(MilterCommand.quit_new_connection)); | |
| 1805 | try testing.expectEqual(@as(u8, 'U'), @backingInt(MilterCommand.unknown)); | |
| 1806 | 1806 | } |
| 1807 | 1807 | |
| 1808 | 1808 | test "MilterCommand fromByte round-trips" { |
| @@ -1829,21 +1829,21 @@ test "MilterCommand toString" { renamed throughout | ||
| 1829 | 1829 | test "MilterResponse byte values" { |
| 1830 | 1830 | const testing = std.testing; |
| 1831 | 1831 | |
| 1832 | try testing.expectEqual(@as(u8, '+'), @intFromEnum(MilterResponse.add_recipient)); | |
| 1833 | try testing.expectEqual(@as(u8, '-'), @intFromEnum(MilterResponse.delete_recipient)); | |
| 1834 | try testing.expectEqual(@as(u8, 'a'), @intFromEnum(MilterResponse.accept)); | |
| 1835 | try testing.expectEqual(@as(u8, 'b'), @intFromEnum(MilterResponse.replace_body)); | |
| 1836 | try testing.expectEqual(@as(u8, 'c'), @intFromEnum(MilterResponse.@"continue")); | |
| 1837 | try testing.expectEqual(@as(u8, 'd'), @intFromEnum(MilterResponse.discard)); | |
| 1838 | try testing.expectEqual(@as(u8, 'h'), @intFromEnum(MilterResponse.add_header)); | |
| 1839 | try testing.expectEqual(@as(u8, 'i'), @intFromEnum(MilterResponse.insert_header)); | |
| 1840 | try testing.expectEqual(@as(u8, 'm'), @intFromEnum(MilterResponse.change_header)); | |
| 1841 | try testing.expectEqual(@as(u8, 'p'), @intFromEnum(MilterResponse.progress)); | |
| 1842 | try testing.expectEqual(@as(u8, 'q'), @intFromEnum(MilterResponse.quarantine)); | |
| 1843 | try testing.expectEqual(@as(u8, 'r'), @intFromEnum(MilterResponse.reject)); | |
| 1844 | try testing.expectEqual(@as(u8, 't'), @intFromEnum(MilterResponse.temp_fail)); | |
| 1845 | try testing.expectEqual(@as(u8, 'y'), @intFromEnum(MilterResponse.reply_code)); | |
| 1846 | try testing.expectEqual(@as(u8, 's'), @intFromEnum(MilterResponse.skip)); | |
| 1832 | try testing.expectEqual(@as(u8, '+'), @backingInt(MilterResponse.add_recipient)); | |
| 1833 | try testing.expectEqual(@as(u8, '-'), @backingInt(MilterResponse.delete_recipient)); | |
| 1834 | try testing.expectEqual(@as(u8, 'a'), @backingInt(MilterResponse.accept)); | |
| 1835 | try testing.expectEqual(@as(u8, 'b'), @backingInt(MilterResponse.replace_body)); | |
| 1836 | try testing.expectEqual(@as(u8, 'c'), @backingInt(MilterResponse.@"continue")); | |
| 1837 | try testing.expectEqual(@as(u8, 'd'), @backingInt(MilterResponse.discard)); | |
| 1838 | try testing.expectEqual(@as(u8, 'h'), @backingInt(MilterResponse.add_header)); | |
| 1839 | try testing.expectEqual(@as(u8, 'i'), @backingInt(MilterResponse.insert_header)); | |
| 1840 | try testing.expectEqual(@as(u8, 'm'), @backingInt(MilterResponse.change_header)); | |
| 1841 | try testing.expectEqual(@as(u8, 'p'), @backingInt(MilterResponse.progress)); | |
| 1842 | try testing.expectEqual(@as(u8, 'q'), @backingInt(MilterResponse.quarantine)); | |
| 1843 | try testing.expectEqual(@as(u8, 'r'), @backingInt(MilterResponse.reject)); | |
| 1844 | try testing.expectEqual(@as(u8, 't'), @backingInt(MilterResponse.temp_fail)); | |
| 1845 | try testing.expectEqual(@as(u8, 'y'), @backingInt(MilterResponse.reply_code)); | |
| 1846 | try testing.expectEqual(@as(u8, 's'), @backingInt(MilterResponse.skip)); | |
| 1847 | 1847 | } |
| 1848 | 1848 | |
| 1849 | 1849 | test "MilterResponse fromByte round-trips" { |
| @@ -2010,10 +2010,10 @@ test "MilterProtocol merge and intersect" { renamed throughout | ||
| 2010 | 2010 | test "MilterFamily byte values" { |
| 2011 | 2011 | const testing = std.testing; |
| 2012 | 2012 | |
| 2013 | try testing.expectEqual(@as(u8, 'U'), @intFromEnum(MilterFamily.unknown)); | |
| 2014 | try testing.expectEqual(@as(u8, 'L'), @intFromEnum(MilterFamily.unix)); | |
| 2015 | try testing.expectEqual(@as(u8, '4'), @intFromEnum(MilterFamily.inet)); | |
| 2016 | try testing.expectEqual(@as(u8, '6'), @intFromEnum(MilterFamily.inet6)); | |
| 2013 | try testing.expectEqual(@as(u8, 'U'), @backingInt(MilterFamily.unknown)); | |
| 2014 | try testing.expectEqual(@as(u8, 'L'), @backingInt(MilterFamily.unix)); | |
| 2015 | try testing.expectEqual(@as(u8, '4'), @backingInt(MilterFamily.inet)); | |
| 2016 | try testing.expectEqual(@as(u8, '6'), @backingInt(MilterFamily.inet6)); | |
| 2017 | 2017 | } |
| 2018 | 2018 | |
| 2019 | 2019 | test "MilterPacket encode command-only packet" { |
| @@ -2039,7 +2039,7 @@ test "MilterPacket encode with data" { | ||
| 2039 | 2039 | |
| 2040 | 2040 | const data = "test.example.com\x00"; |
| 2041 | 2041 | const pkt = MilterPacket{ |
| 2042 | .command = @intFromEnum(MilterCommand.helo), | |
| 2042 | .command = @backingInt(MilterCommand.helo), | |
| 2043 | 2043 | .data = data, |
| 2044 | 2044 | }; |
| 2045 | 2045 | |
| @@ -2089,7 +2089,7 @@ test "MilterPacket encode-decode round-trip" { | ||
| 2089 | 2089 | const testing = std.testing; |
| 2090 | 2090 | |
| 2091 | 2091 | const original = MilterPacket{ |
| 2092 | .command = @intFromEnum(MilterCommand.header), | |
| 2092 | .command = @backingInt(MilterCommand.header), | |
| 2093 | 2093 | .data = "Subject\x00Hello World\x00", |
| 2094 | 2094 | }; |
| 2095 | 2095 | |
| @@ -2132,7 +2132,7 @@ test "MilterPacket encode buffer too small" { | ||
| 2132 | 2132 | const testing = std.testing; |
| 2133 | 2133 | |
| 2134 | 2134 | const pkt = MilterPacket{ |
| 2135 | .command = @intFromEnum(MilterCommand.body), | |
| 2135 | .command = @backingInt(MilterCommand.body), | |
| 2136 | 2136 | .data = "some body data", |
| 2137 | 2137 | }; |
| 2138 | 2138 | |
| @@ -2147,7 +2147,7 @@ test "MilterPacket encodedLen" { | ||
| 2147 | 2147 | try testing.expectEqual(@as(usize, 5), pkt_no_data.encodedLen()); |
| 2148 | 2148 | |
| 2149 | 2149 | const pkt_with_data = MilterPacket{ |
| 2150 | .command = @intFromEnum(MilterCommand.body), | |
| 2150 | .command = @backingInt(MilterCommand.body), | |
| 2151 | 2151 | .data = "Hello", |
| 2152 | 2152 | }; |
| 2153 | 2153 | try testing.expectEqual(@as(usize, 10), pkt_with_data.encodedLen()); |
| @@ -2163,7 +2163,7 @@ test "negotiation packet encoding" { | ||
| 2163 | 2163 | std.mem.writeInt(u32, payload[8..12], MilterProtocol.all_callbacks.toNetworkU32(), .big); |
| 2164 | 2164 | |
| 2165 | 2165 | const pkt = MilterPacket{ |
| 2166 | .command = @intFromEnum(MilterCommand.option_negotiation), | |
| 2166 | .command = @backingInt(MilterCommand.option_negotiation), | |
| 2167 | 2167 | .data = &payload, |
| 2168 | 2168 | }; |
| 2169 | 2169 | |
| @@ -2562,7 +2562,7 @@ test "MilterPacket network byte order verification" { | ||
| 2562 | 2562 | @memset(&data, 'X'); |
| 2563 | 2563 | |
| 2564 | 2564 | const pkt = MilterPacket{ |
| 2565 | .command = @intFromEnum(MilterCommand.body), | |
| 2565 | .command = @backingInt(MilterCommand.body), | |
| 2566 | 2566 | .data = &data, |
| 2567 | 2567 | }; |
| 2568 | 2568 | |
| @@ -378,7 +378,7 @@ pub const WebSocketSession = struct { | ||
| 378 | 378 | defer frame_header.deinit(self.allocator); |
| 379 | 379 | |
| 380 | 380 | // First byte: FIN + RSV + OpCode |
| 381 | const byte1: u8 = 0x80 | @intFromEnum(opcode); // FIN=1, RSV=0, OpCode | |
| 381 | const byte1: u8 = 0x80 | @backingInt(opcode); // FIN=1, RSV=0, OpCode | |
| 382 | 382 | try frame_header.append(self.allocator, byte1); |
| 383 | 383 | |
| 384 | 384 | // Second byte: MASK + Payload length |
| @@ -768,11 +768,11 @@ test "WebSocket accept key generation" { renamed throughout | ||
| 768 | 768 | test "OpCode enum values" { |
| 769 | 769 | const testing = std.testing; |
| 770 | 770 | |
| 771 | try testing.expectEqual(@as(u8, 0x1), @intFromEnum(OpCode.text)); | |
| 772 | try testing.expectEqual(@as(u8, 0x2), @intFromEnum(OpCode.binary)); | |
| 773 | try testing.expectEqual(@as(u8, 0x8), @intFromEnum(OpCode.close)); | |
| 774 | try testing.expectEqual(@as(u8, 0x9), @intFromEnum(OpCode.ping)); | |
| 775 | try testing.expectEqual(@as(u8, 0xA), @intFromEnum(OpCode.pong)); | |
| 771 | try testing.expectEqual(@as(u8, 0x1), @backingInt(OpCode.text)); | |
| 772 | try testing.expectEqual(@as(u8, 0x2), @backingInt(OpCode.binary)); | |
| 773 | try testing.expectEqual(@as(u8, 0x8), @backingInt(OpCode.close)); | |
| 774 | try testing.expectEqual(@as(u8, 0x9), @backingInt(OpCode.ping)); | |
| 775 | try testing.expectEqual(@as(u8, 0xA), @backingInt(OpCode.pong)); | |
| 776 | 776 | } |
| 777 | 777 | |
| 778 | 778 | test "Notification manager" { |
| @@ -993,7 +993,7 @@ pub const AwsSigV4Signer = struct { | ||
| 993 | 993 | |
| 994 | 994 | return try std.fmt.allocPrint(self.allocator, "{d:0>4}{d:0>2}{d:0>2}", .{ |
| 995 | 995 | year_and_day.year, |
| 996 | @intFromEnum(month_day.month), | |
| 996 | @backingInt(month_day.month), | |
| 997 | 997 | month_day.day_index + 1, |
| 998 | 998 | }); |
| 999 | 999 | } |
| @@ -1013,7 +1013,7 @@ pub const AwsSigV4Signer = struct { | ||
| 1013 | 1013 | |
| 1014 | 1014 | return try std.fmt.allocPrint(self.allocator, "{d:0>4}{d:0>2}{d:0>2}T{d:0>2}{d:0>2}{d:0>2}Z", .{ |
| 1015 | 1015 | year_and_day.year, |
| 1016 | @intFromEnum(month_day.month), | |
| 1016 | @backingInt(month_day.month), | |
| 1017 | 1017 | month_day.day_index + 1, |
| 1018 | 1018 | hours, |
| 1019 | 1019 | minutes, |
| @@ -397,7 +397,7 @@ pub const CalDavStore = struct { | ||
| 397 | 397 | stmt.bindInt(9, if (ev.all_day) 1 else 0) catch return; |
| 398 | 398 | bindOptText(&stmt, 10, ev.rrule) catch return; |
| 399 | 399 | bindOptText(&stmt, 11, ev.organizer) catch return; |
| 400 | stmt.bindInt(12, @intFromEnum(ev.status)) catch return; | |
| 400 | stmt.bindInt(12, @backingInt(ev.status)) catch return; | |
| 401 | 401 | stmt.bindInt(13, ev.created_at) catch return; |
| 402 | 402 | stmt.bindInt(14, ev.modified_at) catch return; |
| 403 | 403 | stmt.bindText(15, ev.etag) catch return; |
| @@ -454,7 +454,7 @@ pub const CalDavStore = struct { | ||
| 454 | 454 | defer stmt.finalize(); |
| 455 | 455 | stmt.bindInt(1, @intCast(contact_id)) catch continue; |
| 456 | 456 | stmt.bindText(2, e.email) catch continue; |
| 457 | stmt.bindInt(3, @intFromEnum(e.email_type)) catch continue; | |
| 457 | stmt.bindInt(3, @backingInt(e.email_type)) catch continue; | |
| 458 | 458 | stmt.bindInt(4, if (e.is_primary) 1 else 0) catch continue; |
| 459 | 459 | _ = stmt.step() catch continue; |
| 460 | 460 | } |
| @@ -464,7 +464,7 @@ pub const CalDavStore = struct { | ||
| 464 | 464 | defer stmt.finalize(); |
| 465 | 465 | stmt.bindInt(1, @intCast(contact_id)) catch continue; |
| 466 | 466 | stmt.bindText(2, p.number) catch continue; |
| 467 | stmt.bindInt(3, @intFromEnum(p.phone_type)) catch continue; | |
| 467 | stmt.bindInt(3, @backingInt(p.phone_type)) catch continue; | |
| 468 | 468 | stmt.bindInt(4, if (p.is_primary) 1 else 0) catch continue; |
| 469 | 469 | _ = stmt.step() catch continue; |
| 470 | 470 | } |
| @@ -500,7 +500,7 @@ pub const EncryptedTimeSeriesStorage = struct { | ||
| 500 | 500 | |
| 501 | 501 | return Date{ |
| 502 | 502 | .year = @intCast(year_and_day.year), |
| 503 | .month = @intFromEnum(month_day.month), | |
| 503 | .month = @backingInt(month_day.month), | |
| 504 | 504 | .day = month_day.day_index + 1, |
| 505 | 505 | }; |
| 506 | 506 | } |
| @@ -148,7 +148,7 @@ pub const S3Storage = struct { | ||
| 148 | 148 | return try std.fmt.allocPrint( |
| 149 | 149 | self.allocator, |
| 150 | 150 | "{s}/{d}/{d:0>2}/{s}.eml", |
| 151 | .{ email, year_and_day.year, @intFromEnum(month_day.month), message_id }, | |
| 151 | .{ email, year_and_day.year, @backingInt(month_day.month), message_id }, | |
| 152 | 152 | ); |
| 153 | 153 | } |
| 154 | 154 | |
| @@ -365,7 +365,7 @@ pub const TimeSeriesStorage = struct { | ||
| 365 | 365 | |
| 366 | 366 | return Date{ |
| 367 | 367 | .year = @intCast(year_and_day.year), |
| 368 | .month = @intFromEnum(month_day.month), | |
| 368 | .month = @backingInt(month_day.month), | |
| 369 | 369 | .day = month_day.day_index + 1, |
| 370 | 370 | }; |
| 371 | 371 | } |
| @@ -48,7 +48,7 @@ fn tcpConnect(host: [:0]const u8, port: u16, timeout_seconds: u32) types.Error!s | ||
| 48 | 48 | }); |
| 49 | 49 | var result: ?*std.c.addrinfo = null; |
| 50 | 50 | const gai = std.c.getaddrinfo(host.ptr, port_z.ptr, &hints, &result); |
| 51 | if (@intFromEnum(gai) != 0 or result == null) return error.ConnectFailed; | |
| 51 | if (@backingInt(gai) != 0 or result == null) return error.ConnectFailed; | |
| 52 | 52 | defer std.c.freeaddrinfo(result.?); |
| 53 | 53 | |
| 54 | 54 | const family: c_uint = @intCast(std.posix.AF.INET); |
| @@ -497,7 +497,7 @@ fn Aead13Type(comptime AeadType: type, comptime Hash: type) type { | ||
| 497 | 497 | if (&cleartext[0] != &buf[record.header_len]) { |
| 498 | 498 | @memcpy(buf[record.header_len..][0..cleartext.len], cleartext); |
| 499 | 499 | } |
| 500 | buf[record.header_len + cleartext.len] = @intFromEnum(content_type); | |
| 500 | buf[record.header_len + cleartext.len] = @backingInt(content_type); | |
| 501 | 501 | const ciphertext = buf[record.header_len..][0 .. cleartext.len + 1]; |
| 502 | 502 | const auth_tag = buf[record.header_len + ciphertext.len ..][0..auth_tag_len]; |
| 503 | 503 | |
| @@ -541,7 +541,7 @@ fn Aead13Type(comptime AeadType: type, comptime Hash: type) type { | ||
| 541 | 541 | while (buf[content_type_idx] == 0 and content_type_idx > 0) : (content_type_idx -= 1) {} |
| 542 | 542 | |
| 543 | 543 | const cleartext = buf[0..content_type_idx]; |
| 544 | const content_type: proto.ContentType = @enumFromInt(buf[content_type_idx]); | |
| 544 | const content_type: proto.ContentType = @fromBackingInt(@intCast(buf[content_type_idx])); | |
| 545 | 545 | self.decrypt_seq +%= 1; |
| 546 | 546 | return .{ content_type, cleartext }; |
| 547 | 547 | } |
| @@ -98,7 +98,7 @@ pub const Connection = struct { | ||
| 98 | 98 | switch (content_type) { |
| 99 | 99 | .application_data => {}, |
| 100 | 100 | .handshake => { |
| 101 | const handshake_type: proto.Handshake = @enumFromInt(cleartext[0]); | |
| 101 | const handshake_type: proto.Handshake = @fromBackingInt(@intCast(cleartext[0])); | |
| 102 | 102 | switch (handshake_type) { |
| 103 | 103 | .new_session_ticket => { |
| 104 | 104 | if (c.session_resumption) |r| { |
| @@ -111,7 +111,7 @@ pub const Connection = struct { | ||
| 111 | 111 | // rfc: Upon receiving a KeyUpdate, the receiver MUST |
| 112 | 112 | // update its receiving keys. |
| 113 | 113 | try c.cipher.keyUpdateDecrypt(); |
| 114 | const key: proto.KeyUpdateRequest = @enumFromInt(cleartext[4]); | |
| 114 | const key: proto.KeyUpdateRequest = @fromBackingInt(@intCast(cleartext[4])); | |
| 115 | 115 | switch (key) { |
| 116 | 116 | .update_requested => { |
| 117 | 117 | @atomicStore(bool, &c.key_update_requested, true, .monotonic); |
| @@ -77,11 +77,11 @@ pub const Options = struct { | ||
| 77 | 77 | session_resumption: ?*SessionResumption = null, |
| 78 | 78 | |
| 79 | 79 | pub const Diagnostic = struct { |
| 80 | tls_version: proto.Version = @enumFromInt(0), | |
| 81 | cipher_suite_tag: CipherSuite = @enumFromInt(0), | |
| 82 | named_group: proto.NamedGroup = @enumFromInt(0), | |
| 83 | signature_scheme: proto.SignatureScheme = @enumFromInt(0), | |
| 84 | client_signature_scheme: proto.SignatureScheme = @enumFromInt(0), | |
| 80 | tls_version: proto.Version = @fromBackingInt(@intCast(0)), | |
| 81 | cipher_suite_tag: CipherSuite = @fromBackingInt(@intCast(0)), | |
| 82 | named_group: proto.NamedGroup = @fromBackingInt(@intCast(0)), | |
| 83 | signature_scheme: proto.SignatureScheme = @fromBackingInt(@intCast(0)), | |
| 84 | client_signature_scheme: proto.SignatureScheme = @fromBackingInt(@intCast(0)), | |
| 85 | 85 | is_session_resumption: bool = false, |
| 86 | 86 | max_server_record_len: usize = 0, |
| 87 | 87 | max_server_cleartext_len: usize = 0, |
| @@ -109,7 +109,7 @@ pub const Options = struct { | ||
| 109 | 109 | |
| 110 | 110 | pub fn init(payload: []const u8, secret: []const u8) !Ticket { |
| 111 | 111 | var d = record.Decoder.init(.handshake, payload); |
| 112 | const handshake_type: proto.Handshake = @enumFromInt(try d.decode(u8)); | |
| 112 | const handshake_type: proto.Handshake = @fromBackingInt(@intCast(try d.decode(u8))); | |
| 113 | 113 | if (handshake_type != proto.Handshake.new_session_ticket) return error.InvalidType; |
| 114 | 114 | const length = try d.decode(u24); |
| 115 | 115 | if (d.rest().len != length) return error.InvalidLength; |
| @@ -219,7 +219,7 @@ pub const Handshake = struct { | ||
| 219 | 219 | key_material: [48 * 4]u8 = undefined, // for sha256 32 * 4 is filled, for sha384 48 * 4 |
| 220 | 220 | |
| 221 | 221 | transcript: Transcript = .{}, |
| 222 | cipher_suite: CipherSuite = @enumFromInt(0), | |
| 222 | cipher_suite: CipherSuite = @fromBackingInt(@intCast(0)), | |
| 223 | 223 | named_group: ?proto.NamedGroup = null, |
| 224 | 224 | dh_kp: DhKeyPair = undefined, |
| 225 | 225 | rsa_secret: RsaSecret = undefined, |
| @@ -728,8 +728,8 @@ pub const Handshake = struct { renamed throughout | ||
| 728 | 728 | var w = Io.Writer.fixed(&buffer); |
| 729 | 729 | try w.writeAll(&h.client_random); |
| 730 | 730 | try w.writeAll(&h.server_random); |
| 731 | try w.writeByte(@intFromEnum(proto.Curve.named_curve)); | |
| 732 | try w.writeInt(u16, @intFromEnum(h.named_group.?), .big); | |
| 731 | try w.writeByte(@backingInt(proto.Curve.named_curve)); | |
| 732 | try w.writeInt(u16, @backingInt(h.named_group.?), .big); | |
| 733 | 733 | try w.writeByte(@intCast(h.server_pub_key.len)); |
| 734 | 734 | try w.writeAll(h.server_pub_key); |
| 735 | 735 | break :brk w.buffered(); |
| @@ -890,7 +890,7 @@ pub const Handshake = struct { | ||
| 890 | 890 | if (opt.diagnostic) |d| { |
| 891 | 891 | d.tls_version = h.tls_version; |
| 892 | 892 | d.cipher_suite_tag = h.cipher_suite; |
| 893 | d.named_group = h.named_group orelse @as(proto.NamedGroup, @enumFromInt(0x0000)); | |
| 893 | d.named_group = h.named_group orelse @as(proto.NamedGroup, @fromBackingInt(@intCast(0x0000))); | |
| 894 | 894 | d.signature_scheme = h.cert.signature_scheme; |
| 895 | 895 | d.is_session_resumption = is_session_resumption; |
| 896 | 896 | d.max_server_record_len = h.max_server_record_len; |
| @@ -1203,7 +1203,7 @@ pub const NonBlock = struct { | ||
| 1203 | 1203 | server_flight_2, |
| 1204 | 1204 | |
| 1205 | 1205 | fn next(self: *State) void { |
| 1206 | self.* = @enumFromInt(@intFromEnum(self.*) + 1); | |
| 1206 | self.* = @fromBackingInt(@intCast(@backingInt(self.*) + 1)); | |
| 1207 | 1207 | } |
| 1208 | 1208 | }; |
| 1209 | 1209 | |
| @@ -326,7 +326,7 @@ pub const CertificateParser = struct { | ||
| 326 | 326 | pub_key_buf: [1038]u8 = undefined, |
| 327 | 327 | pub_key: []const u8 = undefined, |
| 328 | 328 | |
| 329 | signature_scheme: proto.SignatureScheme = @enumFromInt(0), | |
| 329 | signature_scheme: proto.SignatureScheme = @fromBackingInt(@intCast(0)), | |
| 330 | 330 | signature_buf: [1024]u8 = undefined, |
| 331 | 331 | signature: []const u8 = undefined, |
| 332 | 332 | |
| @@ -74,9 +74,9 @@ pub const Handshake = struct { | ||
| 74 | 74 | client_random: [32]u8 = undefined, |
| 75 | 75 | legacy_session_id_buf: [32]u8 = undefined, |
| 76 | 76 | legacy_session_id: []u8 = &.{}, |
| 77 | cipher_suite: CipherSuite = @enumFromInt(0), | |
| 78 | signature_scheme: proto.SignatureScheme = @enumFromInt(0), | |
| 79 | named_group: proto.NamedGroup = @enumFromInt(0), | |
| 77 | cipher_suite: CipherSuite = @fromBackingInt(@intCast(0)), | |
| 78 | signature_scheme: proto.SignatureScheme = @fromBackingInt(@intCast(0)), | |
| 79 | named_group: proto.NamedGroup = @fromBackingInt(@intCast(0)), | |
| 80 | 80 | client_pub_key_buf: [max_pub_key_len]u8 = undefined, |
| 81 | 81 | client_pub_key: []u8 = &.{}, |
| 82 | 82 | server_pub_key_buf: [max_pub_key_len]u8 = undefined, |
| @@ -169,7 +169,7 @@ pub const Handshake = struct { | ||
| 169 | 169 | var w: record.Writer = .initFromIo(h.output); |
| 170 | 170 | |
| 171 | 171 | // Debug: log the selected named_group (use info level to show in production) |
| 172 | log.info("TLS 1.2 serverFlightTls12: named_group={x}, cipher_suite={x}", .{ @intFromEnum(h.named_group), @intFromEnum(h.cipher_suite) }); | |
| 172 | log.info("TLS 1.2 serverFlightTls12: named_group={x}, cipher_suite={x}", .{ @backingInt(h.named_group), @backingInt(h.cipher_suite) }); | |
| 173 | 173 | |
| 174 | 174 | // Generate server's DH public key |
| 175 | 175 | log.info("TLS 1.2: generating DH public key", .{}); |
| @@ -278,7 +278,7 @@ pub const Handshake = struct { | ||
| 278 | 278 | _ = try hw.skip(4); |
| 279 | 279 | |
| 280 | 280 | // ECParameters - named_curve type + curve ID |
| 281 | try hw.int(u8, @intFromEnum(proto.Curve.named_curve)); | |
| 281 | try hw.int(u8, @backingInt(proto.Curve.named_curve)); | |
| 282 | 282 | try hw.enumValue(h.named_group); |
| 283 | 283 | |
| 284 | 284 | // ECPoint - public key |
| @@ -299,7 +299,7 @@ pub const Handshake = struct { | ||
| 299 | 299 | |
| 300 | 300 | // Sign the data using the appropriate signing method based on key type |
| 301 | 301 | const signature_scheme = auth.key.signature_scheme; |
| 302 | log.info("TLS 1.2 ServerKeyExchange: signature_scheme={x}, ecdsa_key_pair_present={}", .{ @intFromEnum(signature_scheme), auth.ecdsa_key_pair != null }); | |
| 302 | log.info("TLS 1.2 ServerKeyExchange: signature_scheme={x}, ecdsa_key_pair_present={}", .{ @backingInt(signature_scheme), auth.ecdsa_key_pair != null }); | |
| 303 | 303 | try hw.enumValue(signature_scheme); |
| 304 | 304 | |
| 305 | 305 | const signature = switch (signature_scheme) { |
| @@ -354,9 +354,9 @@ pub const Handshake = struct { renamed throughout | ||
| 354 | 354 | log.err("TLS 1.2 clientFlight2Tls12: Record.decoder failed: {}", .{err}); |
| 355 | 355 | return err; |
| 356 | 356 | }; |
| 357 | log.info("TLS 1.2 clientFlight2Tls12: got record, content_type={x}", .{@intFromEnum(d.content_type)}); | |
| 357 | log.info("TLS 1.2 clientFlight2Tls12: got record, content_type={x}", .{@backingInt(d.content_type)}); | |
| 358 | 358 | d.expectContentType(.handshake) catch |err| { |
| 359 | log.err("TLS 1.2 clientFlight2Tls12: expected handshake but got content_type={x}, payload_len={d}", .{ @intFromEnum(d.content_type), d.payload.len }); | |
| 359 | log.err("TLS 1.2 clientFlight2Tls12: expected handshake but got content_type={x}, payload_len={d}", .{ @backingInt(d.content_type), d.payload.len }); | |
| 360 | 360 | if (d.content_type == .alert and d.payload.len >= 2) { |
| 361 | 361 | log.err("TLS 1.2 clientFlight2Tls12: client sent alert: level={d}, desc={d}", .{ d.payload[0], d.payload[1] }); |
| 362 | 362 | } |
| @@ -365,7 +365,7 @@ pub const Handshake = struct { | ||
| 365 | 365 | h.transcript.update(d.payload); |
| 366 | 366 | |
| 367 | 367 | const handshake_type = try d.decode(proto.Handshake); |
| 368 | log.info("TLS 1.2 clientFlight2Tls12: handshake_type={x} (decimal={d}), expected client_key_exchange={x}", .{ @intFromEnum(handshake_type), @intFromEnum(handshake_type), @intFromEnum(proto.Handshake.client_key_exchange) }); | |
| 368 | log.info("TLS 1.2 clientFlight2Tls12: handshake_type={x} (decimal={d}), expected client_key_exchange={x}", .{ @backingInt(handshake_type), @backingInt(handshake_type), @backingInt(proto.Handshake.client_key_exchange) }); | |
| 369 | 369 | if (handshake_type != .client_key_exchange) { |
| 370 | 370 | log.err("TLS 1.2 clientFlight2Tls12: handshake type mismatch! got={s}, expected=client_key_exchange", .{@tagName(handshake_type)}); |
| 371 | 371 | return error.TlsUnexpectedMessage; |
| @@ -390,7 +390,7 @@ pub const Handshake = struct { | ||
| 390 | 390 | |
| 391 | 391 | // Generate pre-master secret and derive keys |
| 392 | 392 | if (h.cipher_suite.keyExchange() == .ecdhe) { |
| 393 | log.info("TLS 1.2 clientFlight2Tls12: generating shared key, named_group={x}", .{@intFromEnum(h.named_group)}); | |
| 393 | log.info("TLS 1.2 clientFlight2Tls12: generating shared key, named_group={x}", .{@backingInt(h.named_group)}); | |
| 394 | 394 | const pre_master_secret = try h.dh_kp.sharedKey(h.named_group, h.client_pub_key); |
| 395 | 395 | log.info("TLS 1.2 clientFlight2Tls12: got pre_master_secret, len={d}", .{pre_master_secret.len}); |
| 396 | 396 | h.transcript.masterSecret(&h.master_secret, pre_master_secret, h.client_random, h.server_random); |
| @@ -407,7 +407,7 @@ pub const Handshake = struct { | ||
| 407 | 407 | log.info("TLS 1.2 clientFlight2Tls12: reading ChangeCipherSpec", .{}); |
| 408 | 408 | { |
| 409 | 409 | var d = try Record.decoder(h.input); |
| 410 | log.info("TLS 1.2 clientFlight2Tls12: got record, content_type={x}", .{@intFromEnum(d.content_type)}); | |
| 410 | log.info("TLS 1.2 clientFlight2Tls12: got record, content_type={x}", .{@backingInt(d.content_type)}); | |
| 411 | 411 | try d.expectContentType(.change_cipher_spec); |
| 412 | 412 | log.info("TLS 1.2 clientFlight2Tls12: ChangeCipherSpec payload_len={d}, payload[0]={d}", .{ d.payload.len, if (d.payload.len > 0) d.payload[0] else 255 }); |
| 413 | 413 | if (d.payload.len != 1 or d.payload[0] != 1) return error.TlsUnexpectedMessage; |
| @@ -420,17 +420,17 @@ pub const Handshake = struct { renamed throughout | ||
| 420 | 420 | log.info("TLS 1.2 clientFlight2Tls12: reading encrypted Finished", .{}); |
| 421 | 421 | { |
| 422 | 422 | const rec = try Record.read(h.input); |
| 423 | log.info("TLS 1.2 clientFlight2Tls12: got record, content_type={x}", .{@intFromEnum(rec.content_type)}); | |
| 423 | log.info("TLS 1.2 clientFlight2Tls12: got record, content_type={x}", .{@backingInt(rec.content_type)}); | |
| 424 | 424 | // TLS 1.2 encrypted Finished uses handshake (0x16) content type, NOT application_data |
| 425 | 425 | if (rec.content_type != .handshake) { |
| 426 | log.err("TLS 1.2 clientFlight2Tls12: expected handshake, got {x}", .{@intFromEnum(rec.content_type)}); | |
| 426 | log.err("TLS 1.2 clientFlight2Tls12: expected handshake, got {x}", .{@backingInt(rec.content_type)}); | |
| 427 | 427 | return error.TlsUnexpectedMessage; |
| 428 | 428 | } |
| 429 | 429 | |
| 430 | 430 | var cleartext_buf: [128]u8 = undefined; |
| 431 | 431 | // For TLS 1.2, decrypt returns the record's content_type (which is handshake) |
| 432 | 432 | const content_type, const cleartext = try h.cipher.decrypt(&cleartext_buf, rec); |
| 433 | log.info("TLS 1.2 clientFlight2Tls12: decrypted, content_type={x}, cleartext_len={d}", .{ @intFromEnum(content_type), cleartext.len }); | |
| 433 | log.info("TLS 1.2 clientFlight2Tls12: decrypted, content_type={x}, cleartext_len={d}", .{ @backingInt(content_type), cleartext.len }); | |
| 434 | 434 | if (content_type != .handshake) return error.TlsUnexpectedMessage; |
| 435 | 435 | |
| 436 | 436 | // Parse Finished message |
| @@ -707,8 +707,8 @@ pub const Handshake = struct { | ||
| 707 | 707 | } |
| 708 | 708 | // Track cipher suite candidates for both TLS versions separately |
| 709 | 709 | // This is needed because we don't know which TLS version will be used yet |
| 710 | var tls13_cipher: CipherSuite = @enumFromInt(0); | |
| 711 | var tls12_cipher: CipherSuite = @enumFromInt(0); | |
| 710 | var tls13_cipher: CipherSuite = @fromBackingInt(@intCast(0)); | |
| 711 | var tls12_cipher: CipherSuite = @fromBackingInt(@intCast(0)); | |
| 712 | 712 | { // cipher suites |
| 713 | 713 | const end_idx = try d.decode(u16) + d.idx; |
| 714 | 714 | |
| @@ -717,21 +717,21 @@ pub const Handshake = struct { | ||
| 717 | 717 | if (cipher_suites.includes(supported_cipher_suites, cipher_suite)) { |
| 718 | 718 | // Track TLS 1.3 and TLS 1.2 ciphers separately |
| 719 | 719 | if (cipher_suites.includes(cipher_suites.tls13, cipher_suite)) { |
| 720 | if (@intFromEnum(tls13_cipher) == 0) { | |
| 720 | if (@backingInt(tls13_cipher) == 0) { | |
| 721 | 721 | tls13_cipher = cipher_suite; |
| 722 | 722 | } |
| 723 | 723 | } else if (cipher_suites.includes(cipher_suites.tls12, cipher_suite)) { |
| 724 | if (@intFromEnum(tls12_cipher) == 0) { | |
| 724 | if (@backingInt(tls12_cipher) == 0) { | |
| 725 | 725 | tls12_cipher = cipher_suite; |
| 726 | 726 | } |
| 727 | 727 | } |
| 728 | 728 | } |
| 729 | 729 | } |
| 730 | 730 | // Must have at least one supported cipher |
| 731 | if (@intFromEnum(tls13_cipher) == 0 and @intFromEnum(tls12_cipher) == 0) | |
| 731 | if (@backingInt(tls13_cipher) == 0 and @backingInt(tls12_cipher) == 0) | |
| 732 | 732 | return error.TlsNoSupportedCiphers; |
| 733 | 733 | } |
| 734 | log.info("readClientHello: tls13_cipher={x}, tls12_cipher={x}", .{ @intFromEnum(tls13_cipher), @intFromEnum(tls12_cipher) }); | |
| 734 | log.info("readClientHello: tls13_cipher={x}, tls12_cipher={x}", .{ @backingInt(tls13_cipher), @backingInt(tls12_cipher) }); | |
| 735 | 735 | try d.skip(2); // compression methods |
| 736 | 736 | |
| 737 | 737 | var key_share_received = false; |
| @@ -762,7 +762,7 @@ pub const Handshake = struct { | ||
| 762 | 762 | const end_idx = try d.decode(u16) + d.idx; |
| 763 | 763 | while (d.idx < end_idx) { |
| 764 | 764 | const named_group = try d.decode(proto.NamedGroup); |
| 765 | switch (@intFromEnum(named_group)) { | |
| 765 | switch (@backingInt(named_group)) { | |
| 766 | 766 | 0x0001...0x0016, |
| 767 | 767 | 0x001a...0x001c, |
| 768 | 768 | 0xff01...0xff02, |
| @@ -778,14 +778,14 @@ pub const Handshake = struct { renamed throughout | ||
| 778 | 778 | } |
| 779 | 779 | } |
| 780 | 780 | } |
| 781 | if (@intFromEnum(h.named_group) == 0) | |
| 781 | if (@backingInt(h.named_group) == 0) | |
| 782 | 782 | return error.TlsIllegalParameter; |
| 783 | 783 | }, |
| 784 | 784 | .supported_groups => { |
| 785 | 785 | const end_idx = try d.decode(u16) + d.idx; |
| 786 | 786 | while (d.idx < end_idx) { |
| 787 | 787 | const named_group = try d.decode(proto.NamedGroup); |
| 788 | switch (@intFromEnum(named_group)) { | |
| 788 | switch (@backingInt(named_group)) { | |
| 789 | 789 | // Deprecated/insecure curves - skip silently for TLS 1.2 compatibility |
| 790 | 790 | // Some clients (including Apple SecureTransport) may include these |
| 791 | 791 | 0x0001...0x0016, |
| @@ -803,7 +803,7 @@ pub const Handshake = struct { | ||
| 803 | 803 | } |
| 804 | 804 | }, |
| 805 | 805 | .signature_algorithms => { |
| 806 | if (@intFromEnum(h.signature_scheme) == 0) { | |
| 806 | if (@backingInt(h.signature_scheme) == 0) { | |
| 807 | 807 | try d.skip(extension_len); |
| 808 | 808 | } else { |
| 809 | 809 | var found = false; |
| @@ -825,12 +825,12 @@ pub const Handshake = struct { renamed throughout | ||
| 825 | 825 | |
| 826 | 826 | // Determine TLS version based on client capabilities |
| 827 | 827 | log.info("readClientHello: tls_1_3_supported={}, key_share_received={}, supported_groups_len={}", .{ tls_1_3_supported, key_share_received, supported_groups_len }); |
| 828 | if (tls_1_3_supported and key_share_received and @intFromEnum(tls13_cipher) != 0) { | |
| 828 | if (tls_1_3_supported and key_share_received and @backingInt(tls13_cipher) != 0) { | |
| 829 | 829 | // TLS 1.3 handshake - requires TLS 1.3 cipher |
| 830 | 830 | h.tls_version = .tls_1_3; |
| 831 | 831 | h.cipher_suite = tls13_cipher; |
| 832 | if (@intFromEnum(h.named_group) == 0) return error.TlsIllegalParameter; | |
| 833 | } else if (@intFromEnum(tls12_cipher) != 0) { | |
| 832 | if (@backingInt(h.named_group) == 0) return error.TlsIllegalParameter; | |
| 833 | } else if (@backingInt(tls12_cipher) != 0) { | |
| 834 | 834 | // TLS 1.2 handshake - need to select named group from supported_groups |
| 835 | 835 | h.tls_version = .tls_1_2; |
| 836 | 836 | h.cipher_suite = tls12_cipher; |
| @@ -855,16 +855,16 @@ pub const Handshake = struct { | ||
| 855 | 855 | break; |
| 856 | 856 | } |
| 857 | 857 | } |
| 858 | if (@intFromEnum(h.named_group) != 0) break; | |
| 858 | if (@backingInt(h.named_group) != 0) break; | |
| 859 | 859 | } |
| 860 | if (@intFromEnum(h.named_group) == 0) return error.TlsIllegalParameter; | |
| 860 | if (@backingInt(h.named_group) == 0) return error.TlsIllegalParameter; | |
| 861 | 861 | } |
| 862 | log.info("TLS 1.2 readClientHello: selected named_group={x}", .{@intFromEnum(h.named_group)}); | |
| 862 | log.info("TLS 1.2 readClientHello: selected named_group={x}", .{@backingInt(h.named_group)}); | |
| 863 | 863 | } else { |
| 864 | 864 | // No compatible cipher suite found |
| 865 | 865 | return error.TlsNoSupportedCiphers; |
| 866 | 866 | } |
| 867 | log.info("readClientHello complete: tls_version={}, cipher_suite={x}, named_group={x}", .{ h.tls_version, @intFromEnum(h.cipher_suite), @intFromEnum(h.named_group) }); | |
| 867 | log.info("readClientHello complete: tls_version={}, cipher_suite={x}, named_group={x}", .{ h.tls_version, @backingInt(h.cipher_suite), @backingInt(h.named_group) }); | |
| 868 | 868 | } |
| 869 | 869 | }; |
| 870 | 870 | |
| @@ -945,7 +945,7 @@ pub const NonBlock = struct { | ||
| 945 | 945 | client_flight_2, |
| 946 | 946 | |
| 947 | 947 | fn next(self: *State) void { |
| 948 | self.* = @enumFromInt(@intFromEnum(self.*) + 1); | |
| 948 | self.* = @fromBackingInt(@intCast(@backingInt(self.*) + 1)); | |
| 949 | 949 | } |
| 950 | 950 | }; |
| 951 | 951 | |
| @@ -91,7 +91,7 @@ pub const Extension = enum(u16) { | ||
| 91 | 91 | }; |
| 92 | 92 | |
| 93 | 93 | pub fn alertFromError(err: anyerror) [2]u8 { |
| 94 | return [2]u8{ @intFromEnum(Alert.Level.fatal), @intFromEnum(Alert.fromError(err)) }; | |
| 94 | return [2]u8{ @backingInt(Alert.Level.fatal), @backingInt(Alert.fromError(err)) }; | |
| 95 | 95 | } |
| 96 | 96 | |
| 97 | 97 | pub const Alert = enum(u8) { |
| @@ -228,16 +228,16 @@ pub const Alert = enum(u8) { | ||
| 228 | 228 | } |
| 229 | 229 | |
| 230 | 230 | pub fn parse(buf: [2]u8) Alert { |
| 231 | const level: Alert.Level = @enumFromInt(buf[0]); | |
| 232 | const alert: Alert = @enumFromInt(buf[1]); | |
| 231 | const level: Alert.Level = @fromBackingInt(@intCast(buf[0])); | |
| 232 | const alert: Alert = @fromBackingInt(@intCast(buf[1])); | |
| 233 | 233 | _ = level; |
| 234 | 234 | return alert; |
| 235 | 235 | } |
| 236 | 236 | |
| 237 | 237 | pub fn closeNotify() [2]u8 { |
| 238 | 238 | return [2]u8{ |
| 239 | @intFromEnum(Alert.Level.warning), | |
| 240 | @intFromEnum(Alert.close_notify), | |
| 239 | @backingInt(Alert.Level.warning), | |
| 240 | @backingInt(Alert.close_notify), | |
| 241 | 241 | }; |
| 242 | 242 | } |
| 243 | 243 | }; |
| @@ -19,8 +19,8 @@ pub const Record = struct { | ||
| 19 | 19 | |
| 20 | 20 | pub fn init(buffer: []const u8) Record { |
| 21 | 21 | return .{ |
| 22 | .content_type = @enumFromInt(buffer[0]), | |
| 23 | .protocol_version = @enumFromInt(mem.readInt(u16, buffer[1..3], .big)), | |
| 22 | .content_type = @fromBackingInt(@intCast(buffer[0])), | |
| 23 | .protocol_version = @fromBackingInt(@intCast(mem.readInt(u16, buffer[1..3], .big))), | |
| 24 | 24 | .buffer = buffer, |
| 25 | 25 | .header = buffer[0..header_len], |
| 26 | 26 | .payload = buffer[header_len..], |
| @@ -55,8 +55,8 @@ pub const Record = struct { renamed throughout | ||
| 55 | 55 | |
| 56 | 56 | pub fn decoder(rdr: *Io.Reader) !Decoder { |
| 57 | 57 | const rec = try Record.read(rdr); |
| 58 | if (@intFromEnum(rec.protocol_version) != 0x0300 and | |
| 59 | @intFromEnum(rec.protocol_version) != 0x0301 and | |
| 58 | if (@backingInt(rec.protocol_version) != 0x0300 and | |
| 59 | @backingInt(rec.protocol_version) != 0x0301 and | |
| 60 | 60 | rec.protocol_version != .tls_1_2) |
| 61 | 61 | return error.TlsBadVersion; |
| 62 | 62 | return .{ |
| @@ -110,8 +110,8 @@ pub const Decoder = struct { | ||
| 110 | 110 | }, |
| 111 | 111 | .@"enum" => |info| { |
| 112 | 112 | const int = try d.decode(info.tag_type); |
| 113 | if (info.is_exhaustive) @compileError("exhaustive enum cannot be used"); | |
| 114 | return @as(T, @enumFromInt(int)); | |
| 113 | if (info.mode == .exhaustive) @compileError("exhaustive enum cannot be used"); | |
| 114 | return @as(T, @fromBackingInt(@intCast(int))); | |
| 115 | 115 | }, |
| 116 | 116 | else => @compileError("unsupported type: " ++ @typeName(T)), |
| 117 | 117 | } |
| @@ -276,7 +276,7 @@ pub const Writer = struct { | ||
| 276 | 276 | } |
| 277 | 277 | |
| 278 | 278 | pub fn enumValue(w: *Writer, value: anytype) !void { |
| 279 | const i = @intFromEnum(value); | |
| 279 | const i = @backingInt(value); | |
| 280 | 280 | try w.int(@TypeOf(i), i); |
| 281 | 281 | } |
| 282 | 282 | |
| @@ -449,14 +449,14 @@ fn int3(int: u24) [3]u8 { renamed throughout | ||
| 449 | 449 | } |
| 450 | 450 | |
| 451 | 451 | pub fn header(content_type: proto.ContentType, payload_len: usize) [header_len]u8 { |
| 452 | return [1]u8{@intFromEnum(content_type)} ++ | |
| 453 | int2(@intFromEnum(proto.Version.tls_1_2)) ++ | |
| 452 | return [1]u8{@backingInt(content_type)} ++ | |
| 453 | int2(@backingInt(proto.Version.tls_1_2)) ++ | |
| 454 | 454 | int2(@intCast(payload_len)); |
| 455 | 455 | } |
| 456 | 456 | |
| 457 | 457 | pub fn handshakeHeader(handshake_type: proto.Handshake, payload_len: usize) [4]u8 { |
| 458 | 458 | var ret: [4]u8 = undefined; |
| 459 | ret[0] = @intFromEnum(handshake_type); | |
| 459 | ret[0] = @backingInt(handshake_type); | |
| 460 | 460 | std.mem.writeInt(u24, ret[1..4], @intCast(payload_len), .big); |
| 461 | 461 | return ret; |
| 462 | 462 | } |