javascript-solid-server 0.0.2 → 0.0.5
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 +5 -1
- package/package.json +2 -2
- package/src/auth/middleware.js +97 -0
- package/src/auth/token.js +112 -0
- package/src/handlers/container.js +71 -7
- package/src/handlers/resource.js +39 -9
- package/src/ldp/headers.js +31 -6
- package/src/server.js +23 -1
- package/src/wac/checker.js +257 -0
- package/src/wac/parser.js +284 -0
- package/src/webid/profile.js +161 -0
- package/test/auth.test.js +175 -0
- package/test/helpers.js +158 -0
- package/test/ldp.test.js +363 -0
- package/test/pod.test.js +119 -0
- package/test/wac.test.js +189 -0
- package/test/webid.test.js +152 -0
- package/benchmark-report-2025-03-31T14-25-24.234Z.json +0 -44
package/test/pod.test.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pod lifecycle tests
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, before, after } from 'node:test';
|
|
6
|
+
import assert from 'node:assert';
|
|
7
|
+
import {
|
|
8
|
+
startTestServer,
|
|
9
|
+
stopTestServer,
|
|
10
|
+
request,
|
|
11
|
+
createTestPod,
|
|
12
|
+
assertStatus,
|
|
13
|
+
assertHeader,
|
|
14
|
+
assertHeaderContains
|
|
15
|
+
} from './helpers.js';
|
|
16
|
+
|
|
17
|
+
describe('Pod Lifecycle', () => {
|
|
18
|
+
before(async () => {
|
|
19
|
+
await startTestServer();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
after(async () => {
|
|
23
|
+
await stopTestServer();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe('POST /.pods', () => {
|
|
27
|
+
it('should create a new pod', async () => {
|
|
28
|
+
const res = await request('/.pods', {
|
|
29
|
+
method: 'POST',
|
|
30
|
+
headers: { 'Content-Type': 'application/json' },
|
|
31
|
+
body: JSON.stringify({ name: 'alice' })
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
assertStatus(res, 201);
|
|
35
|
+
assertHeader(res, 'Location');
|
|
36
|
+
|
|
37
|
+
const data = await res.json();
|
|
38
|
+
assert.strictEqual(data.name, 'alice');
|
|
39
|
+
assert.ok(data.webId.endsWith('/alice/#me'));
|
|
40
|
+
assert.ok(data.podUri.endsWith('/alice/'));
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should reject duplicate pod names', async () => {
|
|
44
|
+
// First create
|
|
45
|
+
await request('/.pods', {
|
|
46
|
+
method: 'POST',
|
|
47
|
+
headers: { 'Content-Type': 'application/json' },
|
|
48
|
+
body: JSON.stringify({ name: 'bob' })
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Duplicate attempt
|
|
52
|
+
const res = await request('/.pods', {
|
|
53
|
+
method: 'POST',
|
|
54
|
+
headers: { 'Content-Type': 'application/json' },
|
|
55
|
+
body: JSON.stringify({ name: 'bob' })
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
assertStatus(res, 409);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should reject invalid pod names', async () => {
|
|
62
|
+
const res = await request('/.pods', {
|
|
63
|
+
method: 'POST',
|
|
64
|
+
headers: { 'Content-Type': 'application/json' },
|
|
65
|
+
body: JSON.stringify({ name: '../evil' })
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
assertStatus(res, 400);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should reject empty pod name', async () => {
|
|
72
|
+
const res = await request('/.pods', {
|
|
73
|
+
method: 'POST',
|
|
74
|
+
headers: { 'Content-Type': 'application/json' },
|
|
75
|
+
body: JSON.stringify({})
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
assertStatus(res, 400);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe('Pod Structure', () => {
|
|
83
|
+
it('should create standard folders', async () => {
|
|
84
|
+
await createTestPod('carol');
|
|
85
|
+
|
|
86
|
+
// Check inbox exists (needs auth - inbox only allows public append, not read)
|
|
87
|
+
const inbox = await request('/carol/inbox/', { auth: 'carol' });
|
|
88
|
+
assertStatus(inbox, 200);
|
|
89
|
+
|
|
90
|
+
// Check public exists (public read via root ACL default)
|
|
91
|
+
const pub = await request('/carol/public/');
|
|
92
|
+
assertStatus(pub, 200);
|
|
93
|
+
|
|
94
|
+
// Check private exists (needs auth)
|
|
95
|
+
const priv = await request('/carol/private/', { auth: 'carol' });
|
|
96
|
+
assertStatus(priv, 200);
|
|
97
|
+
|
|
98
|
+
// Check settings exists (needs auth)
|
|
99
|
+
const settings = await request('/carol/settings/', { auth: 'carol' });
|
|
100
|
+
assertStatus(settings, 200);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('should create settings files', async () => {
|
|
104
|
+
await createTestPod('dan');
|
|
105
|
+
|
|
106
|
+
// Check prefs (needs auth - settings is private)
|
|
107
|
+
const prefs = await request('/dan/settings/prefs', { auth: 'dan' });
|
|
108
|
+
assertStatus(prefs, 200);
|
|
109
|
+
|
|
110
|
+
// Check public type index (needs auth)
|
|
111
|
+
const pubIndex = await request('/dan/settings/publicTypeIndex', { auth: 'dan' });
|
|
112
|
+
assertStatus(pubIndex, 200);
|
|
113
|
+
|
|
114
|
+
// Check private type index (needs auth)
|
|
115
|
+
const privIndex = await request('/dan/settings/privateTypeIndex', { auth: 'dan' });
|
|
116
|
+
assertStatus(privIndex, 200);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
});
|
package/test/wac.test.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WAC (Web Access Control) tests
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, before, after } from 'node:test';
|
|
6
|
+
import assert from 'node:assert';
|
|
7
|
+
import {
|
|
8
|
+
startTestServer,
|
|
9
|
+
stopTestServer,
|
|
10
|
+
request,
|
|
11
|
+
createTestPod,
|
|
12
|
+
assertStatus,
|
|
13
|
+
assertHeader,
|
|
14
|
+
getBaseUrl
|
|
15
|
+
} from './helpers.js';
|
|
16
|
+
import { parseAcl, AccessMode, generateOwnerAcl, serializeAcl } from '../src/wac/parser.js';
|
|
17
|
+
import { checkAccess, getRequiredMode } from '../src/wac/checker.js';
|
|
18
|
+
|
|
19
|
+
describe('WAC Parser', () => {
|
|
20
|
+
describe('parseAcl', () => {
|
|
21
|
+
it('should parse a simple ACL', () => {
|
|
22
|
+
const acl = {
|
|
23
|
+
'@context': { 'acl': 'http://www.w3.org/ns/auth/acl#' },
|
|
24
|
+
'@graph': [{
|
|
25
|
+
'@id': '#owner',
|
|
26
|
+
'@type': 'acl:Authorization',
|
|
27
|
+
'acl:agent': { '@id': 'https://alice.example/#me' },
|
|
28
|
+
'acl:accessTo': { '@id': 'https://alice.example/resource' },
|
|
29
|
+
'acl:mode': [{ '@id': 'acl:Read' }, { '@id': 'acl:Write' }]
|
|
30
|
+
}]
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const auths = parseAcl(JSON.stringify(acl), 'https://alice.example/.acl');
|
|
34
|
+
|
|
35
|
+
assert.strictEqual(auths.length, 1);
|
|
36
|
+
assert.ok(auths[0].agents.includes('https://alice.example/#me'));
|
|
37
|
+
assert.ok(auths[0].modes.includes(AccessMode.READ));
|
|
38
|
+
assert.ok(auths[0].modes.includes(AccessMode.WRITE));
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should parse public access', () => {
|
|
42
|
+
const acl = {
|
|
43
|
+
'@context': { 'acl': 'http://www.w3.org/ns/auth/acl#', 'foaf': 'http://xmlns.com/foaf/0.1/' },
|
|
44
|
+
'@graph': [{
|
|
45
|
+
'@id': '#public',
|
|
46
|
+
'@type': 'acl:Authorization',
|
|
47
|
+
'acl:agentClass': { '@id': 'foaf:Agent' },
|
|
48
|
+
'acl:accessTo': { '@id': 'https://alice.example/public/' },
|
|
49
|
+
'acl:mode': [{ '@id': 'acl:Read' }]
|
|
50
|
+
}]
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const auths = parseAcl(JSON.stringify(acl), 'https://alice.example/public/.acl');
|
|
54
|
+
|
|
55
|
+
assert.strictEqual(auths.length, 1);
|
|
56
|
+
assert.ok(auths[0].agentClasses.includes('foaf:Agent'));
|
|
57
|
+
assert.ok(auths[0].modes.includes(AccessMode.READ));
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should parse default authorizations for containers', () => {
|
|
61
|
+
const acl = {
|
|
62
|
+
'@context': { 'acl': 'http://www.w3.org/ns/auth/acl#' },
|
|
63
|
+
'@graph': [{
|
|
64
|
+
'@id': '#default',
|
|
65
|
+
'@type': 'acl:Authorization',
|
|
66
|
+
'acl:agent': { '@id': 'https://alice.example/#me' },
|
|
67
|
+
'acl:default': { '@id': 'https://alice.example/folder/' },
|
|
68
|
+
'acl:mode': [{ '@id': 'acl:Read' }]
|
|
69
|
+
}]
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const auths = parseAcl(JSON.stringify(acl), 'https://alice.example/folder/.acl');
|
|
73
|
+
|
|
74
|
+
assert.strictEqual(auths.length, 1);
|
|
75
|
+
assert.ok(auths[0].default.includes('https://alice.example/folder/'));
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should handle invalid JSON gracefully', () => {
|
|
79
|
+
const auths = parseAcl('not valid json', 'https://example.com/.acl');
|
|
80
|
+
assert.strictEqual(auths.length, 0);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe('generateOwnerAcl', () => {
|
|
85
|
+
it('should generate owner ACL with public read', () => {
|
|
86
|
+
const acl = generateOwnerAcl('https://alice.example/', 'https://alice.example/#me', true);
|
|
87
|
+
|
|
88
|
+
assert.ok(acl['@graph'].length >= 2);
|
|
89
|
+
|
|
90
|
+
// Find owner auth
|
|
91
|
+
const ownerAuth = acl['@graph'].find(a => a['@id'] === '#owner');
|
|
92
|
+
assert.ok(ownerAuth);
|
|
93
|
+
assert.strictEqual(ownerAuth['acl:agent']['@id'], 'https://alice.example/#me');
|
|
94
|
+
|
|
95
|
+
// Find public auth
|
|
96
|
+
const publicAuth = acl['@graph'].find(a => a['@id'] === '#public');
|
|
97
|
+
assert.ok(publicAuth);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('WAC Checker', () => {
|
|
103
|
+
describe('getRequiredMode', () => {
|
|
104
|
+
it('should return READ for GET', () => {
|
|
105
|
+
assert.strictEqual(getRequiredMode('GET'), AccessMode.READ);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should return READ for HEAD', () => {
|
|
109
|
+
assert.strictEqual(getRequiredMode('HEAD'), AccessMode.READ);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should return APPEND for POST', () => {
|
|
113
|
+
assert.strictEqual(getRequiredMode('POST'), AccessMode.APPEND);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should return WRITE for PUT', () => {
|
|
117
|
+
assert.strictEqual(getRequiredMode('PUT'), AccessMode.WRITE);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should return WRITE for DELETE', () => {
|
|
121
|
+
assert.strictEqual(getRequiredMode('DELETE'), AccessMode.WRITE);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
describe('WAC Integration', () => {
|
|
127
|
+
let baseUrl;
|
|
128
|
+
|
|
129
|
+
before(async () => {
|
|
130
|
+
const result = await startTestServer();
|
|
131
|
+
baseUrl = result.baseUrl;
|
|
132
|
+
await createTestPod('wactest');
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
after(async () => {
|
|
136
|
+
await stopTestServer();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
describe('ACL Files', () => {
|
|
140
|
+
it('should create root .acl on pod creation', async () => {
|
|
141
|
+
const res = await request('/wactest/.acl');
|
|
142
|
+
|
|
143
|
+
assertStatus(res, 200);
|
|
144
|
+
const content = await res.json();
|
|
145
|
+
assert.ok(content['@graph'], 'Should be JSON-LD');
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('should create private folder .acl', async () => {
|
|
149
|
+
const res = await request('/wactest/private/.acl');
|
|
150
|
+
|
|
151
|
+
assertStatus(res, 200);
|
|
152
|
+
const content = await res.json();
|
|
153
|
+
assert.ok(content['@graph']);
|
|
154
|
+
|
|
155
|
+
// Should only have owner, no public
|
|
156
|
+
const hasPublic = content['@graph'].some(a =>
|
|
157
|
+
a['acl:agentClass'] && a['acl:agentClass']['@id'] === 'foaf:Agent'
|
|
158
|
+
);
|
|
159
|
+
assert.ok(!hasPublic, 'Private folder should not have public access');
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('should create inbox .acl with public append', async () => {
|
|
163
|
+
const res = await request('/wactest/inbox/.acl');
|
|
164
|
+
|
|
165
|
+
assertStatus(res, 200);
|
|
166
|
+
const content = await res.json();
|
|
167
|
+
|
|
168
|
+
// Should have public append
|
|
169
|
+
const publicAuth = content['@graph'].find(a =>
|
|
170
|
+
a['acl:agentClass'] && a['acl:agentClass']['@id'] === 'foaf:Agent'
|
|
171
|
+
);
|
|
172
|
+
assert.ok(publicAuth, 'Inbox should have public access');
|
|
173
|
+
|
|
174
|
+
const modes = publicAuth['acl:mode'].map(m => m['@id']);
|
|
175
|
+
assert.ok(modes.includes('acl:Append'), 'Public should have Append');
|
|
176
|
+
assert.ok(!modes.includes('acl:Read'), 'Public should not have Read');
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
describe('WAC-Allow Header', () => {
|
|
181
|
+
it('should return WAC-Allow header for public container', async () => {
|
|
182
|
+
const res = await request('/wactest/public/');
|
|
183
|
+
|
|
184
|
+
assertHeader(res, 'WAC-Allow');
|
|
185
|
+
const wacAllow = res.headers.get('WAC-Allow');
|
|
186
|
+
assert.ok(wacAllow.includes('public='), 'Should have public permissions');
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
});
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebID Profile tests
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, before, after } from 'node:test';
|
|
6
|
+
import assert from 'node:assert';
|
|
7
|
+
import {
|
|
8
|
+
startTestServer,
|
|
9
|
+
stopTestServer,
|
|
10
|
+
request,
|
|
11
|
+
createTestPod,
|
|
12
|
+
assertStatus,
|
|
13
|
+
assertHeader,
|
|
14
|
+
assertHeaderContains,
|
|
15
|
+
extractJsonLdFromHtml
|
|
16
|
+
} from './helpers.js';
|
|
17
|
+
|
|
18
|
+
describe('WebID Profile', () => {
|
|
19
|
+
let baseUrl;
|
|
20
|
+
let podInfo;
|
|
21
|
+
|
|
22
|
+
before(async () => {
|
|
23
|
+
const result = await startTestServer();
|
|
24
|
+
baseUrl = result.baseUrl;
|
|
25
|
+
podInfo = await createTestPod('webidtest');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
after(async () => {
|
|
29
|
+
await stopTestServer();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('Profile Document', () => {
|
|
33
|
+
it('should serve profile as HTML at pod root', async () => {
|
|
34
|
+
const res = await request('/webidtest/');
|
|
35
|
+
|
|
36
|
+
assertStatus(res, 200);
|
|
37
|
+
assertHeaderContains(res, 'Content-Type', 'text/html');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should contain JSON-LD structured data', async () => {
|
|
41
|
+
const res = await request('/webidtest/');
|
|
42
|
+
const html = await res.text();
|
|
43
|
+
|
|
44
|
+
const jsonLd = extractJsonLdFromHtml(html);
|
|
45
|
+
assert.ok(jsonLd['@context'], 'Should have @context');
|
|
46
|
+
assert.ok(jsonLd['@graph'], 'Should have @graph');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should have correct WebID URI', async () => {
|
|
50
|
+
const res = await request('/webidtest/');
|
|
51
|
+
const html = await res.text();
|
|
52
|
+
const jsonLd = extractJsonLdFromHtml(html);
|
|
53
|
+
|
|
54
|
+
// Find the Person in the graph
|
|
55
|
+
const person = jsonLd['@graph'].find(node =>
|
|
56
|
+
Array.isArray(node['@type'])
|
|
57
|
+
? node['@type'].includes('foaf:Person')
|
|
58
|
+
: node['@type'] === 'foaf:Person'
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
assert.ok(person, 'Should have a foaf:Person');
|
|
62
|
+
assert.ok(person['@id'].endsWith('/webidtest/#me'), 'WebID should end with /#me');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should have foaf:name', async () => {
|
|
66
|
+
const res = await request('/webidtest/');
|
|
67
|
+
const html = await res.text();
|
|
68
|
+
const jsonLd = extractJsonLdFromHtml(html);
|
|
69
|
+
|
|
70
|
+
const person = jsonLd['@graph'].find(node =>
|
|
71
|
+
Array.isArray(node['@type'])
|
|
72
|
+
? node['@type'].includes('foaf:Person')
|
|
73
|
+
: node['@type'] === 'foaf:Person'
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
assert.strictEqual(person['foaf:name'], 'webidtest');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should have solid:oidcIssuer', async () => {
|
|
80
|
+
const res = await request('/webidtest/');
|
|
81
|
+
const html = await res.text();
|
|
82
|
+
const jsonLd = extractJsonLdFromHtml(html);
|
|
83
|
+
|
|
84
|
+
const person = jsonLd['@graph'].find(node =>
|
|
85
|
+
Array.isArray(node['@type'])
|
|
86
|
+
? node['@type'].includes('foaf:Person')
|
|
87
|
+
: node['@type'] === 'foaf:Person'
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
assert.ok(person['oidcIssuer'], 'Should have oidcIssuer');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should have pim:storage pointing to pod', async () => {
|
|
94
|
+
const res = await request('/webidtest/');
|
|
95
|
+
const html = await res.text();
|
|
96
|
+
const jsonLd = extractJsonLdFromHtml(html);
|
|
97
|
+
|
|
98
|
+
const person = jsonLd['@graph'].find(node =>
|
|
99
|
+
Array.isArray(node['@type'])
|
|
100
|
+
? node['@type'].includes('foaf:Person')
|
|
101
|
+
: node['@type'] === 'foaf:Person'
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
assert.ok(person['storage'].endsWith('/webidtest/'), 'Storage should point to pod');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should have ldp:inbox', async () => {
|
|
108
|
+
const res = await request('/webidtest/');
|
|
109
|
+
const html = await res.text();
|
|
110
|
+
const jsonLd = extractJsonLdFromHtml(html);
|
|
111
|
+
|
|
112
|
+
const person = jsonLd['@graph'].find(node =>
|
|
113
|
+
Array.isArray(node['@type'])
|
|
114
|
+
? node['@type'].includes('foaf:Person')
|
|
115
|
+
: node['@type'] === 'foaf:Person'
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
assert.ok(person['inbox'].endsWith('/webidtest/inbox/'), 'Should have inbox');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should have PersonalProfileDocument', async () => {
|
|
122
|
+
const res = await request('/webidtest/');
|
|
123
|
+
const html = await res.text();
|
|
124
|
+
const jsonLd = extractJsonLdFromHtml(html);
|
|
125
|
+
|
|
126
|
+
const doc = jsonLd['@graph'].find(node =>
|
|
127
|
+
node['@type'] === 'foaf:PersonalProfileDocument'
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
assert.ok(doc, 'Should have PersonalProfileDocument');
|
|
131
|
+
assert.ok(doc['foaf:maker'], 'Should have foaf:maker');
|
|
132
|
+
assert.ok(doc['foaf:primaryTopic'], 'Should have foaf:primaryTopic');
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe('WebID Resolution', () => {
|
|
137
|
+
it('should return LDP headers', async () => {
|
|
138
|
+
const res = await request('/webidtest/');
|
|
139
|
+
|
|
140
|
+
assertHeaderContains(res, 'Link', 'ldp#Resource');
|
|
141
|
+
assertHeader(res, 'WAC-Allow');
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('should return CORS headers', async () => {
|
|
145
|
+
const res = await request('/webidtest/', {
|
|
146
|
+
headers: { 'Origin': 'https://example.com' }
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
assertHeader(res, 'Access-Control-Allow-Origin');
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
});
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"timestamp": "2025-03-31T14:25:24.234Z",
|
|
3
|
-
"server": "http://nostr.social:3000",
|
|
4
|
-
"testDuration": 30000,
|
|
5
|
-
"averageResponseTimes": {
|
|
6
|
-
"register": 49.28774029878249,
|
|
7
|
-
"login": 49.07647125548627,
|
|
8
|
-
"read": 145.50252931779679,
|
|
9
|
-
"write": 143.20483738812226,
|
|
10
|
-
"delete": 145.5004399698014
|
|
11
|
-
},
|
|
12
|
-
"throughputResults": [
|
|
13
|
-
{
|
|
14
|
-
"concurrentUsers": 1,
|
|
15
|
-
"operations": 300,
|
|
16
|
-
"duration": 629.3636230230331,
|
|
17
|
-
"throughput": 476.67197312581374
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
"concurrentUsers": 5,
|
|
21
|
-
"operations": 1500,
|
|
22
|
-
"duration": 3072.7389999628067,
|
|
23
|
-
"throughput": 488.16381736885444
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
"concurrentUsers": 10,
|
|
27
|
-
"operations": 3000,
|
|
28
|
-
"duration": 6042.516402959824,
|
|
29
|
-
"throughput": 496.4818959416479
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
"concurrentUsers": 50,
|
|
33
|
-
"operations": 14000,
|
|
34
|
-
"duration": 30000,
|
|
35
|
-
"throughput": 466.6666666666667
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
"concurrentUsers": 100,
|
|
39
|
-
"operations": 13900,
|
|
40
|
-
"duration": 30000,
|
|
41
|
-
"throughput": 463.3333333333333
|
|
42
|
-
}
|
|
43
|
-
]
|
|
44
|
-
}
|