Skip to content

Commit

Permalink
feat(sandbox): implement TX sandboxing PE-3974
Browse files Browse the repository at this point in the history
Implements the arweave.net feature that prepends a base32 encoded ID to
the hostname when serving TXs. The feature is enabled if ARNS_ROOT_HOST
is set. The protocol (https or http) in the redirect URLs can be
overriden using SANDBOX_PROTOCOL.
  • Loading branch information
djwhitt committed Jun 7, 2023
1 parent c8b982f commit 4ef5ed3
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 0 deletions.
2 changes: 2 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,5 @@ services:
- ADMIN_API_KEY=${ADMIN_API_KEY:-}
- ANS104_UNBUNDLE_FILTER=${ANS104_UNBUNDLE_FILTER:-}
- ANS104_DATA_INDEX_FILTER=${ANS104_DATA_INDEX_FILTER:-}
- ARNS_ROOT_HOST=${ARNS_ROOT_HOST:-}
- SANDBOX_PROTOCOL=${SANDBOX_PROTOCOL:-}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"prom-client": "^14.0.1",
"ramda": "^0.28.0",
"retry-axios": "^3.0.0",
"rfc4648": "^1.5.2",
"sql-bricks": "^3.0.0",
"sql-bricks-sqlite": "^0.1.0",
"stream-chain": "^2.2.5",
Expand Down
8 changes: 8 additions & 0 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import YAML from 'yaml';
import * as config from './config.js';
import log from './log.js';
import { createArnsMiddleware } from './middleware/arns.js';
import { createSandboxMiddleware } from './middleware/sandbox.js';
import {
DATA_PATH_REGEX,
RAW_DATA_PATH_REGEX,
Expand Down Expand Up @@ -80,6 +81,13 @@ app.use(
}),
);

app.use(
createSandboxMiddleware({
rootHost: config.ARNS_ROOT_HOST,
sandboxProtocol: config.SANDBOX_PROTOCOL,
}),
);

// OpenAPI Spec
const openapiDocument = YAML.parse(
fs.readFileSync('docs/openapi.yaml', 'utf8'),
Expand Down
2 changes: 2 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,5 @@ export const ANS104_UNBUNDLE_FILTER = createFilter(
export const ANS104_DATA_INDEX_FILTER = createFilter(
JSON.parse(env.varOrDefault('ANS104_DATA_INDEX_FILTER', '{"never": true}')),
);
export const ARNS_ROOT_HOST = env.varOrUndefined('ARNS_ROOT_HOST');
export const SANDBOX_PROTOCOL = env.varOrUndefined('SANDBOX_PROTOCOL');
72 changes: 72 additions & 0 deletions src/middleware/sandbox.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* AR.IO Gateway
* Copyright (C) 2022 - 2023 Permanent Data Solutions, Inc
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Handler, Request } from 'express';
import url from 'node:url';
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];
}
return undefined;
}

function getRequestId(req: Request): string | undefined {
return (req.path.match(/^\/([a-zA-Z0-9-_]{43})/) ?? [])[1];
}

function sandboxFromId(id: string): string {
return base32.stringify(fromB64Url(id), { pad: false }).toLowerCase();
}

export function createSandboxMiddleware({
rootHost,
sandboxProtocol,
}: {
rootHost?: string;
sandboxProtocol?: string;
}): Handler {
return (req, res, next) => {
if (rootHost === undefined) {
next();
return;
}

const id = getRequestId(req);
if (id === undefined) {
next();
return;
}

const reqSandbox = getRequestSandbox(req);
const idSandbox = sandboxFromId(id);
if (reqSandbox !== idSandbox) {
const queryString = url.parse(req.originalUrl).query ?? '';
const path = req.path.replace(/\/\//, '/');
const protocol = sandboxProtocol ?? (req.secure ? 'https' : 'http');
return res.redirect(
302,
`${protocol}://${idSandbox}.${rootHost}${path}?${queryString}`,
);
}

next();
};
}
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5275,6 +5275,11 @@ reusify@^1.0.4:
resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz"
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==

rfc4648@^1.5.2:
version "1.5.2"
resolved "https://registry.yarnpkg.com/rfc4648/-/rfc4648-1.5.2.tgz#cf5dac417dd83e7f4debf52e3797a723c1373383"
integrity sha512-tLOizhR6YGovrEBLatX1sdcuhoSCXddw3mqNVAcKxGJ+J0hFeJ+SjeWCv5UPA/WU3YzWPPuCVYgXBKZUPGpKtg==

rimraf@^2.6.1, rimraf@^2.6.3:
version "2.7.1"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
Expand Down

0 comments on commit 4ef5ed3

Please sign in to comment.