@flayerlabs/gamemode-gate 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/DEPLOY.md +6 -1
  2. package/README.md +4 -2
  3. package/dist/admission.d.ts +107 -0
  4. package/dist/admission.d.ts.map +1 -0
  5. package/dist/admission.js +201 -0
  6. package/dist/admission.js.map +1 -0
  7. package/dist/chain/secure.d.ts +17 -0
  8. package/dist/chain/secure.d.ts.map +1 -1
  9. package/dist/chain/secure.js +40 -0
  10. package/dist/chain/secure.js.map +1 -1
  11. package/dist/index.d.ts +10 -4
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +5 -2
  14. package/dist/index.js.map +1 -1
  15. package/dist/ip-blocks.d.ts +50 -0
  16. package/dist/ip-blocks.d.ts.map +1 -0
  17. package/dist/ip-blocks.js +125 -0
  18. package/dist/ip-blocks.js.map +1 -0
  19. package/dist/join-ticket-ledger.d.ts +135 -0
  20. package/dist/join-ticket-ledger.d.ts.map +1 -0
  21. package/dist/join-ticket-ledger.js +190 -0
  22. package/dist/join-ticket-ledger.js.map +1 -0
  23. package/dist/main.d.ts +16 -0
  24. package/dist/main.d.ts.map +1 -1
  25. package/dist/main.js +36 -2
  26. package/dist/main.js.map +1 -1
  27. package/dist/player-join-tickets.d.ts +10 -0
  28. package/dist/player-join-tickets.d.ts.map +1 -1
  29. package/dist/player-join-tickets.js +27 -14
  30. package/dist/player-join-tickets.js.map +1 -1
  31. package/dist/registry.d.ts +1 -1
  32. package/dist/registry.d.ts.map +1 -1
  33. package/dist/registry.js +4 -4
  34. package/dist/registry.js.map +1 -1
  35. package/dist/server.d.ts +41 -3
  36. package/dist/server.d.ts.map +1 -1
  37. package/dist/server.js +147 -12
  38. package/dist/server.js.map +1 -1
  39. package/dist/store.d.ts +1 -1
  40. package/dist/store.d.ts.map +1 -1
  41. package/dist/store.js +33 -1
  42. package/dist/store.js.map +1 -1
  43. package/dist/turnstile.d.ts +37 -1
  44. package/dist/turnstile.d.ts.map +1 -1
  45. package/dist/turnstile.js +82 -2
  46. package/dist/turnstile.js.map +1 -1
  47. package/dist/version.js +2 -2
  48. package/package.json +3 -3
  49. package/src/admission.ts +273 -0
  50. package/src/chain/secure.ts +52 -0
  51. package/src/index.ts +34 -2
  52. package/src/ip-blocks.ts +154 -0
  53. package/src/join-ticket-ledger.ts +325 -0
  54. package/src/main.ts +56 -2
  55. package/src/player-join-tickets.ts +34 -19
  56. package/src/registry.ts +6 -3
  57. package/src/server.ts +188 -15
  58. package/src/store.ts +33 -1
  59. package/src/turnstile.ts +96 -2
  60. package/src/version.ts +2 -2
package/DEPLOY.md CHANGED
@@ -47,6 +47,10 @@ gate whose signatures a swap can actually verify.
47
47
  | `MIN_LOBBY_LEAD_MS`, `GATE_ENDS_AT_GRACE_S` | no | Defaults 60000 and 10. |
48
48
  | `POINTS_PER_DOLLAR`, `USD_PER_ETH` | no | Your game's economy. Defaults 100 and 3000; `USD_PER_ETH` may be fractional. Boot refuses an economy your `rewardBounds` cannot honour. |
49
49
  | `SPEND_TOKENS` | no | Pin a price for a non-ETH paired token: a JSON array of `{ "address", "usdPerToken", "walletCap" }`, the cap in that token's base units. Symbol and decimals are read from the chain at boot, and boot refuses an economy the cap cannot honour. Tokens not listed are priced from the manager's `PairedTokenRegistry` at adoption (below); only a token the registry does not approve is refused. Needs the paired stack (`POSITION_MANAGER` above). |
50
+ | `TRUSTED_PROXY_HOPS` | no | Default `0`. Proxies between the player and this process: `2` on Railway (its edge, then an internal router), `3` with a CDN in front of it. Decides whose address admission policy sees. Too low and every player shares the proxy's address; too high and a caller picks their own with a header. |
51
+ | `SESSIONS_PER_IP_PER_MINUTE` | no | Sign-ins one address may make in a minute. Default `30` once `TRUSTED_PROXY_HOPS` is set, otherwise `0` (no limit): a gate that cannot tell addresses apart would ration all its players as one. |
52
+ | `TURNSTILE_SITE_KEY`, `TURNSTILE_SECRET` | no | A Cloudflare Turnstile widget whose hostname is the embedding page (`flaunch.gg`). Set both or neither. Sign-in then requires a token, and `/config` announces the site key under `admission.turnstile` so the embedding page can render the widget. |
53
+ | `TURNSTILE_ACTION`, `TURNSTILE_HOSTNAMES` | no | Defaults `game-session` and the host of `SIGN_IN_DOMAIN`. List hostnames comma-separated when you sign in on more than one page. |
50
54
  | `PAIRED_TOKEN_CAP_HEADROOM_PERCENT` | no | Default `25`. Headroom over the smallest cap a flawless round fits under when the gate sizes the cap for a registry-priced pairing in `GET /config/spend-tokens/:address`. |
