Skip to content

Commit

Permalink
Apply suggestions from code review
Browse files Browse the repository at this point in the history
Co-authored-by: Titus <tituswormer@gmail.com>
  • Loading branch information
Murderlon and wooorm committed Sep 15, 2023
1 parent 6c5d824 commit 8bbc986
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 42 deletions.
8 changes: 7 additions & 1 deletion lib/safe-http-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,14 @@ export class SafeHttpClient {
}

/**
* @param {string|URL} url
* Fetch a URL.
*
* @param {URL | string} url
* URL.
* @param {import('undici').RequestInit} options
* Configuration, passed through to `fetch`.
* @returns {Promise<{buffer?: Buffer, headers: import('undici').Headers}>}
* Buffer of response (except when `HEAD`) and headers.
*/
async safeFetch(url, options) {
let response = await fetch(url, options)
Expand Down
12 changes: 4 additions & 8 deletions lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,14 @@ function filterHeaders(allowedHeaders) {
*/
export class Server extends EventEmitter {
/**
* @param {Config} config
* @param {Readonly<Config>} config
*/
constructor(config) {
super()
if (!config.HMACKey) {
throw new Error('HMACKey is required')
}
this.config = config
this.config.serverName ??= 'camo'
this.config = {...config, serverName: config?.serverName || 'camo'}
}

/**
Expand Down Expand Up @@ -125,7 +124,7 @@ export class Server extends EventEmitter {
const filterResponseHeaders = filterHeaders(defaultResponseHeaders)
const client = new SafeHttpClient(this.config.maxSize)
const {buffer, headers: resHeaders} = await client.safeFetch(validUrl, {
// @ts-ignore we can convert req.headers to Headers
// @ts-expect-error: `IncomingHttpHeaders` can be passed to `Headers`
headers: filterRequestHeaders(new Headers(req.headers)),
method: req.method,
// We can't blindly follow redirects as the initial checkUrl
Expand Down Expand Up @@ -169,10 +168,7 @@ export class Server extends EventEmitter {
*/
verifyHMAC(receivedDigest, hex) {
// Hex-decode the URL
const originalUrlBuffer = hexDecode(hex)

// Convert the buffer to a string
const decodedUrl = originalUrlBuffer.toString('utf-8')
const decodedUrl = Buffer.from(hex, 'hex').toString()

// Verify the HMAC digest to ensure the URL hasn't been tampered with
const hmac = crypto.createHmac('sha1', this.config.HMACKey)
Expand Down
74 changes: 41 additions & 33 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,15 @@ npm install camomile
A standalone server.

```js
const {Server} = require('camomile')
import {Server} from 'camomile'

const host = '127.0.0.1'
const port = 1080
const server = new Server({
HMACKey: process.env.CAMOMILE_HMAC_KEY,
})
const HMACKey = process.env.CAMOMILE_HMAC_KEY

if (!HMACKey) throw new Error('Missing `CAMOMILE_HMAC_KEY` in environment')

const server = new Server({HMACKey})

server.listen({host, port})
server.listen({host: '127.0.0.1', port: 1080})
```

## API
Expand All @@ -99,7 +99,7 @@ Name used for the `Via` HTTP header (`string`, default: `'camomile'`).

#### `options.maxSize`

Limit the maximum size of a resource in bytes (`number`, default: `null`).
Limit the maximum size of a resource in bytes (`number`, default: `undefined`).

The server responds with `404` and `Content-Length exceeded`
if the resource is larger than the maximum size.
Expand All @@ -109,39 +109,43 @@ if the resource is larger than the maximum size.
### Example: integrate camomile into Express

```js
const {Server} = require('camomile')
const express = require('express')
import express from 'express'
import {Server} from 'camomile'

const HMACKey = process.env.CAMOMILE_HMAC_KEY
if (!HMACKey) throw new Error('Missing `CAMOMILE_HMAC_KEY` in environment')

const host = '127.0.0.1'
const port = 1080
const app = express()
const uploadApp = express()
const camomile = new Server({
HMACKey: process.env.CAMOMILE_HMAC_KEY,
})
const camomile = new Server({HMACKey})
uploadApp.all('*', camomile.handle.bind(camomile))

uploadApp.all('*', server.handle.bind(server))
app.use('/uploads', uploadApp)
app.listen(port, host)

console.log('Listening on `http://' + host + ':' + port + '/uploads/`')
```

### Example: integrate camomile into Koa

```js
const http = require('node:http')
const url = require('node:url')
const Koa = require('koa')
const {Server} = require('camomile')
import http from 'node:http'
import url from 'node:url'
import {Server} from 'camomile'
import Koa from 'koa'

const HMACKey = process.env.CAMOMILE_HMAC_KEY
if (!HMACKey) throw new Error('Missing `CAMOMILE_HMAC_KEY` in environment')

const port = 1080
const app = new Koa()
const appCallback = app.callback()
const port = 1080
const camomile = new Server({
HMACKey: process.env.CAMOMILE_HMAC_KEY,
})
const camomile = new Server({HMACKey})

const server = http.createServer((req, res) => {
const urlPath = url.parse(req.url).pathname
const urlPath = url.parse(req.url || '').pathname || ''

// handle any requests with the `/files/*` pattern
if (/^\/files\/.+/.test(urlPath.toLowerCase())) {
Expand All @@ -157,16 +161,18 @@ server.listen(port)
### Example: integrate camomile into Fastify

```js
const fastify = require('fastify')({logger: true})
const {Server} = require('camomile')
import createFastify from 'fastify'
import {Server} from 'camomile'

const camomile = new Server({
HMACKey: process.env.CAMOMILE_HMAC_KEY,
})
const HMACKey = process.env.CAMOMILE_HMAC_KEY
if (!HMACKey) throw new Error('Missing `CAMOMILE_HMAC_KEY` in environment')

const fastify = createFastify({logger: true})
const camomile = new Server({HMACKey})

/**
* add new content-type to fastify forewards request
* without any parser to leave body untouched
* Add `content-type` so fastify forewards without a parser to the leave body untouched.
*
* @see https://www.fastify.io/docs/latest/Reference/ContentTypeParser/
*/
fastify.addContentTypeParser(
Expand All @@ -175,8 +181,9 @@ fastify.addContentTypeParser(
)

/**
* let camomile handle preparation and filehandling requests
* fastify exposes raw nodejs http req/res via .raw property
* Use camomile to handle preparation and filehandling requests.
* `.raw` gets the raw Node HTTP request and response objects.
*
* @see https://www.fastify.io/docs/latest/Reference/Request/
* @see https://www.fastify.io/docs/latest/Reference/Reply/#raw
*/
Expand All @@ -186,7 +193,8 @@ fastify.all('/files', (req, res) => {
fastify.all('/files/*', (req, res) => {
camomile.handle(req.raw, res.raw)
})
fastify.listen(3000, (err) => {

fastify.listen({port: 3000}, (err) => {
if (err) {
fastify.log.error(err)
process.exit(1)
Expand Down

0 comments on commit 8bbc986

Please sign in to comment.