Skip to content

Commit

Permalink
feat: add address remapping (#483)
Browse files Browse the repository at this point in the history
* feat: add address remapping

* feat: add homepage env

* feat: ignore cors

* fix: add stamp and upload headers

* fix: always set cors headers

* docs: update readme

* style: fix eslint
  • Loading branch information
Cafe137 authored Dec 11, 2023
1 parent 128f0a7 commit 16b2941
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 1 deletion.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ npm run start
| POSTAGE_EXTENDSTTL | false | Enables extends TTL feature. Works along with POSTAGE_AMOUNT |
| EXPOSE_HASHED_IDENTITY | false | Exposes `x-bee-node` header, which is the hashed identity of the Bee node for identification purposes |
| REUPLOAD_PERIOD | undefined | How frequently are the pinned content checked to be reuploaded. |
| HOMEPAGE | undefined | Swarm hash that loads as the homepage of gateway-proxy |
| REMAP | undefined | Semicolon separated `name=hash` values to rewrite Swarm hashes to human-friendly names |
| ALLOWLIST | undefined | Colon separated list of hashes, ENS domains or CIDs to allow |

### Curl

Expand Down
10 changes: 9 additions & 1 deletion src/bzz-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,15 @@ import { logger } from './logger'

export class NotEnabledError extends Error {}

export function subdomainToBzz(subdomain: string, isCidEnabled: boolean, isEnsEnabled: boolean): string {
export function subdomainToBzz(
subdomain: string,
isCidEnabled: boolean,
isEnsEnabled: boolean,
remap: Record<string, string>,
): string {
if (subdomain in remap) {
return remap[subdomain]
}
try {
const result = swarmCid.decodeCid(subdomain)

Expand Down
6 changes: 6 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface AppConfig {
removePinHeader?: boolean
exposeHashedIdentity?: boolean
readinessCheck?: boolean
homepage?: string
}

export interface ServerConfig {
Expand Down Expand Up @@ -86,6 +87,9 @@ export type EnvironmentVariables = Partial<{
POSTAGE_REFRESH_PERIOD: string
POSTAGE_EXTENDSTTL: string
REUPLOAD_PERIOD: string

// Homepage
HOMEPAGE: string
}>

export const SUPPORTED_LEVELS = ['critical', 'error', 'warn', 'info', 'verbose', 'debug'] as const
Expand Down Expand Up @@ -119,6 +123,7 @@ export function getAppConfig({
REMOVE_PIN_HEADER,
EXPOSE_HASHED_IDENTITY,
READINESS_CHECK,
HOMEPAGE,
}: EnvironmentVariables = {}): AppConfig {
return {
hostname: HOSTNAME || DEFAULT_HOSTNAME,
Expand All @@ -131,6 +136,7 @@ export function getAppConfig({
removePinHeader: REMOVE_PIN_HEADER ? REMOVE_PIN_HEADER === 'true' : true,
exposeHashedIdentity: EXPOSE_HASHED_IDENTITY === 'true',
readinessCheck: READINESS_CHECK === 'true',
homepage: HOMEPAGE,
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ interface Options {
hostname?: string
cidSubdomains?: boolean
ensSubdomains?: boolean
remap: Record<string, string>
}

export function createProxyEndpoints(app: Application, options: Options) {
Expand All @@ -32,11 +33,13 @@ export function createProxyEndpoints(app: Application, options: Options) {

return
}

try {
const newUrl = subdomainToBzz(
subdomain.slice(0, -1), // remove trailing dot
options.cidSubdomains ?? false,
options.ensSubdomains ?? false,
options.remap,
)
await fetchAndRespond(
'GET',
Expand Down
47 changes: 47 additions & 0 deletions src/server.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Bee, BeeDebug } from '@ethersphere/bee-js'
import axios from 'axios'
import bodyParser from 'body-parser'
import { Arrays, Strings } from 'cafe-utility'
import express, { Application } from 'express'
import { AppConfig, DEFAULT_HOSTNAME } from './config'
import { HASHED_IDENTITY_HEADER, fetchBeeIdentity, getHashedIdentity } from './identity'
Expand All @@ -21,6 +23,7 @@ export const createApp = (
removePinHeader,
exposeHashedIdentity,
readinessCheck,
homepage,
}: AppConfig,
stampManager?: StampsManager,
): Application => {
Expand All @@ -38,6 +41,22 @@ export const createApp = (
}),
)

app.use((req, res, next) => {
res.set('Access-Control-Allow-Origin', '*')
res.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
res.set(
'Access-Control-Allow-Headers',
'Content-Type, Authorization, swarm-postage-batch-id, swarm-deferred-upload',
)

if (req.method === 'OPTIONS') {
res.sendStatus(200)

return
}
next()
})

// Register hashed identity
if (exposeHashedIdentity) {
const beeDebug = new BeeDebug(beeDebugApiUrl)
Expand Down Expand Up @@ -113,8 +132,36 @@ export const createApp = (
cidSubdomains,
ensSubdomains,
hostname,
remap: Object.fromEntries(
(Arrays.getArgument(process.argv, 'remap', process.env as any, 'REMAP') || '').split(';').map(x => x.split('=')),

Check warning on line 136 in src/server.ts

View workflow job for this annotation

GitHub Actions / check (14.x)

Unexpected any. Specify a different type
),
})

if (homepage) {
app.use(async (req, res, next) => {
try {
const url = Strings.joinUrl(beeApiUrl, 'bzz', homepage, req.url)
logger.info('attempting to fetch homepage', { url })

// attempt to fetch homepage
const response = await axios.get(url, {
responseType: 'arraybuffer',
})

if (response.status !== 200) {
throw Error('Homepage not available')
}
const contentType = response.headers['content-type']
res.set('content-type', contentType || 'application/octet-stream')
res.send(await response.data)

return
} catch (error) {
next()
}
})
}

app.use(express.static('public'))

app.use((_req, res) => res.sendStatus(404))
Expand Down

0 comments on commit 16b2941

Please sign in to comment.