diff --git a/package-lock.json b/package-lock.json index 72e31ab..afb9d8f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "@types/react": "^18.2.25", "@types/react-dom": "^18.2.10", "concurrently": "^8.2.2", + "express-rate-limit": "^7.4.0", "highcharts": "^11.1.0", "highcharts-react-official": "^3.2.1", "http-proxy-middleware": "^2.0.6", @@ -8480,6 +8481,20 @@ "node": ">= 0.10.0" } }, + "node_modules/express-rate-limit": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.4.0.tgz", + "integrity": "sha512-v1204w3cXu5gCDmAvgvzI6qjzZzoMWKnyVDk3ACgfswTQLYiGen+r8w0VnXnGMmzEN/g8fwIQ4JrFFd4ZP6ssg==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": "4 || 5 || ^5.0.0-beta.1" + } + }, "node_modules/express/node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", diff --git a/package.json b/package.json index b05aedd..b8fa21d 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "@types/react": "^18.2.25", "@types/react-dom": "^18.2.10", "concurrently": "^8.2.2", + "express-rate-limit": "^7.4.0", "highcharts": "^11.1.0", "highcharts-react-official": "^3.2.1", "http-proxy-middleware": "^2.0.6", diff --git a/server/server.ts b/server/server.ts index cd651ed..5b4ca52 100644 --- a/server/server.ts +++ b/server/server.ts @@ -22,7 +22,7 @@ import Pool from "./schemes/Pool"; import Asset, { IAsset } from "./schemes/Asset"; import { ITransaction } from "./schemes/Transaction"; import BigNumber from "bignumber.js"; - +import { rateLimit } from 'express-rate-limit'; // @ts-ignore const __dirname = import.meta.dirname; @@ -31,6 +31,14 @@ const app = express(); const server = http.createServer(app); export const io = new Server(server, { transports: ['websocket', 'polling'] }); + +const requestsLimiter = rateLimit({ + windowMs: 10 * 1000, + limit: 1, + standardHeaders: 'draft-7', + legacyHeaders: false, +}); + (async () => { await initDB(); await sequelize.authenticate(); @@ -55,6 +63,39 @@ export const io = new Server(server, { transports: ['websocket', 'polling'] }); }) app.use(express.static(path.resolve(__dirname, "../build/"))); + app.use([ + "/api/find_outs_in_recent_blocks" + ], requestsLimiter); + + app.get('/api/find_outs_in_recent_blocks', exceptionHandler(async (req, res) => { + const address = req.query.address; + const viewkey = req.query.viewkey; + const limit = req.query.limit || 5; + + + if (!address) { + return res.status(400).json({ error: 'Address is required' }); + } + + if (!viewkey) { + return res.status(400).json({ error: 'Viewkey is required' }); + } + + const response = await axios({ + method: 'get', + url: config.api, + data: { + method: 'getinfo', + params: { + "address": address, + "viewkey": viewkey, + "blocks_limit": limit + } + } + }) + res.json(response.data) + })); + app.get( '/api/get_info/:flags', exceptionHandler(async (req, res) => {