51
55
 
52
56
  ## Paired-token rounds
@@ -104,7 +108,8 @@ be updated; see MIGRATING.md for the rename table.
104
108
  ## Railway shape
105
109
 
106
110
  1. A service running your gate repo (build → `node dist/main.js` or however your repo boots
107
- `startGate`), plus an attached Postgres whose URL lands in `DATABASE_URL`.
111
+ `startGate`), plus an attached Postgres whose URL lands in `DATABASE_URL`. Railway puts two
112
+ proxies in front of the process, so set `TRUSTED_PROXY_HOPS=2`.
108
113
  2. Set the variables above. Generate `SIGNER_PRIVATE_KEY` and `SESSION_SECRET` fresh for each
109
114
  environment.
110
115
  3. The service needs a public HTTPS domain: game submission validates your `gateOrigin` as public
package/README.md CHANGED
@@ -76,8 +76,10 @@ guide's cumulative spend ceilings section for the wire shape and the deploy orde
76
76
 
77
77
  Run one gate process for each game. The current room writer does not support multiple replicas.
78
78
 
79
- Use `createTurnstileAdmit` if the trusted parent supplies Cloudflare Turnstile evidence. The policy
80
- checks session creation. Game action and claim policy remain the gate operator's responsibility.
79
+ Set `TURNSTILE_SITE_KEY` and `TURNSTILE_SECRET` to require Cloudflare Turnstile at sign-in. The gate
80
+ announces the site key so the trusted parent can render the widget. Set `TRUSTED_PROXY_HOPS` so
81
+ admission sees the player's address, not your platform's router. The Turnstile policy checks session
82
+ creation. Game action and claim policy remain the gate operator's responsibility.
81
83
 
