[READ-ONLY] Mirror of https://github.com/thoda-dev/shhh. Self-hostable zero-knowledge pastebin for secrets that expire on their own
docker end-to-end-encryption nuxt nuxtjs pastebin secrets selft-hosted zero-knowledge
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950import type { H3Event } from 'h3'
/** * How many proxies you control sit between the internet and this app. 0 — the default — never reads * X-Forwarded-For and uses the socket address, which is the only value a client cannot influence. * * Anything above 0 is a promise about your deployment, so it is opt-in: the danger is not reading the * header, it is reading it when nothing trustworthy wrote it. */function trustedProxyDepth(): number { const raw = process.env.TRUSTED_PROXY_DEPTH if (!raw) return 0 const depth = Number(raw) return Number.isInteger(depth) && depth >= 0 ? depth : 0}
/** * Resolves the client address from the socket address and the X-Forwarded-For chain. * * Each proxy appends the peer it received the request from, so the chain reads left to right from * least to most trustworthy: the leftmost entries may have been forged by the client, the rightmost * were written by the hop closest to us. Counting `depth` entries from the right therefore lands on * the address our own infrastructure observed, and anything a client prepended is ignored. * * A chain shorter than `depth` means the request did not come through the expected proxies at all — * a direct hit, or a misconfiguration. Falling back to the socket address is the safe reading; using * whatever is there would accept a forged header from a client that bypassed the proxy. */export function resolveClientIp(socketIp: string | undefined, forwardedFor: string | undefined, depth: number): string | undefined { if (depth <= 0 || !forwardedFor) return socketIp
const chain = forwardedFor.split(',').map(part => part.trim()).filter(Boolean) if (chain.length < depth) return socketIp
return chain[chain.length - depth] ?? socketIp}
/** * The address every abuse control in this app is keyed on: the rate limiter, the allowlist, the * blocklist, and the automatic bans. Always go through this rather than `getRequestIP`, whose * `xForwardedFor` option takes the leftmost entry — the one a client can write. */export function getClientIp(event: H3Event): string | undefined { return resolveClientIp( event.node.req.socket.remoteAddress, getRequestHeader(event, 'x-forwarded-for'), trustedProxyDepth() )}