Skip to content

Commit

Permalink
feat: support x-forwarded-path (#579)
Browse files Browse the repository at this point in the history
  • Loading branch information
fenos authored Nov 11, 2024
1 parent 3c19f8d commit a35f159
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 5 deletions.
3 changes: 3 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ type StorageConfigType = {
tenantId: string
requestUrlLengthLimit: number
requestXForwardedHostRegExp?: string
requestAllowXForwardedPrefix?: boolean
logLevel?: string
logflareEnabled?: boolean
logflareApiKey?: string
Expand Down Expand Up @@ -194,6 +195,8 @@ export function getConfig(options?: { reload?: boolean }): StorageConfigType {
'REQUEST_X_FORWARDED_HOST_REGEXP',
'X_FORWARDED_HOST_REGEXP'
),
requestAllowXForwardedPrefix:
getOptionalConfigFromEnv('REQUEST_ALLOW_X_FORWARDED_PATH') === 'true',
requestUrlLengthLimit:
Number(getOptionalConfigFromEnv('REQUEST_URL_LENGTH_LIMIT', 'URL_LENGTH_LIMIT')) || 7_500,
requestTraceHeader: getOptionalConfigFromEnv('REQUEST_TRACE_HEADER', 'REQUEST_ID_HEADER'),
Expand Down
11 changes: 10 additions & 1 deletion src/http/plugins/signature-v4.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const {
serviceKey,
storageS3Region,
isMultitenant,
requestAllowXForwardedPrefix,
s3ProtocolPrefix,
s3ProtocolAllowForwardedHeader,
s3ProtocolEnforceRegion,
Expand All @@ -37,13 +38,21 @@ export const signatureV4 = fastifyPlugin(
token,
} = await createServerSignature(request.tenantId, clientSignature)

let storagePrefix = s3ProtocolPrefix
if (
requestAllowXForwardedPrefix &&
typeof request.headers['x-forwarded-prefix'] === 'string'
) {
storagePrefix = request.headers['x-forwarded-prefix']
}

const isVerified = signatureV4.verify(clientSignature, {
url: request.url,
body: request.body as string | ReadableStream | Buffer,
headers: request.headers as Record<string, string | string[]>,
method: request.method,
query: request.query as Record<string, string>,
prefix: s3ProtocolPrefix,
prefix: storagePrefix,
})

if (!isVerified && !sessionToken) {
Expand Down
11 changes: 9 additions & 2 deletions src/http/routes/tus/lifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { UploadId } from '@storage/protocols/tus'

import { getConfig } from '../../../config'

const { storageS3Bucket, tusPath } = getConfig()
const { storageS3Bucket, tusPath, requestAllowXForwardedPrefix } = getConfig()
const reExtractFileID = /([^/]+)\/?$/

export const SIGNED_URL_SUFFIX = '/sign'
Expand Down Expand Up @@ -92,8 +92,15 @@ export function generateUrl(
}
proto = process.env.NODE_ENV === 'production' ? 'https' : proto

let basePath = path

const forwardedPath = req.headers['x-forwarded-prefix']
if (requestAllowXForwardedPrefix && typeof forwardedPath === 'string') {
basePath = forwardedPath + path
}

const isSigned = req.url?.endsWith(SIGNED_URL_SUFFIX)
const fullPath = isSigned ? `${path}${SIGNED_URL_SUFFIX}` : path
const fullPath = isSigned ? `${basePath}${SIGNED_URL_SUFFIX}` : basePath

if (req.headers['x-forwarded-host']) {
const port = req.headers['x-forwarded-port']
Expand Down
1 change: 1 addition & 0 deletions src/internal/monitoring/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ const whitelistHeaders = (headers: Record<string, unknown>) => {
'x-forwarded-proto',
'x-forwarded-host',
'x-forwarded-port',
'x-forwarded-prefix',
'referer',
'content-length',
'x-real-ip',
Expand Down
4 changes: 2 additions & 2 deletions src/storage/protocols/s3/signature-v4.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ export class SignatureV4 {
const serverSignature = this.sign(clientSignature, request)
return crypto.timingSafeEqual(
Buffer.from(clientSignature.signature),
Buffer.from(serverSignature)
Buffer.from(serverSignature.signature)
)
}

Expand Down Expand Up @@ -223,7 +223,7 @@ export class SignatureV4 {
serverCredentials.service
)

return this.hmac(signingKey, stringToSign).toString('hex')
return { signature: this.hmac(signingKey, stringToSign).toString('hex'), canonicalRequest }
}

protected getPayloadHash(clientSignature: ClientSignature, request: SignatureRequest) {
Expand Down

0 comments on commit a35f159

Please sign in to comment.