diff --git a/src/controllers/APILimitsController.ts b/src/controllers/APILimitsController.ts new file mode 100644 index 0000000..d2ee7d0 --- /dev/null +++ b/src/controllers/APILimitsController.ts @@ -0,0 +1,27 @@ +/** + * API limits manager + * + * @author Pierre HUBERT + */ + +import { RequestHandler } from "../entities/RequestHandler"; +import { Action, APILimitHelper } from "../helpers/APILimitsHelper"; + +/** + * Trigger query limiter + * + * @param h Request handler + * @param action The action to check + * @param trigger TRUE if the counter has to be increased by one / else it is a simple check + */ +export async function limit_query(h: RequestHandler, action: Action, trigger: boolean) { + + // Increment the number of actions / failures done by the user + if(trigger) { + await APILimitHelper.Trigger(h.remoteIP, action) + } + + // Check for counter + if(await APILimitHelper.Count(h.remoteIP, action) > 10) + h.error(429, "Too many request. Please try again later.") +} \ No newline at end of file diff --git a/src/controllers/AccountController.ts b/src/controllers/AccountController.ts index d10e9fb..7535e70 100644 --- a/src/controllers/AccountController.ts +++ b/src/controllers/AccountController.ts @@ -3,6 +3,8 @@ import { AccountHelper } from "../helpers/AccountHelper"; import { UserHelper } from "../helpers/UserHelper"; import { NewAccount } from "../entities/NewAccount"; import { removeHTMLNodes } from "../utils/StringUtils"; +import { limit_query } from "./APILimitsController"; +import { Action } from "../helpers/APILimitsHelper"; /** * Account controller @@ -44,27 +46,29 @@ export class AccountController { /** * Attempt to login user * - * @param handler + * @param h Request handler */ - public static async LoginUser(handler: RequestHandler) { + public static async LoginUser(h: RequestHandler) { // Get post data - const email = handler.postEmail("userMail"); - const password = handler.postString("userPassword"); + const email = h.postEmail("userMail"); + const password = h.postString("userPassword"); - // TODO : add limits + // Limit request + await limit_query(h, Action.LOGIN_FAILED, false); // Authenticate user - const tokens = await AccountHelper.LoginUser(email, password, handler.getClientInfo()); + const tokens = await AccountHelper.LoginUser(email, password, h.getClientInfo()); if(tokens == null) { - // TODO : add limits + // Trigger limit + await limit_query(h, Action.LOGIN_FAILED, true); - handler.error(401, "Invalid e-mail address / password !"); + h.error(401, "Invalid e-mail address / password !"); } // Success - handler.send({ + h.send({ success: "User signed in!", tokens: { token1: tokens.token1, diff --git a/src/helpers/APILimitsHelper.ts b/src/helpers/APILimitsHelper.ts new file mode 100644 index 0000000..5ea28bd --- /dev/null +++ b/src/helpers/APILimitsHelper.ts @@ -0,0 +1,39 @@ +/** + * API Limits helper + * + * This implementation of API limits stores + * the counters inside memory, not in the databas + * + * @author Pierre HUBERT + */ + +// Different supported actions +export enum Action { + LOGIN_FAILED = "login_failed", + CREATE_ACCOUNT = "create_account" +} + +export class APILimitHelper { + + /** + * Trigger the counter (increase it by one) + * + * @param ip Target IP address + * @param action The action to check + */ + public static async Trigger(ip: string, action: Action) { + // TODO : trigger counter + } + + /** + * Count the number of actions perfomed by a user + * + * @param ip Target IP address + * @param action The action to check + */ + public static async Count(ip: string, action: Action) : Promise { + // TODO : return count + return 0; + } +} +