ntfy-reverse-proxy 2.0.4 → 2.1.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/LICENSE +22 -0
- package/README.md +10 -0
- package/build/src/cli/commands/config-io.d.ts +3 -3
- package/build/src/cli/commands/config-io.d.ts.map +1 -1
- package/build/src/cli/commands/config-io.js +1 -1
- package/build/src/cli/commands/config-io.js.map +1 -1
- package/build/src/cli/commands/context.d.ts +7 -7
- package/build/src/cli/commands/context.d.ts.map +1 -1
- package/build/src/cli/commands/context.js +1 -1
- package/build/src/cli/commands/context.js.map +1 -1
- package/build/src/cli/commands/deploy.d.ts +2 -2
- package/build/src/cli/commands/deploy.d.ts.map +1 -1
- package/build/src/cli/commands/deploy.js +72 -30
- package/build/src/cli/commands/deploy.js.map +1 -1
- package/build/src/cli/commands/generate.d.ts +2 -2
- package/build/src/cli/commands/generate.d.ts.map +1 -1
- package/build/src/cli/commands/generate.js +3 -3
- package/build/src/cli/commands/generate.js.map +1 -1
- package/build/src/cli/commands/server.d.ts +5 -5
- package/build/src/cli/commands/server.d.ts.map +1 -1
- package/build/src/cli/commands/server.js.map +1 -1
- package/build/src/cli/commands/settings.d.ts +3 -3
- package/build/src/cli/commands/settings.d.ts.map +1 -1
- package/build/src/cli/commands/settings.js.map +1 -1
- package/build/src/cli/commands/validate.d.ts +2 -2
- package/build/src/cli/commands/validate.d.ts.map +1 -1
- package/build/src/cli/commands/validate.js +3 -0
- package/build/src/cli/commands/validate.js.map +1 -1
- package/build/src/cli/index.d.ts +2 -2
- package/build/src/cli/index.d.ts.map +1 -1
- package/build/src/cli/index.js +4 -4
- package/build/src/cli/index.js.map +1 -1
- package/build/src/cli/menu/interactive.d.ts +2 -2
- package/build/src/cli/menu/interactive.d.ts.map +1 -1
- package/build/src/cli/menu/interactive.js +174 -84
- package/build/src/cli/menu/interactive.js.map +1 -1
- package/build/src/lib/regex.d.ts +4 -1
- package/build/src/lib/regex.d.ts.map +1 -1
- package/build/src/lib/regex.js +4 -1
- package/build/src/lib/regex.js.map +1 -1
- package/build/src/lib/schema.d.ts +24 -0
- package/build/src/lib/schema.d.ts.map +1 -1
- package/build/src/lib/schema.js +11 -2
- package/build/src/lib/schema.js.map +1 -1
- package/build/src/lib/utility.d.ts +2 -2
- package/build/src/lib/utility.d.ts.map +1 -1
- package/build/src/lib/utility.js +1 -1
- package/build/src/lib/utility.js.map +1 -1
- package/build/src/types/cli/commands/config-io.d.ts +12 -12
- package/build/src/types/cli/commands/context.d.ts +96 -58
- package/build/src/types/cli/commands/deploy.d.ts +342 -298
- package/build/src/types/cli/commands/generate.d.ts +40 -24
- package/build/src/types/cli/commands/server.d.ts +23 -23
- package/build/src/types/cli/commands/settings.d.ts +8 -8
- package/build/src/types/cli/commands/validate.d.ts +16 -16
- package/build/src/types/cli/index.d.ts +16 -20
- package/build/src/types/cli/menu/interactive.d.ts +233 -178
- package/build/src/types/lib/schema.d.ts +89 -81
- package/build/src/types/lib/utility.d.ts +4 -2
- package/build/src/types/shared.d.ts +85 -0
- package/build/src/types/tests/cli/commands/context.test.d.ts +102 -31
- package/build/src/types/tests/cli/commands/generate.test.d.ts +50 -4
- package/build/src/types/tests/cli/commands/server.test.d.ts +88 -23
- package/build/src/types/tests/cli/commands/settings.test.d.ts +65 -21
- package/build/src/types/tests/cli/commands/validate.test.d.ts +69 -8
- package/build/src/types/tests/cli/menu/interactive.test.d.ts +2 -2
- package/build/src/types/tests/lib/schema.test.d.ts +258 -3
- package/build/src/types/tests/worker/index.test.d.ts +166 -8
- package/build/src/types/tests/worker/interpreters/ntfy-json.test.d.ts +94 -10
- package/build/src/types/tests/worker/interpreters/pfsense.test.d.ts +163 -4
- package/build/src/types/tests/worker/interpreters/plain-text.test.d.ts +67 -4
- package/build/src/types/tests/worker/interpreters/seerr.test.d.ts +138 -3
- package/build/src/types/tests/worker/interpreters/statuspage.test.d.ts +235 -30
- package/build/src/types/tests/worker/interpreters/synology.test.d.ts +61 -3
- package/build/src/types/tests/worker/interpreters/unifi.test.d.ts +93 -3
- package/build/src/types/tests/worker/landing/page.test.d.ts +73 -50
- package/build/src/types/tests/worker/pipeline/accumulate.test.d.ts +226 -15
- package/build/src/types/tests/worker/pipeline/authenticate.test.d.ts +148 -4
- package/build/src/types/tests/worker/pipeline/email.test.d.ts +82 -8
- package/build/src/types/tests/worker/pipeline/format.test.d.ts +112 -32
- package/build/src/types/tests/worker/pipeline/interpret.test.d.ts +109 -17
- package/build/src/types/tests/worker/pipeline/parse.test.d.ts +70 -5
- package/build/src/types/tests/worker/pipeline/receive.test.d.ts +156 -15
- package/build/src/types/tests/worker/pipeline/respond.test.d.ts +129 -10
- package/build/src/types/tests/worker/pipeline/route.test.d.ts +412 -74
- package/build/src/types/tests/worker/pipeline/send.test.d.ts +58 -23
- package/build/src/types/tests/worker/pipeline/split.test.d.ts +47 -9
- package/build/src/types/worker/handlers.d.ts +193 -0
- package/build/src/types/worker/index.d.ts +58 -203
- package/build/src/types/worker/interpreters/ntfy-json.d.ts +10 -10
- package/build/src/types/worker/interpreters/pfsense.d.ts +57 -49
- package/build/src/types/worker/interpreters/plain-text.d.ts +7 -7
- package/build/src/types/worker/interpreters/seerr.d.ts +63 -61
- package/build/src/types/worker/interpreters/statuspage.d.ts +201 -116
- package/build/src/types/worker/interpreters/synology.d.ts +48 -46
- package/build/src/types/worker/interpreters/unifi.d.ts +79 -54
- package/build/src/types/worker/landing/page.d.ts +30 -23
- package/build/src/types/worker/pipeline/accumulate.d.ts +46 -32
- package/build/src/types/worker/pipeline/authenticate.d.ts +94 -34
- package/build/src/types/worker/pipeline/email.d.ts +114 -50
- package/build/src/types/worker/pipeline/format.d.ts +31 -23
- package/build/src/types/worker/pipeline/interpret.d.ts +34 -34
- package/build/src/types/worker/pipeline/parse.d.ts +25 -19
- package/build/src/types/worker/pipeline/receive.d.ts +36 -34
- package/build/src/types/worker/pipeline/respond.d.ts +119 -63
- package/build/src/types/worker/pipeline/route.d.ts +33 -16
- package/build/src/types/worker/pipeline/send.d.ts +116 -79
- package/build/src/types/worker/pipeline/split.d.ts +21 -16
- package/build/src/worker/handlers.d.ts +5 -4
- package/build/src/worker/handlers.d.ts.map +1 -1
- package/build/src/worker/handlers.js +238 -202
- package/build/src/worker/handlers.js.map +1 -1
- package/build/src/worker/index.d.ts +2 -2
- package/build/src/worker/index.d.ts.map +1 -1
- package/build/src/worker/index.js +37 -9
- package/build/src/worker/index.js.map +1 -1
- package/build/src/worker/interpreters/ntfy-json.d.ts +2 -2
- package/build/src/worker/interpreters/ntfy-json.d.ts.map +1 -1
- package/build/src/worker/interpreters/ntfy-json.js.map +1 -1
- package/build/src/worker/interpreters/pfsense.d.ts +2 -2
- package/build/src/worker/interpreters/pfsense.d.ts.map +1 -1
- package/build/src/worker/interpreters/pfsense.js +20 -27
- package/build/src/worker/interpreters/pfsense.js.map +1 -1
- package/build/src/worker/interpreters/plain-text.d.ts +2 -2
- package/build/src/worker/interpreters/plain-text.d.ts.map +1 -1
- package/build/src/worker/interpreters/plain-text.js.map +1 -1
- package/build/src/worker/interpreters/seerr.d.ts +2 -2
- package/build/src/worker/interpreters/seerr.d.ts.map +1 -1
- package/build/src/worker/interpreters/seerr.js +16 -12
- package/build/src/worker/interpreters/seerr.js.map +1 -1
- package/build/src/worker/interpreters/statuspage.d.ts +2 -2
- package/build/src/worker/interpreters/statuspage.d.ts.map +1 -1
- package/build/src/worker/interpreters/statuspage.js +98 -47
- package/build/src/worker/interpreters/statuspage.js.map +1 -1
- package/build/src/worker/interpreters/synology.d.ts +2 -2
- package/build/src/worker/interpreters/synology.d.ts.map +1 -1
- package/build/src/worker/interpreters/synology.js +9 -5
- package/build/src/worker/interpreters/synology.js.map +1 -1
- package/build/src/worker/interpreters/unifi.d.ts +2 -2
- package/build/src/worker/interpreters/unifi.d.ts.map +1 -1
- package/build/src/worker/interpreters/unifi.js +34 -20
- package/build/src/worker/interpreters/unifi.js.map +1 -1
- package/build/src/worker/landing/page.d.ts +2 -2
- package/build/src/worker/landing/page.d.ts.map +1 -1
- package/build/src/worker/landing/page.js +4 -3
- package/build/src/worker/landing/page.js.map +1 -1
- package/build/src/worker/pipeline/accumulate.d.ts +5 -6
- package/build/src/worker/pipeline/accumulate.d.ts.map +1 -1
- package/build/src/worker/pipeline/accumulate.js +4 -11
- package/build/src/worker/pipeline/accumulate.js.map +1 -1
- package/build/src/worker/pipeline/authenticate.d.ts +2 -2
- package/build/src/worker/pipeline/authenticate.d.ts.map +1 -1
- package/build/src/worker/pipeline/authenticate.js +25 -7
- package/build/src/worker/pipeline/authenticate.js.map +1 -1
- package/build/src/worker/pipeline/email.d.ts +2 -2
- package/build/src/worker/pipeline/email.d.ts.map +1 -1
- package/build/src/worker/pipeline/email.js +34 -11
- package/build/src/worker/pipeline/email.js.map +1 -1
- package/build/src/worker/pipeline/format.d.ts +2 -3
- package/build/src/worker/pipeline/format.d.ts.map +1 -1
- package/build/src/worker/pipeline/format.js +2 -1
- package/build/src/worker/pipeline/format.js.map +1 -1
- package/build/src/worker/pipeline/interpret.d.ts +4 -3
- package/build/src/worker/pipeline/interpret.d.ts.map +1 -1
- package/build/src/worker/pipeline/interpret.js +7 -7
- package/build/src/worker/pipeline/interpret.js.map +1 -1
- package/build/src/worker/pipeline/parse.d.ts +2 -2
- package/build/src/worker/pipeline/parse.d.ts.map +1 -1
- package/build/src/worker/pipeline/parse.js +14 -7
- package/build/src/worker/pipeline/parse.js.map +1 -1
- package/build/src/worker/pipeline/receive.d.ts +2 -2
- package/build/src/worker/pipeline/receive.d.ts.map +1 -1
- package/build/src/worker/pipeline/receive.js +6 -6
- package/build/src/worker/pipeline/receive.js.map +1 -1
- package/build/src/worker/pipeline/respond.d.ts +2 -2
- package/build/src/worker/pipeline/respond.d.ts.map +1 -1
- package/build/src/worker/pipeline/respond.js +1 -1
- package/build/src/worker/pipeline/respond.js.map +1 -1
- package/build/src/worker/pipeline/route.d.ts +2 -3
- package/build/src/worker/pipeline/route.d.ts.map +1 -1
- package/build/src/worker/pipeline/route.js.map +1 -1
- package/build/src/worker/pipeline/send.d.ts +2 -2
- package/build/src/worker/pipeline/send.d.ts.map +1 -1
- package/build/src/worker/pipeline/send.js +80 -41
- package/build/src/worker/pipeline/send.js.map +1 -1
- package/build/src/worker/pipeline/split.d.ts +2 -2
- package/build/src/worker/pipeline/split.d.ts.map +1 -1
- package/build/src/worker/pipeline/split.js +4 -2
- package/build/src/worker/pipeline/split.js.map +1 -1
- package/package.json +7 -6
- package/build/src/types/tests/type-declarations.test.d.ts +0 -173
- package/build/src/types/worker/pipeline/shared.d.ts +0 -85
|
@@ -9,6 +9,15 @@ import { respond } from './pipeline/respond.js';
|
|
|
9
9
|
import { route } from './pipeline/route.js';
|
|
10
10
|
import { send } from './pipeline/send.js';
|
|
11
11
|
import { split } from './pipeline/split.js';
|
|
12
|
+
function shouldNotifyError(ctx, category) {
|
|
13
|
+
if (ctx['error_topic'] === undefined) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
if (ctx['error_events'] === undefined) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
return ctx['error_events'].includes(category);
|
|
20
|
+
}
|
|
12
21
|
async function handleRequest(request, config, kv) {
|
|
13
22
|
try {
|
|
14
23
|
const received = await receive(request, config['settings']['base_domain']);
|
|
@@ -17,7 +26,8 @@ async function handleRequest(request, config, kv) {
|
|
|
17
26
|
}
|
|
18
27
|
if (received['error'] !== undefined) {
|
|
19
28
|
return new Response(JSON.stringify({
|
|
20
|
-
status: 'error',
|
|
29
|
+
status: 'error',
|
|
30
|
+
message: received['error'],
|
|
21
31
|
}, null, 2), {
|
|
22
32
|
status: 405,
|
|
23
33
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -33,7 +43,8 @@ async function handleRequest(request, config, kv) {
|
|
|
33
43
|
|| routed['resolvedServers'] === undefined
|
|
34
44
|
|| routed['primaryServer'] === undefined) {
|
|
35
45
|
return new Response(JSON.stringify({
|
|
36
|
-
status: 'error',
|
|
46
|
+
status: 'error',
|
|
47
|
+
message: routed['error'] ?? 'No context found',
|
|
37
48
|
}, null, 2), {
|
|
38
49
|
status: 404,
|
|
39
50
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -43,30 +54,32 @@ async function handleRequest(request, config, kv) {
|
|
|
43
54
|
const resolvedServers = routed['resolvedServers'];
|
|
44
55
|
const primaryServer = routed['primaryServer'];
|
|
45
56
|
const authResult = authenticate({
|
|
46
|
-
type: 'http',
|
|
57
|
+
type: 'http',
|
|
58
|
+
...((ctx['token'] !== undefined) ? { token: ctx['token'] } : {}),
|
|
47
59
|
}, {
|
|
48
|
-
authorization: received['headers'].get('authorization') ?? undefined,
|
|
60
|
+
authorization: received['headers'].get('authorization') ?? undefined,
|
|
61
|
+
from: undefined,
|
|
49
62
|
});
|
|
50
63
|
if (authResult['authenticated'] === false) {
|
|
51
|
-
if (ctx['error_topic'] !== undefined) {
|
|
64
|
+
if (ctx['error_topic'] !== undefined && shouldNotifyError(ctx, 'authentication') === true) {
|
|
52
65
|
try {
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
if (
|
|
66
|
+
const authErrorAttachmentHeaderEntries = [...received['headers'].entries()].map((entry) => {
|
|
67
|
+
const authEntryName = entry[0];
|
|
68
|
+
const authEntryValue = entry[1];
|
|
69
|
+
if (authEntryName.toLowerCase() === 'authorization') {
|
|
57
70
|
return [
|
|
58
|
-
|
|
71
|
+
authEntryName,
|
|
59
72
|
'REDACTED',
|
|
60
73
|
];
|
|
61
74
|
}
|
|
62
75
|
return [
|
|
63
|
-
|
|
64
|
-
|
|
76
|
+
authEntryName,
|
|
77
|
+
authEntryValue,
|
|
65
78
|
];
|
|
66
79
|
});
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
const
|
|
80
|
+
const authErrorAttachmentHeaders = Object.fromEntries(authErrorAttachmentHeaderEntries);
|
|
81
|
+
const authErrorAttachmentParsed = parse(received['rawBody'], received['headers']);
|
|
82
|
+
const authErrorAttachmentData = {
|
|
70
83
|
timestamp: new Date().toISOString(),
|
|
71
84
|
error: {
|
|
72
85
|
type: 'authentication',
|
|
@@ -80,20 +93,20 @@ async function handleRequest(request, config, kv) {
|
|
|
80
93
|
request: {
|
|
81
94
|
method: received['method'],
|
|
82
95
|
url: received['url'],
|
|
83
|
-
headers:
|
|
84
|
-
...(received['cfProperties'] !== undefined ? { cf: received['cfProperties'] } : {}),
|
|
96
|
+
headers: authErrorAttachmentHeaders,
|
|
97
|
+
...((received['cfProperties'] !== undefined) ? { cf: received['cfProperties'] } : {}),
|
|
85
98
|
},
|
|
86
99
|
response: {
|
|
87
100
|
status: 403,
|
|
88
101
|
},
|
|
89
102
|
body: {
|
|
90
|
-
type:
|
|
91
|
-
...(
|
|
92
|
-
...(
|
|
103
|
+
type: authErrorAttachmentParsed['type'],
|
|
104
|
+
...((authErrorAttachmentParsed['json'] !== undefined) ? { json: authErrorAttachmentParsed['json'] } : {}),
|
|
105
|
+
...((authErrorAttachmentParsed['text'] !== undefined) ? { text: authErrorAttachmentParsed['text'] } : {}),
|
|
93
106
|
},
|
|
94
107
|
};
|
|
95
|
-
const
|
|
96
|
-
const
|
|
108
|
+
const authErrorAttachmentJson = JSON.stringify(authErrorAttachmentData, null, 2);
|
|
109
|
+
const authErrorAttachmentBuffer = new TextEncoder().encode(authErrorAttachmentJson).buffer;
|
|
97
110
|
await send({
|
|
98
111
|
messages: [],
|
|
99
112
|
servers: resolvedServers,
|
|
@@ -101,7 +114,7 @@ async function handleRequest(request, config, kv) {
|
|
|
101
114
|
topic: ctx['error_topic'],
|
|
102
115
|
mode: ctx['mode'],
|
|
103
116
|
visitorIp: received['headers'].get('cf-connecting-ip') ?? undefined,
|
|
104
|
-
attachment:
|
|
117
|
+
attachment: authErrorAttachmentBuffer,
|
|
105
118
|
filename: 'error-debug.json',
|
|
106
119
|
attachmentHeaders: { 'X-Title': 'Authentication Error' },
|
|
107
120
|
});
|
|
@@ -110,7 +123,8 @@ async function handleRequest(request, config, kv) {
|
|
|
110
123
|
}
|
|
111
124
|
}
|
|
112
125
|
return new Response(JSON.stringify({
|
|
113
|
-
status: 'error',
|
|
126
|
+
status: 'error',
|
|
127
|
+
message: 'Unauthorized',
|
|
114
128
|
}, null, 2), {
|
|
115
129
|
status: 403,
|
|
116
130
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -119,7 +133,8 @@ async function handleRequest(request, config, kv) {
|
|
|
119
133
|
const parsed = parse(received['rawBody'], received['headers']);
|
|
120
134
|
if (parsed['type'] === 'unknown') {
|
|
121
135
|
return new Response(JSON.stringify({
|
|
122
|
-
status: 'error',
|
|
136
|
+
status: 'error',
|
|
137
|
+
message: 'Unknown content type',
|
|
123
138
|
}, null, 2), {
|
|
124
139
|
status: 400,
|
|
125
140
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -128,7 +143,9 @@ async function handleRequest(request, config, kv) {
|
|
|
128
143
|
const rawBodyJsonStr = (parsed['json'] !== undefined) ? JSON.stringify(parsed['json']) : '';
|
|
129
144
|
const rawBodyText = parsed['text'] ?? ((rawBodyJsonStr.length > 0) ? rawBodyJsonStr : undefined);
|
|
130
145
|
const debugRawRequestStr = JSON.stringify({
|
|
131
|
-
debug: 'raw_request',
|
|
146
|
+
debug: 'raw_request',
|
|
147
|
+
type: parsed['type'],
|
|
148
|
+
body: rawBodyText ?? '(binary)',
|
|
132
149
|
});
|
|
133
150
|
console.info(debugRawRequestStr);
|
|
134
151
|
const input = parsed['json']
|
|
@@ -140,43 +157,43 @@ async function handleRequest(request, config, kv) {
|
|
|
140
157
|
interpreted = await interpret(ctx['interpreter'], input, (kv !== undefined) ? { kv } : {});
|
|
141
158
|
}
|
|
142
159
|
catch (err) {
|
|
143
|
-
const
|
|
144
|
-
const
|
|
145
|
-
const
|
|
146
|
-
let
|
|
160
|
+
const interpretErrorName = (err instanceof Error) ? err.name : 'Error';
|
|
161
|
+
const interpretErrorMessage = (err instanceof Error) ? err.message : 'Unknown interpretation error';
|
|
162
|
+
const interpretErrorStack = (err instanceof Error) ? err.stack : undefined;
|
|
163
|
+
let interpretErrorIssues = undefined;
|
|
147
164
|
if (err instanceof Error
|
|
148
165
|
&& err.name === 'ZodError'
|
|
149
166
|
&& 'issues' in err) {
|
|
150
|
-
const
|
|
151
|
-
if (Array.isArray(
|
|
152
|
-
|
|
167
|
+
const interpretErrorIssuesRaw = Reflect.get(err, 'issues');
|
|
168
|
+
if (Array.isArray(interpretErrorIssuesRaw) === true) {
|
|
169
|
+
interpretErrorIssues = interpretErrorIssuesRaw;
|
|
153
170
|
}
|
|
154
171
|
}
|
|
155
|
-
if (ctx['error_topic'] !== undefined) {
|
|
172
|
+
if (ctx['error_topic'] !== undefined && shouldNotifyError(ctx, 'interpretation') === true) {
|
|
156
173
|
try {
|
|
157
|
-
const
|
|
158
|
-
const
|
|
159
|
-
const
|
|
160
|
-
if (
|
|
174
|
+
const interpretErrorAttachmentHeaderEntries = [...received['headers'].entries()].map((entry) => {
|
|
175
|
+
const interpretEntryName = entry[0];
|
|
176
|
+
const interpretEntryValue = entry[1];
|
|
177
|
+
if (interpretEntryName.toLowerCase() === 'authorization') {
|
|
161
178
|
return [
|
|
162
|
-
|
|
179
|
+
interpretEntryName,
|
|
163
180
|
'REDACTED',
|
|
164
181
|
];
|
|
165
182
|
}
|
|
166
183
|
return [
|
|
167
|
-
|
|
168
|
-
|
|
184
|
+
interpretEntryName,
|
|
185
|
+
interpretEntryValue,
|
|
169
186
|
];
|
|
170
187
|
});
|
|
171
|
-
const
|
|
172
|
-
const
|
|
188
|
+
const interpretErrorAttachmentHeaders = Object.fromEntries(interpretErrorAttachmentHeaderEntries);
|
|
189
|
+
const interpretErrorAttachmentData = {
|
|
173
190
|
timestamp: new Date().toISOString(),
|
|
174
191
|
error: {
|
|
175
192
|
type: 'interpretation',
|
|
176
|
-
name:
|
|
177
|
-
message:
|
|
178
|
-
...(
|
|
179
|
-
...(
|
|
193
|
+
name: interpretErrorName,
|
|
194
|
+
message: interpretErrorMessage,
|
|
195
|
+
...((interpretErrorStack !== undefined) ? { stack: interpretErrorStack } : {}),
|
|
196
|
+
...((interpretErrorIssues !== undefined) ? { issues: interpretErrorIssues } : {}),
|
|
180
197
|
},
|
|
181
198
|
context: {
|
|
182
199
|
name: ctx['name'],
|
|
@@ -186,20 +203,20 @@ async function handleRequest(request, config, kv) {
|
|
|
186
203
|
request: {
|
|
187
204
|
method: received['method'],
|
|
188
205
|
url: received['url'],
|
|
189
|
-
headers:
|
|
190
|
-
...(received['cfProperties'] !== undefined ? { cf: received['cfProperties'] } : {}),
|
|
206
|
+
headers: interpretErrorAttachmentHeaders,
|
|
207
|
+
...((received['cfProperties'] !== undefined) ? { cf: received['cfProperties'] } : {}),
|
|
191
208
|
},
|
|
192
209
|
response: {
|
|
193
210
|
status: 422,
|
|
194
211
|
},
|
|
195
212
|
body: {
|
|
196
213
|
type: parsed['type'],
|
|
197
|
-
...(parsed['json'] !== undefined ? { json: parsed['json'] } : {}),
|
|
198
|
-
...(parsed['text'] !== undefined ? { text: parsed['text'] } : {}),
|
|
214
|
+
...((parsed['json'] !== undefined) ? { json: parsed['json'] } : {}),
|
|
215
|
+
...((parsed['text'] !== undefined) ? { text: parsed['text'] } : {}),
|
|
199
216
|
},
|
|
200
217
|
};
|
|
201
|
-
const
|
|
202
|
-
const
|
|
218
|
+
const interpretErrorAttachmentJson = JSON.stringify(interpretErrorAttachmentData, null, 2);
|
|
219
|
+
const interpretErrorAttachmentBuffer = new TextEncoder().encode(interpretErrorAttachmentJson).buffer;
|
|
203
220
|
await send({
|
|
204
221
|
messages: [],
|
|
205
222
|
servers: resolvedServers,
|
|
@@ -207,7 +224,7 @@ async function handleRequest(request, config, kv) {
|
|
|
207
224
|
topic: ctx['error_topic'],
|
|
208
225
|
mode: ctx['mode'],
|
|
209
226
|
visitorIp: received['headers'].get('cf-connecting-ip') ?? undefined,
|
|
210
|
-
attachment:
|
|
227
|
+
attachment: interpretErrorAttachmentBuffer,
|
|
211
228
|
filename: 'error-debug.json',
|
|
212
229
|
attachmentHeaders: { 'X-Title': 'Interpretation Error' },
|
|
213
230
|
});
|
|
@@ -216,7 +233,8 @@ async function handleRequest(request, config, kv) {
|
|
|
216
233
|
}
|
|
217
234
|
}
|
|
218
235
|
return new Response(JSON.stringify({
|
|
219
|
-
status: 'error',
|
|
236
|
+
status: 'error',
|
|
237
|
+
message: interpretErrorMessage,
|
|
220
238
|
}, null, 2), {
|
|
221
239
|
status: 422,
|
|
222
240
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -263,11 +281,13 @@ async function handleRequest(request, config, kv) {
|
|
|
263
281
|
return response;
|
|
264
282
|
}
|
|
265
283
|
catch (err) {
|
|
266
|
-
const
|
|
284
|
+
const fatalErrorMessage = (err instanceof Error) ? err.message : 'Internal server error';
|
|
267
285
|
const body = (config['settings']['show_response_output'] === true) ? {
|
|
268
|
-
status: 'error',
|
|
286
|
+
status: 'error',
|
|
287
|
+
message: fatalErrorMessage,
|
|
269
288
|
} : {
|
|
270
|
-
status: 'error',
|
|
289
|
+
status: 'error',
|
|
290
|
+
message: 'Internal server error',
|
|
271
291
|
};
|
|
272
292
|
return new Response(JSON.stringify(body, null, 2), {
|
|
273
293
|
status: 500,
|
|
@@ -276,158 +296,174 @@ async function handleRequest(request, config, kv) {
|
|
|
276
296
|
}
|
|
277
297
|
}
|
|
278
298
|
async function handleEmail(rawEmail, from, config, kv) {
|
|
279
|
-
const parsed = await parseEmail(rawEmail);
|
|
280
|
-
const debugRawEmailStr = JSON.stringify({
|
|
281
|
-
debug: 'raw_email', from, to: parsed['to'], subject: parsed['subject'], rawEmail,
|
|
282
|
-
});
|
|
283
|
-
console.info(debugRawEmailStr);
|
|
284
|
-
const recipientLocalPart = parsed['to'].split('@')[0] ?? '';
|
|
285
|
-
const routed = route('email', recipientLocalPart, config);
|
|
286
|
-
if (routed['error'] !== undefined
|
|
287
|
-
|| routed['context'] === undefined
|
|
288
|
-
|| routed['resolvedServers'] === undefined
|
|
289
|
-
|| routed['primaryServer'] === undefined) {
|
|
290
|
-
return;
|
|
291
|
-
}
|
|
292
|
-
const ctx = routed['context'];
|
|
293
|
-
const resolvedServers = routed['resolvedServers'];
|
|
294
|
-
const primaryServer = routed['primaryServer'];
|
|
295
|
-
const authResult = authenticate({
|
|
296
|
-
type: 'email', ...(ctx['allowed_from'] !== undefined ? { allowed_from: ctx['allowed_from'] } : {}),
|
|
297
|
-
}, {
|
|
298
|
-
authorization: undefined, from,
|
|
299
|
-
});
|
|
300
|
-
if (authResult['authenticated'] === false) {
|
|
301
|
-
if (ctx['error_topic'] !== undefined) {
|
|
302
|
-
try {
|
|
303
|
-
const errorAttachmentData = {
|
|
304
|
-
timestamp: new Date().toISOString(),
|
|
305
|
-
error: {
|
|
306
|
-
type: 'authentication',
|
|
307
|
-
message: authResult['reason'],
|
|
308
|
-
},
|
|
309
|
-
context: {
|
|
310
|
-
name: ctx['name'],
|
|
311
|
-
interpreter: ctx['interpreter'],
|
|
312
|
-
stage: 'authentication',
|
|
313
|
-
},
|
|
314
|
-
email: {
|
|
315
|
-
from,
|
|
316
|
-
to: parsed['to'],
|
|
317
|
-
subject: parsed['subject'],
|
|
318
|
-
textBody: parsed['textBody'],
|
|
319
|
-
},
|
|
320
|
-
};
|
|
321
|
-
const errorAttachmentJson = JSON.stringify(errorAttachmentData, null, 2);
|
|
322
|
-
const errorAttachmentBuffer = new TextEncoder().encode(errorAttachmentJson).buffer;
|
|
323
|
-
await send({
|
|
324
|
-
messages: [],
|
|
325
|
-
servers: resolvedServers,
|
|
326
|
-
primaryServer,
|
|
327
|
-
topic: ctx['error_topic'],
|
|
328
|
-
mode: ctx['mode'],
|
|
329
|
-
attachment: errorAttachmentBuffer,
|
|
330
|
-
filename: 'error-debug.json',
|
|
331
|
-
attachmentHeaders: { 'X-Title': 'Email Authentication Error' },
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
catch {
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
return;
|
|
338
|
-
}
|
|
339
|
-
const emailInput = {
|
|
340
|
-
subject: parsed['subject'],
|
|
341
|
-
textBody: parsed['textBody'],
|
|
342
|
-
from: parsed['from'],
|
|
343
|
-
to: parsed['to'],
|
|
344
|
-
};
|
|
345
|
-
let interpreted = undefined;
|
|
346
299
|
try {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
300
|
+
const parsed = await parseEmail(rawEmail);
|
|
301
|
+
const debugRawEmailStr = JSON.stringify({
|
|
302
|
+
debug: 'raw_email',
|
|
303
|
+
from,
|
|
304
|
+
to: parsed['to'],
|
|
305
|
+
subject: parsed['subject'],
|
|
306
|
+
rawEmail,
|
|
307
|
+
});
|
|
308
|
+
console.info(debugRawEmailStr);
|
|
309
|
+
const recipientLocalPart = parsed['to'].split('@')[0] ?? '';
|
|
310
|
+
const routed = route('email', recipientLocalPart, config);
|
|
311
|
+
if (routed['error'] !== undefined
|
|
312
|
+
|| routed['context'] === undefined
|
|
313
|
+
|| routed['resolvedServers'] === undefined
|
|
314
|
+
|| routed['primaryServer'] === undefined) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const ctx = routed['context'];
|
|
318
|
+
const resolvedServers = routed['resolvedServers'];
|
|
319
|
+
const primaryServer = routed['primaryServer'];
|
|
320
|
+
const authResult = authenticate({
|
|
321
|
+
type: 'email',
|
|
322
|
+
...((ctx['allowed_from'] !== undefined) ? { allowed_from: ctx['allowed_from'] } : {}),
|
|
323
|
+
}, {
|
|
324
|
+
authorization: undefined,
|
|
325
|
+
from,
|
|
326
|
+
});
|
|
327
|
+
if (authResult['authenticated'] === false) {
|
|
328
|
+
if (ctx['error_topic'] !== undefined && shouldNotifyError(ctx, 'authentication') === true) {
|
|
329
|
+
try {
|
|
330
|
+
const authErrorAttachmentData = {
|
|
331
|
+
timestamp: new Date().toISOString(),
|
|
332
|
+
error: {
|
|
333
|
+
type: 'authentication',
|
|
334
|
+
message: authResult['reason'],
|
|
335
|
+
},
|
|
336
|
+
context: {
|
|
337
|
+
name: ctx['name'],
|
|
338
|
+
interpreter: ctx['interpreter'],
|
|
339
|
+
stage: 'authentication',
|
|
340
|
+
},
|
|
341
|
+
email: {
|
|
342
|
+
from,
|
|
343
|
+
to: parsed['to'],
|
|
344
|
+
subject: parsed['subject'],
|
|
345
|
+
textBody: parsed['textBody'],
|
|
346
|
+
},
|
|
347
|
+
};
|
|
348
|
+
const authErrorAttachmentJson = JSON.stringify(authErrorAttachmentData, null, 2);
|
|
349
|
+
const authErrorAttachmentBuffer = new TextEncoder().encode(authErrorAttachmentJson).buffer;
|
|
350
|
+
await send({
|
|
351
|
+
messages: [],
|
|
352
|
+
servers: resolvedServers,
|
|
353
|
+
primaryServer,
|
|
354
|
+
topic: ctx['error_topic'],
|
|
355
|
+
mode: ctx['mode'],
|
|
356
|
+
attachment: authErrorAttachmentBuffer,
|
|
357
|
+
filename: 'error-debug.json',
|
|
358
|
+
attachmentHeaders: { 'X-Title': 'Email Authentication Error' },
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
catch {
|
|
362
|
+
}
|
|
360
363
|
}
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
const emailInput = {
|
|
367
|
+
subject: parsed['subject'],
|
|
368
|
+
textBody: parsed['textBody'],
|
|
369
|
+
from: parsed['from'],
|
|
370
|
+
to: parsed['to'],
|
|
371
|
+
};
|
|
372
|
+
let interpreted = undefined;
|
|
373
|
+
try {
|
|
374
|
+
interpreted = await interpret(ctx['interpreter'], emailInput, (kv !== undefined) ? { kv } : {});
|
|
361
375
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
name: ctx['name'],
|
|
375
|
-
interpreter: ctx['interpreter'],
|
|
376
|
-
stage: 'interpretation',
|
|
377
|
-
},
|
|
378
|
-
email: {
|
|
379
|
-
from,
|
|
380
|
-
to: parsed['to'],
|
|
381
|
-
subject: parsed['subject'],
|
|
382
|
-
textBody: parsed['textBody'],
|
|
383
|
-
},
|
|
384
|
-
};
|
|
385
|
-
const errorAttachmentJson = JSON.stringify(errorAttachmentData, null, 2);
|
|
386
|
-
const errorAttachmentBuffer = new TextEncoder().encode(errorAttachmentJson).buffer;
|
|
387
|
-
await send({
|
|
388
|
-
messages: [],
|
|
389
|
-
servers: resolvedServers,
|
|
390
|
-
primaryServer,
|
|
391
|
-
topic: ctx['error_topic'],
|
|
392
|
-
mode: ctx['mode'],
|
|
393
|
-
attachment: errorAttachmentBuffer,
|
|
394
|
-
filename: 'error-debug.json',
|
|
395
|
-
attachmentHeaders: { 'X-Title': 'Email Interpretation Error' },
|
|
396
|
-
});
|
|
376
|
+
catch (err) {
|
|
377
|
+
const errorName = (err instanceof Error) ? err.name : 'Error';
|
|
378
|
+
const errorMessage = (err instanceof Error) ? err.message : 'Unknown interpretation error';
|
|
379
|
+
const errorStack = (err instanceof Error) ? err.stack : undefined;
|
|
380
|
+
let errorIssues = undefined;
|
|
381
|
+
if (err instanceof Error
|
|
382
|
+
&& err.name === 'ZodError'
|
|
383
|
+
&& 'issues' in err) {
|
|
384
|
+
const errorIssuesRaw = Reflect.get(err, 'issues');
|
|
385
|
+
if (Array.isArray(errorIssuesRaw) === true) {
|
|
386
|
+
errorIssues = errorIssuesRaw;
|
|
387
|
+
}
|
|
397
388
|
}
|
|
398
|
-
|
|
389
|
+
if (ctx['error_topic'] !== undefined && shouldNotifyError(ctx, 'interpretation') === true) {
|
|
390
|
+
try {
|
|
391
|
+
const interpretErrorAttachmentData = {
|
|
392
|
+
timestamp: new Date().toISOString(),
|
|
393
|
+
error: {
|
|
394
|
+
type: 'interpretation',
|
|
395
|
+
name: errorName,
|
|
396
|
+
message: errorMessage,
|
|
397
|
+
...((errorStack !== undefined) ? { stack: errorStack } : {}),
|
|
398
|
+
...((errorIssues !== undefined) ? { issues: errorIssues } : {}),
|
|
399
|
+
},
|
|
400
|
+
context: {
|
|
401
|
+
name: ctx['name'],
|
|
402
|
+
interpreter: ctx['interpreter'],
|
|
403
|
+
stage: 'interpretation',
|
|
404
|
+
},
|
|
405
|
+
email: {
|
|
406
|
+
from,
|
|
407
|
+
to: parsed['to'],
|
|
408
|
+
subject: parsed['subject'],
|
|
409
|
+
textBody: parsed['textBody'],
|
|
410
|
+
},
|
|
411
|
+
};
|
|
412
|
+
const interpretErrorAttachmentJson = JSON.stringify(interpretErrorAttachmentData, null, 2);
|
|
413
|
+
const interpretErrorAttachmentBuffer = new TextEncoder().encode(interpretErrorAttachmentJson).buffer;
|
|
414
|
+
await send({
|
|
415
|
+
messages: [],
|
|
416
|
+
servers: resolvedServers,
|
|
417
|
+
primaryServer,
|
|
418
|
+
topic: ctx['error_topic'],
|
|
419
|
+
mode: ctx['mode'],
|
|
420
|
+
attachment: interpretErrorAttachmentBuffer,
|
|
421
|
+
filename: 'error-debug.json',
|
|
422
|
+
attachmentHeaders: { 'X-Title': 'Email Interpretation Error' },
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
catch {
|
|
426
|
+
}
|
|
399
427
|
}
|
|
428
|
+
return;
|
|
400
429
|
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
430
|
+
if (interpreted === null) {
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
if (interpreted['notification']['title'] === undefined) {
|
|
434
|
+
Reflect.set(interpreted['notification'], 'title', ctx['name']);
|
|
435
|
+
}
|
|
436
|
+
const formatted = format(interpreted['notification'], {
|
|
437
|
+
showVisitorInfo: ctx['show_visitor_info'],
|
|
438
|
+
});
|
|
439
|
+
const messages = split(formatted['body'], formatted['headers']);
|
|
440
|
+
const sendResult = await send({
|
|
441
|
+
messages,
|
|
442
|
+
servers: resolvedServers,
|
|
443
|
+
primaryServer,
|
|
444
|
+
topic: ctx['topic'],
|
|
445
|
+
mode: ctx['mode'],
|
|
446
|
+
attachment: interpreted['attachment'],
|
|
447
|
+
filename: interpreted['notification']['filename'],
|
|
448
|
+
});
|
|
449
|
+
const debugLogStr = JSON.stringify({
|
|
450
|
+
context: ctx['name'],
|
|
451
|
+
interpreter: ctx['interpreter'],
|
|
452
|
+
servers: sendResult['results'],
|
|
453
|
+
bodySize: formatted['body'].length,
|
|
454
|
+
parts: messages.length,
|
|
455
|
+
}, null, 2);
|
|
456
|
+
console.info(debugLogStr);
|
|
405
457
|
}
|
|
406
|
-
|
|
407
|
-
|
|
458
|
+
catch (err) {
|
|
459
|
+
const fatalErrorMessage = (err instanceof Error) ? err.message : 'Unknown error';
|
|
460
|
+
const fatalDebugStr = JSON.stringify({
|
|
461
|
+
debug: 'fatal_email_error',
|
|
462
|
+
error: fatalErrorMessage,
|
|
463
|
+
});
|
|
464
|
+
console.info(fatalDebugStr);
|
|
408
465
|
}
|
|
409
|
-
const formatted = format(interpreted['notification'], {
|
|
410
|
-
showVisitorInfo: ctx['show_visitor_info'],
|
|
411
|
-
});
|
|
412
|
-
const messages = split(formatted['body'], formatted['headers']);
|
|
413
|
-
const sendResult = await send({
|
|
414
|
-
messages,
|
|
415
|
-
servers: resolvedServers,
|
|
416
|
-
primaryServer,
|
|
417
|
-
topic: ctx['topic'],
|
|
418
|
-
mode: ctx['mode'],
|
|
419
|
-
attachment: interpreted['attachment'],
|
|
420
|
-
filename: interpreted['notification']['filename'],
|
|
421
|
-
});
|
|
422
|
-
const debugLogStr = JSON.stringify({
|
|
423
|
-
context: ctx['name'],
|
|
424
|
-
interpreter: ctx['interpreter'],
|
|
425
|
-
servers: sendResult['results'],
|
|
426
|
-
bodySize: formatted['body'].length,
|
|
427
|
-
parts: messages.length,
|
|
428
|
-
}, null, 2);
|
|
429
|
-
console.info(debugLogStr);
|
|
430
466
|
return;
|
|
431
467
|
}
|
|
432
|
-
export { handleEmail, handleRequest, };
|
|
468
|
+
export { handleEmail, handleRequest, shouldNotifyError, };
|
|
433
469
|
//# sourceMappingURL=handlers.js.map
|