From 8441ff97953bea6827caa740ce585386b8ea8776 Mon Sep 17 00:00:00 2001 From: AP Date: Tue, 10 Dec 2019 20:16:46 +0100 Subject: [PATCH] chore: refactor rate limit --- src/helpers/rateLimiter.ts | 37 +++++++++---------- .../mutations/channels/closeChannel.ts | 3 +- src/schemas/mutations/channels/openChannel.ts | 3 +- .../mutations/invoices/createInvoice.ts | 3 +- src/schemas/mutations/invoices/decode.ts | 3 +- .../mutations/invoices/parsePayment.ts | 3 +- src/schemas/mutations/invoices/pay.ts | 3 +- src/schemas/mutations/onchain/getAddress.ts | 3 +- .../mutations/onchain/sendToAddress.ts | 3 +- src/schemas/query/channels/channelBalance.ts | 2 +- src/schemas/query/channels/channels.ts | 2 +- src/schemas/query/channels/closedChannels.ts | 3 +- src/schemas/query/channels/pendingChannels.ts | 2 +- src/schemas/query/data/bitcoinFee.ts | 2 +- src/schemas/query/flow/getInOut.ts | 2 +- src/schemas/query/general/chainBalance.ts | 10 +---- src/schemas/query/general/networkInfo.ts | 2 +- src/schemas/query/general/nodeInfo.ts | 2 +- src/schemas/query/invoices/forwards.ts | 3 +- src/schemas/query/invoices/invoices.ts | 2 +- src/schemas/query/invoices/payments.ts | 2 +- src/schemas/query/report/ForwardChannels.ts | 8 +--- src/schemas/query/report/ForwardReport.ts | 2 +- src/utils/rateLimitConfig.ts | 35 ++++++++++++++++++ 24 files changed, 85 insertions(+), 55 deletions(-) create mode 100644 src/utils/rateLimitConfig.ts diff --git a/src/helpers/rateLimiter.ts b/src/helpers/rateLimiter.ts index 248b5c42..e8d060ac 100644 --- a/src/helpers/rateLimiter.ts +++ b/src/helpers/rateLimiter.ts @@ -1,25 +1,22 @@ -import { getGraphQLRateLimiter } from "graphql-rate-limit"; +import { getGraphQLRateLimiter } from 'graphql-rate-limit'; +import { RateConfig } from '../utils/rateLimitConfig'; const rateLimiter = getGraphQLRateLimiter({ - identifyContext: (ctx: string) => ctx, - formatError: () => "rateLimitReached" + identifyContext: (ctx: string) => ctx, + formatError: () => 'Rate Limit Reached', }); -export const requestLimiter = async ( - root: string, - params: any, - field: string, - max: number, - window: string -) => { - const errorMessage = await rateLimiter( - { - parent: root, - args: params, - context: root, - info: { fieldName: field } as any - }, - { max, window } - ); - if (errorMessage) throw new Error(errorMessage); +export const requestLimiter = async (rate: string, field: string) => { + if (!RateConfig[field]) throw new Error('Invalid Rate Field'); + const { max, window } = RateConfig[field]; + const errorMessage = await rateLimiter( + { + parent: rate, + args: {}, + context: rate, + info: { fieldName: field } as any, + }, + { max, window }, + ); + if (errorMessage) throw new Error(errorMessage); }; diff --git a/src/schemas/mutations/channels/closeChannel.ts b/src/schemas/mutations/channels/closeChannel.ts index fe5bb8ff..b5241c36 100644 --- a/src/schemas/mutations/channels/closeChannel.ts +++ b/src/schemas/mutations/channels/closeChannel.ts @@ -25,7 +25,8 @@ export const closeChannel = { auth: { type: new GraphQLNonNull(GraphQLString) }, }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter(context.ip, params, 'closeChannel', 1, '1s'); + await requestLimiter(context.ip, 'closeChannel') + const lnd = getAuthLnd(params.auth); try { diff --git a/src/schemas/mutations/channels/openChannel.ts b/src/schemas/mutations/channels/openChannel.ts index a8398025..b6a3f67a 100644 --- a/src/schemas/mutations/channels/openChannel.ts +++ b/src/schemas/mutations/channels/openChannel.ts @@ -24,7 +24,8 @@ export const openChannel = { auth: { type: new GraphQLNonNull(GraphQLString) }, }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter(context.ip, params, 'openChannel', 1, '1s'); + await requestLimiter(context.ip, 'openChannel') + const lnd = getAuthLnd(params.auth); try { diff --git a/src/schemas/mutations/invoices/createInvoice.ts b/src/schemas/mutations/invoices/createInvoice.ts index 174ceaf4..329db516 100644 --- a/src/schemas/mutations/invoices/createInvoice.ts +++ b/src/schemas/mutations/invoices/createInvoice.ts @@ -23,7 +23,8 @@ export const createInvoice = { auth: { type: new GraphQLNonNull(GraphQLString) }, }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter(context.ip, params, 'createInvoice', 1, '1s'); + await requestLimiter(context.ip, 'createInvoice') + const lnd = getAuthLnd(params.auth); try { diff --git a/src/schemas/mutations/invoices/decode.ts b/src/schemas/mutations/invoices/decode.ts index bf5ab489..6c86f7b1 100644 --- a/src/schemas/mutations/invoices/decode.ts +++ b/src/schemas/mutations/invoices/decode.ts @@ -32,7 +32,8 @@ export const decodeRequest = { auth: { type: new GraphQLNonNull(GraphQLString) }, }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter(context.ip, params, 'decodeRequest', 1, '1s'); + await requestLimiter(context.ip, 'decode') + const lnd = getAuthLnd(params.auth); try { diff --git a/src/schemas/mutations/invoices/parsePayment.ts b/src/schemas/mutations/invoices/parsePayment.ts index df935536..2633c312 100644 --- a/src/schemas/mutations/invoices/parsePayment.ts +++ b/src/schemas/mutations/invoices/parsePayment.ts @@ -36,7 +36,8 @@ export const parsePayment = { auth: { type: new GraphQLNonNull(GraphQLString) }, }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter(context.ip, params, 'parsePayment', 1, '1s'); + await requestLimiter(context.ip, 'parsePayment'); + const lnd = getAuthLnd(params.auth); try { diff --git a/src/schemas/mutations/invoices/pay.ts b/src/schemas/mutations/invoices/pay.ts index ed4fb7fa..5163eb6e 100644 --- a/src/schemas/mutations/invoices/pay.ts +++ b/src/schemas/mutations/invoices/pay.ts @@ -33,7 +33,8 @@ export const pay = { auth: { type: new GraphQLNonNull(GraphQLString) }, }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter(context.ip, params, 'payRequest', 1, '1s'); + await requestLimiter(context.ip, 'pay') + const lnd = getAuthLnd(params.auth); try { diff --git a/src/schemas/mutations/onchain/getAddress.ts b/src/schemas/mutations/onchain/getAddress.ts index f13c71ce..b9c40da0 100644 --- a/src/schemas/mutations/onchain/getAddress.ts +++ b/src/schemas/mutations/onchain/getAddress.ts @@ -15,7 +15,8 @@ export const createAddress = { nested: { type: GraphQLBoolean }, }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter(context.ip, params, 'createAddress', 1, '1s'); + await requestLimiter(context.ip, 'getAddress') + const lnd = getAuthLnd(params.auth); const format = params.nested ? 'np2wpkh' : 'p2wpkh'; diff --git a/src/schemas/mutations/onchain/sendToAddress.ts b/src/schemas/mutations/onchain/sendToAddress.ts index 98acfc71..9a1c2683 100644 --- a/src/schemas/mutations/onchain/sendToAddress.ts +++ b/src/schemas/mutations/onchain/sendToAddress.ts @@ -29,7 +29,8 @@ export const sendToAddress = { sendAll: { type: GraphQLBoolean }, }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter(context.ip, params, 'sendToAddress', 1, '1s'); + await requestLimiter(context.ip, 'sendToAddress') + const lnd = getAuthLnd(params.auth); const props = params.fee diff --git a/src/schemas/query/channels/channelBalance.ts b/src/schemas/query/channels/channelBalance.ts index 4d17655a..36fc4535 100644 --- a/src/schemas/query/channels/channelBalance.ts +++ b/src/schemas/query/channels/channelBalance.ts @@ -14,7 +14,7 @@ export const getChannelBalance = { type: ChannelBalanceType, args: { auth: { type: new GraphQLNonNull(GraphQLString) } }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter(context.ip, params, 'channelBalance', 1, '1s'); + await requestLimiter(context.ip, 'channelBalance'); const lnd = getAuthLnd(params.auth); diff --git a/src/schemas/query/channels/channels.ts b/src/schemas/query/channels/channels.ts index 85d0daba..c970dafb 100644 --- a/src/schemas/query/channels/channels.ts +++ b/src/schemas/query/channels/channels.ts @@ -39,7 +39,7 @@ export const getChannels = { type: new GraphQLList(ChannelType), args: { auth: { type: new GraphQLNonNull(GraphQLString) } }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter(context.ip, params, 'channels', 1, '1s'); + await requestLimiter(context.ip, 'channels'); const lnd = getAuthLnd(params.auth); diff --git a/src/schemas/query/channels/closedChannels.ts b/src/schemas/query/channels/closedChannels.ts index 6c472c9b..e9e13583 100644 --- a/src/schemas/query/channels/closedChannels.ts +++ b/src/schemas/query/channels/closedChannels.ts @@ -60,7 +60,8 @@ export const getClosedChannels = { auth: { type: new GraphQLNonNull(GraphQLString) }, }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter(context.ip, params, 'closedChannels', 1, '1s'); + await requestLimiter(context.ip, 'closedChannels') + const lnd = getAuthLnd(params.auth); try { diff --git a/src/schemas/query/channels/pendingChannels.ts b/src/schemas/query/channels/pendingChannels.ts index 06d551f8..34f94772 100644 --- a/src/schemas/query/channels/pendingChannels.ts +++ b/src/schemas/query/channels/pendingChannels.ts @@ -33,7 +33,7 @@ export const getPendingChannels = { type: new GraphQLList(PendingChannelType), args: { auth: { type: new GraphQLNonNull(GraphQLString) } }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter(context.ip, params, 'pendingChannels', 1, '1s'); + await requestLimiter(context.ip, 'pendingChannels') const lnd = getAuthLnd(params.auth); diff --git a/src/schemas/query/data/bitcoinFee.ts b/src/schemas/query/data/bitcoinFee.ts index 686dfc54..b495b853 100644 --- a/src/schemas/query/data/bitcoinFee.ts +++ b/src/schemas/query/data/bitcoinFee.ts @@ -14,7 +14,7 @@ export const getBitcoinFees = { }, }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter(context.ip, params, 'bitcoinFee', 1, '1s'); + await requestLimiter(context.ip, 'bitcoinFee') try { const response = await fetch(url); diff --git a/src/schemas/query/flow/getInOut.ts b/src/schemas/query/flow/getInOut.ts index 106d6923..b0cfbfcb 100644 --- a/src/schemas/query/flow/getInOut.ts +++ b/src/schemas/query/flow/getInOut.ts @@ -19,7 +19,7 @@ export const getInOut = { time: { type: GraphQLString }, }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter(context.ip, params, 'getInvoices', 1, '1s'); + await requestLimiter(context.ip, 'getInOut'); const lnd = getAuthLnd(params.auth); diff --git a/src/schemas/query/general/chainBalance.ts b/src/schemas/query/general/chainBalance.ts index 2d9595a6..a6ff00dd 100644 --- a/src/schemas/query/general/chainBalance.ts +++ b/src/schemas/query/general/chainBalance.ts @@ -19,7 +19,7 @@ export const getChainBalance = { type: GraphQLInt, args: { auth: { type: new GraphQLNonNull(GraphQLString) } }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter(context.ip, params, 'chainBalance', 1, '1s'); + await requestLimiter(context.ip, 'chainBalance'); const lnd = getAuthLnd(params.auth); @@ -39,13 +39,7 @@ export const getPendingChainBalance = { type: GraphQLInt, args: { auth: { type: new GraphQLNonNull(GraphQLString) } }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter( - context.ip, - params, - 'pendingChainBalance', - 1, - '1s', - ); + await requestLimiter(context.ip, 'pendingChainBalance'); const lnd = getAuthLnd(params.auth); diff --git a/src/schemas/query/general/networkInfo.ts b/src/schemas/query/general/networkInfo.ts index 691ccf43..092028d8 100644 --- a/src/schemas/query/general/networkInfo.ts +++ b/src/schemas/query/general/networkInfo.ts @@ -20,7 +20,7 @@ export const getNetworkInfo = { type: NetworkInfoType, args: { auth: { type: new GraphQLNonNull(GraphQLString) } }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter(context.ip, params, 'networkInfo', 1, '1s'); + await requestLimiter(context.ip, 'networkInfo') const lnd = getAuthLnd(params.auth); diff --git a/src/schemas/query/general/nodeInfo.ts b/src/schemas/query/general/nodeInfo.ts index 35be061d..abb4fd8e 100644 --- a/src/schemas/query/general/nodeInfo.ts +++ b/src/schemas/query/general/nodeInfo.ts @@ -26,7 +26,7 @@ export const getNodeInfo = { type: NodeInfoType, args: { auth: { type: new GraphQLNonNull(GraphQLString) } }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter(context.ip, params, 'nodeInfo', 1, '1s'); + await requestLimiter(context.ip, 'nodeInfo'); const lnd = getAuthLnd(params.auth); diff --git a/src/schemas/query/invoices/forwards.ts b/src/schemas/query/invoices/forwards.ts index 616be0d5..034faa19 100644 --- a/src/schemas/query/invoices/forwards.ts +++ b/src/schemas/query/invoices/forwards.ts @@ -24,7 +24,8 @@ export const getForwards = { type: new GraphQLList(GetForwardType), args: { auth: { type: new GraphQLNonNull(GraphQLString) } }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter(context.ip, params, 'getForwards', 1, '1s'); + await requestLimiter(context.ip, 'forwards'); + const lnd = getAuthLnd(params.auth); try { diff --git a/src/schemas/query/invoices/invoices.ts b/src/schemas/query/invoices/invoices.ts index fe218611..eb1723b0 100644 --- a/src/schemas/query/invoices/invoices.ts +++ b/src/schemas/query/invoices/invoices.ts @@ -48,7 +48,7 @@ export const getInvoices = { type: new GraphQLList(GetInvoiceType), args: { auth: { type: new GraphQLNonNull(GraphQLString) } }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter(context.ip, params, 'getInvoices', 1, '1s'); + await requestLimiter(context.ip, 'invoices'); const lnd = getAuthLnd(params.auth); diff --git a/src/schemas/query/invoices/payments.ts b/src/schemas/query/invoices/payments.ts index dbb6554c..333b7db6 100644 --- a/src/schemas/query/invoices/payments.ts +++ b/src/schemas/query/invoices/payments.ts @@ -28,7 +28,7 @@ export const getPayments = { type: new GraphQLList(GetPaymentType), args: { auth: { type: new GraphQLNonNull(GraphQLString) } }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter(context.ip, params, 'getPayments', 1, '1s'); + await requestLimiter(context.ip, 'payments'); const lnd = getAuthLnd(params.auth); diff --git a/src/schemas/query/report/ForwardChannels.ts b/src/schemas/query/report/ForwardChannels.ts index be2d87ca..e53a496d 100644 --- a/src/schemas/query/report/ForwardChannels.ts +++ b/src/schemas/query/report/ForwardChannels.ts @@ -17,13 +17,7 @@ export const getForwardChannelsReport = { order: { type: GraphQLString }, }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter( - context.ip, - params, - 'getForwardChannelsReport', - 1, - '1s', - ); + await requestLimiter(context.ip, 'forwardChannels') const lnd = getAuthLnd(params.auth); diff --git a/src/schemas/query/report/ForwardReport.ts b/src/schemas/query/report/ForwardReport.ts index 06544a7d..452ee8b3 100644 --- a/src/schemas/query/report/ForwardReport.ts +++ b/src/schemas/query/report/ForwardReport.ts @@ -20,7 +20,7 @@ export const getForwardReport = { time: { type: GraphQLString }, }, resolve: async (root: any, params: any, context: any) => { - await requestLimiter(context.ip, params, 'getForwardReport', 1, '1s'); + await requestLimiter(context.ip, 'forwardReport'); const lnd = getAuthLnd(params.auth); diff --git a/src/utils/rateLimitConfig.ts b/src/utils/rateLimitConfig.ts new file mode 100644 index 00000000..199473ae --- /dev/null +++ b/src/utils/rateLimitConfig.ts @@ -0,0 +1,35 @@ +interface RateConfigProps { + [key: string]: { + max: number; + window: string; + }; +} + +export const RateConfig: RateConfigProps = { + channelBalance: { max: 3, window: '1s' }, + channelFees: { max: 3, window: '1s' }, + channels: { max: 3, window: '1s' }, + closedChannels: { max: 3, window: '1s' }, + pendingChannels: { max: 3, window: '1s' }, + bitcoinFee: { max: 3, window: '1s' }, + bitcoinPrice: { max: 3, window: '1s' }, + getInOut: { max: 3, window: '1s' }, + chainBalance: { max: 3, window: '1s' }, + pendingChainBalance: { max: 3, window: '1s' }, + networkInfo: { max: 3, window: '1s' }, + nodeInfo: { max: 3, window: '1s' }, + forwards: { max: 3, window: '1s' }, + invoices: { max: 3, window: '1s' }, + payments: { max: 3, window: '1s' }, + forwardChannels: { max: 3, window: '1s' }, + forwardReport: { max: 3, window: '1s' }, + getRoute: { max: 3, window: '1s' }, + closeChannel: { max: 3, window: '1s' }, + openChannel: { max: 3, window: '1s' }, + createInvoice: { max: 3, window: '1s' }, + decode: { max: 3, window: '1s' }, + parsePayment: { max: 3, window: '1s' }, + pay: { max: 3, window: '1s' }, + getAddress: { max: 3, window: '1s' }, + sendToAddress: { max: 3, window: '1s' }, +};