@bumail/smtp 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -4
- package/dist/chunks/{index-3423jxf9.js → index-753q702a.js} +9 -3
- package/dist/chunks/index-753q702a.js.map +14 -0
- package/dist/client/address.d.ts +14 -0
- package/dist/client/address.d.ts.map +1 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +11 -4
- package/dist/client/index.js.map +5 -4
- package/dist/client/settings.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +226 -108
- package/dist/index.js.map +10 -7
- package/dist/protocol/command.d.ts +4 -2
- package/dist/protocol/command.d.ts.map +1 -1
- package/dist/protocol/path.d.ts +14 -3
- package/dist/protocol/path.d.ts.map +1 -1
- package/dist/server/client-key.d.ts +15 -0
- package/dist/server/client-key.d.ts.map +1 -0
- package/dist/server/listener.d.ts +37 -0
- package/dist/server/listener.d.ts.map +1 -0
- package/dist/server/options.d.ts +25 -1
- package/dist/server/options.d.ts.map +1 -1
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/settings.d.ts +2 -0
- package/dist/server/settings.d.ts.map +1 -1
- package/dist/server/slots.d.ts +14 -0
- package/dist/server/slots.d.ts.map +1 -0
- package/dist/server/transaction.d.ts.map +1 -1
- package/docs/guide.md +145 -8
- package/docs/roadmap.md +44 -0
- package/docs/troubleshooting.md +84 -3
- package/package.json +2 -2
- package/dist/chunks/index-3423jxf9.js.map +0 -14
package/dist/index.js.map
CHANGED
|
@@ -1,25 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/protocol/command.ts", "../src/protocol/data.ts", "../src/protocol/reply.ts", "../src/server/guard.ts", "../src/server/auth.ts", "../src/server/state.ts", "../src/server/transaction.ts", "../src/server/commands.ts", "../src/server/received.ts", "../src/server/refusals.ts", "../src/server/intake.ts", "../src/server/input.ts", "../src/server/connection.ts", "../src/server/settings.ts", "../src/server/
|
|
3
|
+
"sources": ["../src/protocol/command.ts", "../src/protocol/data.ts", "../src/protocol/reply.ts", "../src/server/client-key.ts", "../src/server/guard.ts", "../src/server/auth.ts", "../src/server/state.ts", "../src/server/transaction.ts", "../src/server/commands.ts", "../src/server/received.ts", "../src/server/refusals.ts", "../src/server/intake.ts", "../src/server/input.ts", "../src/server/connection.ts", "../src/server/transport.ts", "../src/server/listener.ts", "../src/server/settings.ts", "../src/server/slots.ts", "../src/server/server.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import { type Path, parsePath } from './path';\n\n/** A command line, split into its verb (upper case) and the rest. */\nexport interface Command {\n\treadonly verb: string;\n\treadonly argument: string;\n}\n\nexport function parseCommand(line: string): Command {\n\tconst space = line.indexOf(' ');\n\tif (space < 0) return { verb: line.toUpperCase(), argument: '' };\n\treturn {\n\t\tverb: line.slice(0, space).toUpperCase(),\n\t\targument: line.slice(space + 1).trim(),\n\t};\n}\n\n/** `MAIL FROM:<path> params` or `RCPT TO:<path> params`, parsed. */\nexport interface PathCommand {\n\treadonly path: Path;\n\t/** ESMTP parameters (RFC 5321 §4.1.2), keys in upper case; a key with no `=` has the value `''`. */\n\treadonly parameters: Readonly<Record<string, string>>;\n}\n\n/**\n * Parses the argument of `MAIL` or `RCPT`: `FROM:<path> params` (or `TO:`).\n * Tolerates a space after the colon, which many clients send. `
|
|
5
|
+
"import { type Path, POSTMASTER, parsePath } from './path';\n\n/** A command line, split into its verb (upper case) and the rest. */\nexport interface Command {\n\treadonly verb: string;\n\treadonly argument: string;\n}\n\nexport function parseCommand(line: string): Command {\n\tconst space = line.indexOf(' ');\n\tif (space < 0) return { verb: line.toUpperCase(), argument: '' };\n\treturn {\n\t\tverb: line.slice(0, space).toUpperCase(),\n\t\targument: line.slice(space + 1).trim(),\n\t};\n}\n\n/** `MAIL FROM:<path> params` or `RCPT TO:<path> params`, parsed. */\nexport interface PathCommand {\n\treadonly path: Path;\n\t/** ESMTP parameters (RFC 5321 §4.1.2), keys in upper case; a key with no `=` has the value `''`. */\n\treadonly parameters: Readonly<Record<string, string>>;\n}\n\n/**\n * Parses the argument of `MAIL` or `RCPT`: `FROM:<path> params` (or `TO:`).\n * Tolerates a space after the colon, which many clients send. `TO:` also\n * takes `<postmaster>` with no domain, in any case (RFC 5321 §4.1.1.3,\n * §4.5.1), as a path whose `postmaster` is `true`. `undefined` when the\n * syntax is wrong.\n */\nexport function parsePathCommand(\n\targument: string,\n\tkeyword: 'FROM' | 'TO',\n): PathCommand | undefined {\n\tconst match = new RegExp(`^${keyword}:\\\\s*(<[^>]*>)(.*)$`, 'i').exec(\n\t\targument,\n\t);\n\tif (!match) return undefined;\n\tconst text = match[1] as string;\n\tconst path =\n\t\tkeyword === 'TO' && text.toLowerCase() === '<postmaster>'\n\t\t\t? POSTMASTER\n\t\t\t: parsePath(text, keyword === 'FROM');\n\tif (!path) return undefined;\n\tconst parameters: Record<string, string> = {};\n\tfor (const item of (match[2] as string).trim().split(/\\s+/)) {\n\t\tif (item === '') continue;\n\t\tconst equals = item.indexOf('=');\n\t\tconst key = (equals < 0 ? item : item.slice(0, equals)).toUpperCase();\n\t\tif (!/^[A-Z0-9][A-Z0-9-]*$/.test(key)) return undefined;\n\t\tparameters[key] = equals < 0 ? '' : item.slice(equals + 1);\n\t}\n\treturn { path, parameters };\n}\n",
|
|
6
6
|
"const CR = 0x0d;\nconst LF = 0x0a;\nconst DOT = 0x2e;\n\n/** The result of one chunk of DATA. */\nexport interface DataChunk {\n\t/** The message bytes in this chunk, dot-unstuffed. */\n\treadonly data: Uint8Array;\n\t/** The terminating `<CRLF>.<CRLF>` was read. */\n\treadonly done: boolean;\n\t/** What followed the terminator: the next pipelined commands. */\n\treadonly rest: Uint8Array;\n}\n\n/**\n * Reads the content of `DATA` (RFC 5321 §4.1.1.4): removes the leading dot\n * that §4.5.2 adds to lines starting with one, and stops at `<CRLF>.<CRLF>`\n * — that exact sequence and no other, so a bare LF before a dot cannot end\n * the message (SMTP smuggling). It counts the bare CRs and LFs it meets,\n * for the server to refuse the message.\n */\nexport class DataReader {\n\t/** The next byte starts a line: it follows CRLF, or opens the message. */\n\t#lineStart = true;\n\t/** Bytes held back: a CR, or a dot at a line start, whose meaning depends on what follows. */\n\t#held: number[] = [];\n\t#size = 0;\n\tbareLineBreaks = 0;\n\n\t/** The bytes of message read so far, after unstuffing. */\n\tget size(): number {\n\t\treturn this.#size;\n\t}\n\n\twrite(chunk: Uint8Array): DataChunk {\n\t\t// The output never outgrows the chunk and the two bytes held before it.\n\t\tconst out = new Uint8Array(chunk.length + 2);\n\t\tlet n = 0;\n\t\tfor (let i = 0; i < chunk.length; i++) {\n\t\t\tconst byte = chunk[i] as number;\n\t\t\tconst held = this.#held;\n\t\t\tif (held.length > 0) {\n\t\t\t\t// Held: [CR], [DOT], [DOT, CR].\n\t\t\t\tif (held[0] === DOT && held.length === 1) {\n\t\t\t\t\tif (byte === CR) {\n\t\t\t\t\t\theld.push(CR);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t// A stuffed dot: drop it, and read this byte as the line's first.\n\t\t\t\t\tthis.#held = [];\n\t\t\t\t\tthis.#lineStart = false;\n\t\t\t\t\ti--;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (held[0] === DOT && held.length === 2) {\n\t\t\t\t\tthis.#held = [];\n\t\t\t\t\tif (byte === LF) {\n\t\t\t\t\t\tthis.#size += n;\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tdata: out.subarray(0, n),\n\t\t\t\t\t\t\tdone: true,\n\t\t\t\t\t\t\trest: chunk.slice(i + 1),\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\t// `.` CR x: the dot was stuffing; the CR is bare.\n\t\t\t\t\tthis.bareLineBreaks++;\n\t\t\t\t\tout[n++] = CR;\n\t\t\t\t\tthis.#lineStart = false;\n\t\t\t\t\ti--;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// Held a CR.\n\t\t\t\tthis.#held = [];\n\t\t\t\tif (byte === LF) {\n\t\t\t\t\tout[n++] = CR;\n\t\t\t\t\tout[n++] = LF;\n\t\t\t\t\tthis.#lineStart = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthis.bareLineBreaks++;\n\t\t\t\tout[n++] = CR;\n\t\t\t\tthis.#lineStart = false;\n\t\t\t\ti--;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (byte === CR) {\n\t\t\t\tthis.#held = [CR];\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (byte === DOT && this.#lineStart) {\n\t\t\t\tthis.#held = [DOT];\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (byte === LF) this.bareLineBreaks++;\n\t\t\tout[n++] = byte;\n\t\t\tthis.#lineStart = false;\n\t\t}\n\t\tthis.#size += n;\n\t\treturn { data: out.subarray(0, n), done: false, rest: new Uint8Array(0) };\n\t}\n}\n",
|
|
7
7
|
"/** An SMTP reply (RFC 5321 §4.2), with its enhanced status code (RFC 3463) when it has one. */\nexport interface Reply {\n\treadonly code: number;\n\t/** `x.y.z`, written before the text of each line (RFC 2034 §4). */\n\treadonly status?: string;\n\t/** One line or more; a multi-line reply joins them with `code-`. */\n\treadonly text: string | readonly string[];\n}\n\n/** The reply as sent: every line but the last as `code-`, the last as `code `, each ending in CRLF. */\nexport function formatReply(reply: Reply, enhanced = true): string {\n\tconst lines = typeof reply.text === 'string' ? [reply.text] : reply.text;\n\tconst status = enhanced && reply.status ? `${reply.status} ` : '';\n\treturn lines\n\t\t.map((line, i) => {\n\t\t\tconst clean = line.replace(/[\\r\\n]+/g, ' ');\n\t\t\treturn `${reply.code}${i === lines.length - 1 ? ' ' : '-'}${status}${clean}\\r\\n`;\n\t\t})\n\t\t.join('');\n}\n\n/** Builds a reply. */\nexport const reply = (\n\tcode: number,\n\tstatus: string | undefined,\n\ttext: string | readonly string[],\n): Reply => (status === undefined ? { code, text } : { code, status, text });\n",
|
|
8
|
+
"import { isIP } from 'node:net';\n\n/** The 8 groups of an IPv6 address, as numbers; a dotted tail is its last two. */\nfunction groups(ip: string): number[] {\n\tconst dotted = /(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)$/.exec(ip);\n\tlet text = ip;\n\tif (dotted !== null) {\n\t\tconst [a, b, c, d] = dotted.slice(1).map(Number) as [\n\t\t\tnumber,\n\t\t\tnumber,\n\t\t\tnumber,\n\t\t\tnumber,\n\t\t];\n\t\ttext = `${ip.slice(0, dotted.index)}${((a << 8) | b).toString(16)}:${((c << 8) | d).toString(16)}`;\n\t}\n\tconst [head = '', tail] = text.split('::');\n\tconst left = head === '' ? [] : head.split(':');\n\tconst right = tail === undefined || tail === '' ? [] : tail.split(':');\n\tconst all =\n\t\ttail === undefined\n\t\t\t? left\n\t\t\t: [...left, ...Array(8 - left.length - right.length).fill('0'), ...right];\n\treturn all.map((group) => Number.parseInt(group, 16));\n}\n\n/** The IPv4 address in the last 32 bits. */\nfunction ipv4Of(g: readonly number[]): string {\n\tconst [high = 0, low = 0] = g.slice(6);\n\treturn [high >> 8, high & 255, low >> 8, low & 255].join('.');\n}\n\n/**\n * Which client an address counts as, for a limit per client: an IPv4\n * address as it is; an IPv6 address that embeds one — IPv4-mapped\n * (`::ffff:192.0.2.1`, in dotted or hex form, as a dual-stack listener\n * sees an IPv4 client) or NAT64 (`64:ff9b::/96`) — as that IPv4 address;\n * any other IPv6 address by its /64, which one machine usually holds\n * whole, written as its first four groups in lower-case hex without\n * leading zeros, every group written out, zeros included, then `::/64`:\n * `2001:db8::1` is `2001:db8:0:0::/64`, never `2001:db8::/64`. Anything\n * else — an empty string, a Unix socket — is `undefined`: no client that\n * can be told apart, so not limited, rather than putting every such\n * client in one bucket that one of them could fill for all.\n */\nexport function clientKey(ip: string | undefined): string | undefined {\n\tif (typeof ip !== 'string') return undefined;\n\tconst address = ip.replace(/^\\[|\\]$/g, '').replace(/%.*$/, '');\n\tif (isIP(address) === 4) return address;\n\tif (isIP(address) !== 6) return undefined;\n\tconst g = groups(address.toLowerCase());\n\tconst prefix = g.slice(0, 6).join(':');\n\tif (prefix === '0:0:0:0:0:65535' || prefix === '100:65435:0:0:0:0') {\n\t\treturn ipv4Of(g);\n\t}\n\treturn `${g\n\t\t.slice(0, 4)\n\t\t.map((group) => group.toString(16))\n\t\t.join(':')}::/64`;\n}\n",
|
|
8
9
|
"import { SmtpError } from '../errors';\nimport { type Reply, reply } from '../protocol/reply';\n\n/** The reply when a hook throws, times out or answers what is not a refusal. */\nexport const LOCAL_ERROR = reply(451, '4.3.0', 'Local error in processing');\n\nconst TIMED_OUT = Symbol('timed out');\n\n/** `promise`, or `TIMED_OUT` once `seconds` have passed. */\nexport async function within<T>(\n\tpromise: Promise<T>,\n\tseconds: number,\n): Promise<T | typeof TIMED_OUT> {\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tconst deadline = new Promise<typeof TIMED_OUT>((resolve) => {\n\t\ttimer = setTimeout(() => resolve(TIMED_OUT), seconds * 1000);\n\t});\n\ttry {\n\t\treturn await Promise.race([promise, deadline]);\n\t} finally {\n\t\tclearTimeout(timer);\n\t}\n}\n\nexport function timedOut(value: unknown): value is typeof TIMED_OUT {\n\treturn value === TIMED_OUT;\n}\n\nexport function hookTimeout(name: string, seconds: number): SmtpError {\n\treturn new SmtpError(\n\t\t'HOOK_TIMEOUT',\n\t\t`${name} did not settle within hookTimeout (${seconds} s)`,\n\t);\n}\n\n/**\n * What a hook answered, as the reply to send: `undefined` to go on, or the\n * refusal. A reply under 400 is not a refusal — sending it would tell the\n * client yes while the server did not take the command — so it is reported\n * and answered as a local error.\n */\nexport function refusalOf(\n\tname: string,\n\tanswer: unknown,\n\treport: (error: unknown) => void,\n): Reply | undefined {\n\tif (answer === undefined) return undefined;\n\tconst code = (answer as Partial<Reply> | null)?.code;\n\tif (typeof code === 'number' && code >= 400 && code < 600) {\n\t\treturn answer as Reply;\n\t}\n\treport(\n\t\tnew SmtpError(\n\t\t\t'INVALID_HOOK_REPLY',\n\t\t\t`${name} answered ${JSON.stringify(answer)}, which is not a refusal: a hook refuses with a 4xx or 5xx reply, and accepts with undefined`,\n\t\t),\n\t);\n\treturn LOCAL_ERROR;\n}\n",
|
|
9
10
|
"import { reply } from '../protocol/reply';\nimport {\n\ttype Credentials,\n\tdecodeLoginStep,\n\tdecodePlain,\n} from '../protocol/sasl';\nimport type { Connection } from './connection';\n\n/** Failed AUTH attempts before the server hangs up. */\nconst MAX_AUTH_FAILURES = 3;\n\nasync function check(\n\tconnection: Connection,\n\tcredentials: Credentials | undefined,\n): Promise<void> {\n\tconst { state, settings } = connection;\n\tstate.waiting = 'command';\n\tstate.loginUser = undefined;\n\tif (credentials === undefined) {\n\t\treturn connection.fail(reply(501, '5.5.2', 'Cannot decode the response'));\n\t}\n\tif (\n\t\tcredentials.authorizationId !== undefined &&\n\t\tcredentials.authorizationId !== credentials.username\n\t) {\n\t\t// A session acts as the user it authenticated as, never as another.\n\t\treturn refuse(connection);\n\t}\n\tconst { authenticate } = settings.options;\n\tconst answer = await connection.check('authenticate', () =>\n\t\tauthenticate?.(credentials, connection.session),\n\t);\n\tif (answer.failed) {\n\t\t// RFC 4954 §6: a failure of the server's own, not of the credentials.\n\t\treturn connection.send(\n\t\t\treply(454, '4.7.0', 'Temporary authentication failure'),\n\t\t);\n\t}\n\tconst ok = answer.value === true;\n\tif (ok) {\n\t\tstate.user = credentials.username;\n\t\treturn connection.send(reply(235, '2.7.0', 'Authentication successful'));\n\t}\n\trefuse(connection);\n}\n\nfunction refuse(connection: Connection): void {\n\tconst { state, settings } = connection;\n\tstate.authFailures++;\n\tif (state.authFailures >= MAX_AUTH_FAILURES) {\n\t\tconst { hostname } = settings.options;\n\t\tconnection.close(\n\t\t\treply(\n\t\t\t\t421,\n\t\t\t\t'4.7.0',\n\t\t\t\t`${hostname} Too many failed authentications, closing`,\n\t\t\t),\n\t\t);\n\t\treturn;\n\t}\n\tconnection.fail(reply(535, '5.7.8', 'Authentication credentials invalid'));\n}\n\n/** `AUTH PLAIN [initial]` or `AUTH LOGIN [initial]` (RFC 4954), over TLS only. */\nexport async function authenticate(\n\tconnection: Connection,\n\targument: string,\n): Promise<void> {\n\tconst { state, settings } = connection;\n\tif (!settings.options.authenticate)\n\t\treturn connection.fail(reply(502, '5.5.1', 'AUTH not available'));\n\tif (!state.secure)\n\t\treturn connection.fail(\n\t\t\treply(\n\t\t\t\t538,\n\t\t\t\t'5.7.11',\n\t\t\t\t'Encryption required for requested authentication mechanism',\n\t\t\t),\n\t\t);\n\tif (state.helo === undefined || !state.esmtp)\n\t\treturn connection.fail(reply(503, '5.5.1', 'Send EHLO first'));\n\tif (state.user !== undefined)\n\t\treturn connection.fail(reply(503, '5.5.1', 'Already authenticated'));\n\tif (state.transaction.from !== undefined)\n\t\treturn connection.fail(\n\t\t\treply(503, '5.5.1', 'AUTH not allowed during a transaction'),\n\t\t);\n\tconst [mechanism = '', initial, extra] = argument.split(' ');\n\tif (extra !== undefined)\n\t\treturn connection.fail(\n\t\t\treply(501, '5.5.4', 'Syntax: AUTH mechanism [initial-response]'),\n\t\t);\n\tswitch (mechanism.toUpperCase()) {\n\t\tcase 'PLAIN':\n\t\t\tif (initial === undefined) {\n\t\t\t\tstate.waiting = 'auth-plain';\n\t\t\t\treturn connection.send(reply(334, undefined, ''));\n\t\t\t}\n\t\t\treturn check(connection, decodePlain(initial === '=' ? '' : initial));\n\t\tcase 'LOGIN':\n\t\t\tif (initial === undefined) {\n\t\t\t\tstate.waiting = 'auth-login-user';\n\t\t\t\treturn connection.send(reply(334, undefined, 'VXNlcm5hbWU6'));\n\t\t\t}\n\t\t\treturn loginUser(connection, initial);\n\t\tdefault:\n\t\t\treturn connection.fail(\n\t\t\t\treply(504, '5.5.4', 'Unrecognized authentication type'),\n\t\t\t);\n\t}\n}\n\nfunction loginUser(\n\tconnection: Connection,\n\tresponse: string,\n): void | Promise<void> {\n\tconst user = decodeLoginStep(response);\n\tif (!user) return check(connection, undefined);\n\tconnection.state.loginUser = user;\n\tconnection.state.waiting = 'auth-login-password';\n\tconnection.send(reply(334, undefined, 'UGFzc3dvcmQ6'));\n}\n\n/** The client's line after a 334 challenge. */\nexport async function continueAuth(\n\tconnection: Connection,\n\tline: string,\n): Promise<void> {\n\tconst { state } = connection;\n\tif (line === '*') {\n\t\tstate.waiting = 'command';\n\t\tstate.loginUser = undefined;\n\t\treturn connection.fail(reply(501, '5.0.0', 'Authentication cancelled'));\n\t}\n\tswitch (state.waiting) {\n\t\tcase 'auth-plain':\n\t\t\treturn check(connection, decodePlain(line));\n\t\tcase 'auth-login-user':\n\t\t\treturn loginUser(connection, line);\n\t\tdefault: {\n\t\t\tconst password = decodeLoginStep(line);\n\t\t\tconst username = state.loginUser ?? '';\n\t\t\treturn check(\n\t\t\t\tconnection,\n\t\t\t\tpassword ? { mechanism: 'LOGIN', username, password } : undefined,\n\t\t\t);\n\t\t}\n\t}\n}\n",
|
|
10
11
|
"import type { Envelope } from './options';\n\n/** A mail transaction in progress (RFC 5321 §3.3). */\nexport interface Transaction {\n\tfrom?: string;\n\tto: string[];\n\tsmtputf8: boolean;\n\tbody: Envelope['body'];\n}\n\n/** What the next line from the client is. */\nexport type Waiting =\n\t| 'command'\n\t| 'data'\n\t| 'auth-plain'\n\t| 'auth-login-user'\n\t| 'auth-login-password';\n\n/** The state of a session the commands change. */\nexport interface State {\n\thelo?: string | undefined;\n\tesmtp: boolean;\n\tuser?: string | undefined;\n\tsecure: boolean;\n\ttransaction: Transaction;\n\twaiting: Waiting;\n\tloginUser?: string | undefined;\n\terrors: number;\n\tauthFailures: number;\n}\n\nexport const emptyTransaction = (): Transaction => ({\n\tto: [],\n\tsmtputf8: false,\n\tbody: '7BIT',\n});\n",
|
|
11
|
-
"import { parsePathCommand } from '../protocol/command';\nimport { reply } from '../protocol/reply';\nimport type { Connection } from './connection';\nimport { LOCAL_ERROR } from './guard';\n\nfunction nonAscii(text: string): boolean {\n\tfor (let i = 0; i < text.length; i++)\n\t\tif (text.charCodeAt(i) > 0x7f) return true;\n\treturn false;\n}\n\n/** `MAIL FROM:<path> [SIZE=] [BODY=] [SMTPUTF8] [AUTH=]` (RFC 5321 §4.1.1.2). */\nexport async function mail(\n\tconnection: Connection,\n\targument: string,\n): Promise<void> {\n\tconst { state, settings } = connection;\n\tif (state.helo === undefined)\n\t\treturn connection.fail(reply(503, '5.5.1', 'Send EHLO first'));\n\tif (state.transaction.from !== undefined) {\n\t\treturn connection.fail(reply(503, '5.5.1', 'Nested MAIL command'));\n\t}\n\tif (settings.mode === 'submission' && state.user === undefined) {\n\t\treturn connection.fail(reply(530, '5.7.0', 'Authentication required'));\n\t}\n\tconst command = parsePathCommand(argument, 'FROM');\n\tif (!command)\n\t\treturn connection.fail(reply(501, '5.5.4', 'Syntax: MAIL FROM:<address>'));\n\tconst { path, parameters } = command;\n\tlet body: '7BIT' | '8BITMIME' = '7BIT';\n\tlet smtputf8 = false;\n\tfor (const [key, value] of Object.entries(parameters)) {\n\t\tif (!state.esmtp)\n\t\t\treturn connection.fail(reply(555, '5.5.4', `${key} needs EHLO`));\n\t\tif (key === 'SIZE') {\n\t\t\tif (!/^\\d+$/.test(value))\n\t\t\t\treturn connection.fail(reply(501, '5.5.4', 'Syntax: SIZE=<bytes>'));\n\t\t\tif (Number(value) > settings.maxMessageSize) {\n\t\t\t\treturn connection.fail(\n\t\t\t\t\treply(552, '5.3.4', 'Message too big for system'),\n\t\t\t\t);\n\t\t\t}\n\t\t} else if (key === 'BODY') {\n\t\t\tconst kind = value.toUpperCase();\n\t\t\tif (kind !== '7BIT' && kind !== '8BITMIME') {\n\t\t\t\treturn connection.fail(reply(501, '5.5.4', 'BODY is 7BIT or 8BITMIME'));\n\t\t\t}\n\t\t\tbody = kind;\n\t\t} else if (key === 'SMTPUTF8' && value === '') {\n\t\t\tsmtputf8 = true;\n\t\t} else if (key === 'AUTH') {\n\t\t\t// RFC 4954 §5: the original submitter; taken and not passed on.\n\t\t} else {\n\t\t\treturn connection.fail(reply(555, '5.5.4', `${key} is not supported`));\n\t\t}\n\t}\n\tif (!smtputf8 && nonAscii(path.address)) {\n\t\treturn connection.fail(\n\t\t\treply(553, '5.6.7', 'A non-ASCII address needs SMTPUTF8'),\n\t\t);\n\t}\n\tconst options = settings.options;\n\tconst refused = options.onMailFrom\n\t\t? await connection.hook('onMailFrom', () =>\n\t\t\t\toptions.onMailFrom?.(path, connection.session),\n\t\t\t)\n\t\t: undefined;\n\tif (refused) return connection.send(refused);\n\tstate.transaction = { from: path.address, to: [], smtputf8, body };\n\tconnection.send(reply(250, '2.1.0', 'OK'));\n}\n\n/** `RCPT TO:<path>` (RFC 5321 §4.1.1.3), where relaying is refused without AUTH. */\nexport async function rcpt(\n\tconnection: Connection,\n\targument: string,\n): Promise<void> {\n\tconst { state, settings } = connection;\n\tif (state.transaction.from === undefined)\n\t\treturn connection.fail(reply(503, '5.5.1', 'Send MAIL first'));\n\tconst command = parsePathCommand(argument, 'TO');\n\tif (!command)\n\t\treturn connection.fail(reply(501, '5.5.4', 'Syntax: RCPT TO:<address>'));\n\tconst { path, parameters } = command;\n\tif (Object.keys(parameters).length > 0) {\n\t\treturn connection.fail(\n\t\t\treply(555, '5.5.4', `${Object.keys(parameters)[0]} is not supported`),\n\t\t);\n\t}\n\tif (!state.transaction.smtputf8 && nonAscii(path.address)) {\n\t\treturn connection.fail(\n\t\t\treply(553, '5.6.7', 'A non-ASCII address needs SMTPUTF8'),\n\t\t);\n\t}\n\tif (state.transaction.to.length >= settings.maxRecipients) {\n\t\treturn connection.send(reply(452, '4.5.3', 'Too many recipients'));\n\t}\n\t// Never an open relay: a domain this server does not host takes AUTH.\n\tif (state.user === undefined) {\n\t\tconst local = await connection.check('localDomains', () =>\n\t\t\tsettings.isLocal(path.domain),\n\t\t);\n\t\tif (local.failed) return connection.send(LOCAL_ERROR);\n\t\tif (local.value !== true) {\n\t\t\treturn connection.fail(reply(554, '5.7.1', 'Relay access denied'));\n\t\t}\n\t}\n\tconst options = settings.options;\n\tconst refused = options.onRcptTo\n\t\t? await connection.hook('onRcptTo', () =>\n\t\t\t\toptions.onRcptTo?.(path, connection.session),\n\t\t\t)\n\t\t: undefined;\n\tif (refused) return connection.send(refused);\n\tstate.transaction.to.push(path.address);\n\tconnection.send(reply(250, '2.1.5', 'OK'));\n}\n",
|
|
12
|
+
"import { parsePathCommand } from '../protocol/command';\nimport { reply } from '../protocol/reply';\nimport type { Connection } from './connection';\nimport { LOCAL_ERROR } from './guard';\n\nfunction nonAscii(text: string): boolean {\n\tfor (let i = 0; i < text.length; i++)\n\t\tif (text.charCodeAt(i) > 0x7f) return true;\n\treturn false;\n}\n\n/** `MAIL FROM:<path> [SIZE=] [BODY=] [SMTPUTF8] [AUTH=]` (RFC 5321 §4.1.1.2). */\nexport async function mail(\n\tconnection: Connection,\n\targument: string,\n): Promise<void> {\n\tconst { state, settings } = connection;\n\tif (state.helo === undefined)\n\t\treturn connection.fail(reply(503, '5.5.1', 'Send EHLO first'));\n\tif (state.transaction.from !== undefined) {\n\t\treturn connection.fail(reply(503, '5.5.1', 'Nested MAIL command'));\n\t}\n\tif (settings.mode === 'submission' && state.user === undefined) {\n\t\treturn connection.fail(reply(530, '5.7.0', 'Authentication required'));\n\t}\n\tconst command = parsePathCommand(argument, 'FROM');\n\tif (!command)\n\t\treturn connection.fail(reply(501, '5.5.4', 'Syntax: MAIL FROM:<address>'));\n\tconst { path, parameters } = command;\n\tlet body: '7BIT' | '8BITMIME' = '7BIT';\n\tlet smtputf8 = false;\n\tfor (const [key, value] of Object.entries(parameters)) {\n\t\tif (!state.esmtp)\n\t\t\treturn connection.fail(reply(555, '5.5.4', `${key} needs EHLO`));\n\t\tif (key === 'SIZE') {\n\t\t\tif (!/^\\d+$/.test(value))\n\t\t\t\treturn connection.fail(reply(501, '5.5.4', 'Syntax: SIZE=<bytes>'));\n\t\t\tif (Number(value) > settings.maxMessageSize) {\n\t\t\t\treturn connection.fail(\n\t\t\t\t\treply(552, '5.3.4', 'Message too big for system'),\n\t\t\t\t);\n\t\t\t}\n\t\t} else if (key === 'BODY') {\n\t\t\tconst kind = value.toUpperCase();\n\t\t\tif (kind !== '7BIT' && kind !== '8BITMIME') {\n\t\t\t\treturn connection.fail(reply(501, '5.5.4', 'BODY is 7BIT or 8BITMIME'));\n\t\t\t}\n\t\t\tbody = kind;\n\t\t} else if (key === 'SMTPUTF8' && value === '') {\n\t\t\tsmtputf8 = true;\n\t\t} else if (key === 'AUTH') {\n\t\t\t// RFC 4954 §5: the original submitter; taken and not passed on.\n\t\t} else {\n\t\t\treturn connection.fail(reply(555, '5.5.4', `${key} is not supported`));\n\t\t}\n\t}\n\tif (!smtputf8 && nonAscii(path.address)) {\n\t\treturn connection.fail(\n\t\t\treply(553, '5.6.7', 'A non-ASCII address needs SMTPUTF8'),\n\t\t);\n\t}\n\tconst options = settings.options;\n\tconst refused = options.onMailFrom\n\t\t? await connection.hook('onMailFrom', () =>\n\t\t\t\toptions.onMailFrom?.(path, connection.session),\n\t\t\t)\n\t\t: undefined;\n\tif (refused) return connection.send(refused);\n\tstate.transaction = { from: path.address, to: [], smtputf8, body };\n\tconnection.send(reply(250, '2.1.0', 'OK'));\n}\n\n/** `RCPT TO:<path>` (RFC 5321 §4.1.1.3), where relaying is refused without AUTH. */\nexport async function rcpt(\n\tconnection: Connection,\n\targument: string,\n): Promise<void> {\n\tconst { state, settings } = connection;\n\tif (state.transaction.from === undefined)\n\t\treturn connection.fail(reply(503, '5.5.1', 'Send MAIL first'));\n\tconst command = parsePathCommand(argument, 'TO');\n\tif (!command)\n\t\treturn connection.fail(reply(501, '5.5.4', 'Syntax: RCPT TO:<address>'));\n\tconst { path, parameters } = command;\n\tif (Object.keys(parameters).length > 0) {\n\t\treturn connection.fail(\n\t\t\treply(555, '5.5.4', `${Object.keys(parameters)[0]} is not supported`),\n\t\t);\n\t}\n\tif (!state.transaction.smtputf8 && nonAscii(path.address)) {\n\t\treturn connection.fail(\n\t\t\treply(553, '5.6.7', 'A non-ASCII address needs SMTPUTF8'),\n\t\t);\n\t}\n\tif (state.transaction.to.length >= settings.maxRecipients) {\n\t\treturn connection.send(reply(452, '4.5.3', 'Too many recipients'));\n\t}\n\t// Never an open relay: a domain this server does not host takes AUTH.\n\t// `<postmaster>` with no domain is this server's own (RFC 5321 §4.5.1).\n\tif (state.user === undefined && path.postmaster !== true) {\n\t\tconst local = await connection.check('localDomains', () =>\n\t\t\tsettings.isLocal(path.domain),\n\t\t);\n\t\tif (local.failed) return connection.send(LOCAL_ERROR);\n\t\tif (local.value !== true) {\n\t\t\treturn connection.fail(reply(554, '5.7.1', 'Relay access denied'));\n\t\t}\n\t}\n\tconst options = settings.options;\n\tconst refused = options.onRcptTo\n\t\t? await connection.hook('onRcptTo', () =>\n\t\t\t\toptions.onRcptTo?.(path, connection.session),\n\t\t\t)\n\t\t: undefined;\n\tif (refused) return connection.send(refused);\n\tstate.transaction.to.push(path.address);\n\tconnection.send(reply(250, '2.1.5', 'OK'));\n}\n",
|
|
12
13
|
"import { parseCommand } from '../protocol/command';\nimport { isHelloName } from '../protocol/path';\nimport { reply } from '../protocol/reply';\nimport { authenticate, continueAuth } from './auth';\nimport type { Connection } from './connection';\nimport { emptyTransaction } from './state';\nimport { mail, rcpt } from './transaction';\n\nfunction ehloLines(connection: Connection): string[] {\n\tconst { settings, state } = connection;\n\tconst lines = [\n\t\t`${settings.options.hostname} greets ${state.helo}`,\n\t\t'PIPELINING',\n\t\t`SIZE ${settings.maxMessageSize}`,\n\t\t'8BITMIME',\n\t\t'SMTPUTF8',\n\t\t'ENHANCEDSTATUSCODES',\n\t];\n\tif (settings.options.tls && !state.secure) lines.push('STARTTLS');\n\tif (\n\t\tsettings.options.authenticate &&\n\t\tstate.secure &&\n\t\tstate.user === undefined\n\t) {\n\t\tlines.push('AUTH PLAIN LOGIN');\n\t}\n\treturn lines;\n}\n\nasync function hello(\n\tconnection: Connection,\n\targument: string,\n\tesmtp: boolean,\n): Promise<void> {\n\tif (!isHelloName(argument)) {\n\t\tconnection.fail(\n\t\t\treply(501, '5.5.4', `Syntax: ${esmtp ? 'EHLO' : 'HELO'} hostname`),\n\t\t);\n\t\treturn;\n\t}\n\tconst { state } = connection;\n\tstate.helo = argument;\n\tstate.esmtp = esmtp;\n\t// RFC 5321 §4.1.4: EHLO or HELO resets a transaction in progress.\n\tstate.transaction = emptyTransaction();\n\tconnection.send(\n\t\tesmtp\n\t\t\t? reply(250, undefined, ehloLines(connection))\n\t\t\t: reply(\n\t\t\t\t\t250,\n\t\t\t\t\tundefined,\n\t\t\t\t\t`${connection.settings.options.hostname} greets ${argument}`,\n\t\t\t\t),\n\t);\n}\n\nfunction data(connection: Connection, argument: string): void {\n\tconst { state } = connection;\n\tconst refusal =\n\t\targument !== ''\n\t\t\t? reply(501, '5.5.4', 'Syntax: DATA')\n\t\t\t: state.transaction.from === undefined\n\t\t\t\t? reply(503, '5.5.1', 'Send MAIL first')\n\t\t\t\t: state.transaction.to.length === 0\n\t\t\t\t\t? reply(554, '5.5.1', 'No valid recipients')\n\t\t\t\t\t: undefined;\n\tif (refusal) {\n\t\tconnection.fail(refusal);\n\t\t// What the client pipelined after a refused DATA is message content,\n\t\t// not commands: running it would let a message smuggle commands in.\n\t\tconnection.input.drop();\n\t\treturn;\n\t}\n\tconnection.send(reply(354, undefined, 'End data with <CR><LF>.<CR><LF>'));\n\tconnection.input.beginData();\n}\n\nasync function startTls(\n\tconnection: Connection,\n\targument: string,\n): Promise<void> {\n\tconst { state, settings } = connection;\n\tconst refusal = !settings.options.tls\n\t\t? reply(454, '4.7.0', 'TLS not available')\n\t\t: state.secure\n\t\t\t? reply(503, '5.5.1', 'TLS already active')\n\t\t\t: argument !== ''\n\t\t\t\t? reply(501, '5.5.4', 'Syntax: STARTTLS')\n\t\t\t\t: undefined;\n\tif (refusal) {\n\t\tconnection.fail(refusal);\n\t\treturn;\n\t}\n\tconnection.send(reply(220, '2.0.0', 'Ready to start TLS'));\n\tconnection.input.ignore();\n\t// The 220 must reach the client in clear before the handshake starts.\n\tawait connection.transport.drained();\n\tif (connection.closed) return;\n\tconnection.transport.startTls();\n\tconnection.input.accept();\n\t// RFC 3207 §4.2: everything learnt before TLS is forgotten.\n\tstate.secure = true;\n\tstate.helo = undefined;\n\tstate.esmtp = false;\n\tstate.transaction = emptyTransaction();\n}\n\n/** Runs one command line, or the client's answer to an AUTH challenge. */\nexport async function runCommand(\n\tconnection: Connection,\n\tline: string,\n): Promise<void> {\n\tconst { state } = connection;\n\tif (state.waiting !== 'command') return continueAuth(connection, line);\n\tconst { verb, argument } = parseCommand(line);\n\tswitch (verb) {\n\t\tcase 'EHLO':\n\t\t\treturn hello(connection, argument, true);\n\t\tcase 'HELO':\n\t\t\treturn hello(connection, argument, false);\n\t\tcase 'MAIL':\n\t\t\treturn mail(connection, argument);\n\t\tcase 'RCPT':\n\t\t\treturn rcpt(connection, argument);\n\t\tcase 'DATA':\n\t\t\treturn data(connection, argument);\n\t\tcase 'RSET':\n\t\t\tstate.transaction = emptyTransaction();\n\t\t\treturn connection.send(reply(250, '2.0.0', 'OK'));\n\t\tcase 'NOOP':\n\t\t\treturn connection.send(reply(250, '2.0.0', 'OK'));\n\t\tcase 'VRFY':\n\t\t\treturn connection.send(\n\t\t\t\treply(\n\t\t\t\t\t252,\n\t\t\t\t\t'2.5.0',\n\t\t\t\t\t'Cannot VRFY user; send the message and it will be tried',\n\t\t\t\t),\n\t\t\t);\n\t\tcase 'HELP':\n\t\t\treturn connection.send(reply(214, '2.0.0', 'See RFC 5321'));\n\t\tcase 'QUIT':\n\t\t\treturn connection.quit(\n\t\t\t\treply(\n\t\t\t\t\t221,\n\t\t\t\t\t'2.0.0',\n\t\t\t\t\t`${connection.settings.options.hostname} closing connection`,\n\t\t\t\t),\n\t\t\t);\n\t\tcase 'STARTTLS':\n\t\t\treturn startTls(connection, argument);\n\t\tcase 'AUTH':\n\t\t\treturn authenticate(connection, argument);\n\t\tdefault:\n\t\t\treturn connection.fail(reply(500, '5.5.2', 'Command unrecognized'));\n\t}\n}\n",
|
|
13
14
|
"import type { Connection } from './connection';\n\nconst DAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];\nconst MONTHS = [\n\t'Jan',\n\t'Feb',\n\t'Mar',\n\t'Apr',\n\t'May',\n\t'Jun',\n\t'Jul',\n\t'Aug',\n\t'Sep',\n\t'Oct',\n\t'Nov',\n\t'Dec',\n];\n\nconst two = (n: number) => String(n).padStart(2, '0');\n\n/** An RFC 5322 §3.3 date-time, in UTC. */\nexport function dateTime(date: Date): string {\n\treturn `${DAYS[date.getUTCDay()]}, ${date.getUTCDate()} ${MONTHS[date.getUTCMonth()]} ${date.getUTCFullYear()} ${two(date.getUTCHours())}:${two(date.getUTCMinutes())}:${two(date.getUTCSeconds())} +0000`;\n}\n\n/** RFC 3848: how the message came — SMTP, ESMTP, then S for TLS and A for AUTH. */\nexport function protocolOf(\n\tesmtp: boolean,\n\tsecure: boolean,\n\tauthenticated: boolean,\n): string {\n\tif (!esmtp) return 'SMTP';\n\treturn `ESMTP${secure ? 'S' : ''}${authenticated ? 'A' : ''}`;\n}\n\n/** Keeps a client-given name printable in a header: anything else becomes `?`. */\nfunction printable(text: string): string {\n\tlet out = '';\n\tfor (const char of text) {\n\t\tconst code = char.charCodeAt(0);\n\t\tout += code > 0x20 && code < 0x7f ? char : '?';\n\t}\n\treturn out;\n}\n\n/** Whether an address can go into the `for` clause as it is: printable, and no `;` to end the clause early. */\nfunction plain(address: string): boolean {\n\treturn printable(address) === address && !address.includes(';');\n}\n\n/**\n * The Received field the server puts on top (RFC 5321 §4.4): who sent the\n * message, from where, how, to whom when there is one recipient, and when.\n */\nexport function receivedField(\n\tconnection: Connection,\n\trecipients: readonly string[],\n\tid: string,\n\tnow = new Date(),\n): string {\n\tconst { state, transport, settings } = connection;\n\tconst lines = [\n\t\t`Received: from ${printable(state.helo ?? 'unknown')} ([${printable(transport.remoteAddress)}])`,\n\t\t`\\tby ${settings.options.hostname} with ${protocolOf(state.esmtp, state.secure, state.user !== undefined)} id ${id}`,\n\t];\n\tconst [recipient] = recipients;\n\tif (recipients.length === 1 && recipient !== undefined && plain(recipient)) {\n\t\tlines.push(`\\tfor <${recipient}>`);\n\t}\n\tlines[lines.length - 1] += `; ${dateTime(now)}`;\n\treturn `${lines.join('\\r\\n')}\\r\\n`;\n}\n",
|
|
14
15
|
"import { SmtpError } from '../errors';\nimport { reply } from '../protocol/reply';\n\n/** Why a message on its way in is refused, as the reply and the error `onData` and `onError` see. */\n\nexport const TOO_BIG = reply(552, '5.3.4', 'Message too big for system');\n\nexport const BARE_LINE_BREAK = reply(\n\t550,\n\t'5.6.11',\n\t'Bare CR or LF is not allowed in a message',\n);\n\nexport function tooBig(maxMessageSize: number): SmtpError {\n\treturn new SmtpError(\n\t\t'MESSAGE_TOO_BIG',\n\t\t`The message is larger than maxMessageSize (${maxMessageSize} bytes); do not deliver it`,\n\t);\n}\n\n/** A bare CR or LF is how SMTP smuggling hides a second message. */\nexport function bareLineBreak(): SmtpError {\n\treturn new SmtpError(\n\t\t'BARE_LINE_BREAK',\n\t\t'The message holds a bare CR or LF (SMTP smuggling); do not deliver it',\n\t);\n}\n\n/**\n * The connection closed mid-message, or after its end but before the reply:\n * the client hung up, or the server closed it (idle timeout, socket error).\n */\nexport function connectionLost(ended: boolean): SmtpError {\n\treturn new SmtpError(\n\t\t'CONNECTION_LOST',\n\t\tended\n\t\t\t? 'The connection closed before the reply to the message; do not deliver it'\n\t\t\t: 'The connection closed before the end of the message; do not deliver it',\n\t);\n}\n\nexport function notAnswered(seconds: number): SmtpError {\n\treturn new SmtpError(\n\t\t'HOOK_TIMEOUT',\n\t\t`onData did not answer within hookTimeout (${seconds} s); do not deliver it`,\n\t);\n}\n\nexport function notReadInTime(seconds: number): SmtpError {\n\treturn new SmtpError(\n\t\t'HOOK_TIMEOUT',\n\t\t`onData did not read the message within hookTimeout (${seconds} s); do not deliver it`,\n\t);\n}\n\nexport function notRead(): SmtpError {\n\treturn new SmtpError(\n\t\t'MESSAGE_NOT_READ',\n\t\t'onData answered without reading the message to its end; it was not taken',\n\t);\n}\n",
|
|
15
16
|
"import type { SmtpError } from '../errors';\nimport { DataReader } from '../protocol/data';\nimport { type Reply, reply } from '../protocol/reply';\nimport type { Connection } from './connection';\nimport { hookTimeout, LOCAL_ERROR, refusalOf, timedOut, within } from './guard';\nimport type { ReceivedMessage } from './options';\nimport { receivedField } from './received';\nimport {\n\tBARE_LINE_BREAK,\n\tbareLineBreak,\n\tconnectionLost,\n\tnotAnswered,\n\tnotRead,\n\tnotReadInTime,\n\tTOO_BIG,\n\ttooBig,\n} from './refusals';\nimport type { Transaction } from './state';\n\n/** Bytes of message held for `onData` before the server stops reading the client. */\nconst HIGH_WATER_MARK = 64 * 1024;\n\n/**\n * One message on its way in: the content of DATA, unstuffed, fed to\n * `onData` as a stream while the client sends it. At most\n * `HIGH_WATER_MARK` bytes wait to be read; past that the server waits for\n * `onData` to read, and so stops reading the client.\n *\n * The stream ends in an `SmtpError` when the message must not be\n * delivered, and the reply to DATA is then that refusal, whatever `onData`\n * answered. The 250 goes out only when `onData` read the stream to its\n * clean end and accepted; a stream left unread errors with\n * `MESSAGE_NOT_READ`. When the message's `signal` aborts is set out on\n * `ReceivedMessage.signal`.\n */\nexport class Intake {\n\treadonly id = crypto.getRandomValues(new Uint8Array(10)).toHex();\n\treadonly #connection: Connection;\n\treadonly #reader = new DataReader();\n\t#controller!: ReadableStreamDefaultController<Uint8Array>;\n\t/** What waits for `onData` to pull. */\n\t#queue: Uint8Array[] = [];\n\t#queued = 0;\n\t/** The end of DATA came, cleanly. */\n\t#ended = false;\n\t/** `onData` pulled the last byte and saw the stream close. */\n\t#read = false;\n\t#state: 'open' | 'closed' | 'errored' | 'cancelled' = 'open';\n\t#failure: Reply | undefined;\n\t#wakers: (() => void)[] = [];\n\treadonly #delivery: Promise<Reply | undefined>;\n\t/** Whether `onData` had read to the end when it answered. */\n\t#readWhenAnswered = false;\n\t/** Aborts when the server refuses the message after `onData` had it. */\n\treadonly #refusal = new AbortController();\n\n\tconstructor(connection: Connection, transaction: Transaction) {\n\t\tthis.#connection = connection;\n\t\t// High-water mark 0: a byte leaves the queue only when onData asks\n\t\t// for it, so the server knows whether it read to the end.\n\t\tconst content = new ReadableStream<Uint8Array>(\n\t\t\t{\n\t\t\t\tstart: (controller) => {\n\t\t\t\t\tthis.#controller = controller;\n\t\t\t\t},\n\t\t\t\tpull: (controller) => this.#pull(controller),\n\t\t\t\tcancel: () => {\n\t\t\t\t\tif (this.#state === 'open') this.#state = 'cancelled';\n\t\t\t\t\tthis.#queue = [];\n\t\t\t\t\tthis.#queued = 0;\n\t\t\t\t\tthis.#wake();\n\t\t\t\t},\n\t\t\t},\n\t\t\t{ highWaterMark: 0 },\n\t\t);\n\t\tthis.#push(\n\t\t\tnew TextEncoder().encode(\n\t\t\t\treceivedField(connection, transaction.to, this.id),\n\t\t\t),\n\t\t);\n\t\tconst message: ReceivedMessage = {\n\t\t\tid: this.id,\n\t\t\tenvelope: {\n\t\t\t\tfrom: transaction.from ?? '',\n\t\t\t\tto: [...transaction.to],\n\t\t\t\tsmtputf8: transaction.smtputf8,\n\t\t\t\tbody: transaction.body,\n\t\t\t},\n\t\t\tcontent,\n\t\t\tsignal: this.#refusal.signal,\n\t\t};\n\t\tthis.#delivery = this.#deliver(message);\n\t}\n\n\t/**\n\t * `onData`'s answer as the reply: `undefined`, its refusal, or 451 when\n\t * it threw or answered what is not a refusal — which also aborts the\n\t * signal, since the message was not taken.\n\t */\n\tasync #deliver(message: ReceivedMessage): Promise<Reply | undefined> {\n\t\tconst connection = this.#connection;\n\t\t/** onData refused the message itself, with a valid 4xx or 5xx reply. */\n\t\tlet ownRefusal = false;\n\t\tconst refuse = (error: unknown) => {\n\t\t\tthis.#refusal.abort(error);\n\t\t\tconnection.report(error);\n\t\t};\n\t\ttry {\n\t\t\t// Keeps onData starting after Input has set up the transaction, as\n\t\t\t// connection.hook did; nothing observable depends on it today.\n\t\t\tawait Promise.resolve();\n\t\t\tconst answer = await connection.settings.options.onData(\n\t\t\t\tmessage,\n\t\t\t\tconnection.session,\n\t\t\t);\n\t\t\tconst refusal = refusalOf('onData', answer, refuse);\n\t\t\townRefusal = refusal !== undefined && refusal === answer;\n\t\t\treturn refusal;\n\t\t} catch (error) {\n\t\t\trefuse(error);\n\t\t\treturn LOCAL_ERROR;\n\t\t} finally {\n\t\t\tthis.#readWhenAnswered = this.#read;\n\t\t\t// Answered before the end: a reader left running must not reach a\n\t\t\t// clean end. The signal aborts only if the server refuses for it.\n\t\t\tif (!this.#read) this.#stop(!ownRefusal);\n\t\t\tthis.#wake();\n\t\t}\n\t}\n\n\t/** A chunk of DATA; resolves once there is room for the next. */\n\tasync write(chunk: Uint8Array): Promise<{ done: boolean; rest: Uint8Array }> {\n\t\tconst { data, done, rest } = this.#reader.write(chunk);\n\t\tconst { maxMessageSize } = this.#connection.settings;\n\t\tif (this.#failure) return { done, rest };\n\t\tif (this.#reader.size > maxMessageSize) {\n\t\t\tthis.#fail(TOO_BIG, tooBig(maxMessageSize));\n\t\t} else if (this.#reader.bareLineBreaks > 0) {\n\t\t\t// A bare CR or LF is how SMTP smuggling hides a second message.\n\t\t\tthis.#fail(BARE_LINE_BREAK, bareLineBreak());\n\t\t} else if (this.#state === 'open' && data.length > 0) {\n\t\t\tthis.#push(data);\n\t\t\tawait this.#room();\n\t\t}\n\t\treturn { done, rest };\n\t}\n\n\t/** The end of DATA: the reply to send. */\n\tasync finish(): Promise<Reply> {\n\t\tif (this.#failure) return this.#failure;\n\t\tthis.#ended = true;\n\t\tthis.#wake();\n\t\tconst { hookTimeout: seconds } = this.#connection.settings;\n\t\tconst answer = await within(this.#delivery, seconds);\n\t\tif (timedOut(answer)) {\n\t\t\tthis.#connection.report(hookTimeout('onData', seconds));\n\t\t\t// The client is told 451 and will try again: a late read must not\n\t\t\t// take it, and a read already finished learns it through the signal.\n\t\t\tthis.#fail(LOCAL_ERROR, notAnswered(seconds));\n\t\t\treturn LOCAL_ERROR;\n\t\t}\n\t\tif (answer) return answer;\n\t\tif (!this.#readWhenAnswered) {\n\t\t\tconst error = notRead();\n\t\t\tthis.#refusal.abort(error);\n\t\t\tthis.#connection.report(error);\n\t\t\treturn LOCAL_ERROR;\n\t\t}\n\t\treturn reply(250, '2.0.0', `OK queued as ${this.id}`);\n\t}\n\n\t/** The connection closed, mid-message or before the reply was sent. */\n\tabort(): void {\n\t\tthis.#fail(LOCAL_ERROR, connectionLost(this.#ended));\n\t}\n\n\t#push(bytes: Uint8Array): void {\n\t\tthis.#queue.push(bytes);\n\t\tthis.#queued += bytes.length;\n\t\tthis.#wake();\n\t}\n\n\t/** onData asks for more: the next chunk, the end, or a wait for either. */\n\tasync #pull(\n\t\tcontroller: ReadableStreamDefaultController<Uint8Array>,\n\t): Promise<void> {\n\t\tfor (;;) {\n\t\t\tif (this.#state !== 'open') return;\n\t\t\tconst next = this.#queue.shift();\n\t\t\tif (next) {\n\t\t\t\tthis.#queued -= next.length;\n\t\t\t\tcontroller.enqueue(next);\n\t\t\t\tthis.#wake();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (this.#ended) {\n\t\t\t\tthis.#read = true;\n\t\t\t\tthis.#state = 'closed';\n\t\t\t\tcontroller.close();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait new Promise<void>((wake) => this.#wakers.push(wake));\n\t\t}\n\t}\n\n\t/**\n\t * onData answered without reading to the end: the stream errors, and\n\t * takes no more. The signal aborts too, unless onData refused itself.\n\t */\n\t#stop(abortSignal: boolean): void {\n\t\tif (this.#state !== 'open') return;\n\t\tconst error = notRead();\n\t\tif (abortSignal) this.#refusal.abort(error);\n\t\tthis.#controller.error(error);\n\t\tthis.#state = 'cancelled';\n\t\tthis.#queue = [];\n\t\tthis.#queued = 0;\n\t}\n\n\t#fail(answer: Reply, error: SmtpError): void {\n\t\tthis.#failure ??= answer;\n\t\tthis.#refusal.abort(error);\n\t\tif (this.#state === 'open') this.#controller.error(error);\n\t\tthis.#state = 'errored';\n\t\tthis.#queue = [];\n\t\tthis.#queued = 0;\n\t\tthis.#wake();\n\t}\n\n\t/** Waits while the queue is full; gives up on an `onData` that stopped reading. */\n\tasync #room(): Promise<void> {\n\t\tconst { hookTimeout: seconds } = this.#connection.settings;\n\t\twhile (this.#state === 'open' && this.#queued > HIGH_WATER_MARK) {\n\t\t\tconst woken = await within(\n\t\t\t\tnew Promise<void>((wake) => this.#wakers.push(wake)),\n\t\t\t\tseconds,\n\t\t\t);\n\t\t\tif (timedOut(woken)) {\n\t\t\t\tthis.#connection.report(hookTimeout('onData', seconds));\n\t\t\t\tthis.#fail(LOCAL_ERROR, notReadInTime(seconds));\n\t\t\t}\n\t\t}\n\t}\n\n\t#wake(): void {\n\t\tfor (const wake of this.#wakers.splice(0)) wake();\n\t}\n}\n",
|
|
16
17
|
"import { LineSplitter } from '../protocol/lines';\nimport { reply } from '../protocol/reply';\nimport { runCommand } from './commands';\nimport type { Connection } from './connection';\nimport { Intake } from './intake';\nimport { emptyTransaction } from './state';\n\n/** Bytes waiting to be read past which the server stops reading the client. */\nconst INPUT_LIMIT = 64 * 1024;\n\n/**\n * What a client sends, read in order: command lines one at a time, each\n * answered before the next runs, and the message after DATA. It holds a\n * bounded amount: past `INPUT_LIMIT` waiting bytes it pauses the socket,\n * and it waits for the replies to leave before reading on.\n */\nexport class Input {\n\treadonly #connection: Connection;\n\t#input: Uint8Array[] = [];\n\t#queued = 0;\n\t#paused = false;\n\treadonly #lines = new LineSplitter();\n\t#intake: Intake | undefined;\n\t/** A message whole, while `onData` answers it and before the reply is sent. */\n\t#answering: Intake | undefined;\n\t/** The work in progress on what the client sent; settled when all of it is answered. */\n\t#pumping: Promise<void> | undefined;\n\t/** The 220 went out: input before it breaks RFC 5321 §4.3.1. */\n\t#greeted = false;\n\t/** The client talked before the greeting. */\n\tearly = false;\n\t/** Set while the 220 to STARTTLS leaves: clear text then is never read. */\n\t#ignoring = false;\n\t/** Set by `drop`: the line loop drops what it still holds. */\n\t#dropped = false;\n\n\tconstructor(connection: Connection) {\n\t\tthis.#connection = connection;\n\t}\n\n\tgreeted(): void {\n\t\tthis.#greeted = true;\n\t}\n\n\treceive(chunk: Uint8Array): void {\n\t\tif (this.#ignoring) return;\n\t\tif (!this.#greeted) {\n\t\t\tthis.early = true;\n\t\t\treturn;\n\t\t}\n\t\tthis.#input.push(chunk.slice());\n\t\tthis.#queued += chunk.length;\n\t\tif (this.#queued > INPUT_LIMIT && !this.#paused) {\n\t\t\tthis.#paused = true;\n\t\t\tthis.#connection.transport.pause();\n\t\t}\n\t\tthis.#kick();\n\t}\n\n\t/** The connection closed: a message on its way in must not be delivered. */\n\tabort(): void {\n\t\tthis.#intake?.abort();\n\t\tthis.#intake = undefined;\n\t\t// The connection closed before the reply, so the client will send the\n\t\t// message again: onData learns it through the signal.\n\t\tthis.#answering?.abort();\n\t\tthis.#answering = undefined;\n\t}\n\n\t/**\n\t * Forgets what the client sent ahead and reads nothing until `accept`:\n\t * what comes in clear before TLS never counts (RFC 3207 §4.2,\n\t * CVE-2011-0411).\n\t */\n\tignore(): void {\n\t\tthis.drop();\n\t\tthis.#input = [];\n\t\tthis.#queued = 0;\n\t\tthis.#ignoring = true;\n\t\tthis.#resume();\n\t}\n\n\taccept(): void {\n\t\tthis.#ignoring = false;\n\t}\n\n\t/** Drops the rest of the chunk being read: after a refused DATA, it is message content, not commands. */\n\tdrop(): void {\n\t\tthis.#lines.clear();\n\t\tthis.#dropped = true;\n\t}\n\n\t/** Starts receiving a message: `onData` is called, and gets it as it comes. */\n\tbeginData(): void {\n\t\tconst connection = this.#connection;\n\t\tthis.#intake = new Intake(connection, connection.state.transaction);\n\t\tconnection.state.waiting = 'data';\n\t}\n\n\t/** Resolves once everything received so far is answered. */\n\tasync idle(): Promise<void> {\n\t\twhile (this.#pumping) await this.#pumping;\n\t}\n\n\t#kick(): void {\n\t\tif (this.#pumping) return;\n\t\tconst connection = this.#connection;\n\t\tthis.#pumping = this.#pump()\n\t\t\t.catch((error) => {\n\t\t\t\tconnection.report(error);\n\t\t\t\tconnection.close(reply(421, '4.3.0', 'Local error, closing'));\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tthis.#pumping = undefined;\n\t\t\t\t// Bytes that came after the loop's last look.\n\t\t\t\tif (!connection.closed && this.#input.length > 0) this.#kick();\n\t\t\t});\n\t}\n\n\t#resume(): void {\n\t\tif (this.#paused && this.#queued <= INPUT_LIMIT / 2) {\n\t\t\tthis.#paused = false;\n\t\t\tthis.#connection.transport.resume();\n\t\t}\n\t}\n\n\tasync #pump(): Promise<void> {\n\t\twhile (!this.#connection.closed && this.#input.length > 0) {\n\t\t\tconst chunk = this.#input.shift() as Uint8Array;\n\t\t\tthis.#queued -= chunk.length;\n\t\t\tthis.#resume();\n\t\t\tif (this.#connection.state.waiting === 'data') await this.#data(chunk);\n\t\t\telse await this.#commands(chunk);\n\t\t}\n\t}\n\n\tasync #commands(chunk: Uint8Array): Promise<void> {\n\t\tthis.#lines.push(chunk);\n\t\twhile (!this.#connection.closed) {\n\t\t\t// The replies so far leave before the next command runs.\n\t\t\tawait this.#connection.transport.drained();\n\t\t\tconst event = this.#lines.next();\n\t\t\tif (!event) return;\n\t\t\tif (!('line' in event)) {\n\t\t\t\tthis.#connection.fail(reply(500, '5.5.6', 'Line too long'));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis.#dropped = false;\n\t\t\tawait runCommand(this.#connection, event.line);\n\t\t\tif (this.#dropped) return;\n\t\t\tif (this.#connection.state.waiting === 'data') {\n\t\t\t\t// Message content pipelined right after DATA.\n\t\t\t\tconst rest = this.#lines.takeRest();\n\t\t\t\tif (rest.length > 0) this.#unshift(rest.slice());\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tasync #data(chunk: Uint8Array): Promise<void> {\n\t\tconst intake = this.#intake as Intake;\n\t\tconst { done, rest } = await intake.write(chunk);\n\t\tif (!done || this.#connection.closed) return;\n\t\tthis.#intake = undefined;\n\t\tthis.#answering = intake;\n\t\tthis.#connection.state.waiting = 'command';\n\t\tthis.#connection.state.transaction = emptyTransaction();\n\t\tconst answer = await intake.finish();\n\t\tthis.#answering = undefined;\n\t\tthis.#connection.send(answer);\n\t\tif (rest.length > 0) this.#unshift(rest);\n\t}\n\n\t/** Puts bytes back at the front, counted again: the pump took them off the count. */\n\t#unshift(bytes: Uint8Array): void {\n\t\tthis.#input.unshift(bytes);\n\t\tthis.#queued += bytes.length;\n\t\tif (this.#queued > INPUT_LIMIT && !this.#paused) {\n\t\t\tthis.#paused = true;\n\t\t\tthis.#connection.transport.pause();\n\t\t}\n\t}\n}\n",
|
|
17
18
|
"import { formatReply, type Reply, reply } from '../protocol/reply';\nimport { hookTimeout, LOCAL_ERROR, refusalOf, timedOut, within } from './guard';\nimport { Input } from './input';\nimport type { HookResult, Session } from './options';\nimport type { Settings } from './settings';\nimport { emptyTransaction, type State } from './state';\nimport type { Transport } from './transport';\n\n/**\n * One SMTP session (RFC 5321): reads commands, one at a time and in order —\n * PIPELINING sends several at once, and each reply waits for the hooks of\n * the commands before it — and the message after DATA.\n */\nexport class Connection {\n\treadonly settings: Settings;\n\t#transport: Transport;\n\treadonly id = crypto.getRandomValues(new Uint8Array(8)).toHex();\n\treadonly data: Record<string, unknown> = {};\n\treadonly state: State;\n\t/** What the client sends: commands, then message content after DATA. */\n\treadonly input: Input = new Input(this);\n\t#closed = false;\n\n\tconstructor(settings: Settings, transport: Transport) {\n\t\tthis.settings = settings;\n\t\tthis.#transport = transport;\n\t\tthis.state = {\n\t\t\tesmtp: false,\n\t\t\tsecure: transport.secure,\n\t\t\ttransaction: emptyTransaction(),\n\t\t\twaiting: 'command',\n\t\t\terrors: 0,\n\t\t\tauthFailures: 0,\n\t\t};\n\t}\n\n\tget transport(): Transport {\n\t\treturn this.#transport;\n\t}\n\n\t/** After STARTTLS: writes and hang-ups go through the encrypted socket. */\n\tuseTransport(transport: Transport): void {\n\t\tthis.#transport = transport;\n\t}\n\n\tget session(): Session {\n\t\tconst { helo, user } = this.state;\n\t\treturn {\n\t\t\tid: this.id,\n\t\t\tremoteAddress: this.transport.remoteAddress,\n\t\t\tsecure: this.state.secure,\n\t\t\tesmtp: this.state.esmtp,\n\t\t\t...(helo === undefined ? {} : { helo }),\n\t\t\t...(user === undefined ? {} : { user }),\n\t\t\tdata: this.data,\n\t\t};\n\t}\n\n\tget closed(): boolean {\n\t\treturn this.#closed;\n\t}\n\n\tsend(answer: Reply): void {\n\t\tif (this.#closed) return;\n\t\tthis.transport.write(formatReply(answer, this.state.esmtp));\n\t}\n\n\t/**\n\t * Hangs up, the server's decision (a refusal, too many errors, the idle\n\t * time): `answer` is written, but nothing waits for a client that\n\t * stopped reading. The connection is closed at once, and what it has\n\t * not read is dropped, so a close always completes.\n\t */\n\tclose(answer?: Reply): void {\n\t\tif (this.#closed) return;\n\t\tif (answer) this.send(answer);\n\t\tthis.#closed = true;\n\t\tthis.input.abort();\n\t\tthis.transport.abort();\n\t}\n\n\t/** QUIT: `answer` leaves whole, then the connection hangs up. */\n\tquit(answer: Reply): void {\n\t\tif (this.#closed) return;\n\t\tthis.send(answer);\n\t\tthis.#closed = true;\n\t\tthis.input.abort();\n\t\tthis.transport.end();\n\t}\n\n\t/** Counts a failed command; past the limit, hangs up. */\n\tfail(answer: Reply): void {\n\t\tthis.state.errors++;\n\t\tif (this.state.errors >= this.settings.maxErrors) {\n\t\t\tconst { hostname } = this.settings.options;\n\t\t\tthis.close(reply(421, '4.7.0', `${hostname} Too many errors, closing`));\n\t\t} else {\n\t\t\tthis.send(answer);\n\t\t}\n\t}\n\n\t/** Hands an error to `onError`, which may not throw back. */\n\treport(error: unknown): void {\n\t\ttry {\n\t\t\tthis.settings.options.onError?.(error, this.session);\n\t\t} catch {\n\t\t\t// The app's error handler failing is not the client's business.\n\t\t}\n\t}\n\n\t/**\n\t * Runs a hook: its refusal, or `undefined`. A throw, a reply that is not\n\t * a refusal, or — with `deadline` — no answer within `hookTimeout` is\n\t * reported and answered `451 4.3.0`.\n\t */\n\tasync hook(\n\t\tname: string,\n\t\trun: () => HookResult | Promise<HookResult>,\n\t\tdeadline = true,\n\t): Promise<Reply | undefined> {\n\t\tconst answer = await this.check(name, run, deadline);\n\t\tif (answer.failed) return LOCAL_ERROR;\n\t\treturn refusalOf(name, answer.value, (error) => this.report(error));\n\t}\n\n\t/** Runs app code that answers a value: `failed` when it threw or timed out, which is reported. */\n\tasync check<T>(\n\t\tname: string,\n\t\trun: () => T | Promise<T>,\n\t\tdeadline = true,\n\t): Promise<{ failed: false; value: T } | { failed: true }> {\n\t\tconst seconds = this.settings.hookTimeout;\n\t\ttry {\n\t\t\tconst running = Promise.resolve().then(run);\n\t\t\tconst value = deadline ? await within(running, seconds) : await running;\n\t\t\tif (timedOut(value)) {\n\t\t\t\tthis.report(hookTimeout(name, seconds));\n\t\t\t\treturn { failed: true };\n\t\t\t}\n\t\t\treturn { failed: false, value };\n\t\t} catch (error) {\n\t\t\tthis.report(error);\n\t\t\treturn { failed: true };\n\t\t}\n\t}\n\n\t/** The greeting, or the refusal of `onConnect`, or of a client that talked first. */\n\tasync open(): Promise<void> {\n\t\tconst { options } = this.settings;\n\t\tconst refused = options.onConnect\n\t\t\t? await this.hook('onConnect', () => options.onConnect?.(this.session))\n\t\t\t: undefined;\n\t\tif (refused) return this.close(refused);\n\t\tconst { greetingDelay } = this.settings;\n\t\tif (greetingDelay > 0) await Bun.sleep(greetingDelay * 1000);\n\t\tif (this.#closed) return;\n\t\tif (this.input.early) {\n\t\t\t// RFC 5321 §4.3.1: the client waits for the greeting; a spammer often does not.\n\t\t\treturn this.close(\n\t\t\t\treply(554, '5.5.0', `${options.hostname} Talked before the greeting`),\n\t\t\t);\n\t\t}\n\t\tthis.send(reply(220, undefined, `${options.hostname} ESMTP ready`));\n\t\t// The client's idle time starts at the greeting, not at connect: what\n\t\t// greetingDelay and onConnect took is not taken from it.\n\t\tthis.transport.restartIdle(this.settings.timeout);\n\t\tthis.input.greeted();\n\t}\n\n\t/** Bytes from the client; processed in order, after what came before. */\n\treceive(chunk: Uint8Array): void {\n\t\tif (!this.#closed) this.input.receive(chunk);\n\t}\n\n\t/** Resolves once everything received so far is answered. */\n\tidle(): Promise<void> {\n\t\treturn this.input.idle();\n\t}\n}\n",
|
|
18
|
-
"import { SmtpError } from '../errors';\nimport type { SmtpServerOptions } from './options';\n\n/** The options with their defaults, checked once. */\nexport interface Settings {\n\treadonly options: SmtpServerOptions;\n\treadonly mode: 'mx' | 'submission';\n\treadonly maxMessageSize: number;\n\treadonly maxRecipients: number;\n\treadonly maxConnections: number;\n\treadonly maxErrors: number;\n\treadonly timeout: number;\n\treadonly hookTimeout: number;\n\treadonly greetingDelay: number;\n\tisLocal(domain: string): boolean | Promise<boolean>;\n}\n\n/** The longest delay `setTimeout` takes, in whole seconds: past 2^31 − 1 ms it fires after 1 ms. */\nconst MAX_TIMER_SECONDS = Math.floor(2_147_483_647 / 1000);\n\nconst invalid = (message: string) =>\n\tnew SmtpError('INVALID_OPTION', `createSmtpServer(): ${message}`);\n\nfunction positive(\n\tname: string,\n\tvalue: number | undefined,\n\tfallback: number,\n): number {\n\tif (value === undefined) return fallback;\n\tif (!Number.isSafeInteger(value) || value < 1) {\n\t\tthrow invalid(`${name} must be a positive integer, not ${value}`);\n\t}\n\treturn value;\n}\n\n/** `positive`, and short enough for `setTimeout`, which a longer delay makes fire at once. */\nfunction timer(\n\tname: string,\n\tvalue: number | undefined,\n\tfallback: number,\n): number {\n\tconst seconds = positive(name, value, fallback);\n\tif (seconds > MAX_TIMER_SECONDS) {\n\t\tthrow invalid(\n\t\t\t`${name} must be at most ${MAX_TIMER_SECONDS} seconds, not ${seconds}`,\n\t\t);\n\t}\n\treturn seconds;\n}\n\nfunction nonNegative(\n\tname: string,\n\tvalue: number | undefined,\n\tfallback: number,\n): number {\n\tif (value === undefined) return fallback;\n\tif (!Number.isFinite(value) || value < 0) {\n\t\tthrow invalid(\n\t\t\t`${name} must be a number of seconds, 0 or more, not ${value}`,\n\t\t);\n\t}\n\treturn value;\n}\n\n/** `localDomains` as a lookup; the domain it is given is lower case. */\nfunction localLookup(\n\tlocal: SmtpServerOptions['localDomains'],\n): (domain: string) => boolean | Promise<boolean> {\n\tif (typeof local === 'function') return local;\n\tif (\n\t\tArray.isArray(local) &&\n\t\tlocal.every((domain: unknown) => typeof domain === 'string')\n\t) {\n\t\tconst domains = new Set(\n\t\t\t(local as readonly string[]).map((domain) => domain.toLowerCase()),\n\t\t);\n\t\treturn (domain) => domains.has(domain);\n\t}\n\tthrow invalid('localDomains must be an array of domains or a function');\n}\n\nexport function settingsOf(options: SmtpServerOptions): Settings {\n\tif (\n\t\ttypeof options.hostname !== 'string' ||\n\t\t!/^[A-Za-z0-9.-]+$/.test(options.hostname)\n\t) {\n\t\tthrow invalid(`\"${options.hostname}\" is not a host name`);\n\t}\n\tif (typeof options.onData !== 'function') {\n\t\tthrow invalid('onData must be a function: it is where messages go');\n\t}\n\tif (options.implicitTls && !options.tls) {\n\t\tthrow invalid('implicitTls needs tls: { key, cert }');\n\t}\n\tif (options.mode === 'submission' && !options.authenticate) {\n\t\tthrow invalid(\n\t\t\t'submission takes mail only from authenticated users, so it needs authenticate',\n\t\t);\n\t}\n\tif (options.authenticate && !options.tls) {\n\t\tthrow invalid(\n\t\t\t'authenticate needs tls: { key, cert }, since AUTH is offered only once encrypted',\n\t\t);\n\t}\n\tconst isLocal = localLookup(options.localDomains);\n\tconst timeout = positive('timeout', options.timeout, 300);\n\tconst greetingDelay = nonNegative('greetingDelay', options.greetingDelay, 0);\n\tif (greetingDelay >= timeout) {\n\t\tthrow invalid(\n\t\t\t`greetingDelay (${greetingDelay} s) must be shorter than timeout (${timeout} s), or every client times out before the greeting`,\n\t\t);\n\t}\n\treturn {\n\t\toptions,\n\t\tmode: options.mode ?? 'mx',\n\t\tmaxMessageSize: positive(\n\t\t\t'maxMessageSize',\n\t\t\toptions.maxMessageSize,\n\t\t\t25 * 1024 * 1024,\n\t\t),\n\t\tmaxRecipients: positive('maxRecipients', options.maxRecipients, 100),\n\t\tmaxConnections: positive('maxConnections', options.maxConnections, 1000),\n\t\tmaxErrors: positive('maxErrors', options.maxErrors, 10),\n\t\ttimeout,\n\t\thookTimeout: timer('hookTimeout', options.hookTimeout, 60),\n\t\tgreetingDelay,\n\t\tisLocal: (domain) => isLocal(domain.toLowerCase()),\n\t};\n}\n",
|
|
19
19
|
"import type { Socket } from 'bun';\nimport { Outgoing } from '../io/outgoing';\n\n/** What a connection needs from its socket: Bun's, or a fake one in specs. */\nexport interface Transport {\n\treadonly remoteAddress: string;\n\treadonly secure: boolean;\n\t/** Queues text for the client; what the socket cannot take now is kept for `drain`. */\n\twrite(text: string): void;\n\t/** Resolves once everything written has left. */\n\tdrained(): Promise<void>;\n\t/**\n\t * Hangs up once everything written has left: a graceful close, as after\n\t * QUIT. A socket not closed within `CLOSE_GRACE_MS` is terminated.\n\t * If the server paused reading, it reads again first, since a half-close\n\t * does not complete over input left unread.\n\t */\n\tend(): void;\n\t/**\n\t * Hangs up now, the server's decision: what the socket already took\n\t * leaves, but what still waits for a client that stopped reading is\n\t * dropped and the connection reset, so the close never hangs on it.\n\t * With nothing queued it hangs up as `end()` does, within the same grace.\n\t */\n\tabort(): void;\n\t/** Stops reading from the client, while the server catches up. */\n\tpause(): void;\n\tresume(): void;\n\t/** Starts TLS on the connection, once the 220 to STARTTLS has left. */\n\tstartTls(): void;\n\t/** Starts the idle time again, as a byte from the client does. */\n\trestartIdle(seconds: number): void;\n}\n\n/**\n * How long any end may wait on the client — for what is queued to leave,\n * then for the close itself — before the socket is terminated.\n */\nexport const CLOSE_GRACE_MS = 5_000;\n\n/**\n * A hang-up while the server paused reading lingers: it reads again and\n * drops what the client sent until nothing came for `LINGER_QUIET_MS`,\n * then half-closes. Bun closes the socket at once on `shutdown(true)`, and\n * Linux answers a close over unread input with a reset that loses the last\n * reply. A client still sending after `LINGER_MAX_MS` is reset.\n */\nexport const LINGER_QUIET_MS = 20;\nexport const LINGER_MAX_MS = 500;\n\n/**\n * A Bun socket as a Transport. What the socket cannot take now waits in an\n * `Outgoing` for the `drain` event, so no reply is lost to a client that\n * reads slowly.\n */\nexport class SocketTransport implements Transport {\n\treadonly #socket: Socket<unknown>;\n\treadonly remoteAddress: string;\n\treadonly secure: boolean;\n\treadonly #startTls: () => void;\n\treadonly #outgoing: Outgoing;\n\t#ending = false;\n\t/** The socket closed: every later write, end or abort is a no-op. */\n\t#closed = false;\n\t/** The server stopped reading: what the client sends waits in the socket. */\n\t#paused = false;\n\t#grace: ReturnType<typeof setTimeout> | undefined;\n\t/** A paused hang-up waiting for the client's input to stop: how it will shut down, when it stops waiting, its timer. */\n\t#linger:\n\t\t| {\n\t\t\t\tdrained: boolean;\n\t\t\t\tuntil: number;\n\t\t\t\ttimer?: ReturnType<typeof setTimeout>;\n\t\t }\n\t\t| undefined;\n\n\tconstructor(\n\t\tsocket: Socket<unknown>,\n\t\tsecure: boolean,\n\t\tstartTls: () => void,\n\t\tremoteAddress = socket.remoteAddress,\n\t) {\n\t\tthis.#socket = socket;\n\t\tthis.secure = secure;\n\t\tthis.#startTls = startTls;\n\t\tthis.remoteAddress = remoteAddress;\n\t\tthis.#outgoing = new Outgoing((bytes) => socket.write(bytes));\n\t}\n\n\twrite(text: string): void {\n\t\tif (this.#closed) return;\n\t\tthis.#outgoing.write(new TextEncoder().encode(text));\n\t}\n\n\t/** Bun's `drain`: the socket can take more. */\n\tdrain(): void {\n\t\tif (this.#outgoing.drain() && this.#ending) this.#hangUp(true);\n\t}\n\n\tdrained(): Promise<void> {\n\t\treturn this.#outgoing.drained();\n\t}\n\n\t/**\n\t * Bun's `data`: the client sent bytes. While a hang-up lingers, they are\n\t * dropped, and the half-close waits until they stop — `LINGER_MAX_MS` at\n\t * most: a client still sending then is reset. Re-arming the timer on each\n\t * chunk would let a client that never pauses keep it from firing, and a\n\t * half-close over its input may never fire `close` (Linux).\n\t */\n\treceived(): void {\n\t\tconst linger = this.#linger;\n\t\tif (!linger) return;\n\t\tconst left = linger.until - Date.now();\n\t\tif (left <= 0) this.#terminate();\n\t\telse this.#lingerFor(Math.min(LINGER_QUIET_MS, left));\n\t}\n\n\t/** The socket closed: nothing more will leave. */\n\tclosed(): void {\n\t\tthis.#closed = true;\n\t\tthis.#disarm();\n\t\tthis.#stopLingering();\n\t\tthis.#outgoing.clear();\n\t}\n\n\t/** After `closed()`, does nothing: no grace is armed on a dead socket. */\n\tend(): void {\n\t\tif (this.#closed) return;\n\t\tthis.#arm();\n\t\tif (this.#outgoing.empty) this.#hangUp(false);\n\t\telse this.#ending = true;\n\t}\n\n\tabort(): void {\n\t\tif (this.#closed) return;\n\t\tif (this.#outgoing.empty) this.end();\n\t\telse this.#terminate();\n\t}\n\n\t/**\n\t * Hangs up with a half-close, `shutdown(true)`, not Bun's `end`: on TLS,\n\t * `end` waits for the client's own close, which a client that stopped\n\t * reading never sends, and a `terminate` after it no longer closes the\n\t * socket (Bun 1.4). The half-close fires `close` at once, and a client\n\t * that reads later still gets every byte, then the end. A full\n\t * `shutdown()` would hold a paused client until the grace, then lose\n\t * its last reply to the reset.\n\t *\n\t * Except on TLS right after a queue drained (`drained`): there the last\n\t * write may still sit in Bun's own TLS buffer, which a half-close drops\n\t * (Bun 1.4.2: up to 96 KiB lost by a client reading slowly). The client\n\t * was reading a moment ago, so a full `shutdown()` closes once it\n\t * answers, and the grace bounds it if it stops.\n\t *\n\t * Reading paused, it reads again first: over input the server never\n\t * read, a half-close does not fire `close` (Bun 1.4.2), and the slot\n\t * waited for the grace. And it lingers: Bun closes the socket as soon as\n\t * it half-closes, and on Linux a close with input still unread is a\n\t * reset, which loses the last reply. So it drops what the client sends\n\t * until that stops for `LINGER_QUIET_MS` (`LINGER_MAX_MS` at most), then\n\t * half-closes: `close` fires at once, and a client that stopped sending\n\t * still gets the last reply and the end. One still sending at\n\t * `LINGER_MAX_MS` is reset (`received()`).\n\t */\n\t#hangUp(drained: boolean): void {\n\t\tthis.#ending = false;\n\t\tif (this.#linger) return;\n\t\tif (!this.#paused) {\n\t\t\tthis.#shutdown(drained);\n\t\t\treturn;\n\t\t}\n\t\tthis.resume();\n\t\tthis.#linger = { drained, until: Date.now() + LINGER_MAX_MS };\n\t\tthis.#lingerFor(LINGER_QUIET_MS);\n\t}\n\n\t/**\n\t * Half-closes in `ms`, unless the client sends again first. Armed for\n\t * less than `LINGER_QUIET_MS`, the input never went quiet before\n\t * `LINGER_MAX_MS`: it resets instead.\n\t */\n\t#lingerFor(ms: number): void {\n\t\tconst linger = this.#linger;\n\t\tif (!linger) return;\n\t\tclearTimeout(linger.timer);\n\t\tlinger.timer = setTimeout(() => {\n\t\t\tif (ms < LINGER_QUIET_MS) return this.#terminate();\n\t\t\tthis.#stopLingering();\n\t\t\tthis.#shutdown(linger.drained);\n\t\t}, ms);\n\t\tlinger.timer.unref?.();\n\t}\n\n\t#stopLingering(): void {\n\t\tclearTimeout(this.#linger?.timer);\n\t\tthis.#linger = undefined;\n\t}\n\n\t#shutdown(drained: boolean): void {\n\t\tif (drained && this.secure) this.#socket.shutdown();\n\t\telse this.#socket.shutdown(true);\n\t}\n\n\t/** Drops what is queued and resets the connection. */\n\t#terminate(): void {\n\t\tthis.#disarm();\n\t\tthis.#stopLingering();\n\t\tthis.#outgoing.clear();\n\t\tthis.#socket.terminate();\n\t}\n\n\t/** Terminates the socket once the grace is up, unless it closed first; the first deadline stands. */\n\t#arm(): void {\n\t\tif (this.#grace) return;\n\t\tthis.#grace = setTimeout(() => this.#terminate(), CLOSE_GRACE_MS);\n\t\tthis.#grace.unref?.();\n\t}\n\n\t#disarm(): void {\n\t\tclearTimeout(this.#grace);\n\t\tthis.#grace = undefined;\n\t}\n\n\tpause(): void {\n\t\tthis.#paused = true;\n\t\tthis.#socket.pause();\n\t}\n\n\tresume(): void {\n\t\tthis.#paused = false;\n\t\tthis.#socket.resume();\n\t}\n\n\tstartTls(): void {\n\t\tthis.#startTls();\n\t}\n\n\trestartIdle(seconds: number): void {\n\t\tthis.#socket.timeout(seconds);\n\t}\n}\n",
|
|
20
|
-
"import type { Socket, SocketHandler
|
|
20
|
+
"import type { Socket, SocketHandler } from 'bun';\nimport { reply } from '../protocol/reply';\nimport { clientKey } from './client-key';\nimport { Connection } from './connection';\nimport type { Settings } from './settings';\nimport type { Slots } from './slots';\nimport { SocketTransport } from './transport';\n\n/**\n * What a socket of the SMTP server does: the handlers the clear socket and\n * the TLS one share, the STARTTLS upgrade, and the listener's own `open`,\n * `handshake` and `close`, which count a socket from its TCP connection.\n */\n\nexport interface SocketState {\n\tconnection?: Connection;\n\ttransport?: SocketTransport;\n\t/** Bytes on the raw socket after STARTTLS are the TLS stream itself: ignored. */\n\tupgraded: boolean;\n\t/**\n\t * Implicit TLS whose handshake has not completed: the socket is counted,\n\t * but bounded by `handshakeTimeout`, and `start` waits for the handshake.\n\t */\n\thandshaking?: boolean;\n\t/** What the server does once the handshake completes: greet, or turn away. */\n\tstart?: () => void;\n}\n\n/**\n * The handlers both the clear socket and the TLS one share: input, drain,\n * idle time. `socket.data` is read with `?.` throughout: Bun may report an\n * error or a close on a socket whose `open` never ran.\n */\nexport function handlers(settings: Settings): SocketHandler<SocketState> {\n\tconst idle = reply(\n\t\t421,\n\t\t'4.4.2',\n\t\t`${settings.options.hostname} Idle too long, closing`,\n\t);\n\treturn {\n\t\tdata(socket, chunk) {\n\t\t\tif (!socket.data || socket.data.upgraded) return;\n\t\t\t// A hang-up that lingers waits for the client to stop sending.\n\t\t\tsocket.data.transport?.received();\n\t\t\t// Any byte from the client starts the idle time again.\n\t\t\tsocket.timeout(settings.timeout);\n\t\t\tsocket.data.connection?.receive(chunk);\n\t\t},\n\t\tdrain(socket) {\n\t\t\tif (socket.data && !socket.data.upgraded) socket.data.transport?.drain();\n\t\t},\n\t\terror(socket) {\n\t\t\tsocket.data?.connection?.close();\n\t\t},\n\t\ttimeout(socket) {\n\t\t\tif (!socket.data || socket.data.upgraded) return;\n\t\t\t// A TLS handshake that never completed: nothing to say, no one to say it to.\n\t\t\tif (socket.data.handshaking) return socket.terminate();\n\t\t\tconst { connection, transport } = socket.data;\n\t\t\t// Closed already, after QUIT, and the 221 still waits for a client\n\t\t\t// that stopped reading: the idle time is up for that too.\n\t\t\tif (connection?.closed) transport?.abort();\n\t\t\telse connection?.close(idle);\n\t\t},\n\t};\n}\n\n/** Writes one reply and hangs up, through a transport so the hang-up is bounded as every other is. */\nfunction turnAway(\n\tsocket: Socket<SocketState>,\n\tsecure: boolean,\n\tline: string,\n): void {\n\tconst refused = new SocketTransport(\n\t\tsocket as Socket<unknown>,\n\t\tsecure,\n\t\t() => {},\n\t);\n\tsocket.data.transport = refused;\n\trefused.write(line);\n\trefused.end();\n}\n\n/** Wraps a socket; STARTTLS swaps it for the encrypted one. */\nfunction transportOf(\n\tsocket: Socket<SocketState>,\n\tsettings: Settings,\n\tsecure: boolean,\n\tslots: Slots<Connection>,\n): SocketTransport {\n\tconst transport = new SocketTransport(\n\t\tsocket as Socket<unknown>,\n\t\tsecure,\n\t\t() => {\n\t\t\tconst tls = settings.options.tls;\n\t\t\tconst connection = socket.data.connection;\n\t\t\tif (!tls || !connection) return;\n\t\t\tsocket.data.upgraded = true;\n\t\t\tconst [, encrypted] = socket.upgradeTLS<SocketState>({\n\t\t\t\ttls: { key: tls.key, cert: tls.cert },\n\t\t\t\tdata: { connection, upgraded: false },\n\t\t\t\tsocket: {\n\t\t\t\t\t...handlers(settings),\n\t\t\t\t\tclose: (s) => {\n\t\t\t\t\t\tslots.release(connection);\n\t\t\t\t\t\ts.data.transport?.closed();\n\t\t\t\t\t\tconnection.close();\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t});\n\t\t\tencrypted.timeout(settings.timeout);\n\t\t\tconst next = new SocketTransport(\n\t\t\t\tencrypted as Socket<unknown>,\n\t\t\t\ttrue,\n\t\t\t\t() => {},\n\t\t\t\tsocket.remoteAddress,\n\t\t\t);\n\t\t\tencrypted.data.transport = next;\n\t\t\tconnection.useTransport(next);\n\t\t},\n\t);\n\tsocket.data.transport = transport;\n\treturn transport;\n}\n\n/**\n * The listener's own handlers: `open` counts a socket and greets it or turns\n * it away, `handshake` lets implicit TLS start once encrypted, `close`\n * frees the slot. `handshaking` holds the sockets still in their\n * handshake, for `stop(true)`.\n */\nexport function listenerHandlers(\n\tsettings: Settings,\n\tslots: Slots<Connection>,\n\thandshaking: Set<Socket<SocketState>>,\n\tsecure: boolean,\n): Pick<SocketHandler<SocketState>, 'open' | 'handshake' | 'close'> {\n\treturn {\n\t\t// With a `handshake` handler, Bun calls `open` on implicit TLS\n\t\t// as soon as TCP connects; without one, only once the\n\t\t// handshake completed, so a client that never sends its\n\t\t// ClientHello would be counted by no limit and bounded by no\n\t\t// timer.\n\t\topen(socket) {\n\t\t\tsocket.data = { upgraded: false, handshaking: secure };\n\t\t\tsocket.timeout(secure ? settings.handshakeTimeout : settings.timeout);\n\t\t\tconst begin = (start: () => void) => {\n\t\t\t\tif (!secure) return start();\n\t\t\t\thandshaking.add(socket);\n\t\t\t\tsocket.data.start = start;\n\t\t\t};\n\t\t\tif (slots.size >= settings.maxConnections) {\n\t\t\t\treturn begin(() =>\n\t\t\t\t\tturnAway(\n\t\t\t\t\t\tsocket,\n\t\t\t\t\t\tsecure,\n\t\t\t\t\t\t`421 4.3.2 ${settings.options.hostname} Too many connections, try later\\r\\n`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst key = clientKey(socket.remoteAddress);\n\t\t\tif (slots.of(key) >= settings.maxConnectionsPerClient) {\n\t\t\t\treturn begin(() =>\n\t\t\t\t\tturnAway(\n\t\t\t\t\t\tsocket,\n\t\t\t\t\t\tsecure,\n\t\t\t\t\t\t`421 4.7.0 ${settings.options.hostname} Too many connections from your address, try later\\r\\n`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst connection = new Connection(\n\t\t\t\tsettings,\n\t\t\t\ttransportOf(socket, settings, secure, slots),\n\t\t\t);\n\t\t\tslots.take(connection, key);\n\t\t\tsocket.data.connection = connection;\n\t\t\tbegin(() => void connection.open());\n\t\t},\n\t\thandshake(socket, success) {\n\t\t\tconst state = socket.data;\n\t\t\tif (!state?.handshaking) return;\n\t\t\thandshaking.delete(socket);\n\t\t\t// A failed handshake: Bun closes the socket, and `close` counts it out.\n\t\t\tif (!success) return;\n\t\t\tstate.handshaking = false;\n\t\t\tsocket.timeout(settings.timeout);\n\t\t\tconst start = state.start;\n\t\t\tdelete state.start;\n\t\t\tstart?.();\n\t\t},\n\t\tclose(socket) {\n\t\t\thandshaking.delete(socket);\n\t\t\tconst connection = socket.data?.connection;\n\t\t\tif (connection) slots.release(connection);\n\t\t\tsocket.data?.transport?.closed();\n\t\t\tconnection?.close();\n\t\t},\n\t};\n}\n",
|
|
21
|
+
"import { SmtpError } from '../errors';\nimport type { SmtpServerOptions } from './options';\n\n/** The options with their defaults, checked once. */\nexport interface Settings {\n\treadonly options: SmtpServerOptions;\n\treadonly mode: 'mx' | 'submission';\n\treadonly maxMessageSize: number;\n\treadonly maxRecipients: number;\n\treadonly maxConnections: number;\n\treadonly maxConnectionsPerClient: number;\n\treadonly maxErrors: number;\n\treadonly timeout: number;\n\treadonly hookTimeout: number;\n\treadonly handshakeTimeout: number;\n\treadonly greetingDelay: number;\n\tisLocal(domain: string): boolean | Promise<boolean>;\n}\n\n/** The longest delay `setTimeout` takes, in whole seconds: past 2^31 − 1 ms it fires after 1 ms. */\nconst MAX_TIMER_SECONDS = Math.floor(2_147_483_647 / 1000);\n\nconst invalid = (message: string) =>\n\tnew SmtpError('INVALID_OPTION', `createSmtpServer(): ${message}`);\n\nfunction positive(\n\tname: string,\n\tvalue: number | undefined,\n\tfallback: number,\n): number {\n\tif (value === undefined) return fallback;\n\tif (!Number.isSafeInteger(value) || value < 1) {\n\t\tthrow invalid(`${name} must be a positive integer, not ${value}`);\n\t}\n\treturn value;\n}\n\n/** `positive`, and short enough for `setTimeout`, which a longer delay makes fire at once. */\nfunction timer(\n\tname: string,\n\tvalue: number | undefined,\n\tfallback: number,\n): number {\n\tconst seconds = positive(name, value, fallback);\n\tif (seconds > MAX_TIMER_SECONDS) {\n\t\tthrow invalid(\n\t\t\t`${name} must be at most ${MAX_TIMER_SECONDS} seconds, not ${seconds}`,\n\t\t);\n\t}\n\treturn seconds;\n}\n\nfunction nonNegative(\n\tname: string,\n\tvalue: number | undefined,\n\tfallback: number,\n): number {\n\tif (value === undefined) return fallback;\n\tif (!Number.isFinite(value) || value < 0) {\n\t\tthrow invalid(\n\t\t\t`${name} must be a number of seconds, 0 or more, not ${value}`,\n\t\t);\n\t}\n\treturn value;\n}\n\n/** `localDomains` as a lookup; the domain it is given is lower case. */\nfunction localLookup(\n\tlocal: SmtpServerOptions['localDomains'],\n): (domain: string) => boolean | Promise<boolean> {\n\tif (typeof local === 'function') return local;\n\tif (\n\t\tArray.isArray(local) &&\n\t\tlocal.every((domain: unknown) => typeof domain === 'string')\n\t) {\n\t\tconst domains = new Set(\n\t\t\t(local as readonly string[]).map((domain) => domain.toLowerCase()),\n\t\t);\n\t\treturn (domain) => domains.has(domain);\n\t}\n\tthrow invalid('localDomains must be an array of domains or a function');\n}\n\nexport function settingsOf(options: SmtpServerOptions): Settings {\n\tif (\n\t\ttypeof options.hostname !== 'string' ||\n\t\t!/^[A-Za-z0-9.-]+$/.test(options.hostname)\n\t) {\n\t\tthrow invalid(`\"${options.hostname}\" is not a host name`);\n\t}\n\tif (typeof options.onData !== 'function') {\n\t\tthrow invalid('onData must be a function: it is where messages go');\n\t}\n\tif (options.implicitTls && !options.tls) {\n\t\tthrow invalid('implicitTls needs tls: { key, cert }');\n\t}\n\tif (options.mode === 'submission' && !options.authenticate) {\n\t\tthrow invalid(\n\t\t\t'submission takes mail only from authenticated users, so it needs authenticate',\n\t\t);\n\t}\n\tif (options.authenticate && !options.tls) {\n\t\tthrow invalid(\n\t\t\t'authenticate needs tls: { key, cert }, since AUTH is offered only once encrypted',\n\t\t);\n\t}\n\tconst isLocal = localLookup(options.localDomains);\n\tconst timeout = positive('timeout', options.timeout, 300);\n\tconst greetingDelay = nonNegative('greetingDelay', options.greetingDelay, 0);\n\tif (greetingDelay >= timeout) {\n\t\tthrow invalid(\n\t\t\t`greetingDelay (${greetingDelay} s) must be shorter than timeout (${timeout} s), or every client times out before the greeting`,\n\t\t);\n\t}\n\treturn {\n\t\toptions,\n\t\tmode: options.mode ?? 'mx',\n\t\tmaxMessageSize: positive(\n\t\t\t'maxMessageSize',\n\t\t\toptions.maxMessageSize,\n\t\t\t25 * 1024 * 1024,\n\t\t),\n\t\tmaxRecipients: positive('maxRecipients', options.maxRecipients, 100),\n\t\tmaxConnections: positive('maxConnections', options.maxConnections, 1000),\n\t\tmaxConnectionsPerClient: positive(\n\t\t\t'maxConnectionsPerClient',\n\t\t\toptions.maxConnectionsPerClient,\n\t\t\t10,\n\t\t),\n\t\tmaxErrors: positive('maxErrors', options.maxErrors, 10),\n\t\ttimeout,\n\t\thookTimeout: timer('hookTimeout', options.hookTimeout, 60),\n\t\thandshakeTimeout: positive(\n\t\t\t'handshakeTimeout',\n\t\t\toptions.handshakeTimeout,\n\t\t\t10,\n\t\t),\n\t\tgreetingDelay,\n\t\tisLocal: (domain) => isLocal(domain.toLowerCase()),\n\t};\n}\n",
|
|
22
|
+
"/**\n * The connections a server holds, and how many each client holds, by\n * `clientKey`. `release` is idempotent: every close handler calls it.\n */\nexport class Slots<T> {\n\treadonly #open = new Map<T, string | undefined>();\n\treadonly #perClient = new Map<string, number>();\n\n\tget size(): number {\n\t\treturn this.#open.size;\n\t}\n\n\t/** How many connections the client `key` holds. */\n\tof(key: string | undefined): number {\n\t\treturn key === undefined ? 0 : (this.#perClient.get(key) ?? 0);\n\t}\n\n\ttake(connection: T, key: string | undefined): void {\n\t\tthis.#open.set(connection, key);\n\t\tif (key !== undefined) this.#perClient.set(key, this.of(key) + 1);\n\t}\n\n\trelease(connection: T): void {\n\t\tif (!this.#open.has(connection)) return;\n\t\tconst key = this.#open.get(connection);\n\t\tthis.#open.delete(connection);\n\t\tif (key === undefined) return;\n\t\tconst left = this.of(key) - 1;\n\t\tif (left > 0) this.#perClient.set(key, left);\n\t\telse this.#perClient.delete(key);\n\t}\n\n\tconnections(): T[] {\n\t\treturn [...this.#open.keys()];\n\t}\n}\n",
|
|
23
|
+
"import type { Socket, TCPSocketListener } from 'bun';\nimport { SmtpError } from '../errors';\nimport type { Connection } from './connection';\nimport { handlers, listenerHandlers, type SocketState } from './listener';\nimport type { SmtpServerOptions } from './options';\nimport { settingsOf } from './settings';\nimport { Slots } from './slots';\n\nexport interface SmtpServer {\n\t/** Starts listening; resolves once the port is bound. Once only: a second call throws. */\n\tlisten(options: {\n\t\tport: number;\n\t\thostname?: string;\n\t}): Promise<{ port: number; hostname: string }>;\n\t/** Stops listening; `closeConnections` hangs up on every client too. */\n\tstop(closeConnections?: boolean): void;\n\t/** Open connections. */\n\treadonly connections: number;\n}\n\n/**\n * An SMTP server (RFC 5321) on `Bun.listen`: EHLO with PIPELINING, SIZE,\n * 8BITMIME, SMTPUTF8 and ENHANCEDSTATUSCODES; STARTTLS (RFC 3207) or\n * implicit TLS (RFC 8314); AUTH PLAIN and LOGIN over TLS only (RFC 4954);\n * policy through hooks. It never relays without AUTH: a recipient outside\n * `localDomains` is refused to an unauthenticated session, whatever the\n * hooks say.\n */\nexport function createSmtpServer(options: SmtpServerOptions): SmtpServer {\n\tconst settings = settingsOf(options);\n\tlet listener: TCPSocketListener<SocketState> | undefined;\n\tconst slots = new Slots<Connection>();\n\t/** Implicit TLS sockets still in their handshake, for `stop(true)`. */\n\tconst handshaking = new Set<Socket<SocketState>>();\n\tconst secure = options.implicitTls === true;\n\treturn {\n\t\tget connections() {\n\t\t\treturn slots.size;\n\t\t},\n\t\tasync listen({ port, hostname = '0.0.0.0' }) {\n\t\t\tif (listener) {\n\t\t\t\tthrow new SmtpError(\n\t\t\t\t\t'ALREADY_LISTENING',\n\t\t\t\t\t`listen(): the server is already listening on ${listener.hostname}:${listener.port}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tlistener = Bun.listen<SocketState>({\n\t\t\t\thostname,\n\t\t\t\tport,\n\t\t\t\t...(secure && options.tls\n\t\t\t\t\t? { tls: { key: options.tls.key, cert: options.tls.cert } }\n\t\t\t\t\t: {}),\n\t\t\t\tsocket: {\n\t\t\t\t\t...handlers(settings),\n\t\t\t\t\t...listenerHandlers(settings, slots, handshaking, secure),\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn { port: listener.port, hostname: listener.hostname };\n\t\t},\n\t\tstop(closeConnections = false) {\n\t\t\tlistener?.stop(closeConnections);\n\t\t\tlistener = undefined;\n\t\t\tif (!closeConnections) return;\n\t\t\t// Bun's `stop(true)` closes the sockets the listener holds, and a\n\t\t\t// socket STARTTLS moved to TLS is no longer one of them: hang up on\n\t\t\t// every connection here, as a timeout does. A socket still in its\n\t\t\t// handshake has no TLS to say 421 on: it is reset.\n\t\t\tconst stuck = new Set<Connection | undefined>();\n\t\t\tfor (const socket of [...handshaking]) {\n\t\t\t\tstuck.add(socket.data?.connection);\n\t\t\t\thandshaking.delete(socket);\n\t\t\t\tsocket.terminate();\n\t\t\t}\n\t\t\tfor (const connection of slots.connections()) {\n\t\t\t\tif (!stuck.has(connection)) connection.close();\n\t\t\t}\n\t\t},\n\t};\n}\n"
|
|
21
24
|
],
|
|
22
|
-
"mappings": "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",
|
|
23
|
-
"debugId": "
|
|
25
|
+
"mappings": "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",
|
|
26
|
+
"debugId": "388406E838895A3964756E2164756E21",
|
|
24
27
|
"names": []
|
|
25
28
|
}
|
|
@@ -13,8 +13,10 @@ export interface PathCommand {
|
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
15
|
* Parses the argument of `MAIL` or `RCPT`: `FROM:<path> params` (or `TO:`).
|
|
16
|
-
* Tolerates a space after the colon, which many clients send. `
|
|
17
|
-
*
|
|
16
|
+
* Tolerates a space after the colon, which many clients send. `TO:` also
|
|
17
|
+
* takes `<postmaster>` with no domain, in any case (RFC 5321 §4.1.1.3,
|
|
18
|
+
* §4.5.1), as a path whose `postmaster` is `true`. `undefined` when the
|
|
19
|
+
* syntax is wrong.
|
|
18
20
|
*/
|
|
19
21
|
export declare function parsePathCommand(argument: string, keyword: 'FROM' | 'TO'): PathCommand | undefined;
|
|
20
22
|
//# sourceMappingURL=command.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/protocol/command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/protocol/command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,EAAyB,MAAM,QAAQ,CAAC;AAE1D,qEAAqE;AACrE,MAAM,WAAW,OAAO;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOlD;AAED,oEAAoE;AACpE,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,oGAAoG;IACpG,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACtD;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GAAG,IAAI,GACpB,WAAW,GAAG,SAAS,CAoBzB"}
|
package/dist/protocol/path.d.ts
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
/** An envelope address, as `MAIL FROM` and `RCPT TO` give it. */
|
|
2
2
|
export interface Path {
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* `local@domain`; `''` for the null reverse-path `<>`; `'postmaster'`
|
|
5
|
+
* for `RCPT TO:<postmaster>`, which has no domain.
|
|
6
|
+
*/
|
|
4
7
|
readonly address: string;
|
|
5
8
|
readonly local: string;
|
|
6
|
-
/** Lower case
|
|
9
|
+
/** Lower case; `''` for `<>` and for `<postmaster>`. */
|
|
7
10
|
readonly domain: string;
|
|
11
|
+
/**
|
|
12
|
+
* `true` for `RCPT TO:<postmaster>`, in any case, with no domain (RFC
|
|
13
|
+
* 5321 §4.5.1): the postmaster of this server, whatever domains it
|
|
14
|
+
* hosts. Absent for every other path, `<postmaster@domain>` included.
|
|
15
|
+
*/
|
|
16
|
+
readonly postmaster?: true;
|
|
8
17
|
}
|
|
18
|
+
/** The bare `<postmaster>` path `RCPT TO` takes (RFC 5321 §4.1.1.3, §4.5.1). */
|
|
19
|
+
export declare const POSTMASTER: Path;
|
|
9
20
|
/**
|
|
10
21
|
* An address literal (§4.1.3): `[IPv6:…]`, its tag in any case (a quoted
|
|
11
22
|
* string in RFC 5234 is), or `[a.b.c.d]` with each octet at most 255.
|
|
@@ -28,7 +39,7 @@ export type SourceRoute = 'discard' | 'refuse';
|
|
|
28
39
|
* `sourceRoute` is `'discard'`, the default, provided each hop is
|
|
29
40
|
* `@domain`; with `'refuse'` the path is not one. A C0 control (CR, LF,
|
|
30
41
|
* NUL…), DEL or `>` anywhere refuses the path, as do C1 controls,
|
|
31
|
-
* Unicode format characters and lone surrogates. An IPv4 address literal
|
|
42
|
+
* U+2028 and U+2029, Unicode format characters and lone surrogates. An IPv4 address literal
|
|
32
43
|
* takes octets up to 255.
|
|
33
44
|
* Non-ASCII is allowed: whether the session may use it is SMTPUTF8's
|
|
34
45
|
* question (RFC 6531), not the grammar's. `undefined` when it is not a path.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/protocol/path.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,MAAM,WAAW,IAAI;IACpB
|
|
1
|
+
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/protocol/path.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,MAAM,WAAW,IAAI;IACpB;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,wDAAwD;IACxD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC;CAC3B;AAED,gFAAgF;AAChF,eAAO,MAAM,UAAU,EAAE,IAKvB,CAAC;AAwCH;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAItD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAIjD;AAUD;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;AAgB/C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CACxB,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,OAAO,EAClB,WAAW,GAAE,WAAuB,GAClC,IAAI,GAAG,SAAS,CAuBlB"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which client an address counts as, for a limit per client: an IPv4
|
|
3
|
+
* address as it is; an IPv6 address that embeds one — IPv4-mapped
|
|
4
|
+
* (`::ffff:192.0.2.1`, in dotted or hex form, as a dual-stack listener
|
|
5
|
+
* sees an IPv4 client) or NAT64 (`64:ff9b::/96`) — as that IPv4 address;
|
|
6
|
+
* any other IPv6 address by its /64, which one machine usually holds
|
|
7
|
+
* whole, written as its first four groups in lower-case hex without
|
|
8
|
+
* leading zeros, every group written out, zeros included, then `::/64`:
|
|
9
|
+
* `2001:db8::1` is `2001:db8:0:0::/64`, never `2001:db8::/64`. Anything
|
|
10
|
+
* else — an empty string, a Unix socket — is `undefined`: no client that
|
|
11
|
+
* can be told apart, so not limited, rather than putting every such
|
|
12
|
+
* client in one bucket that one of them could fill for all.
|
|
13
|
+
*/
|
|
14
|
+
export declare function clientKey(ip: string | undefined): string | undefined;
|
|
15
|
+
//# sourceMappingURL=client-key.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-key.d.ts","sourceRoot":"","sources":["../../src/server/client-key.ts"],"names":[],"mappings":"AA+BA;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAcpE"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Socket, SocketHandler } from 'bun';
|
|
2
|
+
import { Connection } from './connection';
|
|
3
|
+
import type { Settings } from './settings';
|
|
4
|
+
import type { Slots } from './slots';
|
|
5
|
+
import { SocketTransport } from './transport';
|
|
6
|
+
/**
|
|
7
|
+
* What a socket of the SMTP server does: the handlers the clear socket and
|
|
8
|
+
* the TLS one share, the STARTTLS upgrade, and the listener's own `open`,
|
|
9
|
+
* `handshake` and `close`, which count a socket from its TCP connection.
|
|
10
|
+
*/
|
|
11
|
+
export interface SocketState {
|
|
12
|
+
connection?: Connection;
|
|
13
|
+
transport?: SocketTransport;
|
|
14
|
+
/** Bytes on the raw socket after STARTTLS are the TLS stream itself: ignored. */
|
|
15
|
+
upgraded: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Implicit TLS whose handshake has not completed: the socket is counted,
|
|
18
|
+
* but bounded by `handshakeTimeout`, and `start` waits for the handshake.
|
|
19
|
+
*/
|
|
20
|
+
handshaking?: boolean;
|
|
21
|
+
/** What the server does once the handshake completes: greet, or turn away. */
|
|
22
|
+
start?: () => void;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The handlers both the clear socket and the TLS one share: input, drain,
|
|
26
|
+
* idle time. `socket.data` is read with `?.` throughout: Bun may report an
|
|
27
|
+
* error or a close on a socket whose `open` never ran.
|
|
28
|
+
*/
|
|
29
|
+
export declare function handlers(settings: Settings): SocketHandler<SocketState>;
|
|
30
|
+
/**
|
|
31
|
+
* The listener's own handlers: `open` counts a socket and greets it or turns
|
|
32
|
+
* it away, `handshake` lets implicit TLS start once encrypted, `close`
|
|
33
|
+
* frees the slot. `handshaking` holds the sockets still in their
|
|
34
|
+
* handshake, for `stop(true)`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function listenerHandlers(settings: Settings, slots: Slots<Connection>, handshaking: Set<Socket<SocketState>>, secure: boolean): Pick<SocketHandler<SocketState>, 'open' | 'handshake' | 'close'>;
|
|
37
|
+
//# sourceMappingURL=listener.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../../src/server/listener.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAGjD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C;;;;GAIG;AAEH,MAAM,WAAW,WAAW;IAC3B,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,iFAAiF;IACjF,QAAQ,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,aAAa,CAAC,WAAW,CAAC,CAgCvE;AA4DD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC/B,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,EACxB,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,EACrC,MAAM,EAAE,OAAO,GACb,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC,CA8DlE"}
|
package/dist/server/options.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export interface Session {
|
|
|
24
24
|
export interface Envelope {
|
|
25
25
|
/** `''` for the null reverse-path `<>`: a bounce. */
|
|
26
26
|
readonly from: string;
|
|
27
|
+
/** `local@domain` each; `'postmaster'`, with no domain, for `RCPT TO:<postmaster>`. */
|
|
27
28
|
readonly to: readonly string[];
|
|
28
29
|
/** The client asked for SMTPUTF8 (RFC 6531). */
|
|
29
30
|
readonly smtputf8: boolean;
|
|
@@ -70,7 +71,12 @@ export interface ReceivedMessage {
|
|
|
70
71
|
*/
|
|
71
72
|
export type HookResult = Reply | undefined | void;
|
|
72
73
|
export interface SmtpHooks {
|
|
73
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* A client connected, and was let in by `maxConnections` and
|
|
76
|
+
* `maxConnectionsPerClient`. A reply refuses it: the server sends it
|
|
77
|
+
* instead of its greeting and closes. `session.remoteAddress` says who
|
|
78
|
+
* it is; `clientKey` groups it as the limits do.
|
|
79
|
+
*/
|
|
74
80
|
onConnect?(session: Session): HookResult | Promise<HookResult>;
|
|
75
81
|
/** After the server's own checks of MAIL FROM. */
|
|
76
82
|
onMailFrom?(path: Path, session: Session): HookResult | Promise<HookResult>;
|
|
@@ -123,10 +129,28 @@ export interface SmtpServerOptions extends SmtpHooks {
|
|
|
123
129
|
readonly maxRecipients?: number;
|
|
124
130
|
/** Open connections at once. Default 1000. */
|
|
125
131
|
readonly maxConnections?: number;
|
|
132
|
+
/**
|
|
133
|
+
* Open connections at once from one client, so one address cannot take
|
|
134
|
+
* every `maxConnections` slot. A client is an IPv4 address, or an IPv6
|
|
135
|
+
* address by its /64; an IPv4-mapped or NAT64 address counts as the
|
|
136
|
+
* IPv4 address inside it (see `clientKey`). One more is answered
|
|
137
|
+
* `421 4.7.0` and closed. A remote address that is not an IP address
|
|
138
|
+
* is not limited by it. Default 10.
|
|
139
|
+
*/
|
|
140
|
+
readonly maxConnectionsPerClient?: number;
|
|
126
141
|
/** Commands that fail before the server hangs up. Default 10. */
|
|
127
142
|
readonly maxErrors?: number;
|
|
128
143
|
/** Idle time before the server hangs up, in seconds; any byte from the client starts it again. Default 300, RFC 5321 §4.5.3.2.7's. */
|
|
129
144
|
readonly timeout?: number;
|
|
145
|
+
/**
|
|
146
|
+
* Seconds a client on implicit TLS has to complete its handshake, from
|
|
147
|
+
* the TCP connection on; past it, the socket is closed without a word.
|
|
148
|
+
* The socket holds its slot of `maxConnections` and
|
|
149
|
+
* `maxConnectionsPerClient` meanwhile. Bun's socket timer ticks in steps
|
|
150
|
+
* of about 4 s, so the close comes up to that much later. A STARTTLS
|
|
151
|
+
* handshake is bounded by `timeout`. Default 10.
|
|
152
|
+
*/
|
|
153
|
+
readonly handshakeTimeout?: number;
|
|
130
154
|
/**
|
|
131
155
|
* Seconds the server waits, once `onConnect` accepted, before its 220
|
|
132
156
|
* greeting. A client that talks in that time is refused with `554`
|