javascript-solid-server 0.0.119 → 0.0.120
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/docs/payments.md +37 -0
- package/package.json +1 -1
- package/src/auth/middleware.js +2 -2
- package/src/server.js +14 -2
- package/src/wac/checker.js +24 -9
- package/src/wac/parser.js +19 -1
- package/test/wac.test.js +121 -0
- package/.claude/settings.local.json +0 -338
package/docs/payments.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
## HTTP 402 Paid Access
|
|
2
2
|
|
|
3
|
+
JSS supports two approaches to paid content:
|
|
4
|
+
|
|
5
|
+
1. **ACL Conditions** — any resource at any URL can require payment via `acl:condition` in its ACL file
|
|
6
|
+
2. **Pay Route** — the `/pay/*` prefix provides a full payment backend with deposits, balances, and token trading
|
|
7
|
+
|
|
8
|
+
### ACL-Based Payments (Generic)
|
|
9
|
+
|
|
10
|
+
Any resource can be payment-gated by adding a `PaymentCondition` to its ACL:
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"@context": { "acl": "http://www.w3.org/ns/auth/acl#" },
|
|
15
|
+
"@graph": [{
|
|
16
|
+
"@type": "acl:Authorization",
|
|
17
|
+
"acl:agentClass": { "@id": "acl:AuthenticatedAgent" },
|
|
18
|
+
"acl:accessTo": { "@id": "/premium/article.jsonld" },
|
|
19
|
+
"acl:mode": [{ "@id": "acl:Read" }],
|
|
20
|
+
"acl:condition": {
|
|
21
|
+
"@type": "PaymentCondition",
|
|
22
|
+
"amount": "1000",
|
|
23
|
+
"currency": "sats"
|
|
24
|
+
}
|
|
25
|
+
}]
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
When a client requests the resource:
|
|
30
|
+
|
|
31
|
+
1. Server evaluates the ACL and finds the `PaymentCondition`
|
|
32
|
+
2. Server responds with `402 Payment Required` and payment details in the body
|
|
33
|
+
3. Client completes payment and retries with proof
|
|
34
|
+
4. Server verifies and grants access
|
|
35
|
+
|
|
36
|
+
**Design: fail-closed** — if the server encounters a condition type it doesn't support, access is denied. Unsupported conditions are never silently ignored.
|
|
37
|
+
|
|
38
|
+
### Pay Route (Full Backend)
|
|
39
|
+
|
|
3
40
|
Monetize API endpoints with per-request satoshi payments. Resources under `/pay/*` require NIP-98 authentication and a positive balance.
|
|
4
41
|
|
|
5
42
|
```bash
|
package/package.json
CHANGED
package/src/auth/middleware.js
CHANGED
|
@@ -102,7 +102,7 @@ export async function authorize(request, reply, options = {}) {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
// Check WAC permissions
|
|
105
|
-
const { allowed, wacAllow } = await checkAccess({
|
|
105
|
+
const { allowed, wacAllow, paymentRequired } = await checkAccess({
|
|
106
106
|
resourceUrl: checkUrl,
|
|
107
107
|
resourcePath: checkPath,
|
|
108
108
|
isContainer: checkIsContainer,
|
|
@@ -110,7 +110,7 @@ export async function authorize(request, reply, options = {}) {
|
|
|
110
110
|
requiredMode
|
|
111
111
|
});
|
|
112
112
|
|
|
113
|
-
return { authorized: allowed, webId, wacAllow, authError };
|
|
113
|
+
return { authorized: allowed, webId, wacAllow, authError, paymentRequired };
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
/**
|
package/src/server.js
CHANGED
|
@@ -389,10 +389,14 @@ export function createServer(options = {}) {
|
|
|
389
389
|
const requiredMode = needsWrite ? AccessMode.WRITE : AccessMode.READ;
|
|
390
390
|
|
|
391
391
|
// Run WAC authorization with the correct mode for git operations
|
|
392
|
-
const { authorized, webId, wacAllow, authError } = await authorize(request, reply, { requiredMode });
|
|
392
|
+
const { authorized, webId, wacAllow, authError, paymentRequired } = await authorize(request, reply, { requiredMode });
|
|
393
393
|
request.webId = webId;
|
|
394
394
|
request.wacAllow = wacAllow;
|
|
395
395
|
|
|
396
|
+
if (paymentRequired) {
|
|
397
|
+
return reply.code(402).send({ type: 'PaymentRequired', ...paymentRequired });
|
|
398
|
+
}
|
|
399
|
+
|
|
396
400
|
if (!authorized) {
|
|
397
401
|
const message = needsWrite ? 'Write access required for push' : 'Read access required for clone';
|
|
398
402
|
reply.header('WAC-Allow', wacAllow);
|
|
@@ -444,7 +448,7 @@ export function createServer(options = {}) {
|
|
|
444
448
|
return;
|
|
445
449
|
}
|
|
446
450
|
|
|
447
|
-
const { authorized, webId, wacAllow, authError } = await authorize(request, reply);
|
|
451
|
+
const { authorized, webId, wacAllow, authError, paymentRequired } = await authorize(request, reply);
|
|
448
452
|
|
|
449
453
|
// Store webId and wacAllow on request for handlers to use
|
|
450
454
|
request.webId = webId;
|
|
@@ -453,6 +457,14 @@ export function createServer(options = {}) {
|
|
|
453
457
|
// Set WAC-Allow header for all responses (handlers may override)
|
|
454
458
|
reply.header('WAC-Allow', wacAllow);
|
|
455
459
|
|
|
460
|
+
// Handle payment-gated resources
|
|
461
|
+
if (paymentRequired) {
|
|
462
|
+
return reply.code(402).send({
|
|
463
|
+
type: 'PaymentRequired',
|
|
464
|
+
...paymentRequired
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
|
|
456
468
|
if (!authorized) {
|
|
457
469
|
return handleUnauthorized(request, reply, webId !== null, wacAllow, authError);
|
|
458
470
|
}
|
package/src/wac/checker.js
CHANGED
|
@@ -37,7 +37,7 @@ export async function checkAccess({
|
|
|
37
37
|
|
|
38
38
|
// Check authorizations
|
|
39
39
|
// Note: For default ACLs, we check if the ACL's default rules apply to the actual resource URL
|
|
40
|
-
const
|
|
40
|
+
const result = checkAuthorizations(
|
|
41
41
|
authorizations,
|
|
42
42
|
resourceUrl, // Use actual resource URL, not the ACL container URL
|
|
43
43
|
agentWebId,
|
|
@@ -48,7 +48,7 @@ export async function checkAccess({
|
|
|
48
48
|
// Calculate WAC-Allow header
|
|
49
49
|
const wacAllow = calculateWacAllow(authorizations, resourceUrl, agentWebId, isDefault);
|
|
50
50
|
|
|
51
|
-
return { allowed, wacAllow };
|
|
51
|
+
return { allowed: result.allowed, wacAllow, paymentRequired: result.paymentRequired || null };
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/**
|
|
@@ -125,6 +125,9 @@ function getParentPath(path) {
|
|
|
125
125
|
/**
|
|
126
126
|
* Check if any authorization grants the required mode
|
|
127
127
|
*/
|
|
128
|
+
// Supported condition types
|
|
129
|
+
const SUPPORTED_CONDITIONS = ['PaymentCondition', 'https://webacl.org/ns#PaymentCondition'];
|
|
130
|
+
|
|
128
131
|
function checkAuthorizations(authorizations, targetUrl, agentWebId, requiredMode, isDefault) {
|
|
129
132
|
for (const auth of authorizations) {
|
|
130
133
|
// For default ACLs, check if auth has default rules and matches target
|
|
@@ -144,17 +147,29 @@ function checkAuthorizations(authorizations, targetUrl, agentWebId, requiredMode
|
|
|
144
147
|
if (!agentAuthorized) continue;
|
|
145
148
|
|
|
146
149
|
// Check if mode is granted
|
|
147
|
-
|
|
148
|
-
|
|
150
|
+
const modeGranted = auth.modes.includes(requiredMode) ||
|
|
151
|
+
(requiredMode === AccessMode.APPEND && auth.modes.includes(AccessMode.WRITE));
|
|
152
|
+
if (!modeGranted) continue;
|
|
153
|
+
|
|
154
|
+
// Check conditions (fail-closed)
|
|
155
|
+
if (auth.conditions && auth.conditions.length > 0) {
|
|
156
|
+
// Fail-closed: skip this auth if any condition type is unsupported
|
|
157
|
+
const unsupported = auth.conditions.find(c => !SUPPORTED_CONDITIONS.includes(c.type));
|
|
158
|
+
if (unsupported) continue;
|
|
159
|
+
|
|
160
|
+
// Check payment condition
|
|
161
|
+
const paymentCondition = auth.conditions.find(c =>
|
|
162
|
+
c.type === 'PaymentCondition' || c.type === 'https://webacl.org/ns#PaymentCondition'
|
|
163
|
+
);
|
|
164
|
+
if (paymentCondition) {
|
|
165
|
+
return { allowed: false, paymentRequired: paymentCondition };
|
|
166
|
+
}
|
|
149
167
|
}
|
|
150
168
|
|
|
151
|
-
|
|
152
|
-
if (requiredMode === AccessMode.APPEND && auth.modes.includes(AccessMode.WRITE)) {
|
|
153
|
-
return true;
|
|
154
|
-
}
|
|
169
|
+
return { allowed: true };
|
|
155
170
|
}
|
|
156
171
|
|
|
157
|
-
return false;
|
|
172
|
+
return { allowed: false };
|
|
158
173
|
}
|
|
159
174
|
|
|
160
175
|
/**
|
package/src/wac/parser.js
CHANGED
|
@@ -133,7 +133,8 @@ function parseAuthorization(node, aclUrl) {
|
|
|
133
133
|
agents: [], // Specific WebIDs
|
|
134
134
|
agentClasses: [], // Agent classes (public, authenticated)
|
|
135
135
|
agentGroups: [], // Groups
|
|
136
|
-
modes: []
|
|
136
|
+
modes: [], // Access modes
|
|
137
|
+
conditions: [] // Access conditions (e.g. PaymentCondition)
|
|
137
138
|
};
|
|
138
139
|
|
|
139
140
|
// Parse accessTo - resolve relative URLs
|
|
@@ -157,9 +158,26 @@ function parseAuthorization(node, aclUrl) {
|
|
|
157
158
|
// Parse modes
|
|
158
159
|
auth.modes = parseUriArray(node['acl:mode'] || node['mode']).map(normalizeMode);
|
|
159
160
|
|
|
161
|
+
// Parse conditions
|
|
162
|
+
auth.conditions = parseConditions(node['acl:condition'] || node['condition']);
|
|
163
|
+
|
|
160
164
|
return auth;
|
|
161
165
|
}
|
|
162
166
|
|
|
167
|
+
/**
|
|
168
|
+
* Parse conditions from an authorization node
|
|
169
|
+
*/
|
|
170
|
+
function parseConditions(value) {
|
|
171
|
+
if (!value) return [];
|
|
172
|
+
const values = Array.isArray(value) ? value : [value];
|
|
173
|
+
return values.map(v => {
|
|
174
|
+
if (typeof v !== 'object' || v === null) return null;
|
|
175
|
+
const type = v['@type'] || v.type;
|
|
176
|
+
if (!type) return null;
|
|
177
|
+
return { ...v, type };
|
|
178
|
+
}).filter(Boolean);
|
|
179
|
+
}
|
|
180
|
+
|
|
163
181
|
/**
|
|
164
182
|
* Parse a value that could be a URI, @id object, or array of either
|
|
165
183
|
*/
|
package/test/wac.test.js
CHANGED
|
@@ -335,3 +335,124 @@ describe('WAC Integration', () => {
|
|
|
335
335
|
});
|
|
336
336
|
});
|
|
337
337
|
});
|
|
338
|
+
|
|
339
|
+
describe('WAC Conditions', () => {
|
|
340
|
+
describe('parseAcl with conditions', () => {
|
|
341
|
+
it('should parse a PaymentCondition', async () => {
|
|
342
|
+
const acl = {
|
|
343
|
+
'@context': { 'acl': 'http://www.w3.org/ns/auth/acl#' },
|
|
344
|
+
'@graph': [{
|
|
345
|
+
'@id': '#paid',
|
|
346
|
+
'@type': 'acl:Authorization',
|
|
347
|
+
'acl:agentClass': { '@id': 'acl:AuthenticatedAgent' },
|
|
348
|
+
'acl:accessTo': { '@id': 'https://alice.example/premium/article.jsonld' },
|
|
349
|
+
'acl:mode': [{ '@id': 'acl:Read' }],
|
|
350
|
+
'acl:condition': {
|
|
351
|
+
'@type': 'PaymentCondition',
|
|
352
|
+
'amount': '1000',
|
|
353
|
+
'currency': 'sats'
|
|
354
|
+
}
|
|
355
|
+
}]
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
const auths = await parseAcl(JSON.stringify(acl), 'https://alice.example/premium/.acl');
|
|
359
|
+
|
|
360
|
+
assert.strictEqual(auths.length, 1);
|
|
361
|
+
assert.strictEqual(auths[0].conditions.length, 1);
|
|
362
|
+
assert.strictEqual(auths[0].conditions[0].type, 'PaymentCondition');
|
|
363
|
+
assert.strictEqual(auths[0].conditions[0].amount, '1000');
|
|
364
|
+
assert.strictEqual(auths[0].conditions[0].currency, 'sats');
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it('should parse multiple conditions', async () => {
|
|
368
|
+
const acl = {
|
|
369
|
+
'@context': { 'acl': 'http://www.w3.org/ns/auth/acl#' },
|
|
370
|
+
'@graph': [{
|
|
371
|
+
'@id': '#restricted',
|
|
372
|
+
'@type': 'acl:Authorization',
|
|
373
|
+
'acl:agent': { '@id': 'https://bob.example/#me' },
|
|
374
|
+
'acl:accessTo': { '@id': 'https://alice.example/resource' },
|
|
375
|
+
'acl:mode': [{ '@id': 'acl:Read' }],
|
|
376
|
+
'acl:condition': [
|
|
377
|
+
{ '@type': 'PaymentCondition', 'amount': '500', 'currency': 'sats' },
|
|
378
|
+
{ '@type': 'ClientCondition', 'client': 'https://trusted.app/pane.js' }
|
|
379
|
+
]
|
|
380
|
+
}]
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
const auths = await parseAcl(JSON.stringify(acl), 'https://alice.example/.acl');
|
|
384
|
+
|
|
385
|
+
assert.strictEqual(auths[0].conditions.length, 2);
|
|
386
|
+
assert.strictEqual(auths[0].conditions[0].type, 'PaymentCondition');
|
|
387
|
+
assert.strictEqual(auths[0].conditions[1].type, 'ClientCondition');
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
it('should parse authorization without conditions', async () => {
|
|
391
|
+
const acl = {
|
|
392
|
+
'@context': { 'acl': 'http://www.w3.org/ns/auth/acl#' },
|
|
393
|
+
'@graph': [{
|
|
394
|
+
'@id': '#public',
|
|
395
|
+
'@type': 'acl:Authorization',
|
|
396
|
+
'acl:agentClass': { '@id': 'http://xmlns.com/foaf/0.1/Agent' },
|
|
397
|
+
'acl:accessTo': { '@id': 'https://alice.example/public/' },
|
|
398
|
+
'acl:mode': [{ '@id': 'acl:Read' }]
|
|
399
|
+
}]
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
const auths = await parseAcl(JSON.stringify(acl), 'https://alice.example/.acl');
|
|
403
|
+
|
|
404
|
+
assert.strictEqual(auths[0].conditions.length, 0);
|
|
405
|
+
});
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
describe('fail-closed conditions', () => {
|
|
409
|
+
it('should parse unsupported condition types', async () => {
|
|
410
|
+
const acl = {
|
|
411
|
+
'@context': { 'acl': 'http://www.w3.org/ns/auth/acl#' },
|
|
412
|
+
'@graph': [{
|
|
413
|
+
'@id': '#restricted',
|
|
414
|
+
'@type': 'acl:Authorization',
|
|
415
|
+
'acl:agent': { '@id': 'https://bob.example/#me' },
|
|
416
|
+
'acl:accessTo': { '@id': 'https://alice.example/resource' },
|
|
417
|
+
'acl:mode': [{ '@id': 'acl:Read' }],
|
|
418
|
+
'acl:condition': {
|
|
419
|
+
'@type': 'UnknownFutureCondition',
|
|
420
|
+
'foo': 'bar'
|
|
421
|
+
}
|
|
422
|
+
}]
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
const auths = await parseAcl(JSON.stringify(acl), 'https://alice.example/.acl');
|
|
426
|
+
|
|
427
|
+
assert.strictEqual(auths[0].conditions.length, 1);
|
|
428
|
+
assert.strictEqual(auths[0].conditions[0].type, 'UnknownFutureCondition');
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
it('should parse PaymentCondition with all fields', async () => {
|
|
432
|
+
const acl = {
|
|
433
|
+
'@context': { 'acl': 'http://www.w3.org/ns/auth/acl#' },
|
|
434
|
+
'@graph': [{
|
|
435
|
+
'@id': '#paid',
|
|
436
|
+
'@type': 'acl:Authorization',
|
|
437
|
+
'acl:agentClass': { '@id': 'acl:AuthenticatedAgent' },
|
|
438
|
+
'acl:accessTo': { '@id': 'https://alice.example/premium/article.jsonld' },
|
|
439
|
+
'acl:mode': [{ '@id': 'acl:Read' }],
|
|
440
|
+
'acl:condition': {
|
|
441
|
+
'@type': 'PaymentCondition',
|
|
442
|
+
'amount': '1000',
|
|
443
|
+
'currency': 'sats',
|
|
444
|
+
'protocol': 'lightning'
|
|
445
|
+
}
|
|
446
|
+
}]
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
const auths = await parseAcl(JSON.stringify(acl), 'https://alice.example/premium/.acl');
|
|
450
|
+
const condition = auths[0].conditions[0];
|
|
451
|
+
|
|
452
|
+
assert.strictEqual(condition.type, 'PaymentCondition');
|
|
453
|
+
assert.strictEqual(condition.amount, '1000');
|
|
454
|
+
assert.strictEqual(condition.currency, 'sats');
|
|
455
|
+
assert.strictEqual(condition.protocol, 'lightning');
|
|
456
|
+
});
|
|
457
|
+
});
|
|
458
|
+
});
|
|
@@ -1,338 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"permissions": {
|
|
3
|
-
"allow": [
|
|
4
|
-
"WebSearch",
|
|
5
|
-
"WebFetch(domain:github.com)",
|
|
6
|
-
"WebFetch(domain:raw.githubusercontent.com)",
|
|
7
|
-
"Bash(cat:*)",
|
|
8
|
-
"WebFetch(domain:www.inrupt.com)",
|
|
9
|
-
"Bash(npm install:*)",
|
|
10
|
-
"Bash(timeout 3 node:*)",
|
|
11
|
-
"Bash(PORT=3030 timeout 3 node:*)",
|
|
12
|
-
"Bash(git commit:*)",
|
|
13
|
-
"Bash(pkill:*)",
|
|
14
|
-
"Bash(curl:*)",
|
|
15
|
-
"Bash(npm test:*)",
|
|
16
|
-
"Bash(git add:*)",
|
|
17
|
-
"WebFetch(domain:solid.github.io)",
|
|
18
|
-
"Bash(node:*)",
|
|
19
|
-
"WebFetch(domain:solidservers.org)",
|
|
20
|
-
"WebFetch(domain:solid-contrib.github.io)",
|
|
21
|
-
"Bash(git clone:*)",
|
|
22
|
-
"Bash(chmod:*)",
|
|
23
|
-
"Bash(JSS_PORT=4000 JSS_CONNEG=true node bin/jss.js:*)",
|
|
24
|
-
"Bash(find:*)",
|
|
25
|
-
"Bash(timeout 5 node:*)",
|
|
26
|
-
"Bash(npm view:*)",
|
|
27
|
-
"Bash(npm ls:*)",
|
|
28
|
-
"Bash(timeout 10 node:*)",
|
|
29
|
-
"Bash(npm run test:cth:*)",
|
|
30
|
-
"Bash(__NEW_LINE__ curl -s -X POST http://localhost:4000/.pods )",
|
|
31
|
-
"Bash(lsof:*)",
|
|
32
|
-
"Bash(xargs kill -9)",
|
|
33
|
-
"Bash(docker:*)",
|
|
34
|
-
"Bash(solidproject/conformance-test-harness )",
|
|
35
|
-
"Bash(timeout 30 node:*)",
|
|
36
|
-
"Bash(timeout 20 node:*)",
|
|
37
|
-
"Bash(timeout 25 node:*)",
|
|
38
|
-
"Bash(JSS_PORT=4000 JSS_CONNEG=true timeout 5 node:*)",
|
|
39
|
-
"Bash(pgrep:*)",
|
|
40
|
-
"Bash(python3:*)",
|
|
41
|
-
"Bash(ls:*)",
|
|
42
|
-
"Bash(timeout 15 node:*)",
|
|
43
|
-
"Bash(echo 'No .idp folder' echo find /home/melvin/remote/github.com/JavaScriptSolidServer/JavaScriptSolidServer/data/.idp/ -name *.json)",
|
|
44
|
-
"Bash(echo '=== Interactions ===' ls -la /home/melvin/remote/github.com/JavaScriptSolidServer/JavaScriptSolidServer/data/.idp/interaction/ echo echo '=== Latest interaction ===' cat /home/melvin/remote/github.com/JavaScriptSolidServer/JavaScriptSolidServer/data/.idp/interaction/*.json)",
|
|
45
|
-
"Bash(1 echo \"\" echo \"=== Server errors ===\" grep -E \"(error|Error)\" /tmp/jss.log)",
|
|
46
|
-
"Bash(echo 'Server not ready' curl -s -X POST http://localhost:4000/.pods -H 'Content-Type: application/json' -d {\"\"name\"\":\"\"alice\"\",\"\"email\"\":\"\"alice@example.com\"\",\"\"password\"\":\"\"alicepassword123\"\"})",
|
|
47
|
-
"Bash(head -1 curl -s -X POST http://localhost:4000/.pods -H \"Content-Type: application/json\" -d '{\"\"\"\"name\"\"\"\":\"\"\"\"bob\"\"\"\",\"\"\"\"email\"\"\"\":\"\"\"\"bob@example.com\"\"\"\",\"\"\"\"password\"\"\"\":\"\"\"\"bobpassword123\"\"\"\"}')",
|
|
48
|
-
"Bash(xargs:*)",
|
|
49
|
-
"Bash(fuser:*)",
|
|
50
|
-
"Bash(kill:*)",
|
|
51
|
-
"Bash(ACCESS_TOKEN=\"eyJhbGciOiJFUzI1NiIsImtpZCI6IjQwY2U0YzIzLWY2OWQtNDU4NS05ODg2LTE4MDQzZWIyZjU2ZCJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjQwMDAvIiwic3ViIjoiYjhlZjY5YWUtODc0ZS00MDg5LThiMDktOGQwY2QyM2VlZWY3IiwiYXVkIjoic29saWQiLCJ3ZWJpZCI6Imh0dHA6Ly9sb2NhbGhvc3Q0MDAwL2FsaWNlLyNtZSIsImlhdCI6MTc2NjgyOTQ5MiwiZXhwIjoxNzY2ODMzMDkyLCJqdGkiOiIwMWY4ODVlZS05ZjY2LTQ3M2MtYmZkNC05MWM4ZGU3NGJhZjYiLCJjbGllbnRfaWQiOiJjcmVkZW50aWFsc19jbGllbnQiLCJzY29wZSI6Im9wZW5pZCB3ZWJpZCJ9.DYTlSRkORyDN28XtXk-zbR7xNLViD97KkPqUKb6chV860BaIgwa1suif4TxHQDnK_ejvbvmZ46_n5WwwRnf_Zw\" curl -sI -X PUT http://localhost:4000/alice/cth-test/ -H \"Content-Type: text/turtle\" -H \"Authorization: Bearer $ACCESS_TOKEN\")",
|
|
52
|
-
"Bash(timeout 60 docker run:*)",
|
|
53
|
-
"Bash(rm:*)",
|
|
54
|
-
"Bash(mkdir:*)",
|
|
55
|
-
"WebFetch(domain:communitysolidserver.github.io)",
|
|
56
|
-
"WebFetch(domain:solidos.github.io)",
|
|
57
|
-
"WebFetch(domain:solidcommunity.net)",
|
|
58
|
-
"WebFetch(domain:www.npmjs.com)",
|
|
59
|
-
"Bash(pm2 list:*)",
|
|
60
|
-
"Bash(pm2 logs:*)",
|
|
61
|
-
"Bash(pm2 restart:*)",
|
|
62
|
-
"Bash(timeout 60 npm test:*)",
|
|
63
|
-
"Bash(pm2 stop:*)",
|
|
64
|
-
"Bash(pm2 delete:*)",
|
|
65
|
-
"Bash(pm2 start:*)",
|
|
66
|
-
"Bash(DATA_ROOT=/home/melvin/jss/data pm2 start:*)",
|
|
67
|
-
"Bash(pm2 save:*)",
|
|
68
|
-
"Bash(gh issue create:*)",
|
|
69
|
-
"Bash(gh issue view:*)",
|
|
70
|
-
"Bash(gh issue edit:*)",
|
|
71
|
-
"WebFetch(domain:nostrcg.github.io)",
|
|
72
|
-
"WebFetch(domain:melvincarvalho.github.io)",
|
|
73
|
-
"WebFetch(domain:dev.to)",
|
|
74
|
-
"WebFetch(domain:solidproject.org)",
|
|
75
|
-
"WebFetch(domain:www.w3.org)",
|
|
76
|
-
"Bash(wc:*)",
|
|
77
|
-
"Bash(TOKEN=\"eyJraW5kIjoyNzIzNSwidGFncyI6W1sidSIsImh0dHA6Ly9sb2NhbGhvc3Q6NDAwMC9kZW1vL25vc3RyLXpvbmUvIl0sWyJtZXRob2QiLCJHRVQiXV0sImNyZWF0ZWRfYXQiOjE3NjY5MzQ1NjksImNvbnRlbnQiOiIiLCJwdWJrZXkiOiI4OTg5OWNmOWEyNGE5ZTdlMTNmODU3MGRkMGI1MmJiOTQyMjllNDI2OGM1MGQ1OWZhNjdhMzQ0MGQ0NmFhZTdkIiwiaWQiOiJiNTUyMDUyOTVmYmQwYzhjZDYwMzk1NTgwOWYxZGM5Y2MwMjdlY2U4N2NjYmNlNzcwNWY2MjdmNmQ0ODk1MGJkIiwic2lnIjoiOWYzN2Y0NzIyZDlkNmFmZGQ5OTNkYTM0MDg2MWQ2YzQ4MmY1NzQ1MmFmZTIwZmY2YmI5OTAxNGIwOTU3NjUwMWZiNTgyZjEzNzNlZmVhNjI4ZDI5ZjlhMzhmZTgyODU0ODlmMzAzYzlmYmJjYWE0OTQxZjUyZGZlMWYxNzVkOWMifQ==\")",
|
|
78
|
-
"WebFetch(domain:solid-lite.org)",
|
|
79
|
-
"Bash(git push:*)",
|
|
80
|
-
"WebFetch(domain:linkedwebstorage.com)",
|
|
81
|
-
"WebFetch(domain:w3c.github.io)",
|
|
82
|
-
"WebFetch(domain:socialdocs.org)",
|
|
83
|
-
"WebFetch(domain:nosdav.com)",
|
|
84
|
-
"WebFetch(domain:sandy-mount.com)",
|
|
85
|
-
"WebFetch(domain:ditto.pub)",
|
|
86
|
-
"WebFetch(domain:blocktrails.org)",
|
|
87
|
-
"WebFetch(domain:microfed.org)",
|
|
88
|
-
"WebFetch(domain:soliddocs.org)",
|
|
89
|
-
"WebFetch(domain:agenticalliance.com)",
|
|
90
|
-
"WebFetch(domain:activitypub.rocks)",
|
|
91
|
-
"WebFetch(domain:nostrgit.org)",
|
|
92
|
-
"Bash(convert:*)",
|
|
93
|
-
"WebFetch(domain:instantdomainsearch.com)",
|
|
94
|
-
"Bash(for domain in jss.dev jss.sh jss.io jss.app solidserver.dev solid-server.dev)",
|
|
95
|
-
"Bash(do echo -n '$domain: ')",
|
|
96
|
-
"Bash(whois $domain)",
|
|
97
|
-
"Bash(done)",
|
|
98
|
-
"Bash(for domain in jss.dev jss.sh jss.io jss.app solidserver.dev)",
|
|
99
|
-
"Bash(host:*)",
|
|
100
|
-
"WebFetch(domain:nostr-components.github.io)",
|
|
101
|
-
"Bash(ssh melvincarvalho.com \"pm2 list && echo ''---HAPROXY---'' && cat /etc/haproxy/haproxy.cfg 2>/dev/null | grep -A5 ''melvin\\|backend\\|frontend\\|acl host''\")",
|
|
102
|
-
"Bash(ssh:*)",
|
|
103
|
-
"Bash(time curl -s --connect-timeout 10 https://melvin.solid.live/credit/count.ttl)",
|
|
104
|
-
"Bash(time curl -s --connect-timeout 10 https://melvin.solid.live/)",
|
|
105
|
-
"Bash(time curl:*)",
|
|
106
|
-
"Bash(time curl -s 'https://melvin.solid.live/credit/count.ttl')",
|
|
107
|
-
"Bash(grep:*)",
|
|
108
|
-
"Bash(scp:*)",
|
|
109
|
-
"Bash(for i in 1 2 3)",
|
|
110
|
-
"Bash(do echo \"Attempt $i:\")",
|
|
111
|
-
"Bash(for i in 1 2 3 4 5)",
|
|
112
|
-
"Bash(do curl -so /dev/null -w \"%{http_code} \" https://melvincarvalho.com/js/handlemutation.js)",
|
|
113
|
-
"Bash(for i in 1 2 3 4 5 6 7 8 9 10)",
|
|
114
|
-
"Bash(if [ ! -d \"jose\" ])",
|
|
115
|
-
"Bash(then git clone --depth 1 --branch v0.7.0 https://github.com/solid/jose.git)",
|
|
116
|
-
"Bash(fi)",
|
|
117
|
-
"Bash(timeout 45 node:*)",
|
|
118
|
-
"Bash(gh issue list:*)",
|
|
119
|
-
"Bash(DATA_ROOT=/tmp/jss-git-test JSS_PORT=4444 timeout 3 node:*)",
|
|
120
|
-
"Bash(pm2 show:*)",
|
|
121
|
-
"Bash(git config:*)",
|
|
122
|
-
"Bash(npm version:*)",
|
|
123
|
-
"Bash(git init:*)",
|
|
124
|
-
"Bash(gh repo create:*)",
|
|
125
|
-
"Bash(./bin/git-credential-nostr generate:*)",
|
|
126
|
-
"Bash(./bin/git-credential-nostr get:*)",
|
|
127
|
-
"Bash(git-credential-nostr:*)",
|
|
128
|
-
"Bash(git branch:*)",
|
|
129
|
-
"Bash(GIT_TRACE=1 GIT_CURL_VERBOSE=1 git push:*)",
|
|
130
|
-
"Bash(GIT_CURL_VERBOSE=1 git push:*)",
|
|
131
|
-
"Bash(git reset:*)",
|
|
132
|
-
"Bash(echo:*)",
|
|
133
|
-
"Bash(unset DATA_ROOT)",
|
|
134
|
-
"Bash(timeout 30 npm test:*)",
|
|
135
|
-
"Bash(/home/melvin/remote/github.com/JavaScriptSolidServer/git-credential-nostr/bin/git-credential-nostr acl:*)",
|
|
136
|
-
"Bash(npm cache clean:*)",
|
|
137
|
-
"Bash(git checkout:*)",
|
|
138
|
-
"Bash(gh gist edit:*)",
|
|
139
|
-
"Bash(gh gist view:*)",
|
|
140
|
-
"Bash(./bin/git-credential-nostr acl:*)",
|
|
141
|
-
"Bash(DATA_ROOT=/tmp/jss-git-test/data node:*)",
|
|
142
|
-
"Bash(git remote set-url:*)",
|
|
143
|
-
"Bash(for:*)",
|
|
144
|
-
"Bash(if [ ! -d \"node-solid-server\" ])",
|
|
145
|
-
"Bash(then git clone --depth 1 https://github.com/nodeSolidServer/node-solid-server.git)",
|
|
146
|
-
"Bash(node test-local-nss2.js:*)",
|
|
147
|
-
"Bash(npm test)",
|
|
148
|
-
"Bash(repos.json)",
|
|
149
|
-
"Bash(*.log)",
|
|
150
|
-
"Bash(node --check:*)",
|
|
151
|
-
"Bash(gh repo view:*)",
|
|
152
|
-
"Bash(noskey --help:*)",
|
|
153
|
-
"Bash(npx noskey --help:*)",
|
|
154
|
-
"Bash(noskey:*)",
|
|
155
|
-
"Bash(node -e:*)",
|
|
156
|
-
"Bash(node src/publish.js:*)",
|
|
157
|
-
"Bash(git remote add:*)",
|
|
158
|
-
"Bash(git fetch:*)",
|
|
159
|
-
"Bash(git rev-parse:*)",
|
|
160
|
-
"Bash(f502f06c1d7553f4b7159e8d57a1e14819dc3053b59399e080882cc8e6bb62ad )",
|
|
161
|
-
"Bash(798715377357003683b979b41c5d99c0312e6e788d789f0d5df710465483aa3e )",
|
|
162
|
-
"Bash(f810e7491da3390109ddc13a74a1fff985ba3a4735024f2b714c12d213f5ea11 )",
|
|
163
|
-
"Bash(1 )",
|
|
164
|
-
"Bash(911912000 )",
|
|
165
|
-
"Bash(4ccef8c68cf18f8f156a0bb017dfd6e0cc7ebf1672fa2d769e02e2efc700328b 1000000 )",
|
|
166
|
-
"Bash(798715377357003683b979b41c5d99c0312e6e788d789f0d5df710465483aa3e 910911000 )",
|
|
167
|
-
"Bash(~/.gitmark/faucet.txt)",
|
|
168
|
-
"Bash(blocktrails --version:*)",
|
|
169
|
-
"Bash(blocktrails --help:*)",
|
|
170
|
-
"Bash(blocktrails show:*)",
|
|
171
|
-
"Bash(git restore:*)",
|
|
172
|
-
"Bash(npm show:*)",
|
|
173
|
-
"WebFetch(domain:gitlab.com)",
|
|
174
|
-
"Bash(gh repo edit:*)",
|
|
175
|
-
"WebFetch(domain:blocktrails.github.io)",
|
|
176
|
-
"Bash(jq:*)",
|
|
177
|
-
"Bash(SOLID_SYNC=true timeout 45 node:*)",
|
|
178
|
-
"Bash(git -C /home/melvin/remote/github.com/blocktrails/gitmark-amm status)",
|
|
179
|
-
"Bash(SOLID_SYNC=true ANCHOR=true timeout 8 node:*)",
|
|
180
|
-
"Bash(SOLID_SYNC=true ANCHOR=true node:*)",
|
|
181
|
-
"Bash(git -C /home/melvin/remote/github.com/blocktrails/gitmark-amm diff src/watcher.js)",
|
|
182
|
-
"Bash(git -C /home/melvin/remote/github.com/blocktrails/gitmark-amm add src/watcher.js)",
|
|
183
|
-
"Bash(git -C /home/melvin/remote/github.com/blocktrails/gitmark-amm commit -m \"$\\(cat <<''EOF''\nAdd transfer API and HTTP 402 middleware\n\n- Add POST /transfer endpoint for user-to-user token transfers\n- Add verify402Payment middleware for token-gated APIs\n- Add GET /api/quote demo endpoint \\(costs 1 GSAT\\)\n- Add GET /balance/:did and GET /state endpoints\n- Fix anchor function to use encodeBech32m for address derivation\n- Remove OP_RETURN from anchor tx \\(state hash stored in state.json\\)\nEOF\n\\)\")",
|
|
184
|
-
"Bash(git -C /home/melvin/remote/github.com/blocktrails/gitmark-amm push)",
|
|
185
|
-
"Bash(git -C /home/melvin/remote/github.com/blocktrails/gitmark-amm add demo.html src/watcher.js debug.html paywall.html transfer.html)",
|
|
186
|
-
"Bash(git -C /home/melvin/remote/github.com/blocktrails/gitmark-amm commit -m \"$\\(cat <<''EOF''\nAdd NIP-98 paywall, transfer, withdraw, and debug pages\n\n- Implement NIP-98 \\(kind 27235\\) for HTTP 402 authentication\n- Add paywall.html demo page showing NIP-98 flow\n- Add transfer.html for user-to-user GSAT transfers\n- Add debug.html with anchors, state, verify, withdraw, and users tabs\n- Add POST /withdraw endpoint for sats → Bitcoin address\n- Add navigation to demo.html linking all pages\nEOF\n\\)\")",
|
|
187
|
-
"Bash(git -C /home/melvin/remote/github.com/blocktrails/gitmark-amm add test-amm.mjs package.json)",
|
|
188
|
-
"Bash(git -C /home/melvin/remote/github.com/blocktrails/gitmark-amm commit -m \"$\\(cat <<''EOF''\nAdd AMM tests for math, signatures, and NIP-98\n\n- AMM math tests \\(calculateGsatOut, calculateSatsOut, slippage, k invariant\\)\n- Signature verification tests \\(sell, transfer, withdraw requests\\)\n- NIP-98 event creation, verification, and encoding tests\n- Update package.json with test script\nEOF\n\\)\")",
|
|
189
|
-
"Bash(SOLID_SYNC=true node src/watcher.js:*)",
|
|
190
|
-
"Bash(git -C /home/melvin/remote/github.com/blocktrails/gitmark-amm add demo.html src/watcher.js)",
|
|
191
|
-
"Bash(git -C /home/melvin/remote/github.com/blocktrails/gitmark-amm commit -m \"$\\(cat <<''EOF''\nAdd smart polling with manual deposit check\n\n- Change poll interval from 30s to 10 minutes\n- Add POST /check endpoint for manual deposit scan\n- Add 10-second rate limit between manual checks\n- Add \"Check Deposits\" button to demo.html\nEOF\n\\)\")",
|
|
192
|
-
"Bash(git -C /home/melvin/remote/github.com/blocktrails/gitmark-amm add:*)",
|
|
193
|
-
"Bash(git -C /home/melvin/remote/github.com/blocktrails/gitmark-amm commit -m \"Use blocktrails npm package instead of local path\")",
|
|
194
|
-
"Bash(for addr in tb1pdypd4k38q4x0qz5x7hqavjhfpgt2n4tm0egggx587aafqn3wsnds8gm3yf tb1pqxmrkvuyea9v7vv323tmptjfle5tj9y6cpe5g8wqvlz6d5xmfhlqctx7py tb1p0fv2683x2j5htf9n7fkpmxsy4h7yuxmetelq2c6vp8u2zw9rhp2s5kha7v)",
|
|
195
|
-
"Bash(do echo -n \"$addr: \" curl -s \"https://mempool.space/testnet4/api/address/$addr\")",
|
|
196
|
-
"WebFetch(domain:webledgers.org)",
|
|
197
|
-
"Bash(npm pack:*)",
|
|
198
|
-
"Bash(npm info:*)",
|
|
199
|
-
"Bash(tar:*)",
|
|
200
|
-
"Bash(TEST_API=1 API_URL=https://api.solid.social node:*)",
|
|
201
|
-
"Bash(webledgers show:*)",
|
|
202
|
-
"Bash(webledgers set-balance:*)",
|
|
203
|
-
"Bash(ssh melvincarvalho.com \"pm2 list | grep jss\")",
|
|
204
|
-
"Bash(ssh melvincarvalho.com \"cd /home/ubuntu/jss && git pull && pm2 restart jss\")",
|
|
205
|
-
"WebFetch(domain:registry.npmjs.org)",
|
|
206
|
-
"WebFetch(domain:solid-chat.com)",
|
|
207
|
-
"WebFetch(domain:developer.chrome.com)",
|
|
208
|
-
"WebFetch(domain:css-tricks.com)",
|
|
209
|
-
"Bash(node bin/jss.js:*)",
|
|
210
|
-
"WebFetch(domain:nostr.social)",
|
|
211
|
-
"Bash(xargs curl -s)",
|
|
212
|
-
"Bash(ssh phone:*)",
|
|
213
|
-
"Bash(dig:*)",
|
|
214
|
-
"WebFetch(domain:fonstr.com)",
|
|
215
|
-
"Bash(node -e \"import\\(''nostr-tools''\\).then\\(m => console.log\\(Object.keys\\(m\\).join\\(''\\\\n''\\)\\)\\)\":*)",
|
|
216
|
-
"Bash(gh repo list:*)",
|
|
217
|
-
"Bash(gh search:*)",
|
|
218
|
-
"Bash(__NEW_LINE__ echo \"\")",
|
|
219
|
-
"WebFetch(domain:webfinger.net)",
|
|
220
|
-
"Bash(npm update:*)",
|
|
221
|
-
"Bash(timeout 8 node:*)",
|
|
222
|
-
"Bash(gh pr view:*)",
|
|
223
|
-
"Bash(gh pr diff:*)",
|
|
224
|
-
"Bash(gh pr review:*)",
|
|
225
|
-
"Bash(gh api:*)",
|
|
226
|
-
"Bash(gh pr comment:*)",
|
|
227
|
-
"Bash(git pull:*)",
|
|
228
|
-
"Bash(gh pr:*)",
|
|
229
|
-
"Bash(node --test:*)",
|
|
230
|
-
"Bash(TOKEN_SECRET=test node --test:*)",
|
|
231
|
-
"Bash(gh search issues:*)",
|
|
232
|
-
"Bash(timeout 60 bash:*)",
|
|
233
|
-
"Bash(timeout 90 bash -c:*)",
|
|
234
|
-
"Bash(git commit -m \"$\\(cat <<''EOF''\nsecurity: add ACL check on WebSocket subscription requests\n\nCheck WAC read permission before allowing subscription to prevent\ninformation leakage via notifications. Unauthorized subscriptions\nnow receive ''err <url> forbidden'' response.\n\nSecurity improvements:\n- Check ACL read access before allowing subscription\n- Validate URLs are on this server \\(prevents SSRF-like probing\\)\n- Add subscription limit and URL length validation\n\nFixes #62\nEOF\n\\)\")",
|
|
235
|
-
"Bash(gh repo fork:*)",
|
|
236
|
-
"Bash(timeout 180 npm test:*)",
|
|
237
|
-
"Bash(git show:*)",
|
|
238
|
-
"Bash(git -C /home/melvin/remote/github.com/nodeSolidServer/node-solid-server log --oneline -30 -- \"test/integration/acl-tls-test.mjs\" \"test-esm/integration/acl-tls-test.js\")",
|
|
239
|
-
"Bash(git -C /home/melvin/remote/github.com/nodeSolidServer/node-solid-server log --oneline --follow -30 -- \"test/integration/acl-tls-test.mjs\")",
|
|
240
|
-
"Bash(git -C /home/melvin/remote/github.com/nodeSolidServer/node-solid-server show 778095ad --stat)",
|
|
241
|
-
"Bash(git -C /home/melvin/remote/github.com/nodeSolidServer/node-solid-server show 778095ad)",
|
|
242
|
-
"Bash(git -C /home/melvin/remote/github.com/nodeSolidServer/node-solid-server show b183c7a0)",
|
|
243
|
-
"Bash(git -C /home/melvin/remote/github.com/nodeSolidServer/node-solid-server log --oneline --before=\"2019-10-29\" --after=\"2019-10-01\" -20)",
|
|
244
|
-
"Bash(git -C /home/melvin/remote/github.com/nodeSolidServer/node-solid-server show 1a92a912 --stat)",
|
|
245
|
-
"Bash(git -C /home/melvin/remote/github.com/nodeSolidServer/node-solid-server log --oneline --all --grep=jaxoncreed)",
|
|
246
|
-
"Bash(git -C /home/melvin/remote/github.com/nodeSolidServer/node-solid-server log --oneline --author=\"jaxoncreed\" -30)",
|
|
247
|
-
"Bash(git -C /home/melvin/remote/github.com/nodeSolidServer/node-solid-server log --oneline --author=\"[Dd]mitri\" -20)",
|
|
248
|
-
"Bash(git -C /home/melvin/remote/github.com/nodeSolidServer/node-solid-server log --oneline --all --grep=\"oidc\" -20)",
|
|
249
|
-
"Bash(npm install)",
|
|
250
|
-
"Bash(timeout 60 npx mocha:*)",
|
|
251
|
-
"Bash(timeout 120 npx mocha:*)",
|
|
252
|
-
"Bash(timeout 30 npx mocha:*)",
|
|
253
|
-
"Bash(openssl x509:*)",
|
|
254
|
-
"Bash(gh pr checks:*)",
|
|
255
|
-
"Bash(gh run view:*)",
|
|
256
|
-
"Bash(gh pr edit:*)",
|
|
257
|
-
"WebFetch(domain:patch-diff.githubusercontent.com)",
|
|
258
|
-
"Bash(git rebase:*)",
|
|
259
|
-
"Bash(timeout 10 npm start)",
|
|
260
|
-
"Bash(node bin/jss.js start:*)",
|
|
261
|
-
"Bash(ssh solid.social \"cd /var/www/jss && git pull && pm2 restart jss\")",
|
|
262
|
-
"Bash(ssh solid.social:*)",
|
|
263
|
-
"Bash(git -C /tmp/lws-server log --oneline --all -20)",
|
|
264
|
-
"Bash(git -C /tmp/lws-server branch -a)",
|
|
265
|
-
"Bash(git -C /tmp/lws-server show-branch -a)",
|
|
266
|
-
"WebFetch(domain:web-platform-tests.org)",
|
|
267
|
-
"Bash(file:*)",
|
|
268
|
-
"WebFetch(domain:karate.apache.org)",
|
|
269
|
-
"WebFetch(domain:restfulapi.net)",
|
|
270
|
-
"Bash(npm run test:jss:*)",
|
|
271
|
-
"Bash(node /home/melvin/remote/github.com/JavaScriptSolidServer/JavaScriptSolidServer/bin/jss.js start:*)",
|
|
272
|
-
"Bash(VERBOSE=true npm run test:jss:*)",
|
|
273
|
-
"Bash(npm whoami:*)",
|
|
274
|
-
"Bash(node bin/lws-test.js:*)",
|
|
275
|
-
"Bash(timeout 2 node:*)",
|
|
276
|
-
"Bash(node index.js:*)",
|
|
277
|
-
"Bash(timeout 3 npx lws-server@0.0.3:*)",
|
|
278
|
-
"Bash(npx lws-server@0.0.3)",
|
|
279
|
-
"Bash(node /tmp/jssd/verify-spacing.js:*)",
|
|
280
|
-
"Bash(gh run list:*)",
|
|
281
|
-
"Bash(pm2 startup:*)",
|
|
282
|
-
"Bash(npm run build:*)",
|
|
283
|
-
"Bash(npx esbuild:*)",
|
|
284
|
-
"Bash(gzip:*)",
|
|
285
|
-
"Bash(sort:*)",
|
|
286
|
-
"Bash(echo __NEW_LINE_496cf3994d374e5c__ echo '1. jsonld \\(277 KB\\) - used by:' grep -r \"from ['''']jsonld\" src/ --include=*.ts --include=*.js 2)",
|
|
287
|
-
"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)",
|
|
288
|
-
"Bash(head -3 __NEW_LINE_496cf3994d374e5c__ echo echo '3. n3 \\(156 KB\\) - used by:' grep -r \"from ['''']n3\" src/ --include=*.ts --include=*.js 2)",
|
|
289
|
-
"Bash(/dev/null __NEW_LINE_496cf3994d374e5c__ echo echo '4. @xmldom/xmldom \\(136 KB\\) - used by:' grep -r xmldom src/ --include=*.ts --include=*.js 2)",
|
|
290
|
-
"Bash(/dev/null __NEW_LINE_496cf3994d374e5c__ echo echo '5. @frogcat/ttl2jsonld \\(135 KB\\) - used by:' grep -r ttl2jsonld src/ --include=*.ts --include=*.js)",
|
|
291
|
-
"Bash(echo \"\" __NEW_LINE_b9f7c85f1ada8a30__ echo \"1. jsonld \\(277 KB\\):\" grep -rn \"jsonld\" src/ --include=\"*.ts\" --include=\"*.js\")",
|
|
292
|
-
"Bash(head -5 __NEW_LINE_b9f7c85f1ada8a30__ echo \"\" echo \"2. n3 \\(156 KB\\):\" grep -rn \"from ''''n3''''\" src/ --include=\"*.ts\" --include=\"*.js\")",
|
|
293
|
-
"Bash(head -5 __NEW_LINE_b9f7c85f1ada8a30__ echo \"\" echo \"3. @xmldom \\(136 KB\\):\" grep -rn \"xmldom\" src/ --include=\"*.ts\" --include=\"*.js\")",
|
|
294
|
-
"Bash(head -5 __NEW_LINE_b9f7c85f1ada8a30__ echo \"\" echo \"4. @frogcat/ttl2jsonld \\(135 KB\\):\" grep -rn \"ttl2jsonld\" src/ --include=\"*.ts\" --include=\"*.js\")",
|
|
295
|
-
"Bash(head -5 __NEW_LINE_b9f7c85f1ada8a30__ echo \"\" echo \"5. cross-fetch \\(20 KB\\):\" grep -rn \"cross-fetch\" src/ --include=\"*.ts\" --include=\"*.js\")",
|
|
296
|
-
"Bash(head -5 __NEW_LINE_b9f7c85f1ada8a30__ echo \"\" echo \"6. solid-namespace \\(3 KB\\):\" grep -rn \"solid-namespace\" src/ --include=\"*.ts\" --include=\"*.js\")",
|
|
297
|
-
"Bash(echo __NEW_LINE_fbfd1802fc51eb60__ echo '1. jsonld \\(277 KB\\):' grep -n jsonld src/*.ts src/*.js)",
|
|
298
|
-
"Bash(grep -E \"import|require\" __NEW_LINE_fbfd1802fc51eb60__ echo echo '2. n3 \\(156 KB\\):' grep -n ''n3'' src/*.ts src/*.js)",
|
|
299
|
-
"Bash(grep -E \"import|require\" __NEW_LINE_fbfd1802fc51eb60__ echo echo '3. @xmldom \\(136 KB\\):' grep -n xmldom src/*.ts src/*.js)",
|
|
300
|
-
"Bash(grep -E \"import|require\" __NEW_LINE_fbfd1802fc51eb60__ echo echo '4. @frogcat/ttl2jsonld \\(135 KB\\):' grep -n ttl2jsonld src/*.ts src/*.js)",
|
|
301
|
-
"Bash(grep -E \"import|require\" __NEW_LINE_fbfd1802fc51eb60__ echo echo '5. cross-fetch \\(20 KB\\):' grep -n cross-fetch src/*.ts src/*.js)",
|
|
302
|
-
"Bash(grep -E \"import|require\" __NEW_LINE_fbfd1802fc51eb60__ echo echo '6. solid-namespace \\(3 KB\\):' grep -n solid-namespace src/*.ts src/*.js)",
|
|
303
|
-
"Bash(npm run build:all:*)",
|
|
304
|
-
"Bash(git status:*)",
|
|
305
|
-
"Bash(npm run lint-fix:*)",
|
|
306
|
-
"Bash(npm uninstall:*)",
|
|
307
|
-
"Bash(npm search:*)",
|
|
308
|
-
"Bash(npm run lint:*)",
|
|
309
|
-
"Bash(npm run typecheck:*)",
|
|
310
|
-
"Bash(du:*)",
|
|
311
|
-
"Bash(for pkg in activitystreams-pane chat-pane contacts-pane folder-pane issue-pane meeting-pane profile-pane source-pane pane-registry)",
|
|
312
|
-
"Bash(do du -sh node_modules/$pkg)",
|
|
313
|
-
"Bash(for pkg in solid-ui solid-logic react react-dom lodash core-js @inrupt marked dompurify)",
|
|
314
|
-
"Bash(npm why:*)",
|
|
315
|
-
"Bash(for pkg in activitystreams-pane chat-pane contacts-pane folder-pane issue-pane meeting-pane profile-pane source-pane)",
|
|
316
|
-
"Bash(wc -l echo 'Brings: mime-types \\(we already removed this pattern\\)' echo echo '=== profile-pane unique deps ===')",
|
|
317
|
-
"Bash(npm run build-prod:*)",
|
|
318
|
-
"Bash(ln:*)",
|
|
319
|
-
"WebFetch(domain:remotestorage.io)",
|
|
320
|
-
"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\\)\")",
|
|
321
|
-
"Bash(npx serve --help:*)",
|
|
322
|
-
"Bash(npm exec serve:*)",
|
|
323
|
-
"Bash(npm link)",
|
|
324
|
-
"Bash(npm link:*)",
|
|
325
|
-
"Bash(git push)",
|
|
326
|
-
"Bash(ulimit:*)",
|
|
327
|
-
"Bash(gh label:*)",
|
|
328
|
-
"Bash(mongosh --eval \"db.runCommand\\({ ping: 1 }\\)\" 2>&1 | head -5)",
|
|
329
|
-
"Bash(which jss && jss --version 2>&1)",
|
|
330
|
-
"Bash(jss start --help 2>&1 | grep -i mongo)",
|
|
331
|
-
"Bash(grep -A5 '\"\"files\"\"' package.json)",
|
|
332
|
-
"Bash(mkdir -p /tmp/wt-check)",
|
|
333
|
-
"Bash(npm init:*)",
|
|
334
|
-
"WebFetch(domain:webtorrent.io)",
|
|
335
|
-
"Bash(TORRENT=/home/melvin/.claude/projects/-home-melvin-remote-github-com-JavaScriptSolidServer-JavaScriptSolidServer/a05da419-92b7-4056-93b8-e97b2035d4ae/tool-results/webfetch-1774004425803-fce7mx.bin npx -y parse-torrent $TORRENT)"
|
|
336
|
-
]
|
|
337
|
-
}
|
|
338
|
-
}
|