@commonpub/layer 0.3.23 → 0.3.24
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@commonpub/layer",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.24",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./nuxt.config.ts",
|
|
6
6
|
"files": [
|
|
@@ -44,15 +44,15 @@
|
|
|
44
44
|
"vue": "^3.4.0",
|
|
45
45
|
"vue-router": "^4.3.0",
|
|
46
46
|
"zod": "^4.3.6",
|
|
47
|
-
"@commonpub/config": "0.7.1",
|
|
48
47
|
"@commonpub/auth": "0.5.0",
|
|
49
|
-
"@commonpub/editor": "0.5.0",
|
|
50
|
-
"@commonpub/protocol": "0.9.5",
|
|
51
48
|
"@commonpub/docs": "0.5.2",
|
|
49
|
+
"@commonpub/protocol": "0.9.5",
|
|
50
|
+
"@commonpub/editor": "0.5.0",
|
|
52
51
|
"@commonpub/schema": "0.8.12",
|
|
52
|
+
"@commonpub/server": "2.15.0",
|
|
53
|
+
"@commonpub/config": "0.7.1",
|
|
53
54
|
"@commonpub/ui": "0.7.1",
|
|
54
|
-
"@commonpub/learning": "0.5.0"
|
|
55
|
-
"@commonpub/server": "2.15.0"
|
|
55
|
+
"@commonpub/learning": "0.5.0"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {}
|
|
58
58
|
}
|
|
@@ -10,17 +10,24 @@ export default defineEventHandler(async (event) => {
|
|
|
10
10
|
const user = requireAuth(event);
|
|
11
11
|
const { url, purpose } = await parseBody(event, schema);
|
|
12
12
|
|
|
13
|
-
// SSRF protection — block private IPs
|
|
13
|
+
// SSRF protection — block private/internal IPs
|
|
14
14
|
const parsed = new URL(url);
|
|
15
|
-
const hostname = parsed.hostname;
|
|
15
|
+
const hostname = parsed.hostname.toLowerCase();
|
|
16
|
+
const h = hostname.replace(/^\[|\]$/g, '');
|
|
16
17
|
if (
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
h === 'localhost' ||
|
|
19
|
+
h === 'localhost.localdomain' ||
|
|
20
|
+
h === 'metadata.google.internal' ||
|
|
21
|
+
h.endsWith('.local') ||
|
|
22
|
+
/^127\./.test(h) ||
|
|
23
|
+
/^10\./.test(h) ||
|
|
24
|
+
/^172\.(1[6-9]|2\d|3[01])\./.test(h) ||
|
|
25
|
+
/^192\.168\./.test(h) ||
|
|
26
|
+
/^169\.254\./.test(h) ||
|
|
27
|
+
/^0\./.test(h) ||
|
|
28
|
+
h === '::1' ||
|
|
29
|
+
/^f[cd]/i.test(h) ||
|
|
30
|
+
/^fe80/i.test(h)
|
|
24
31
|
) {
|
|
25
32
|
throw createError({ statusCode: 400, statusMessage: 'Cannot fetch from private/local addresses' });
|
|
26
33
|
}
|
|
@@ -29,15 +29,22 @@ export default defineEventHandler(async (event) => {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
// Block localhost/private IPs (SSRF prevention)
|
|
32
|
-
const hostname = parsed.hostname;
|
|
32
|
+
const hostname = parsed.hostname.toLowerCase();
|
|
33
|
+
const h = hostname.replace(/^\[|\]$/g, ''); // strip IPv6 brackets
|
|
33
34
|
if (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
h === 'localhost' ||
|
|
36
|
+
h === 'localhost.localdomain' ||
|
|
37
|
+
h === 'metadata.google.internal' ||
|
|
38
|
+
h.endsWith('.local') ||
|
|
39
|
+
/^127\./.test(h) ||
|
|
40
|
+
/^10\./.test(h) ||
|
|
41
|
+
/^172\.(1[6-9]|2\d|3[01])\./.test(h) ||
|
|
42
|
+
/^192\.168\./.test(h) ||
|
|
43
|
+
/^169\.254\./.test(h) ||
|
|
44
|
+
/^0\./.test(h) ||
|
|
45
|
+
h === '::1' ||
|
|
46
|
+
/^f[cd]/i.test(h) ||
|
|
47
|
+
/^fe80/i.test(h)
|
|
41
48
|
) {
|
|
42
49
|
throw createError({ statusCode: 403, statusMessage: 'Private addresses not allowed' });
|
|
43
50
|
}
|
|
@@ -30,8 +30,12 @@ export default defineEventHandler(async (event) => {
|
|
|
30
30
|
controller.enqueue(encoder.encode(`data: ${JSON.stringify({ type: 'counts', notifications, messages })}\n\n`));
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
// Send initial counts
|
|
34
|
-
|
|
33
|
+
// Send initial counts — if DB is unavailable, send zeros and let polling retry
|
|
34
|
+
try {
|
|
35
|
+
await sendCounts();
|
|
36
|
+
} catch {
|
|
37
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify({ type: 'counts', notifications: 0, messages: 0 })}\n\n`));
|
|
38
|
+
}
|
|
35
39
|
|
|
36
40
|
// Poll every 10 seconds
|
|
37
41
|
const interval = setInterval(async () => {
|
|
@@ -39,7 +39,11 @@ export default defineNitroPlugin((nitro) => {
|
|
|
39
39
|
// Run first sync after a brief delay to avoid startup contention
|
|
40
40
|
runSync(domain, intervalMs, backfillOnSync);
|
|
41
41
|
|
|
42
|
-
interval = setInterval(() =>
|
|
42
|
+
interval = setInterval(() => {
|
|
43
|
+
runSync(domain, intervalMs, backfillOnSync).catch((err) => {
|
|
44
|
+
console.error('[hub-sync] Sync worker unexpected error:', err instanceof Error ? err.message : err);
|
|
45
|
+
});
|
|
46
|
+
}, intervalMs);
|
|
43
47
|
} catch (err) {
|
|
44
48
|
console.error('[hub-sync] Failed to start:', err instanceof Error ? err.message : err);
|
|
45
49
|
}
|
|
@@ -64,7 +64,11 @@ export default defineNitroPlugin((nitro) => {
|
|
|
64
64
|
|
|
65
65
|
// Digest scheduler — runs every hour, sends digests for users whose digest window has elapsed
|
|
66
66
|
const DIGEST_INTERVAL_MS = 60 * 60 * 1000; // 1 hour
|
|
67
|
-
digestInterval = setInterval(() =>
|
|
67
|
+
digestInterval = setInterval(() => {
|
|
68
|
+
runDigest(siteUrl, siteName).catch((err) => {
|
|
69
|
+
console.error('[notification-email] Digest scheduler unexpected error:', err instanceof Error ? err.message : err);
|
|
70
|
+
});
|
|
71
|
+
}, DIGEST_INTERVAL_MS);
|
|
68
72
|
|
|
69
73
|
console.log('[notification-email] Digest scheduler started (interval: 1h)');
|
|
70
74
|
} catch (err) {
|