javascript-solid-server 0.0.81 → 0.0.83
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/.claude/settings.local.json +44 -1
- package/bin/jss.js +14 -0
- package/fonstr-data/index.html +120 -0
- package/package.json +1 -1
- package/src/auth/middleware.js +6 -0
- package/src/config.js +8 -0
- package/src/handlers/container.js +12 -2
- package/src/handlers/resource.js +17 -2
- package/src/server.js +2 -0
|
@@ -277,7 +277,50 @@
|
|
|
277
277
|
"Bash(node index.js:*)",
|
|
278
278
|
"Bash(timeout 3 npx lws-server@0.0.3:*)",
|
|
279
279
|
"Bash(npx lws-server@0.0.3)",
|
|
280
|
-
"Bash(node /tmp/jssd/verify-spacing.js:*)"
|
|
280
|
+
"Bash(node /tmp/jssd/verify-spacing.js:*)",
|
|
281
|
+
"Bash(gh run list:*)",
|
|
282
|
+
"Bash(pm2 startup:*)",
|
|
283
|
+
"Bash(npm run build:*)",
|
|
284
|
+
"Bash(npx esbuild:*)",
|
|
285
|
+
"Bash(gzip:*)",
|
|
286
|
+
"Bash(sort:*)",
|
|
287
|
+
"Bash(echo __NEW_LINE_496cf3994d374e5c__ echo '1. jsonld \\(277 KB\\) - used by:' grep -r \"from ['''']jsonld\" src/ --include=*.ts --include=*.js 2)",
|
|
288
|
+
"Bash(/dev/null __NEW_LINE_496cf3994d374e5c__ echo echo '2. readable-stream \\(180 KB\\) - used by:' grep -r readable-stream node_modules/n3/package.json node_modules/jsonld/package.json)",
|
|
289
|
+
"Bash(head -3 __NEW_LINE_496cf3994d374e5c__ echo echo '3. n3 \\(156 KB\\) - used by:' grep -r \"from ['''']n3\" src/ --include=*.ts --include=*.js 2)",
|
|
290
|
+
"Bash(/dev/null __NEW_LINE_496cf3994d374e5c__ echo echo '4. @xmldom/xmldom \\(136 KB\\) - used by:' grep -r xmldom src/ --include=*.ts --include=*.js 2)",
|
|
291
|
+
"Bash(/dev/null __NEW_LINE_496cf3994d374e5c__ echo echo '5. @frogcat/ttl2jsonld \\(135 KB\\) - used by:' grep -r ttl2jsonld src/ --include=*.ts --include=*.js)",
|
|
292
|
+
"Bash(echo \"\" __NEW_LINE_b9f7c85f1ada8a30__ echo \"1. jsonld \\(277 KB\\):\" grep -rn \"jsonld\" src/ --include=\"*.ts\" --include=\"*.js\")",
|
|
293
|
+
"Bash(head -5 __NEW_LINE_b9f7c85f1ada8a30__ echo \"\" echo \"2. n3 \\(156 KB\\):\" grep -rn \"from ''''n3''''\" src/ --include=\"*.ts\" --include=\"*.js\")",
|
|
294
|
+
"Bash(head -5 __NEW_LINE_b9f7c85f1ada8a30__ echo \"\" echo \"3. @xmldom \\(136 KB\\):\" grep -rn \"xmldom\" src/ --include=\"*.ts\" --include=\"*.js\")",
|
|
295
|
+
"Bash(head -5 __NEW_LINE_b9f7c85f1ada8a30__ echo \"\" echo \"4. @frogcat/ttl2jsonld \\(135 KB\\):\" grep -rn \"ttl2jsonld\" src/ --include=\"*.ts\" --include=\"*.js\")",
|
|
296
|
+
"Bash(head -5 __NEW_LINE_b9f7c85f1ada8a30__ echo \"\" echo \"5. cross-fetch \\(20 KB\\):\" grep -rn \"cross-fetch\" src/ --include=\"*.ts\" --include=\"*.js\")",
|
|
297
|
+
"Bash(head -5 __NEW_LINE_b9f7c85f1ada8a30__ echo \"\" echo \"6. solid-namespace \\(3 KB\\):\" grep -rn \"solid-namespace\" src/ --include=\"*.ts\" --include=\"*.js\")",
|
|
298
|
+
"Bash(echo __NEW_LINE_fbfd1802fc51eb60__ echo '1. jsonld \\(277 KB\\):' grep -n jsonld src/*.ts src/*.js)",
|
|
299
|
+
"Bash(grep -E \"import|require\" __NEW_LINE_fbfd1802fc51eb60__ echo echo '2. n3 \\(156 KB\\):' grep -n ''n3'' src/*.ts src/*.js)",
|
|
300
|
+
"Bash(grep -E \"import|require\" __NEW_LINE_fbfd1802fc51eb60__ echo echo '3. @xmldom \\(136 KB\\):' grep -n xmldom src/*.ts src/*.js)",
|
|
301
|
+
"Bash(grep -E \"import|require\" __NEW_LINE_fbfd1802fc51eb60__ echo echo '4. @frogcat/ttl2jsonld \\(135 KB\\):' grep -n ttl2jsonld src/*.ts src/*.js)",
|
|
302
|
+
"Bash(grep -E \"import|require\" __NEW_LINE_fbfd1802fc51eb60__ echo echo '5. cross-fetch \\(20 KB\\):' grep -n cross-fetch src/*.ts src/*.js)",
|
|
303
|
+
"Bash(grep -E \"import|require\" __NEW_LINE_fbfd1802fc51eb60__ echo echo '6. solid-namespace \\(3 KB\\):' grep -n solid-namespace src/*.ts src/*.js)",
|
|
304
|
+
"Bash(npm run build:all:*)",
|
|
305
|
+
"Bash(git status:*)",
|
|
306
|
+
"Bash(npm run lint-fix:*)",
|
|
307
|
+
"Bash(npm uninstall:*)",
|
|
308
|
+
"Bash(npm search:*)",
|
|
309
|
+
"Bash(npm run lint:*)",
|
|
310
|
+
"Bash(npm run typecheck:*)",
|
|
311
|
+
"Bash(du:*)",
|
|
312
|
+
"Bash(for pkg in activitystreams-pane chat-pane contacts-pane folder-pane issue-pane meeting-pane profile-pane source-pane pane-registry)",
|
|
313
|
+
"Bash(do du -sh node_modules/$pkg)",
|
|
314
|
+
"Bash(for pkg in solid-ui solid-logic react react-dom lodash core-js @inrupt marked dompurify)",
|
|
315
|
+
"Bash(npm why:*)",
|
|
316
|
+
"Bash(for pkg in activitystreams-pane chat-pane contacts-pane folder-pane issue-pane meeting-pane profile-pane source-pane)",
|
|
317
|
+
"Bash(wc -l echo 'Brings: mime-types \\(we already removed this pattern\\)' echo echo '=== profile-pane unique deps ===')",
|
|
318
|
+
"Bash(npm run build-prod:*)",
|
|
319
|
+
"Bash(ln:*)",
|
|
320
|
+
"WebFetch(domain:remotestorage.io)",
|
|
321
|
+
"Bash(gh issue create --title \"Feature: --public flag to skip WAC and allow open access\" --body \"$\\(cat << ''ENDOFFILE''\n## Summary\n\nAdd a `--public` flag that disables WAC \\(Web Access Control\\) checks, allowing unauthenticated read/write access to all resources. This enables JSS to be used as a simple file server similar to `npx serve`, but with REST write capabilities.\n\n**Difficulty**: 15/100 \n**Estimated Effort**: 2-4 hours \n**Dependencies**: None\n\n---\n\n## Motivation\n\nCurrently, JSS requires either:\n1. ACL files to grant access, or\n2. Authentication via Solid-OIDC\n\nThis makes it impossible to use JSS as a simple \"just serve this folder\" tool like `npx serve`. The `--public` flag would enable:\n\n1. **Quick local development** - No auth setup needed\n2. **Simple file sharing** - LAN file server with write support\n3. **jsserve wrapper** - Foundation for `npx jsserve` \\(see future issue\\)\n4. **WebDAV alternative** - Simple REST-based file server\n5. **Testing/demos** - Quick Solid server without auth complexity\n\n---\n\n## Proposed Implementation\n\n### CLI Flag\n\n```bash\njss start --public # Open read/write, no auth\njss start --public --read-only # Open read, no writes \\(like npx serve\\)\n```\n\n### Environment Variable\n\n```bash\nJSS_PUBLIC=true jss start\n```\n\n### Config File\n\n```json\n{\n \"public\": true\n}\n```\n\n---\n\n## Implementation Details\n\n### 1. Add flag to CLI \\(`bin/jss.js`\\)\n\n```javascript\n.option\\(''--public'', ''Allow unauthenticated access to all resources \\(disables WAC\\)''\\)\n.option\\(''--read-only'', ''Disable PUT/DELETE methods \\(read-only mode\\)''\\)\n```\n\n### 2. Add to config \\(`src/config.js`\\)\n\n```javascript\nconst DEFAULTS = {\n // ... existing ...\n public: false,\n readOnly: false,\n};\n\n// Environment variable mapping\nif \\(process.env.JSS_PUBLIC\\) {\n config.public = process.env.JSS_PUBLIC === ''true'';\n}\nif \\(process.env.JSS_READ_ONLY\\) {\n config.readOnly = process.env.JSS_READ_ONLY === ''true'';\n}\n```\n\n### 3. Skip WAC when public \\(`src/auth/middleware.js`\\)\n\n```javascript\nexport async function authorize\\(request, reply\\) {\n // Public mode - skip all auth/WAC checks\n if \\(request.config?.public\\) {\n return; // Allow request to proceed\n }\n \n // ... existing WAC logic ...\n}\n```\n\n### 4. Block writes when read-only \\(`src/handlers/resource.js`, `src/handlers/container.js`\\)\n\n```javascript\n// At start of PUT/DELETE handlers\nif \\(request.config?.readOnly\\) {\n return reply.code\\(405\\).send\\({ \n error: ''Method Not Allowed'',\n message: ''Server is in read-only mode''\n }\\);\n}\n```\n\n---\n\n## Behavior Matrix\n\n| Flag Combination | GET | PUT/DELETE | Auth Required |\n|------------------|-----|------------|---------------|\n| \\(default\\) | ACL | ACL | Yes \\(if ACL requires\\) |\n| `--public` | ✅ Allow | ✅ Allow | No |\n| `--public --read-only` | ✅ Allow | ❌ Block | No |\n| `--read-only` \\(no public\\) | ACL | ❌ Block | Yes |\n\n---\n\n## Security Considerations\n\n### Warning on Startup\n\nWhen `--public` is enabled, show a clear warning:\n\n```\n⚠️ WARNING: Server running in PUBLIC mode\n All files are readable and writable without authentication.\n Do not use in production or expose to the internet.\n```\n\n### Binding to localhost by default?\n\nConsider: When `--public` is set, should the default host be `localhost` instead of `0.0.0.0`?\n\n```javascript\nif \\(config.public && !explicitHostSet\\) {\n config.host = ''localhost''; // Safer default for public mode\n}\n```\n\nUser can override with `--public --host 0.0.0.0` if they explicitly want network access.\n\n---\n\n## Examples\n\n### Local Development\n```bash\n# Quick Solid-compatible file server for development\njss start --public --port 3000 --root ./test-data\n```\n\n### Read-Only File Sharing\n```bash\n# Share files on LAN, no writes allowed\njss start --public --read-only --host 0.0.0.0 --root ~/shared\n```\n\n### Testing Solid Apps\n```bash\n# Test app without auth complexity\njss start --public --root ./fixtures\nnpm test\n```\n\n---\n\n## Files to Modify\n\n| File | Changes |\n|------|---------|\n| `bin/jss.js` | Add `--public` and `--read-only` options \\(~5 LOC\\) |\n| `src/config.js` | Add defaults and env var mapping \\(~10 LOC\\) |\n| `src/auth/middleware.js` | Skip WAC when public \\(~5 LOC\\) |\n| `src/handlers/resource.js` | Block writes when read-only \\(~5 LOC\\) |\n| `src/handlers/container.js` | Block writes when read-only \\(~5 LOC\\) |\n| **Total** | **~30 LOC** |\n\n---\n\n## Testing\n\n```javascript\ndescribe\\(''--public flag'', \\(\\) => {\n it\\(''should allow unauthenticated GET'', async \\(\\) => {\n const server = await createServer\\({ public: true, root: tmpDir }\\);\n const res = await request\\(server\\).get\\(''/file.txt''\\);\n expect\\(res.status\\).toBe\\(200\\);\n }\\);\n\n it\\(''should allow unauthenticated PUT'', async \\(\\) => {\n const server = await createServer\\({ public: true, root: tmpDir }\\);\n const res = await request\\(server\\)\n .put\\(''/new-file.txt''\\)\n .send\\(''content''\\);\n expect\\(res.status\\).toBe\\(201\\);\n }\\);\n\n it\\(''should block PUT when read-only'', async \\(\\) => {\n const server = await createServer\\({ public: true, readOnly: true, root: tmpDir }\\);\n const res = await request\\(server\\)\n .put\\(''/new-file.txt''\\)\n .send\\(''content''\\);\n expect\\(res.status\\).toBe\\(405\\);\n }\\);\n}\\);\n```\n\n---\n\n## Related Issues\n\n- Future: `jsserve` package \\(thin wrapper using this flag\\)\n- #100 - Production Readiness \\(this is a dev/convenience feature\\)\n\n---\n\n## Open Questions\n\n1. Should `--public` default to `localhost` binding for safety?\n2. Should there be a `--public-read` \\(read-only public\\) shorthand?\n3. Should `--public` disable IdP/login UI entirely, or just make it optional?\nENDOFFILE\n\\)\")",
|
|
322
|
+
"Bash(npx serve --help:*)",
|
|
323
|
+
"Bash(npm exec serve:*)"
|
|
281
324
|
]
|
|
282
325
|
}
|
|
283
326
|
}
|
package/bin/jss.js
CHANGED
|
@@ -76,6 +76,8 @@ program
|
|
|
76
76
|
.option('--single-user-name <name>', 'Username for single-user mode (default: me)')
|
|
77
77
|
.option('--webid-tls', 'Enable WebID-TLS client certificate authentication')
|
|
78
78
|
.option('--no-webid-tls', 'Disable WebID-TLS authentication')
|
|
79
|
+
.option('--public', 'Allow unauthenticated access (skip WAC, open read/write)')
|
|
80
|
+
.option('--read-only', 'Disable PUT/DELETE/PATCH methods (read-only mode)')
|
|
79
81
|
.option('-q, --quiet', 'Suppress log output')
|
|
80
82
|
.option('--print-config', 'Print configuration and exit')
|
|
81
83
|
.action(async (options) => {
|
|
@@ -131,6 +133,8 @@ program
|
|
|
131
133
|
webidTls: config.webidTls,
|
|
132
134
|
singleUser: config.singleUser,
|
|
133
135
|
singleUserName: config.singleUserName,
|
|
136
|
+
public: config.public,
|
|
137
|
+
readOnly: config.readOnly,
|
|
134
138
|
});
|
|
135
139
|
|
|
136
140
|
await server.listen({ port: config.port, host: config.host });
|
|
@@ -156,6 +160,16 @@ program
|
|
|
156
160
|
if (config.singleUser) console.log(` Single-user: ${config.singleUserName || 'me'} (registration disabled)`);
|
|
157
161
|
else if (config.inviteOnly) console.log(' Registration: invite-only');
|
|
158
162
|
if (config.webidTls) console.log(' WebID-TLS: enabled (client certificate auth)');
|
|
163
|
+
if (config.public) {
|
|
164
|
+
console.log('');
|
|
165
|
+
console.log(' ⚠️ WARNING: PUBLIC MODE ENABLED');
|
|
166
|
+
console.log(' All files are accessible without authentication.');
|
|
167
|
+
if (!config.readOnly) {
|
|
168
|
+
console.log(' Anyone can read, write, and delete files.');
|
|
169
|
+
}
|
|
170
|
+
console.log(' Do not expose to the internet!');
|
|
171
|
+
}
|
|
172
|
+
if (config.readOnly) console.log(' Read-only: enabled (PUT/DELETE/PATCH disabled)');
|
|
159
173
|
console.log('\n Press Ctrl+C to stop\n');
|
|
160
174
|
}
|
|
161
175
|
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>fonstr - Your Nostr Relay</title>
|
|
7
|
+
<style>
|
|
8
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
|
+
body {
|
|
10
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
11
|
+
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
|
|
12
|
+
color: white;
|
|
13
|
+
min-height: 100vh;
|
|
14
|
+
display: flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
justify-content: center;
|
|
17
|
+
padding: 2rem;
|
|
18
|
+
}
|
|
19
|
+
.container {
|
|
20
|
+
text-align: center;
|
|
21
|
+
max-width: 600px;
|
|
22
|
+
}
|
|
23
|
+
h1 {
|
|
24
|
+
font-size: 3rem;
|
|
25
|
+
margin-bottom: 0.5rem;
|
|
26
|
+
}
|
|
27
|
+
.emoji {
|
|
28
|
+
font-size: 4rem;
|
|
29
|
+
margin-bottom: 1rem;
|
|
30
|
+
}
|
|
31
|
+
p {
|
|
32
|
+
font-size: 1.25rem;
|
|
33
|
+
opacity: 0.95;
|
|
34
|
+
margin-bottom: 2rem;
|
|
35
|
+
line-height: 1.6;
|
|
36
|
+
}
|
|
37
|
+
.relay-info {
|
|
38
|
+
background: rgba(255, 255, 255, 0.2);
|
|
39
|
+
backdrop-filter: blur(10px);
|
|
40
|
+
border-radius: 1rem;
|
|
41
|
+
padding: 2rem;
|
|
42
|
+
margin: 2rem 0;
|
|
43
|
+
}
|
|
44
|
+
code {
|
|
45
|
+
background: rgba(255, 255, 255, 0.3);
|
|
46
|
+
padding: 0.5rem 1rem;
|
|
47
|
+
border-radius: 0.5rem;
|
|
48
|
+
font-size: 1.1rem;
|
|
49
|
+
display: inline-block;
|
|
50
|
+
margin: 0.5rem 0;
|
|
51
|
+
font-family: 'Monaco', 'Menlo', monospace;
|
|
52
|
+
}
|
|
53
|
+
.stats {
|
|
54
|
+
display: grid;
|
|
55
|
+
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
|
56
|
+
gap: 1rem;
|
|
57
|
+
margin-top: 2rem;
|
|
58
|
+
}
|
|
59
|
+
.stat {
|
|
60
|
+
background: rgba(255, 255, 255, 0.15);
|
|
61
|
+
padding: 1rem;
|
|
62
|
+
border-radius: 0.5rem;
|
|
63
|
+
}
|
|
64
|
+
.stat-label {
|
|
65
|
+
font-size: 0.9rem;
|
|
66
|
+
opacity: 0.8;
|
|
67
|
+
}
|
|
68
|
+
.stat-value {
|
|
69
|
+
font-size: 1.5rem;
|
|
70
|
+
font-weight: 700;
|
|
71
|
+
margin-top: 0.25rem;
|
|
72
|
+
}
|
|
73
|
+
a {
|
|
74
|
+
color: white;
|
|
75
|
+
text-decoration: none;
|
|
76
|
+
border-bottom: 2px solid rgba(255, 255, 255, 0.5);
|
|
77
|
+
transition: border-color 0.2s;
|
|
78
|
+
}
|
|
79
|
+
a:hover {
|
|
80
|
+
border-color: white;
|
|
81
|
+
}
|
|
82
|
+
</style>
|
|
83
|
+
</head>
|
|
84
|
+
<body>
|
|
85
|
+
<div class="container">
|
|
86
|
+
<div class="emoji">⚡</div>
|
|
87
|
+
<h1>fonstr</h1>
|
|
88
|
+
<p>Your Nostr relay is running!</p>
|
|
89
|
+
|
|
90
|
+
<div class="relay-info">
|
|
91
|
+
<p style="font-size: 1rem; margin-bottom: 1rem; opacity: 0.9;">Connect to your relay:</p>
|
|
92
|
+
<code>ws://localhost:4444/relay</code>
|
|
93
|
+
|
|
94
|
+
<div class="stats">
|
|
95
|
+
<div class="stat">
|
|
96
|
+
<div class="stat-label">Status</div>
|
|
97
|
+
<div class="stat-value">✓ Online</div>
|
|
98
|
+
</div>
|
|
99
|
+
<div class="stat">
|
|
100
|
+
<div class="stat-label">Protocol</div>
|
|
101
|
+
<div class="stat-value">NIP-01</div>
|
|
102
|
+
</div>
|
|
103
|
+
<div class="stat">
|
|
104
|
+
<div class="stat-label">Port</div>
|
|
105
|
+
<div class="stat-value">4444</div>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
<p style="font-size: 1rem;">
|
|
111
|
+
Add this relay to your favorite Nostr client and start using it!<br>
|
|
112
|
+
<a href="https://fonstr.com" target="_blank">Learn more about fonstr</a>
|
|
113
|
+
</p>
|
|
114
|
+
|
|
115
|
+
<p style="font-size: 0.9rem; opacity: 0.7; margin-top: 2rem;">
|
|
116
|
+
Replace this page by editing <code style="font-size: 0.8rem;">index.html</code> in your data directory
|
|
117
|
+
</p>
|
|
118
|
+
</div>
|
|
119
|
+
</body>
|
|
120
|
+
</html>
|
package/package.json
CHANGED
package/src/auth/middleware.js
CHANGED
|
@@ -28,6 +28,12 @@ export async function authorize(request, reply, options = {}) {
|
|
|
28
28
|
return { authorized: true, webId: null, wacAllow: 'user="read write append control", public="read write append"', authError: null };
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
// Public mode - skip all WAC checks, allow unauthenticated access
|
|
32
|
+
if (request.config?.public) {
|
|
33
|
+
const modes = request.config?.readOnly ? 'read' : 'read write append';
|
|
34
|
+
return { authorized: true, webId: null, wacAllow: `public="${modes}"`, authError: null };
|
|
35
|
+
}
|
|
36
|
+
|
|
31
37
|
// Get WebID from token (supports both simple and Solid-OIDC tokens)
|
|
32
38
|
const { webId, error: authError } = await getWebIdFromRequestAsync(request);
|
|
33
39
|
|
package/src/config.js
CHANGED
|
@@ -73,6 +73,12 @@ export const defaults = {
|
|
|
73
73
|
// Storage quota (bytes) - 50MB default
|
|
74
74
|
defaultQuota: 50 * 1024 * 1024,
|
|
75
75
|
|
|
76
|
+
// Public mode - skip WAC, allow unauthenticated access
|
|
77
|
+
public: false,
|
|
78
|
+
|
|
79
|
+
// Read-only mode - disable PUT/DELETE/PATCH
|
|
80
|
+
readOnly: false,
|
|
81
|
+
|
|
76
82
|
// Logging
|
|
77
83
|
logger: true,
|
|
78
84
|
quiet: false,
|
|
@@ -117,6 +123,8 @@ const envMap = {
|
|
|
117
123
|
JSS_SINGLE_USER_NAME: 'singleUserName',
|
|
118
124
|
JSS_WEBID_TLS: 'webidTls',
|
|
119
125
|
JSS_DEFAULT_QUOTA: 'defaultQuota',
|
|
126
|
+
JSS_PUBLIC: 'public',
|
|
127
|
+
JSS_READ_ONLY: 'readOnly',
|
|
120
128
|
};
|
|
121
129
|
|
|
122
130
|
/**
|
|
@@ -25,6 +25,11 @@ function getRequestPaths(request) {
|
|
|
25
25
|
* Handle POST request to container (create new resource)
|
|
26
26
|
*/
|
|
27
27
|
export async function handlePost(request, reply) {
|
|
28
|
+
// Read-only mode - block all writes
|
|
29
|
+
if (request.config?.readOnly) {
|
|
30
|
+
return reply.code(405).send({ error: 'Method Not Allowed', message: 'Server is in read-only mode' });
|
|
31
|
+
}
|
|
32
|
+
|
|
28
33
|
const { urlPath, storagePath } = getRequestPaths(request);
|
|
29
34
|
|
|
30
35
|
// Ensure target is a container
|
|
@@ -107,8 +112,8 @@ export async function handlePost(request, reply) {
|
|
|
107
112
|
}
|
|
108
113
|
}
|
|
109
114
|
|
|
110
|
-
// Check storage quota before writing
|
|
111
|
-
const podName = getPodName(request);
|
|
115
|
+
// Check storage quota before writing (skip in public mode - no pod structure)
|
|
116
|
+
const podName = request.config?.public ? null : getPodName(request);
|
|
112
117
|
if (podName) {
|
|
113
118
|
const { allowed, error } = await checkQuota(podName, content.length, request.defaultQuota || 0);
|
|
114
119
|
if (!allowed) {
|
|
@@ -233,6 +238,11 @@ export async function createPodStructure(name, webId, podUri, issuer, defaultQuo
|
|
|
233
238
|
* /{name}/settings/privateTypeIndex
|
|
234
239
|
*/
|
|
235
240
|
export async function handleCreatePod(request, reply) {
|
|
241
|
+
// Read-only mode - block pod creation
|
|
242
|
+
if (request.config?.readOnly) {
|
|
243
|
+
return reply.code(405).send({ error: 'Method Not Allowed', message: 'Server is in read-only mode' });
|
|
244
|
+
}
|
|
245
|
+
|
|
236
246
|
const { name, email, password } = request.body || {};
|
|
237
247
|
const idpEnabled = request.idpEnabled;
|
|
238
248
|
|
package/src/handlers/resource.js
CHANGED
|
@@ -511,6 +511,11 @@ export async function handleHead(request, reply) {
|
|
|
511
511
|
* Handle PUT request
|
|
512
512
|
*/
|
|
513
513
|
export async function handlePut(request, reply) {
|
|
514
|
+
// Read-only mode - block all writes
|
|
515
|
+
if (request.config?.readOnly) {
|
|
516
|
+
return reply.code(405).send({ error: 'Method Not Allowed', message: 'Server is in read-only mode' });
|
|
517
|
+
}
|
|
518
|
+
|
|
514
519
|
const { urlPath, storagePath, resourceUrl } = getRequestPaths(request);
|
|
515
520
|
const connegEnabled = request.connegEnabled || false;
|
|
516
521
|
|
|
@@ -603,8 +608,8 @@ export async function handlePut(request, reply) {
|
|
|
603
608
|
}
|
|
604
609
|
}
|
|
605
610
|
|
|
606
|
-
// Check storage quota before writing
|
|
607
|
-
const podName = getPodName(request);
|
|
611
|
+
// Check storage quota before writing (skip in public mode - no pod structure)
|
|
612
|
+
const podName = request.config?.public ? null : getPodName(request);
|
|
608
613
|
const oldSize = stats?.size || 0;
|
|
609
614
|
const sizeDelta = content.length - oldSize;
|
|
610
615
|
|
|
@@ -644,6 +649,11 @@ export async function handlePut(request, reply) {
|
|
|
644
649
|
* Handle DELETE request
|
|
645
650
|
*/
|
|
646
651
|
export async function handleDelete(request, reply) {
|
|
652
|
+
// Read-only mode - block all writes
|
|
653
|
+
if (request.config?.readOnly) {
|
|
654
|
+
return reply.code(405).send({ error: 'Method Not Allowed', message: 'Server is in read-only mode' });
|
|
655
|
+
}
|
|
656
|
+
|
|
647
657
|
const { storagePath, resourceUrl } = getRequestPaths(request);
|
|
648
658
|
|
|
649
659
|
// Check if resource exists and get current ETag
|
|
@@ -716,6 +726,11 @@ export async function handleOptions(request, reply) {
|
|
|
716
726
|
* Supports N3 Patch format (text/n3) and SPARQL Update for updating RDF resources
|
|
717
727
|
*/
|
|
718
728
|
export async function handlePatch(request, reply) {
|
|
729
|
+
// Read-only mode - block all writes
|
|
730
|
+
if (request.config?.readOnly) {
|
|
731
|
+
return reply.code(405).send({ error: 'Method Not Allowed', message: 'Server is in read-only mode' });
|
|
732
|
+
}
|
|
733
|
+
|
|
719
734
|
const { urlPath, storagePath, resourceUrl } = getRequestPaths(request);
|
|
720
735
|
|
|
721
736
|
// Don't allow PATCH to containers
|
package/src/server.js
CHANGED
|
@@ -135,6 +135,7 @@ export function createServer(options = {}) {
|
|
|
135
135
|
fastify.decorateRequest('mashlibVersion', null);
|
|
136
136
|
fastify.decorateRequest('solidosUiEnabled', null);
|
|
137
137
|
fastify.decorateRequest('defaultQuota', null);
|
|
138
|
+
fastify.decorateRequest('config', null);
|
|
138
139
|
fastify.addHook('onRequest', async (request) => {
|
|
139
140
|
request.connegEnabled = connegEnabled;
|
|
140
141
|
request.notificationsEnabled = notificationsEnabled;
|
|
@@ -146,6 +147,7 @@ export function createServer(options = {}) {
|
|
|
146
147
|
request.mashlibVersion = mashlibVersion;
|
|
147
148
|
request.solidosUiEnabled = solidosUiEnabled;
|
|
148
149
|
request.defaultQuota = defaultQuota;
|
|
150
|
+
request.config = { public: options.public, readOnly: options.readOnly };
|
|
149
151
|
|
|
150
152
|
// Extract pod name from subdomain if enabled
|
|
151
153
|
if (subdomainsEnabled && baseDomain) {
|