Skip to content

Allow customized fn to get client ip #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ There is an optional parameters object that can also control it's behavior by pa

`custom` (default undefined) sets a custom key extraction & transform function that allows you to perform your own key lookups, perhaps via an existing session cookie or similar, and also allows you to transform any existing key that has been extracted using the previous settings - you might [prefix keys to indicate their usage as Stripe does](https://docs.stripe.com/docs/api/authentication) for instance. This will override all other methods if specified.

`client_ip` (default uses SvelteKit's `GetClientAddress`) sets a custom function to obtain the Client IP address, only called if `.anonymous()` is used.

`key_length` (default 32) sets the length, in bytes, of the API key to generate. If you want shorter API keys you could consider setting it to a lower value such as 24 or 16 (but too low risks conflicts when generating new keys). Keys are converted to human-readable format using Base62 for compactness and easy copy-paste.

So as a more complete example your `src/lib/api_keys.ts` may end up looking something like this, but using whatever key store and token bucket implementations make sense for you:
Expand Down
6 changes: 4 additions & 2 deletions src/lib/api-keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import de from 'bad-words-next/data/de.json'
import type { KeyInfoData } from './key-info'
import type { KeyStore } from './key-store'
import type { TokenBuckets } from './bucket'
import { Api } from './api'
import { Api, type ClientIP } from './api'

const BASE62 = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
const base62 = basex(BASE62)
Expand All @@ -32,6 +32,7 @@ interface BaseParam {
cookie?: string
custom?: CustomFn
key_length?: number
client_ip?: ClientIP
}

// SearchParam defines the URL searchParam to use for the API key
Expand Down Expand Up @@ -146,8 +147,9 @@ export class ApiKeys {

const key = await this.extract(event)
const info = await this.validate(key)
const client_ip = this.options.client_ip ?? ((event) => event.getClientAddress())

locals.api = new Api(event, this.buckets, key, info)
locals.api = new Api(event, this.buckets, client_ip, key, info)

return await resolve(event)
}
Expand Down
5 changes: 4 additions & 1 deletion src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import type { TokenBuckets } from './bucket'
import type { KeyInfo } from './key-info'
import type { Refill } from './refill'

export type ClientIP = (event: RequestEvent) => string

export class Api {
private _name = ''
private _cost = 1
Expand Down Expand Up @@ -40,6 +42,7 @@ export class Api {
constructor(
private readonly event: RequestEvent,
private readonly bucket: TokenBuckets,
private readonly client_ip: ClientIP,
public readonly key: string | null,
public readonly info: KeyInfo | null,
) {}
Expand Down Expand Up @@ -182,7 +185,7 @@ export class Api {
}

// TODO: hash client IP address (?)
const bucketPrefix = info?.user || this.event.getClientAddress()
const bucketPrefix = info?.user || this.client_ip(this.event)
const bucketKey = bucketPrefix + ':' + this._name

// apply rate limiting
Expand Down