From e4b21099d31467dee971c08b795b8a5e05886d11 Mon Sep 17 00:00:00 2001 From: K Date: Wed, 20 Sep 2023 17:02:38 +0000 Subject: [PATCH 1/3] feat(sandbox): add subdomain support Enables the sandbox feature to work when the node is hosted on a subdomain. Added to allow hosting on exiting domains. --- src/middleware/sandbox.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/middleware/sandbox.ts b/src/middleware/sandbox.ts index aa82c631..ab6604e9 100644 --- a/src/middleware/sandbox.ts +++ b/src/middleware/sandbox.ts @@ -21,9 +21,10 @@ import { base32 } from 'rfc4648'; import { fromB64Url } from '../lib/encoding.js'; -function getRequestSandbox(req: Request): string | undefined { - if (req.subdomains.length === 1) { - return req.subdomains[0]; +function getRequestSandbox(req: Request, rootHost: string): string | undefined { + const rootHostSubdomainLength = rootHost.split('.').length - 2; + if (req.subdomains.length > rootHostSubdomainLength) { + return req.subdomains[req.subdomains.length - 1]; } return undefined; } @@ -55,7 +56,7 @@ export function createSandboxMiddleware({ return; } - const reqSandbox = getRequestSandbox(req); + const reqSandbox = getRequestSandbox(req, rootHost); const idSandbox = sandboxFromId(id); if (reqSandbox !== idSandbox) { const queryString = url.parse(req.originalUrl).query ?? ''; From e658edd40c2480c2279f2c19d216e3a06e5036bc Mon Sep 17 00:00:00 2001 From: K Date: Wed, 20 Sep 2023 17:03:10 +0000 Subject: [PATCH 2/3] feat(arns): add subdomain support Enables the arns feature to work when the node is hosted on a subdomain. Added to allow hosting on exiting domains. --- src/app.ts | 1 + src/middleware/arns.ts | 41 +++++++++++++++++++++++++---------------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/app.ts b/src/app.ts index 8514859c..32589ac7 100644 --- a/src/app.ts +++ b/src/app.ts @@ -83,6 +83,7 @@ if (config.ARNS_ROOT_HOST !== undefined) { app.use( createArnsMiddleware({ dataHandler, + rootHost: config.ARNS_ROOT_HOST, nameResolver: system.nameResolver, }), ); diff --git a/src/middleware/arns.ts b/src/middleware/arns.ts index bfa28e4e..2483f61b 100644 --- a/src/middleware/arns.ts +++ b/src/middleware/arns.ts @@ -25,33 +25,42 @@ const EXCLUDED_SUBDOMAINS = new Set('www'); export const createArnsMiddleware = ({ dataHandler, + rootHost, nameResolver, }: { dataHandler: Handler; + rootHost: string; nameResolver: NameResolver; }): Handler => asyncMiddleware(async (req, res, next) => { + const rootHostSubdomainLength = rootHost.split('.').length - 2; if ( - Array.isArray(req.subdomains) && - req.subdomains.length === 1 && - !EXCLUDED_SUBDOMAINS.has(req.subdomains[0]) && + // Ignore subdomains that are part of the ArNS root hostname. + !Array.isArray(req.subdomains) || + req.subdomains.length === rootHostSubdomainLength + ) { + next(); + return; + } + const arnsSubdomain = req.subdomains[req.subdomains.length - 1]; + if ( + EXCLUDED_SUBDOMAINS.has(arnsSubdomain) || // Avoid collisions with sandbox URLs by ensuring the subdomain length // is below the mininimum length of a sandbox subdomain. Undernames are // are an exception because they can be longer and '_' cannot appear in // base32. - (req.subdomains[0].length <= 48 || req.subdomains[0].match(/_/)) + (arnsSubdomain.length > 48 && !arnsSubdomain.match(/_/)) ) { - const { resolvedId, ttl } = await nameResolver.resolve(req.subdomains[0]); - if (resolvedId !== undefined) { - res.header('X-ArNS-Resolved-Id', resolvedId); - res.header('X-ArNS-TTL-Seconds', ttl.toString()); - res.header('Cache-Control', `public, max-age=${ttl}`); - dataHandler(req, res, next); - return; - } else { - sendNotFound(res); - return; - } + next(); + return; + } + const { resolvedId, ttl } = await nameResolver.resolve(arnsSubdomain); + if (resolvedId === undefined) { + sendNotFound(res); + return; } - next(); + res.header('X-ArNS-Resolved-Id', resolvedId); + res.header('X-ArNS-TTL-Seconds', ttl.toString()); + res.header('Cache-Control', `public, max-age=${ttl}`); + dataHandler(req, res, next); }); From 54ea665b52b6425280cbaf9c2b62903ff72f7c03 Mon Sep 17 00:00:00 2001 From: K Date: Tue, 26 Sep 2023 08:35:38 +0000 Subject: [PATCH 3/3] refactor(sandbox, arns): switch params to config As both middlewares need the root host's subdomain count, moving it to the config eliminates duplicates. This also allows to remove the rootHost constructor param and take it directly from the config. --- src/app.ts | 2 -- src/config.ts | 2 ++ src/middleware/arns.ts | 8 +++----- src/middleware/sandbox.ts | 14 ++++++-------- 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/app.ts b/src/app.ts index 32589ac7..6df5b94a 100644 --- a/src/app.ts +++ b/src/app.ts @@ -83,14 +83,12 @@ if (config.ARNS_ROOT_HOST !== undefined) { app.use( createArnsMiddleware({ dataHandler, - rootHost: config.ARNS_ROOT_HOST, nameResolver: system.nameResolver, }), ); app.use( createSandboxMiddleware({ - rootHost: config.ARNS_ROOT_HOST, sandboxProtocol: config.SANDBOX_PROTOCOL, }), ); diff --git a/src/config.ts b/src/config.ts index 6c3fed52..bf27aab2 100644 --- a/src/config.ts +++ b/src/config.ts @@ -70,6 +70,8 @@ export const ANS104_INDEX_FILTER = createFilter( JSON.parse(ANS104_INDEX_FILTER_STRING), ); export const ARNS_ROOT_HOST = env.varOrUndefined('ARNS_ROOT_HOST'); +export const ROOT_HOST_SUBDOMAIN_LENGTH = + ARNS_ROOT_HOST !== undefined ? ARNS_ROOT_HOST.split('.').length - 2 : 0; export const SANDBOX_PROTOCOL = env.varOrUndefined('SANDBOX_PROTOCOL'); export const START_WRITERS = env.varOrDefault('START_WRITERS', 'true') === 'true'; diff --git a/src/middleware/arns.ts b/src/middleware/arns.ts index 2483f61b..d537bba9 100644 --- a/src/middleware/arns.ts +++ b/src/middleware/arns.ts @@ -18,6 +18,7 @@ import { Handler } from 'express'; import { asyncMiddleware } from 'middleware-async'; +import * as config from '../config.js'; import { sendNotFound } from '../routes/data.js'; import { NameResolver } from '../types.js'; @@ -25,24 +26,21 @@ const EXCLUDED_SUBDOMAINS = new Set('www'); export const createArnsMiddleware = ({ dataHandler, - rootHost, nameResolver, }: { dataHandler: Handler; - rootHost: string; nameResolver: NameResolver; }): Handler => asyncMiddleware(async (req, res, next) => { - const rootHostSubdomainLength = rootHost.split('.').length - 2; if ( // Ignore subdomains that are part of the ArNS root hostname. !Array.isArray(req.subdomains) || - req.subdomains.length === rootHostSubdomainLength + req.subdomains.length === config.ROOT_HOST_SUBDOMAIN_LENGTH ) { next(); return; } - const arnsSubdomain = req.subdomains[req.subdomains.length - 1]; + const arnsSubdomain = req.subdomains[config.ROOT_HOST_SUBDOMAIN_LENGTH - 1]; if ( EXCLUDED_SUBDOMAINS.has(arnsSubdomain) || // Avoid collisions with sandbox URLs by ensuring the subdomain length diff --git a/src/middleware/sandbox.ts b/src/middleware/sandbox.ts index ab6604e9..41f0cc53 100644 --- a/src/middleware/sandbox.ts +++ b/src/middleware/sandbox.ts @@ -19,11 +19,11 @@ import { Handler, Request } from 'express'; import url from 'node:url'; import { base32 } from 'rfc4648'; +import * as config from '../config.js'; import { fromB64Url } from '../lib/encoding.js'; -function getRequestSandbox(req: Request, rootHost: string): string | undefined { - const rootHostSubdomainLength = rootHost.split('.').length - 2; - if (req.subdomains.length > rootHostSubdomainLength) { +function getRequestSandbox(req: Request): string | undefined { + if (req.subdomains.length > config.ROOT_HOST_SUBDOMAIN_LENGTH) { return req.subdomains[req.subdomains.length - 1]; } return undefined; @@ -38,14 +38,12 @@ function sandboxFromId(id: string): string { } export function createSandboxMiddleware({ - rootHost, sandboxProtocol, }: { - rootHost?: string; sandboxProtocol?: string; }): Handler { return (req, res, next) => { - if (rootHost === undefined) { + if (config.ARNS_ROOT_HOST === undefined) { next(); return; } @@ -56,7 +54,7 @@ export function createSandboxMiddleware({ return; } - const reqSandbox = getRequestSandbox(req, rootHost); + const reqSandbox = getRequestSandbox(req); const idSandbox = sandboxFromId(id); if (reqSandbox !== idSandbox) { const queryString = url.parse(req.originalUrl).query ?? ''; @@ -64,7 +62,7 @@ export function createSandboxMiddleware({ const protocol = sandboxProtocol ?? (req.secure ? 'https' : 'http'); return res.redirect( 302, - `${protocol}://${idSandbox}.${rootHost}${path}?${queryString}`, + `${protocol}://${idSandbox}.${config.ARNS_ROOT_HOST}${path}?${queryString}`, ); }