diff --git a/build/flecks.yml b/build/flecks.yml index 9e5bcd3..fbb821c 100644 --- a/build/flecks.yml +++ b/build/flecks.yml @@ -15,7 +15,6 @@ - '($1#L$2)' '@flecks/electron:./packages/electron': {} '@flecks/fleck:./packages/fleck': {} -'@flecks/governor:./packages/governor': {} '@flecks/passport:./packages/passport': {} '@flecks/passport-local:./packages/passport-local': {} '@flecks/passport-local-react:./packages/passport-local-react': {} diff --git a/packages/governor/.gitignore b/packages/governor/.gitignore deleted file mode 100644 index 1f22b9c..0000000 --- a/packages/governor/.gitignore +++ /dev/null @@ -1,116 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next -out - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -# yarn v2 -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* diff --git a/packages/governor/CHANGELOG.md b/packages/governor/CHANGELOG.md deleted file mode 100644 index 18f0441..0000000 --- a/packages/governor/CHANGELOG.md +++ /dev/null @@ -1,139 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [3.1.3](https://github.com/cha0s/flecks/compare/v3.1.1...v3.1.3) (2024-01-26) - -**Note:** Version bump only for package @flecks/governor - - - - - -## [3.1.1](https://github.com/cha0s/flecks/compare/v3.1.0...v3.1.1) (2024-01-26) - -**Note:** Version bump only for package @flecks/governor - - - - - -# [3.1.0](https://github.com/cha0s/flecks/compare/v1.4.1...v3.1.0) (2024-01-26) - - -### Bug Fixes - -* lint ([675aaad](https://github.com/cha0s/flecks/commit/675aaadaedd539ebbef9ab0ace9e9ae8832d1e08)) -* priority ([841c2fa](https://github.com/cha0s/flecks/commit/841c2faaa14a9385fa18a846e36a4770fc025166)) - - -### Features - -* **fleck:** ProcessAssets ([84a30df](https://github.com/cha0s/flecks/commit/84a30df67ab0c8b5c34bb61657f6103775839e82)) -* webpack 5 ([f039f7b](https://github.com/cha0s/flecks/commit/f039f7b8f69b3c8b9564714890b2fe2d4cd8a22d)) - - - - - -## [2.0.3](https://github.com/cha0s/flecks/compare/v2.0.2...v2.0.3) (2023-11-22) - - -### Bug Fixes - -* electron ([81fc978](https://github.com/cha0s/flecks/commit/81fc978da2b8d32e303d165fe7c2f6071ac8e741)) - - - - - -## [2.0.2](https://github.com/cha0s/flecks/compare/v2.0.1...v2.0.2) (2023-11-22) - -**Note:** Version bump only for package @flecks/governor - - - - - -## [2.0.1](https://github.com/cha0s/flecks/compare/v2.0.0...v2.0.1) (2023-11-22) - -**Note:** Version bump only for package @flecks/governor - - - - - -# [2.0.0](https://github.com/cha0s/flecks/compare/v1.4.1...v2.0.0) (2023-11-22) - - -### Features - -* webpack 5 support ([288b368](https://github.com/cha0s/flecks/commit/288b368b9ff96be5ccb58bd811838a4a4bb6c48c)) - - - - - -## [1.4.1](https://github.com/cha0s/flecks/compare/v1.4.0...v1.4.1) (2022-03-19) - -**Note:** Version bump only for package @flecks/governor - - - - - -# [1.4.0](https://github.com/cha0s/flecks/compare/v1.3.0...v1.4.0) (2022-03-19) - -**Note:** Version bump only for package @flecks/governor - - - - - -# [1.3.0](https://github.com/cha0s/flecks/compare/v1.2.1...v1.3.0) (2022-03-09) - -**Note:** Version bump only for package @flecks/governor - - - - - -## [1.2.1](https://github.com/cha0s/flecks/compare/v1.2.0...v1.2.1) (2022-03-08) - -**Note:** Version bump only for package @flecks/governor - - - - - -# [1.2.0](https://github.com/cha0s/flecks/compare/v1.1.1...v1.2.0) (2022-03-07) - - -### Bug Fixes - -* old redis ([0a8c66a](https://github.com/cha0s/flecks/commit/0a8c66ad7d6da5d63563c40c509f5a165146d7be)) - - - - - -## [1.1.1](https://github.com/cha0s/flecks/compare/v1.1.0...v1.1.1) (2022-02-28) - -**Note:** Version bump only for package @flecks/governor - - - - - -# [1.1.0](https://github.com/cha0s/flecks/compare/v1.0.2...v1.1.0) (2022-02-28) - -**Note:** Version bump only for package @flecks/governor - - - - - -## [1.0.2](https://github.com/cha0s/flecks/compare/v1.0.1...v1.0.2) (2022-02-28) - -**Note:** Version bump only for package @flecks/governor diff --git a/packages/governor/package.json b/packages/governor/package.json deleted file mode 100644 index 99b23f9..0000000 --- a/packages/governor/package.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "@flecks/governor", - "version": "3.1.3", - "author": "cha0s", - "license": "MIT", - "scripts": { - "build": "flecks build", - "clean": "flecks clean", - "lint": "flecks lint", - "postversion": "npm run build", - "test": "flecks test" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/cha0s/flecks.git", - "directory": "packages/governor" - }, - "publishConfig": { - "access": "public" - }, - "files": [ - "client.js", - "server.js" - ], - "dependencies": { - "@flecks/core": "^3.1.0", - "@flecks/db": "^3.1.3", - "@flecks/redis": "^3.1.3", - "rate-limiter-flexible": "^2.1.13" - }, - "devDependencies": { - "@flecks/build": "^3.1.3", - "@flecks/fleck": "^3.1.3" - } -} diff --git a/packages/governor/src/client/index.js b/packages/governor/src/client/index.js deleted file mode 100644 index 975046a..0000000 --- a/packages/governor/src/client/index.js +++ /dev/null @@ -1,2 +0,0 @@ -// eslint-disable-next-line import/prefer-default-export -export {default as createLimiter} from './limiter'; diff --git a/packages/governor/src/client/limiter.js b/packages/governor/src/client/limiter.js deleted file mode 100644 index 7bfb822..0000000 --- a/packages/governor/src/client/limiter.js +++ /dev/null @@ -1,3 +0,0 @@ -import RateLimiterMemory from 'rate-limiter-flexible/lib/RateLimiterMemory'; - -export default (flecks, options) => new RateLimiterMemory(options); diff --git a/packages/governor/src/limited-packet.js b/packages/governor/src/limited-packet.js deleted file mode 100644 index c6dad33..0000000 --- a/packages/governor/src/limited-packet.js +++ /dev/null @@ -1,29 +0,0 @@ -export default (flecks, [name, Packet]) => { - const {ValidationError} = flecks.fleck('@flecks/socket'); - return class LimitedPacket extends Packet { - - constructor(...args) { - super(...args); - this.limit = flecks.governor.packet[name]; - } - - static async validate(packet, socket) { - try { - await packet.limit.consume(socket.id); - } - catch (error) { - if (error.msBeforeNext) { - throw new ValidationError({ - code: 429, - ttr: Math.round(error.msBeforeNext / 1000) || 1, - }); - } - throw error; - } - if (super.validate) { - await super.validate(packet, socket); - } - } - - }; -}; diff --git a/packages/governor/src/limiter.js b/packages/governor/src/limiter.js deleted file mode 100644 index a9756c6..0000000 --- a/packages/governor/src/limiter.js +++ /dev/null @@ -1,13 +0,0 @@ -import {createClient} from '@flecks/redis/server'; -import {RateLimiterRedis} from 'rate-limiter-flexible'; - -export default async (flecks, options) => { - const storeClient = await createClient(flecks); - const legacyClient = storeClient.duplicate({legacyMode: true}); - await legacyClient.connect(); - return new RateLimiterRedis({ - ...options, - // @todo node-redis@4 - storeClient: legacyClient, - }); -}; diff --git a/packages/governor/src/models/ban.js b/packages/governor/src/models/ban.js deleted file mode 100644 index 33eccfc..0000000 --- a/packages/governor/src/models/ban.js +++ /dev/null @@ -1,72 +0,0 @@ -export default (flecks) => { - const {Model, Op, Types} = flecks.fleck('@flecks/db/server'); - const {config: {'@flecks/governor/server': {keys}}} = flecks; - return class Ban extends Model { - - static get attributes() { - return { - ttl: { - type: Types.INTEGER, - defaultValue: 0, - }, - ...Object.fromEntries(keys.map((key) => ([key, {type: Types.STRING}]))), - }; - } - - static async check(req) { - const ban = this.fromRequest(req, keys); - const candidates = Object.entries(ban) - .reduce((r, [key, value]) => [...r, {[key]: value}], []); - const where = { - where: { - [Op.or]: candidates, - }, - }; - const bans = await this.findAll(where); - const pruned = bans - .reduce((r, ban) => { - if (ban && ban.ttl > 0) { - const expiresAt = new Date(ban.createdAt); - expiresAt.setSeconds(expiresAt.getSeconds() + ban.ttl); - if (Date.now() >= expiresAt.getTime()) { - this.destroy({where: {id: ban.id}}); - return [...r, null]; - } - ban.ttl = Math.ceil((expiresAt.getTime() - Date.now()) / 1000); - } - return [...r, ban]; - }, []) - .filter((ban) => !!ban) - .map((ban) => { - const {ttl, ...json} = ban.toJSON(); - return json; - }); - if (0 === pruned.length) { - return; - } - throw new Error(this.format(pruned)); - } - - static format(bans) { - return [ - 'bans = [', - bans.map((ban) => { - const entries = Object.entries(ban) - .filter(([key]) => -1 === ['id', 'createdAt', 'updatedAt'].indexOf(key)); - return [ - ' {', - entries.map(([key, value]) => ` ${key}: ${value},`).join('\n'), - ' },', - ].join('\n'); - }).join('\n'), - '];', - ].join('\n'); - } - - static fromRequest(req, keys, ttl = 0) { - return keys.reduce((r, key) => ({...r, [key]: req[key]}), ttl ? {ttl} : {}); - } - - }; - -}; diff --git a/packages/governor/src/server.js b/packages/governor/src/server.js deleted file mode 100644 index ea5651b..0000000 --- a/packages/governor/src/server.js +++ /dev/null @@ -1,146 +0,0 @@ -import {ByType, Flecks} from '@flecks/core'; -import {RateLimiterRes} from 'rate-limiter-flexible'; - -import LimitedPacket from './limited-packet'; -import createLimiter from './limiter'; - -export {default as createLimiter} from './limiter'; - -export const hooks = { - '@flecks/core.config': () => ({ - /** - * All keys used to determine fingerprint. - */ - keys: ['ip'], - web: { - keys: ['ip'], - points: 60, - duration: 30, - ttl: 30, - }, - socket: { - keys: ['ip'], - points: 60, - duration: 30, - ttl: 30, - }, - }), - '@flecks/db.models': Flecks.provide(require.context('./models', false, /\.js$/)), - '@flecks/web/server.request.route': Flecks.priority( - (flecks) => { - const {web} = flecks.get('@flecks/governor/server'); - return async (req, res, next) => { - const {Ban} = flecks.db.Models; - try { - await Ban.check(req); - } - catch (error) { - res.status(403).send(`
${error.message}`); - return; - } - req.ban = async (keys, ttl = 0) => { - const ban = Ban.fromRequest(req, keys, ttl); - await Ban.create({...ban}); - res.status(403).send(`
${Ban.format([ban])}`); - }; - try { - await flecks.governor.web.consume(req.ip); - next(); - } - catch (error) { - if (!(error instanceof RateLimiterRes)) { - throw error; - } - const {ttl, keys} = web; - const ban = Ban.fromRequest(req, keys, ttl); - await Ban.create({...ban}); - res.status(429).send(`
${Ban.format([ban])}`); - } - }; - }, - {after: '@flecks/passport/server'}, - ), - '@flecks/server.up': Flecks.priority( - async (flecks) => { - if (flecks.fleck('@flecks/web/server')) { - const {web} = flecks.get('@flecks/governor/server'); - flecks.governor.web = await createLimiter( - flecks, - { - keyPrefix: '@flecks/governor.web.request.route', - ...web, - }, - ); - } - if (flecks.fleck('@flecks/socket/server')) { - flecks.governor.packet = Object.fromEntries( - await Promise.all( - Object.entries(flecks.socket.Packets[ByType]) - .filter(([, Packet]) => Packet.limit) - .map(async ([name, Packet]) => ( - [ - name, - await createLimiter( - flecks, - {keyPrefix: `@flecks/governor.packet.${name}`, ...Packet.limit}, - ), - ] - )), - ), - ); - const {socket} = flecks.get('@flecks/governor/server'); - flecks.governor.socket = await createLimiter( - flecks, - { - keyPrefix: '@flecks/governor.socket.request.socket', - ...socket, - }, - ); - } - }, - {before: '@flecks/web/server', after: '@flecks/redis/server'}, - ), - '@flecks/socket/server.request.socket': (flecks) => ( - async (socket, next) => { - const {handshake: req} = socket; - const {Ban} = flecks.db.Models; - try { - await Ban.check(req); - } - catch (error) { - next(error); - return; - } - req.ban = async (keys, ttl) => { - await Ban.create(Ban.fromRequest(req, keys, ttl)); - socket.disconnect(); - }; - try { - await flecks.governor.socket.consume(req.ip); - next(); - } - catch (error) { - if (!(error instanceof RateLimiterRes)) { - throw error; - } - const {ttl, keys} = socket; - await Ban.create(Ban.fromRequest(req, keys, ttl)); - next(error); - } - } - ), - '@flecks/socket.packets.decorate': (Packets, flecks) => ( - Object.fromEntries( - Object.entries(Packets).map(([keyPrefix, Packet]) => [ - keyPrefix, - !Packet.limit ? Packet : LimitedPacket(flecks, [keyPrefix, Packet]), - ]), - ) - ), -}; - -export const mixin = (Flecks) => class FlecksWithGovernor extends Flecks { - - governor = {}; - -}; diff --git a/packages/passport/src/server/index.js b/packages/passport/src/server/index.js index 501644c..79cf22b 100644 --- a/packages/passport/src/server/index.js +++ b/packages/passport/src/server/index.js @@ -82,7 +82,7 @@ export const hooks = { }); }); }, - {after: '@flecks/session/server', before: '@flecks/governor/server'}, + {after: '@flecks/session/server'}, ), '@flecks/web.routes': (flecks) => { const {