javascript-solid-server 0.0.149 → 0.0.150

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": "javascript-solid-server",
3
- "version": "0.0.149",
3
+ "version": "0.0.150",
4
4
  "description": "A minimal, fast Solid server",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -23,13 +23,18 @@ import { generateDatabrowserHtml, generateModuleDatabrowserHtml } from '../mashl
23
23
  * @param {string} urlPath - URL path (e.g. /alice/public/file.ttl)
24
24
  * @returns {string} Normalized resource URL
25
25
  */
26
- function buildResourceUrl(request, urlPath) {
26
+ export function buildResourceUrl(request, urlPath) {
27
27
  // Use request.headers.host (includes port) instead of request.hostname (strips port)
28
28
  const host = request.headers.host || request.hostname;
29
29
  if (request.subdomainsEnabled && request.baseDomain &&
30
30
  request.hostname === request.baseDomain && !request.podName) {
31
31
  const pathMatch = urlPath.match(/^\/([^/]+)(\/.*)?$/);
32
- if (pathMatch && !pathMatch[1].startsWith('.')) {
32
+ // Treat a path segment as a pod name only if it looks like one:
33
+ // - not a dotfile (.well-known, .acl, .meta, ...)
34
+ // - no dot (pod names are DNS labels; file names have extensions)
35
+ // This avoids rewriting /mashlib.js to https://mashlib.js.basedomain/
36
+ // which would fail WAC against the base domain's ACL. (#307)
37
+ if (pathMatch && !pathMatch[1].startsWith('.') && !pathMatch[1].includes('.')) {
33
38
  const podName = pathMatch[1];
34
39
  const remainder = pathMatch[2] || '/';
35
40
  return `${request.protocol}://${podName}.${request.baseDomain}${remainder}`;
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Regression tests for #307 — buildResourceUrl rewriting the base-domain
3
+ * root file paths into non-existent pod subdomains.
4
+ *
5
+ * Unit tests against buildResourceUrl directly, since Node's fetch() overrides
6
+ * the Host header with the TCP target, which makes end-to-end tests of
7
+ * subdomain routing impossible without a real reverse proxy.
8
+ */
9
+
10
+ import { describe, it } from 'node:test';
11
+ import assert from 'node:assert';
12
+ import { buildResourceUrl } from '../src/auth/middleware.js';
13
+
14
+ function makeRequest({ hostname, baseDomain, subdomainsEnabled = true, podName = null, protocol = 'https' }) {
15
+ return {
16
+ protocol,
17
+ hostname,
18
+ headers: { host: hostname },
19
+ subdomainsEnabled,
20
+ baseDomain,
21
+ podName
22
+ };
23
+ }
24
+
25
+ describe('buildResourceUrl — base-domain files (#307)', () => {
26
+ const baseDomain = 'example.com';
27
+
28
+ it('base-domain root (/) — no rewrite', () => {
29
+ const req = makeRequest({ hostname: baseDomain, baseDomain });
30
+ assert.strictEqual(buildResourceUrl(req, '/'), 'https://example.com/');
31
+ });
32
+
33
+ it('base-domain /welcome.js — no rewrite (filename has extension)', () => {
34
+ const req = makeRequest({ hostname: baseDomain, baseDomain });
35
+ assert.strictEqual(buildResourceUrl(req, '/welcome.js'), 'https://example.com/welcome.js');
36
+ });
37
+
38
+ it('base-domain /mashlib.js — no rewrite', () => {
39
+ const req = makeRequest({ hostname: baseDomain, baseDomain });
40
+ assert.strictEqual(buildResourceUrl(req, '/mashlib.js'), 'https://example.com/mashlib.js');
41
+ });
42
+
43
+ it('base-domain /terms.html — no rewrite', () => {
44
+ const req = makeRequest({ hostname: baseDomain, baseDomain });
45
+ assert.strictEqual(buildResourceUrl(req, '/terms.html'), 'https://example.com/terms.html');
46
+ });
47
+
48
+ it('base-domain /.well-known/foo — no rewrite (leading dot)', () => {
49
+ const req = makeRequest({ hostname: baseDomain, baseDomain });
50
+ assert.strictEqual(
51
+ buildResourceUrl(req, '/.well-known/foo'),
52
+ 'https://example.com/.well-known/foo'
53
+ );
54
+ });
55
+ });
56
+
57
+ describe('buildResourceUrl — pod routing still works', () => {
58
+ const baseDomain = 'example.com';
59
+
60
+ it('base-domain /alice/ — rewrites to alice.example.com (no dot → pod name)', () => {
61
+ const req = makeRequest({ hostname: baseDomain, baseDomain });
62
+ assert.strictEqual(buildResourceUrl(req, '/alice/'), 'https://alice.example.com/');
63
+ });
64
+
65
+ it('base-domain /alice — rewrites (bare pod-root without trailing slash)', () => {
66
+ const req = makeRequest({ hostname: baseDomain, baseDomain });
67
+ assert.strictEqual(buildResourceUrl(req, '/alice'), 'https://alice.example.com/');
68
+ });
69
+
70
+ it('base-domain /alice/profile/card.jsonld — rewrites to alice.example.com/profile/card.jsonld', () => {
71
+ const req = makeRequest({ hostname: baseDomain, baseDomain });
72
+ assert.strictEqual(
73
+ buildResourceUrl(req, '/alice/profile/card.jsonld'),
74
+ 'https://alice.example.com/profile/card.jsonld'
75
+ );
76
+ });
77
+
78
+ it('already-on-subdomain request — no rewrite (hostname !== baseDomain)', () => {
79
+ const req = makeRequest({
80
+ hostname: 'alice.example.com',
81
+ baseDomain,
82
+ podName: 'alice'
83
+ });
84
+ assert.strictEqual(
85
+ buildResourceUrl(req, '/profile/card.jsonld'),
86
+ 'https://alice.example.com/profile/card.jsonld'
87
+ );
88
+ });
89
+ });
90
+
91
+ describe('buildResourceUrl — subdomain mode disabled', () => {
92
+ it('no rewrite when subdomainsEnabled is false', () => {
93
+ const req = makeRequest({
94
+ hostname: 'example.com',
95
+ baseDomain: 'example.com',
96
+ subdomainsEnabled: false
97
+ });
98
+ assert.strictEqual(buildResourceUrl(req, '/alice/'), 'https://example.com/alice/');
99
+ });
100
+
101
+ it('no rewrite when baseDomain is not set', () => {
102
+ const req = makeRequest({
103
+ hostname: 'example.com',
104
+ baseDomain: null,
105
+ subdomainsEnabled: true
106
+ });
107
+ assert.strictEqual(buildResourceUrl(req, '/alice/'), 'https://example.com/alice/');
108
+ });
109
+ });