82
84
  Read the [production gate guide](https://github.com/flayerlabs/gamemode-sdk/blob/main/docs/guides/run-a-gate.md)
83
85
  before deploying a gate.
@@ -0,0 +1,107 @@
1
+ import type { AdmissionRequest, Admit } from './server.js';
2
+ type Checkpoint = AdmissionRequest['at'];
3
+ /** IPv4 arriving over a dual-stack socket is the same caller as the bare IPv4 address. */
4
+ export declare function normaliseIp(ip: string): string;
5
+ /**
6
+ * Run several admission policies as one. The first refusal is the answer.
7
+ *
8
+ * In order, so put the cheap local checks first: a rate limit that refuses saves the Turnstile
9
+ * round trip behind it, and a spent Turnstile token is not wasted on a caller already over budget.
10
+ */
11
+ export declare function composeAdmit(...policies: readonly (Admit | undefined)[]): Admit;
12
+ /** At most `max` requests in any `windowMs`, approximately: two adjacent windows are weighed. */
13
+ export interface Rate {
14
+ max: number;
15
+ windowMs: number;
16
+ }
17
+ export interface CheckpointLimits {
18
+ /** Skipped when the caller's address is unknown. */
19
+ perIp?: Rate;
20
+ /** Skipped at `session`, where nobody has proved who they are yet. */
21
+ perPlayer?: Rate;
22
+ }
23
+ export type RateLimits = Partial<Record<Checkpoint, CheckpointLimits>>;
24
+ export interface RateLimitAdmitOptions {
25
+ limits: RateLimits;
26
+ /** Most distinct callers remembered at once. Bounds memory under rotating addresses. */
27
+ maxKeys?: number;
28
+ /** Test seam. */
29
+ now?: () => number;
30
+ }
31
+ /**
32
+ * Budgets generous enough for a household or an office behind one address, and far too small to
33
+ * farm sessions or tickets with. Gameplay and claims have no default: only the game knows its
34
+ * cadence, and a false refusal on a claim costs a player a purchase.
35
+ */
36
+ export declare const DEFAULT_RATE_LIMITS: RateLimits;
37
+ /**
38
+ * A request budget per address and per wallet, kept in this process.
39
+ *
40
+ * In memory because a gate is one process per game: there is no second replica for a caller to
41
+ * spread across, and a budget that survives a restart is not worth a database write on every
42
+ * action. The budget is spent only by admitted requests, so a caller refused by an earlier policy
43
+ * in {@link composeAdmit} does not burn it.
44
+ *
45
+ * Needs the real caller address. Behind a proxy, set `trustedProxyHops` first: otherwise every
46
+ * player shares the proxy's address and one budget.
47
+ */
48
+ export declare function createRateLimitAdmit(options: RateLimitAdmitOptions): Admit;
49
+ /** What a reputation provider says about an address. Absent fields mean "not known to be". */
50
+ export interface IpVerdict {
51
+ vpn?: boolean;
52
+ proxy?: boolean;
53
+ tor?: boolean;
54
+ /** A privacy relay such as iCloud Private Relay. Ordinary people use these. */
55
+ relay?: boolean;
56
+ /** A datacentre or cloud address. */
57
+ hosting?: boolean;
58
+ }
59
+ export type IpLookup = (ip: string, signal: AbortSignal) => Promise<IpVerdict>;
60
+ export interface IpReputationAdmitOptions {
61
+ /** Your provider. The gate ships no default: every provider needs an account only you have. */
62
+ lookup: IpLookup;
63
+ /** Which checkpoints consult the provider. Defaults to `session` only. */
64
+ at?: readonly Checkpoint[];
65
+ /**
66
+ * Whether a verdict is a refusal. Defaults to VPN, proxy, Tor or hosting. Relays are admitted by
67
+ * default, because refusing them refuses every Safari user with Private Relay on.
68
+ */
69
+ refuse?: (verdict: IpVerdict) => boolean;
70
+ /** How long a verdict is reused. Defaults to one hour. */
71
+ cacheMs?: number;
72
+ /** Defaults to 2,000. */
73
+ timeoutMs?: number;
74
+ /** Most addresses remembered at once. Defaults to 50,000. */
75
+ maxCached?: number;
76
+ /**
77
+ * What to do when the provider fails or times out. Defaults to admitting: an outage at a third
78
+ * party should not close your game. Set true only if a lockout is cheaper for you than a bot.
79
+ */
80
+ failClosed?: boolean;
81
+ /** Test seam. */
82
+ now?: () => number;
83
+ }
84
+ /**
85
+ * Refuse callers whose address a reputation provider calls anonymising.
86
+ *
87
+ * A seam, not a detector. Proxy and VPN detection is a paid data product with false positives, and
88
+ * which of them a game can live with is the operator's call. Whatever the provider, one lookup is
89
+ * made per address per `cacheMs`, and concurrent requests from one address share it.
90
+ */
91
+ export declare function createIpReputationAdmit(options: IpReputationAdmitOptions): Admit;
92
+ export interface IpinfoPrivacyOptions {
93
+ /** An IPinfo token on a plan that includes privacy detection. */
94
+ token: string;
95
+ /** Test seam. */
96
+ fetch?: typeof globalThis.fetch;
97
+ }
98
+ /**
99
+ * A reference {@link IpLookup} for IPinfo's privacy detection endpoint.
100
+ *
101
+ * Here to show the shape of an adapter, and because it is one HTTP call. Check the response
102
+ * against your own IPinfo plan before relying on it: this library has no IPinfo account and does
103
+ * not test against the live service.
104
+ */
105
+ export declare function ipinfoPrivacyLookup(options: IpinfoPrivacyOptions): IpLookup;
106
+ export {};
107
+ //# sourceMappingURL=admission.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admission.d.ts","sourceRoot":"","sources":["../src/admission.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,gBAAgB,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEtE,KAAK,UAAU,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;AAKzC,0FAA0F;AAC1F,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAG9C;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,QAAQ,EAAE,SAAS,CAAC,KAAK,GAAG,SAAS,CAAC,EAAE,GAAG,KAAK,CAS/E;AAED,iGAAiG;AACjG,MAAM,WAAW,IAAI;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,oDAAoD;IACpD,KAAK,CAAC,EAAE,IAAI,CAAC;IACb,sEAAsE;IACtE,SAAS,CAAC,EAAE,IAAI,CAAC;CAClB;AAED,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAEvE,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,UAAU,CAAC;IACnB,wFAAwF;IACxF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB;IACjB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,UAGjC,CAAC;AAoBF;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,KAAK,CAmD1E;AAED,8FAA8F;AAC9F,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,+EAA+E;IAC/E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,qCAAqC;IACrC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,QAAQ,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;AAE/E,MAAM,WAAW,wBAAwB;IACvC,+FAA+F;IAC/F,MAAM,EAAE,QAAQ,CAAC;IACjB,0EAA0E;IAC1E,EAAE,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAC3B;;;OAGG;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,SAAS,KAAK,OAAO,CAAC;IACzC,0DAA0D;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yBAAyB;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iBAAiB;IACjB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAKD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,wBAAwB,GAAG,KAAK,CA4ChF;AAED,MAAM,WAAW,oBAAoB;IACnC,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB;IACjB,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,QAAQ,CAmB3E"}
@@ -0,0 +1,201 @@
1
+ const TOO_MANY = { ok: false, reason: 'too many tries, wait a minute' };
2
+ const SUSPICIOUS = { ok: false, reason: 'you cannot play from this network' };
3
+ /** IPv4 arriving over a dual-stack socket is the same caller as the bare IPv4 address. */
4
+ export function normaliseIp(ip) {
5
+ const mapped = /^::ffff:(\d{1,3}(?:\.\d{1,3}){3})$/i.exec(ip);
6
+ return (mapped ? mapped[1] : ip).toLowerCase();
7
+ }
8
+ /**
9
+ * Run several admission policies as one. The first refusal is the answer.
10
+ *
11
+ * In order, so put the cheap local checks first: a rate limit that refuses saves the Turnstile
12
+ * round trip behind it, and a spent Turnstile token is not wasted on a caller already over budget.
13
+ */
14
+ export function composeAdmit(...policies) {
15
+ const active = policies.filter((policy) => policy !== undefined);
16
+ return async (request) => {
17
+ for (const policy of active) {
18
+ const admission = await policy(request);
19
+ if (!admission.ok)
20
+ return admission;
21
+ }
22
+ return { ok: true };
23
+ };
24
+ }
25
+ /**
26
+ * Budgets generous enough for a household or an office behind one address, and far too small to
27
+ * farm sessions or tickets with. Gameplay and claims have no default: only the game knows its
28
+ * cadence, and a false refusal on a claim costs a player a purchase.
29
+ */
30
+ export const DEFAULT_RATE_LIMITS = {
31
+ session: { perIp: { max: 30, windowMs: 60_000 } },
32
+ ticket: { perIp: { max: 60, windowMs: 60_000 } },
33
+ };
34
+ const DEFAULT_MAX_KEYS = 100_000;
35
+ function assertRate(rate, name) {
36
+ if (rate === undefined)
37
+ return;
38
+ if (!Number.isSafeInteger(rate.max) || rate.max <= 0)
39
+ throw new RangeError(`${name}.max must be a positive safe integer`);
40
+ if (!Number.isSafeInteger(rate.windowMs) || rate.windowMs <= 0) {
41
+ throw new RangeError(`${name}.windowMs must be a positive safe integer`);
42
+ }
43
+ }
44
+ /**
45
+ * A request budget per address and per wallet, kept in this process.
46
+ *
47
+ * In memory because a gate is one process per game: there is no second replica for a caller to
48
+ * spread across, and a budget that survives a restart is not worth a database write on every
49
+ * action. The budget is spent only by admitted requests, so a caller refused by an earlier policy
50
+ * in {@link composeAdmit} does not burn it.
51
+ *
52
+ * Needs the real caller address. Behind a proxy, set `trustedProxyHops` first: otherwise every
53
+ * player shares the proxy's address and one budget.
54
+ */
55
+ export function createRateLimitAdmit(options) {
56
+ for (const [at, limits] of Object.entries(options.limits)) {
57
+ assertRate(limits?.perIp, `limits.${at}.perIp`);
58
+ assertRate(limits?.perPlayer, `limits.${at}.perPlayer`);
59
+ }
60
+ const maxKeys = options.maxKeys ?? DEFAULT_MAX_KEYS;
61
+ if (!Number.isSafeInteger(maxKeys) || maxKeys <= 0)
62
+ throw new RangeError('maxKeys must be a positive safe integer');
63
+ const now = options.now ?? Date.now;
64
+ const buckets = new Map();
65
+ /** Whether one more request fits, without spending it. */
66
+ const fits = (key, rate, at) => {
67
+ const bucket = buckets.get(key);
68
+ if (!bucket)
69
+ return true;
70
+ const elapsed = at - bucket.start;
71
+ if (elapsed >= 2 * rate.windowMs)
72
+ return true;
73
+ const [current, previous] = elapsed >= rate.windowMs ? [0, bucket.count] : [bucket.count, bucket.previous];
74
+ const into = elapsed % rate.windowMs;
75
+ return current + previous * (1 - into / rate.windowMs) < rate.max;
76
+ };
77
+ const spend = (key, rate, at) => {
78
+ const bucket = buckets.get(key);
79
+ const elapsed = bucket ? at - bucket.start : Infinity;
80
+ if (!bucket || elapsed >= 2 * rate.windowMs) {
81
+ buckets.delete(key);
82
+ if (buckets.size >= maxKeys)
83
+ buckets.delete(buckets.keys().next().value);
84
+ buckets.set(key, { start: at, count: 1, previous: 0 });
85
+ }
86
+ else if (elapsed >= rate.windowMs) {
87
+ bucket.previous = bucket.count;
88
+ bucket.count = 1;
89
+ bucket.start += rate.windowMs;
90
+ }
91
+ else {
92
+ bucket.count += 1;
93
+ }
94
+ };
95
+ return (request) => {
96
+ const limits = options.limits[request.at];
97
+ if (!limits)
98
+ return { ok: true };
99
+ const at = now();
100
+ const checks = [];
101
+ if (limits.perIp && request.ip)
102
+ checks.push([`${request.at}:ip:${normaliseIp(request.ip)}`, limits.perIp]);
103
+ if (limits.perPlayer && request.player) {
104
+ checks.push([`${request.at}:player:${request.player.toLowerCase()}`, limits.perPlayer]);
105
+ }
106
+ // All budgets are checked before any is spent, so a refusal by one does not drain another.
107
+ if (checks.some(([key, rate]) => !fits(key, rate, at)))
108
+ return TOO_MANY;
109
+ for (const [key, rate] of checks)
110
+ spend(key, rate, at);
111
+ return { ok: true };
112
+ };
113
+ }
114
+ const defaultRefuse = (verdict) => verdict.vpn === true || verdict.proxy === true || verdict.tor === true || verdict.hosting === true;
115
+ /**
116
+ * Refuse callers whose address a reputation provider calls anonymising.
117
+ *
118
+ * A seam, not a detector. Proxy and VPN detection is a paid data product with false positives, and
119
+ * which of them a game can live with is the operator's call. Whatever the provider, one lookup is
120
+ * made per address per `cacheMs`, and concurrent requests from one address share it.
121
+ */
122
+ export function createIpReputationAdmit(options) {
123
+ const checkpoints = new Set(options.at ?? ['session']);
124
+ const refuse = options.refuse ?? defaultRefuse;
125
+ const cacheMs = options.cacheMs ?? 60 * 60_000;
126
+ const timeoutMs = options.timeoutMs ?? 2_000;
127
+ const maxCached = options.maxCached ?? 50_000;
128
+ for (const [name, value] of [['cacheMs', cacheMs], ['timeoutMs', timeoutMs], ['maxCached', maxCached]]) {
129
+ if (!Number.isSafeInteger(value) || value <= 0)
130
+ throw new RangeError(`${name} must be a positive safe integer`);
131
+ }
132
+ const now = options.now ?? Date.now;
133
+ const cache = new Map();
134
+ const inFlight = new Map();
135
+ const ask = async (ip) => {
136
+ try {
137
+ const refused = refuse(await options.lookup(ip, AbortSignal.timeout(timeoutMs)));
138
+ cache.delete(ip);
139
+ if (cache.size >= maxCached)
140
+ cache.delete(cache.keys().next().value);
141
+ cache.set(ip, { refused, until: now() + cacheMs });
142
+ return refused;
143
+ }
144
+ catch {
145
+ // Not cached: the next request asks again rather than inheriting an outage.
146
+ return null;
147
+ }
148
+ };
149
+ return async (request) => {
150
+ if (!checkpoints.has(request.at) || !request.ip)
151
+ return { ok: true };
152
+ const ip = normaliseIp(request.ip);
153
+ const cached = cache.get(ip);
154
+ let refused;
155
+ if (cached && cached.until > now()) {
156
+ refused = cached.refused;
157
+ }
158
+ else {
159
+ let pending = inFlight.get(ip);
160
+ if (!pending) {
161
+ pending = ask(ip).finally(() => inFlight.delete(ip));
162
+ inFlight.set(ip, pending);
163
+ }
164
+ refused = await pending;
165
+ }
166
+ if (refused === null)
167
+ return options.failClosed ? SUSPICIOUS : { ok: true };
168
+ return refused ? SUSPICIOUS : { ok: true };
169
+ };
170
+ }
171
+ /**
172
+ * A reference {@link IpLookup} for IPinfo's privacy detection endpoint.
173
+ *
174
+ * Here to show the shape of an adapter, and because it is one HTTP call. Check the response
175
+ * against your own IPinfo plan before relying on it: this library has no IPinfo account and does
176
+ * not test against the live service.
177
+ */
178
+ export function ipinfoPrivacyLookup(options) {
179
+ if (!options.token)
180
+ throw new RangeError('IPinfo token is required');
181
+ const request = options.fetch ?? globalThis.fetch;
182
+ return async (ip, signal) => {
183
+ const response = await request(`https://ipinfo.io/${encodeURIComponent(ip)}/privacy`, {
184
+ headers: { authorization: `Bearer ${options.token}`, accept: 'application/json' },
185
+ signal,
186
+ });
187
+ if (!response.ok)
188
+ throw new Error(`IPinfo answered ${response.status}`);
189
+ const body = (await response.json());
190
+ if (typeof body !== 'object' || body === null)
191
+ throw new Error('IPinfo answered with something other than an object');
192
+ return {
193
+ vpn: body.vpn === true,
194
+ proxy: body.proxy === true,
195
+ tor: body.tor === true,
196
+ relay: body.relay === true,
197
+ hosting: body.hosting === true,
198
+ };
199
+ };
200
+ }
201
+ //# sourceMappingURL=admission.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admission.js","sourceRoot":"","sources":["../src/admission.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,23 @@ import type { FlaunchVariant } from './chains.js';
4
4
  export declare const DEMO_SESSION_SECRET = "dev-secret-that-is-long-enough-to-pass";
5
5
  /** `ProtocolRoles.POSITION_MANAGER` in flaunch-contracts: the role a calculator demands of its caller. */
6
6
  export declare const POSITION_MANAGER_ROLE: `0x${string}`;
7
+ /** What the calculator says its own EIP-712 domain is, or why it could not be read. */
8
+ export type CalculatorDomain = {
9
+ ok: true;
10
+ name: string;
11
+ version: string;
12
+ } | {
13
+ ok: false;
14
+ reason: string;
15
+ };
16
+ /**
17
+ * Does this calculator verify signatures under the domain this gate signs?
18
+ *
19
+ * Reads `eip712Domain()` (EIP-5267) and compares name and version with the typed data the gate's
20
+ * signer produces. Same shape as {@link checkPositionManagerWiring}: a verdict with a reason the
21
+ * operator can act on, because the fix is one env var (`SPEND_GATED_CALCULATOR`), not a redeploy.
22
+ */
23
+ export declare function checkCalculatorDomain(client: Pick<PublicClient, 'readContract'>, calculator: `0x${string}`): Promise<CalculatorDomain>;
7
24
  export interface SecureConfig {
8
25
  chainId: number;
9
26
  signerPrivateKey: string;
@@ -1 +1 @@
1
- {"version":3,"file":"secure.d.ts","sourceRoot":"","sources":["../../src/chain/secure.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,YAAY,EAAE,MAAM,MAAM,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAelD,gFAAgF;AAChF,eAAO,MAAM,mBAAmB,2CAA2C,CAAC;AAE5E,0GAA0G;AAC1G,eAAO,MAAM,qBAAqB,eAAsC,CAAC;AASzE,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,KAAK,MAAM,EAAE,CAAC;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,eAAe,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;IAChC,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;CAC1B;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBlG;AAED;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAC7B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,KAAK,MAAM,EAAE,CAAA;CAAE,GACvC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAElC;;;;;;;;;;;;GAYG;AACH,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,EAC1C,MAAM,EAAE;IAAE,eAAe,EAAE,KAAK,MAAM,EAAE,CAAC;IAAC,oBAAoB,EAAE,KAAK,MAAM,EAAE,CAAA;CAAE,GAC9E,OAAO,CAAC,qBAAqB,CAAC,CAmDhC"}
1
+ {"version":3,"file":"secure.d.ts","sourceRoot":"","sources":["../../src/chain/secure.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,YAAY,EAAE,MAAM,MAAM,CAAC;AAErE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAelD,gFAAgF;AAChF,eAAO,MAAM,mBAAmB,2CAA2C,CAAC;AAE5E,0GAA0G;AAC1G,eAAO,MAAM,qBAAqB,eAAsC,CAAC;AAsBzE,uFAAuF;AACvF,MAAM,MAAM,gBAAgB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3G;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,EAC1C,UAAU,EAAE,KAAK,MAAM,EAAE,GACxB,OAAO,CAAC,gBAAgB,CAAC,CAoB3B;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,KAAK,MAAM,EAAE,CAAC;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,eAAe,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;IAChC,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;CAC1B;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA4BlG;AAED;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAC7B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,KAAK,MAAM,EAAE,CAAA;CAAE,GACvC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAElC;;;;;;;;;;;;GAYG;AACH,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,EAC1C,MAAM,EAAE;IAAE,eAAe,EAAE,KAAK,MAAM,EAAE,CAAC;IAAC,oBAAoB,EAAE,KAAK,MAAM,EAAE,CAAA;CAAE,GAC9E,OAAO,CAAC,qBAAqB,CAAC,CAmDhC"}
@@ -1,4 +1,5 @@
1
1
  import { keccak256, parseAbi, toHex } from 'viem';
2
+ import { spendAuthorisationTypedData } from '@flayerlabs/gamemode-spec/embed';
2
3
  /**
3
4
  * The boot-time refusals {@link PayloadSigner}'s doc comment promises.
4
5
  *
@@ -19,7 +20,43 @@ const wiringAbi = parseAbi([
19
20
  'function registeredCalculators(address) view returns (bool)',
20
21
  'function hasRole(bytes32 role, address account) view returns (bool)',
21
22
  'function approvedRouters(address) view returns (bool)',
23
+ 'function eip712Domain() view returns (bytes1 fields, string name, string version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] extensions)',
22
24
  ]);
25
+ /**
26
+ * The EIP-712 domain this gate signs under, read off the typed-data builder so the two can never
27
+ * disagree. A calculator whose on-chain domain differs (the version-1 generation, say) rejects every
28
+ * authorisation this gate mints as `InvalidSigner` — at claim time, in a round that will not come
29
+ * back — so boot refuses it here instead.
30
+ */
31
+ const SIGNING_DOMAIN = spendAuthorisationTypedData({ buyer: `0x${'00'.repeat(20)}`, poolId: `0x${'00'.repeat(32)}`, deadline: 0n, spendCeilingWei: 0n }, 1, `0x${'00'.repeat(20)}`).domain;
32
+ /**
33
+ * Does this calculator verify signatures under the domain this gate signs?
34
+ *
35
+ * Reads `eip712Domain()` (EIP-5267) and compares name and version with the typed data the gate's
36
+ * signer produces. Same shape as {@link checkPositionManagerWiring}: a verdict with a reason the
37
+ * operator can act on, because the fix is one env var (`SPEND_GATED_CALCULATOR`), not a redeploy.
38
+ */
39
+ export async function checkCalculatorDomain(client, calculator) {
40
+ let name;
41
+ let version;
42
+ try {
43
+ const domain = (await client.readContract({ address: calculator, abi: wiringAbi, functionName: 'eip712Domain' }));
44
+ name = String(domain[1]);
45
+ version = String(domain[2]);
46
+ }
47
+ catch {
48
+ return { ok: false, reason: `${calculator} does not answer eip712Domain() — is it a SpendGatedSignerFeeCalculator?` };
49
+ }
50
+ if (name !== SIGNING_DOMAIN.name || version !== SIGNING_DOMAIN.version) {
51
+ return {
52
+ ok: false,
53
+ reason: `SPEND_GATED_CALCULATOR ${calculator} verifies "${name}" version ${version}, but this gate signs ` +
54
+ `"${SIGNING_DOMAIN.name}" version ${SIGNING_DOMAIN.version}; every authorisation it minted would be refused as ` +
55
+ 'InvalidSigner. Point SPEND_GATED_CALCULATOR at the calculator generation this SDK pairs with',
56
+ };
57
+ }
58
+ return { ok: true, name, version };
59
+ }
23
60
  export async function assertSecureConfig(client, config) {
24
61
  const key = config.signerPrivateKey.toLowerCase();
25
62
  if (key === DEMO_SIGNING_KEY || key === ZERO_KEY) {
@@ -41,6 +78,9 @@ export async function assertSecureConfig(client, config) {
41
78
  if (!code || code === '0x') {
42
79
  throw new Error(`SPEND_GATED_CALCULATOR ${config.spendGatedCalculator} holds no code on chain ${chainId}`);
43
80
  }
81
+ const domain = await checkCalculatorDomain(client, config.spendGatedCalculator);
82
+ if (!domain.ok)
83
+ throw new Error(domain.reason);
44
84
  if (config.positionManager)
45
85
  await assertWiring(client, config);
46
86
  }
@@ -1 +1 @@
1
- {"version":3,"file":"secure.js","sourceRoot":"","sources":["../../src/chain/secure.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"secure.js","sourceRoot":"","sources":["../../src/chain/secure.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,8 +1,12 @@
1
1
  /** Public server-side surface for a production Game Mode gate. */
2
- export { Claims, DEFAULT_SETTLEMENT_TAIL_MS, Room, Sessions, createGate, createGameServerGate, } from './server.js';
3
- export type { Admission, AdmissionRequest, Admit, AnnouncedSpendToken, ConfigForLaunch, GameServerGateOptions, GateOptions, MaxPointsForLaunch, PriceFor, VerifiedLaunch, } from './server.js';
4
- export { createTurnstileAdmit } from './turnstile.js';
5
- export type { TurnstileAdmitOptions } from './turnstile.js';
2
+ export { Claims, DEFAULT_SETTLEMENT_TAIL_MS, MAX_TRUSTED_PROXY_HOPS, Room, Sessions, createGate, createGameServerGate, } from './server.js';
3
+ export type { Admission, AdmissionAnnouncement, AdmissionRequest, Admit, AnnouncedSpendToken, ConfigForLaunch, GameServerGateOptions, GateOptions, MaxPointsForLaunch, PriceFor, VerifiedLaunch, } from './server.js';
4
+ export { DEFAULT_RATE_LIMITS, composeAdmit, createIpReputationAdmit, createRateLimitAdmit, ipinfoPrivacyLookup, } from './admission.js';
5
+ export type { CheckpointLimits, IpLookup, IpReputationAdmitOptions, IpVerdict, IpinfoPrivacyOptions, Rate, RateLimitAdmitOptions, RateLimits, } from './admission.js';
6
+ export { IpBlocks, MAX_IP_BLOCKS } from './ip-blocks.js';
7
+ export type { IpBlock, IpBlockRefusal, IpBlockResult } from './ip-blocks.js';
8
+ export { createTurnstileAdmit, isTurnstileTestingSecret, resolveTurnstileEnv, turnstileAdmission } from './turnstile.js';
9
+ export type { TurnstileAdmitOptions, TurnstileConfig } from './turnstile.js';
6
10
  export { Ledger } from './ledger.js';
7
11
  export type { Authorisation, Quote } from './ledger.js';
8
12
  export { PayloadSigner, encodeHookData } from './chain/signer.js';
@@ -22,6 +26,8 @@ export { createGameRegistry } from './game-registry.js';
22
26
  export type { GameRegistryOptions } from './game-registry.js';
23
27
  export type { GameServerAwardReceipt, GameServerAwardRefusal, GameServerAwardRequest, GameServerPlayerRefusal, GameServerPlayerResult, GameServerPlayerStanding, } from './game-server-awards.js';
24
28
  export { PLAYER_JOIN_TICKET_TTL_MS, verifyPlayerJoinTicket } from './player-join-tickets.js';
29
+ export { DEFAULT_MAX_JOIN_TICKETS_PER_MINUTE } from './join-ticket-ledger.js';
30
+ export type { JoinTicketConsumeRefusal, JoinTicketConsumption, JoinTicketCounts, JoinTicketIssueRefusal, JoinTicketPolicy, JoinTicketRecord, JoinTicketReleaseSelector, JoinTicketStatus, } from './join-ticket-ledger.js';
25
31
  export type { VerifiedPlayerJoin, VerifyPlayerJoinTicketOptions } from './player-join-tickets.js';
26
32
  /**
27
33
  * The deployment story: {@link startGate} turns a rules module and an environment into a running
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,OAAO,EACL,MAAM,EACN,0BAA0B,EAC1B,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,oBAAoB,GACrB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,SAAS,EACT,gBAAgB,EAChB,KAAK,EACL,mBAAmB,EACnB,eAAe,EACf,qBAAqB,EACrB,WAAW,EACX,kBAAkB,EAClB,QAAQ,EACR,cAAc,GACf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,YAAY,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAE5D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAClE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,sBAAsB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC7G,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvH,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC3E,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,uBAAuB,EACvB,UAAU,EACV,mBAAmB,EACnB,uBAAuB,EACvB,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,YAAY,EACV,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAC7F,YAAY,EAAE,kBAAkB,EAAE,6BAA6B,EAAE,MAAM,0BAA0B,CAAC;AAElG;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACtD,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACxG,YAAY,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACnG,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACnF,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAC1G,YAAY,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC5F,YAAY,EAAE,eAAe,EAAE,qBAAqB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAExH,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,YAAY,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  /** Public server-side surface for a production Game Mode gate. */
2
- export { Claims, DEFAULT_SETTLEMENT_TAIL_MS, Room, Sessions, createGate, createGameServerGate, } from './server.js';
3
- export { createTurnstileAdmit } from './turnstile.js';
2
+ export { Claims, DEFAULT_SETTLEMENT_TAIL_MS, MAX_TRUSTED_PROXY_HOPS, Room, Sessions, createGate, createGameServerGate, } from './server.js';
3
+ export { DEFAULT_RATE_LIMITS, composeAdmit, createIpReputationAdmit, createRateLimitAdmit, ipinfoPrivacyLookup, } from './admission.js';
4
+ export { IpBlocks, MAX_IP_BLOCKS } from './ip-blocks.js';
5
+ export { createTurnstileAdmit, isTurnstileTestingSecret, resolveTurnstileEnv, turnstileAdmission } from './turnstile.js';
4
6
  export { Ledger } from './ledger.js';
5
7
  export { PayloadSigner, encodeHookData } from './chain/signer.js';
6
8
  export { Discovery, WiringCache, poolIdOf, resolvePositionManager, verifyLaunch } from './chain/discover.js';
@@ -12,6 +14,7 @@ export { createDemoGate } from './demo.js';
12
14
  export { InvalidRegistration, RegistrationConflict, checkRegistration, disableGameRegistration, gateOrigin, pinGameRegistration, resolveGameRegistration, securityProfile, } from './registry.js';
13
15
  export { createGameRegistry } from './game-registry.js';
14
16
  export { PLAYER_JOIN_TICKET_TTL_MS, verifyPlayerJoinTicket } from './player-join-tickets.js';
17
+ export { DEFAULT_MAX_JOIN_TICKETS_PER_MINUTE } from './join-ticket-ledger.js';
15
18
  /**
16
19
  * The deployment story: {@link startGate} turns a rules module and an environment into a running
17
20
  * gate (see DEPLOY.md), and the pieces below it stay exported for anyone wiring their own.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,OAAO,EACL,MAAM,EACN,0BAA0B,EAC1B,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,oBAAoB,GACrB,MAAM,aAAa,CAAC;AAarB,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAGtD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAElE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,sBAAsB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAE7G,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE3E,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,uBAAuB,EACvB,UAAU,EACV,mBAAmB,EACnB,uBAAuB,EACvB,eAAe,GAChB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAUxD,OAAO,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAG7F;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGtD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEnF,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAE1G,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG5F,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,OAAO,EACL,MAAM,EACN,0BAA0B,EAC1B,sBAAsB,EACtB,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,oBAAoB,GACrB,MAAM,aAAa,CAAC;AAcrB,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,uBAAuB,EACvB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAWxB,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEzD,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGzH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAElE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,sBAAsB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAE7G,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE3E,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,uBAAuB,EACvB,UAAU,EACV,mBAAmB,EACnB,uBAAuB,EACvB,eAAe,GAChB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAUxD,OAAO,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAC7F,OAAO,EAAE,mCAAmC,EAAE,MAAM,yBAAyB,CAAC;AAa9E;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGtD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEnF,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAE1G,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG5F,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,50 @@
1
+ import type { Pool } from 'pg';
2
+ /** A list longer than this is a job for a firewall in front of the gate, not a table inside it. */
3
+ export declare const MAX_IP_BLOCKS = 10000;
4
+ export interface IpBlock {
5
+ /** Canonical network, such as `203.0.113.0/24` or `2001:db8::/32`. A single address is a /32 or /128. */
6
+ cidr: string;
7
+ /** An operator's note. Never shown to the player. */
8
+ reason: string | null;
9
+ createdAt: number;
10
+ /** Milliseconds, or null for a block that stays until it is removed. */
11
+ expiresAt: number | null;
12
+ }
13
+ export type IpBlockRefusal = 'ip_block.invalid' | 'ip_block.limit_exceeded';
14
+ export type IpBlockResult = {
15
+ ok: true;
16
+ block: IpBlock;
17
+ } | {
18
+ ok: false;
19
+ refuse: IpBlockRefusal;
20
+ };
21
+ /**
22
+ * Addresses and networks this gate refuses, kept in Postgres and matched in memory.
23
+ *
24
+ * The table is the record; the in-memory list is what a request is checked against, because an
25
+ * admission check runs on every action and a query per action is not affordable. The list is
26
+ * rebuilt after every write through this instance and at most every `refreshMs` otherwise, so a
27
+ * block written by another process takes effect within that interval.
28
+ */
29
+ export declare class IpBlocks {
30
+ private readonly pool;
31
+ private readonly refreshMs;
32
+ private matcher;
33
+ private loadedAt;
34
+ private loading;
35
+ constructor(pool: Pool, refreshMs?: number);
36
+ /** Whether an address is blocked. Loads the list on first use and refreshes it when stale. */
37
+ blocks(ip: string | null, now?: number): Promise<boolean>;
38
+ /** Block an address or network. Blocking it again updates the reason and expiry. */
39
+ add(input: {
40
+ cidr?: unknown;
41
+ reason?: unknown;
42
+ expiresAt?: unknown;
43
+ }, now?: number): Promise<IpBlockResult>;
44
+ /** Remove a block. True if there was one. */
45
+ remove(cidr: unknown, now?: number): Promise<boolean | null>;
46
+ /** Every block still in force, newest first. */
47
+ list(now?: number): Promise<IpBlock[]>;
48
+ private reload;
49
+ }
50
+ //# sourceMappingURL=ip-blocks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ip-blocks.d.ts","sourceRoot":"","sources":["../src/ip-blocks.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAG/B,mGAAmG;AACnG,eAAO,MAAM,aAAa,QAAS,CAAC;AAIpC,MAAM,WAAW,OAAO;IACtB,yGAAyG;IACzG,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,MAAM,cAAc,GAAG,kBAAkB,GAAG,yBAAyB,CAAC;AAE5E,MAAM,MAAM,aAAa,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,cAAc,CAAA;CAAE,CAAC;AAgCjG;;;;;;;GAOG;AACH,qBAAa,QAAQ;IAMjB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAN5B,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,OAAO,CAA8B;gBAG1B,IAAI,EAAE,IAAI,EACV,SAAS,SAAqB;IAGjD,8FAA8F;IACxF,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,SAAa,GAAG,OAAO,CAAC,OAAO,CAAC;IAWnE,oFAAoF;IAC9E,GAAG,CAAC,KAAK,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,GAAG,SAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IA0BrH,6CAA6C;IACvC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,SAAa,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAWtE,gDAAgD;IAC1C,IAAI,CAAC,GAAG,SAAa,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAUhD,OAAO,CAAC,MAAM;CAoBf"}