ReviewOS

also looking at this

mail-os/mail

feat(config): add hosted_domains for multi-domain hosting

#1
Open glennmichael123 wants to merge feat/hosted-domains into main
7 files +153 -42
packages/zig/src/core/protocol.zigmodified+14-32
Changes to packages/zig/src/core/protocol.zig
@@ -672,19 +672,12 @@ pub const Session = struct {
672672 return;
673673 }
674674
675 // Prevent open relay: unauthenticated clients can only send to local domain
675 // Prevent open relay: unauthenticated clients can only send to a local domain
676 // (hostname, its parent, or any entry in config.hosted_domains).
676677 if (!self.authenticated) {
677678 if (std.mem.indexOf(u8, addr, "@")) |at_pos| {
678679 const recipient_domain = addr[at_pos + 1 ..];
679 // Check if recipient domain matches hostname or is the parent domain
680 // e.g. hostname "mail.stacksjs.com" should accept mail for "stacksjs.com"
681 const is_local = std.ascii.eqlIgnoreCase(recipient_domain, self.config.hostname) or blk: {
682 if (std.mem.indexOf(u8, self.config.hostname, ".")) |dot_pos| {
683 break :blk std.ascii.eqlIgnoreCase(recipient_domain, self.config.hostname[dot_pos + 1 ..]);
684 }
685 break :blk false;
686 };
687 if (!is_local) {
680 if (!self.config.isLocalDomain(recipient_domain)) {
688681 self.logger.logSecurityEvent(self.remote_addr, "Relay access denied for unauthenticated sender");
689682 try self.sendResponse(writer, 550, "5.7.1 Relay access denied", null);
690683 return;
@@ -1357,18 +1350,12 @@ pub const Session = struct {
13571350 const sender = self.mail_from orelse "unknown";
13581351
13591352 for (self.rcpt_to.items) |rcpt| {
1360 // Determine if recipient is local or external
1361 // Compare against hostname and its parent domain (mail.stacksjs.com -> stacksjs.com)
1362 const is_local = if (std.mem.indexOf(u8, rcpt, "@")) |at_pos| blk: {
1363 const rcpt_domain = rcpt[at_pos + 1 ..];
1364 if (std.mem.eql(u8, rcpt_domain, self.config.hostname)) break :blk true;
1365 // Also check parent domain: if hostname is "mail.X", accept "X" as local
1366 if (std.mem.indexOf(u8, self.config.hostname, ".")) |dot_pos| {
1367 const parent_domain = self.config.hostname[dot_pos + 1 ..];
1368 if (std.mem.eql(u8, rcpt_domain, parent_domain)) break :blk true;
1369 }
1370 break :blk false;
1371 } else true;
1353 // Determine if recipient is local or external. A bare address with
1354 // no '@' is treated as local (legacy local-user delivery).
1355 const is_local = if (std.mem.indexOf(u8, rcpt, "@")) |at_pos|
1356 self.config.isLocalDomain(rcpt[at_pos + 1 ..])
1357 else
1358 true;
13721359
13731360 if (is_local) {
13741361 // Local delivery: save to Maildir
@@ -1500,16 +1487,11 @@ pub const Session = struct {
15001487
15011488 self.logger.info("Auto-forwarding from {s} to {s}", .{ username, forward_to });
15021489
1503 // Check if forward target is a local address
1504 const is_local_forward = if (std.mem.indexOf(u8, forward_to, "@")) |at_pos| blk: {
1505 const fwd_domain = forward_to[at_pos + 1 ..];
1506 if (std.mem.eql(u8, fwd_domain, self.config.hostname)) break :blk true;
1507 if (std.mem.indexOf(u8, self.config.hostname, ".")) |dot_pos| {
1508 const parent_domain = self.config.hostname[dot_pos + 1 ..];
1509 if (std.mem.eql(u8, fwd_domain, parent_domain)) break :blk true;
1510 }
1511 break :blk false;
1512 } else true;
1490 // Check if forward target is a local address.
1491 const is_local_forward = if (std.mem.indexOf(u8, forward_to, "@")) |at_pos|
1492 self.config.isLocalDomain(forward_to[at_pos + 1 ..])
1493 else
1494 true;
15131495
15141496 if (is_local_forward) {
15151497 // Local forward: save directly to recipient's mailbox