roster-server 2.1.4 → 2.1.8

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/index.js CHANGED
@@ -86,6 +86,14 @@ function buildCertLookupCandidates(servername) {
86
86
  return candidates;
87
87
  }
88
88
 
89
+ function parseBooleanFlag(value, fallback = false) {
90
+ if (value === undefined || value === null || value === '') return fallback;
91
+ const normalized = String(value).trim().toLowerCase();
92
+ if (['1', 'true', 'yes', 'on'].includes(normalized)) return true;
93
+ if (['0', 'false', 'no', 'off'].includes(normalized)) return false;
94
+ return fallback;
95
+ }
96
+
89
97
  // Virtual Server that completely isolates applications
90
98
  class VirtualServer extends EventEmitter {
91
99
  constructor(domain) {
@@ -222,6 +230,9 @@ class Roster {
222
230
  this.maxLocalPort = options.maxLocalPort || 9999;
223
231
  this.tlsMinVersion = options.tlsMinVersion ?? 'TLSv1.2';
224
232
  this.tlsMaxVersion = options.tlsMaxVersion ?? 'TLSv1.3';
233
+ this.disableWildcard = options.disableWildcard !== undefined
234
+ ? parseBooleanFlag(options.disableWildcard, false)
235
+ : parseBooleanFlag(process.env.ROSTER_DISABLE_WILDCARD, false);
225
236
 
226
237
  const port = options.port === undefined ? 443 : options.port;
227
238
  if (port === 80 && !this.local) {
@@ -299,6 +310,10 @@ class Roster {
299
310
 
300
311
  if (siteApp) {
301
312
  if (domain.startsWith('*.')) {
313
+ if (this.disableWildcard) {
314
+ log.warn(`⚠️ Wildcard site skipped (disableWildcard enabled): ${domain}`);
315
+ continue;
316
+ }
302
317
  // Wildcard site: one handler for all subdomains (e.g. *.example.com)
303
318
  this.domains.push(domain);
304
319
  this.sites[domain] = siteApp;
@@ -513,6 +528,10 @@ class Roster {
513
528
  const { domain, port } = this.parseDomainWithPort(domainString);
514
529
 
515
530
  if (domain.startsWith('*.')) {
531
+ if (this.disableWildcard) {
532
+ log.warn(`⚠️ Wildcard registration ignored (disableWildcard enabled): ${domain}`);
533
+ return this;
534
+ }
516
535
  const domainKey = port === this.defaultPort ? domain : `${domain}:${port}`;
517
536
  this.domains.push(domain);
518
537
  this.sites[domainKey] = requestHandler;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roster-server",
3
- "version": "2.1.4",
3
+ "version": "2.1.8",
4
4
  "description": "👾 RosterServer - A domain host router to host multiple HTTPS.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -168,6 +168,14 @@ describe('Roster', () => {
168
168
  roster.register('*.example.com', wildcardHandler);
169
169
  assert.strictEqual(roster.getHandlerForHost('api.example.com'), exactHandler);
170
170
  });
171
+ it('ignores wildcard registration when disableWildcard is true', () => {
172
+ const roster = new Roster({ local: true, disableWildcard: true });
173
+ const handler = () => {};
174
+ roster.register('*.example.com', handler);
175
+ assert.strictEqual(roster.sites['*.example.com'], undefined);
176
+ assert.strictEqual(roster.getHandlerForHost('api.example.com'), null);
177
+ assert.strictEqual(roster.wildcardZones.has('example.com'), false);
178
+ });
171
179
  });
172
180
 
173
181
  describe('getHandlerForPortData', () => {
@@ -290,6 +298,21 @@ describe('Roster', () => {
290
298
  const roster = new Roster({ local: false, dnsChallenge: false });
291
299
  assert.strictEqual(roster.dnsChallenge, null);
292
300
  });
301
+ it('enables disableWildcard from constructor option', () => {
302
+ const roster = new Roster({ local: true, disableWildcard: true });
303
+ assert.strictEqual(roster.disableWildcard, true);
304
+ });
305
+ it('reads disableWildcard from env var', () => {
306
+ const previous = process.env.ROSTER_DISABLE_WILDCARD;
307
+ process.env.ROSTER_DISABLE_WILDCARD = '1';
308
+ try {
309
+ const roster = new Roster({ local: true });
310
+ assert.strictEqual(roster.disableWildcard, true);
311
+ } finally {
312
+ if (previous === undefined) delete process.env.ROSTER_DISABLE_WILDCARD;
313
+ else process.env.ROSTER_DISABLE_WILDCARD = previous;
314
+ }
315
+ });
293
316
  });
294
317
 
295
318
  describe('register (normal domain)', () => {
@@ -470,6 +493,26 @@ describe('Roster loadSites', () => {
470
493
  }
471
494
  });
472
495
 
496
+ it('skips wildcard site from www when disableWildcard is true', async () => {
497
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'roster-test-'));
498
+ const wwwPath = path.join(tmpDir, 'www');
499
+ const siteDir = path.join(wwwPath, '*.wildcard.example');
500
+ fs.mkdirSync(siteDir, { recursive: true });
501
+ fs.writeFileSync(
502
+ path.join(siteDir, 'index.js'),
503
+ 'module.exports = () => (req, res) => { res.writeHead(200); res.end("wildcard"); };',
504
+ 'utf8'
505
+ );
506
+ try {
507
+ const roster = new Roster({ wwwPath, local: true, disableWildcard: true });
508
+ await roster.loadSites();
509
+ assert.strictEqual(roster.sites['*.wildcard.example'], undefined);
510
+ assert.strictEqual(roster.wildcardZones.has('wildcard.example'), false);
511
+ } finally {
512
+ fs.rmSync(tmpDir, { recursive: true, force: true });
513
+ }
514
+ });
515
+
473
516
  it('does not throw when www path does not exist', async () => {
474
517
  const roster = new Roster({
475
518
  wwwPath: path.join(os.tmpdir(), 'roster-nonexistent-' + Date.now()),