Skip to content

Commit

Permalink
adjust add limit to OPT attempts
Browse files Browse the repository at this point in the history
  • Loading branch information
Janderson Souza Matias authored and Janderson Souza Matias committed Jun 17, 2024
1 parent 1de591e commit ba28a17
Show file tree
Hide file tree
Showing 11 changed files with 142 additions and 12 deletions.
19 changes: 19 additions & 0 deletions src/database/migrations/1718665191767-migrations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { MigrationInterface, QueryRunner } from "typeorm";

export class Migrations1718665191767 implements MigrationInterface {
name = "Migrations1718665191767";

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE TABLE "login_attempt" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "email" character varying NOT NULL, "created_at" bigint NOT NULL, CONSTRAINT "PK_72829cd4f7424e3cdfd46c476c0" PRIMARY KEY ("id"))`
);
await queryRunner.query(
`ALTER TABLE "user" ADD "force_logout" boolean NOT NULL DEFAULT false`
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "force_logout"`);
await queryRunner.query(`DROP TABLE "login_attempt"`);
}
}
26 changes: 26 additions & 0 deletions src/database/migrations/1718665323971-migrations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { MigrationInterface, QueryRunner } from "typeorm";

export class Migrations1718665323971 implements MigrationInterface {
name = "Migrations1718665323971";

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "login_attempt" DROP COLUMN "created_at"`
);
await queryRunner.query(
`ALTER TABLE "login_attempt" ADD "created_at" TIMESTAMP NOT NULL DEFAULT now()`
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "session" DROP CONSTRAINT "FK_5351647a4a00ccbca90adb057f6"`
);
await queryRunner.query(
`ALTER TABLE "login_attempt" DROP COLUMN "created_at"`
);
await queryRunner.query(
`ALTER TABLE "login_attempt" ADD "created_at" bigint NOT NULL`
);
}
}
23 changes: 23 additions & 0 deletions src/database/migrations/1718665677392-migrations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { MigrationInterface, QueryRunner } from "typeorm";

export class Migrations1718665677392 implements MigrationInterface {
name = "Migrations1718665677392";

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "login_attempt" DROP COLUMN "created_at"`
);
await queryRunner.query(
`ALTER TABLE "login_attempt" ADD "created_at" bigint NOT NULL`
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "login_attempt" DROP COLUMN "created_at"`
);
await queryRunner.query(
`ALTER TABLE "login_attempt" ADD "created_at" TIMESTAMP NOT NULL DEFAULT now()`
);
}
}
14 changes: 14 additions & 0 deletions src/modules/auth/controller/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ export default class AuthenticationController {
if (!user?.email) {
return res.status(404).send({ user });
}
const loginAttempts = await Authentication.countLoginAttempt(user.email);

if (loginAttempts >= 10) {
return res
.status(400)
.send({ error: "Number of attempts exceeded, try again later" });
}

const otp = await Authentication.verifyOTP(user.email, code);

Expand Down Expand Up @@ -134,6 +141,13 @@ export default class AuthenticationController {
if (!coach?.email) {
return res.status(404).send({ coach });
}
const loginAttempts = await Authentication.countLoginAttempt(coach.email);

if (loginAttempts >= 10) {
return res
.status(400)
.send({ error: "Number of attempts exceeded, try again later" });
}

const otp = await Authentication.verifyOTP(coach.email, code);

Expand Down
22 changes: 22 additions & 0 deletions src/modules/auth/entity/login_attempt.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {
Column,
CreateDateColumn,
Entity,
PrimaryGeneratedColumn,
} from "typeorm";

@Entity()
export class LoginAttempt {
constructor(otp?: Partial<LoginAttempt>) {
Object.assign(this, otp);
}

@PrimaryGeneratedColumn("uuid")
id?: string;

@Column()
email?: string;

@Column({ type: "bigint" })
created_at?: number;
}
9 changes: 1 addition & 8 deletions src/modules/auth/entity/otp.entity.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
import { Coach } from "../../coach/entity/coach.entity";
import {
Column,
Entity,
ManyToOne,
JoinColumn,
PrimaryGeneratedColumn,
} from "typeorm";
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";

@Entity()
export class Otp {
Expand Down
25 changes: 25 additions & 0 deletions src/modules/auth/service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import sgMail from "@sendgrid/mail";
import { OTP_EMAIL_NP, OTP_EMAIL_SL } from "./template-email";
import { Otp } from "../entity/otp.entity";
import { MoreThan } from "typeorm";
import { UserService } from "../../user/service";
import { LoginAttempt } from "../entity/login_attempt.entity";

const { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_UNAUTHORIZED } =
constants;
Expand Down Expand Up @@ -49,6 +51,11 @@ export default class Authentication {
throw new UnauthorizedException("Invalid token");
}

if (user.force_logout) {
await UserService.updateAdmin(user.id, { ...user, force_logout: false });
throw new UnauthorizedException("This user was updated");
}

const { ...userWithoutPassword } = user;

return new User(userWithoutPassword);
Expand Down Expand Up @@ -133,6 +140,22 @@ export default class Authentication {
});
};

public static saveLoginAttempt = async (email: string) => {
const otpRepository = await dataSource.getRepository(LoginAttempt);

await otpRepository.save({ email, created_at: new Date().getTime() });
};

public static countLoginAttempt = async (email: string) => {
const otpRepository = await dataSource.getRepository(LoginAttempt);
const tenMinutesAgo = new Date().getTime() - 10 * 60 * 1000;

return await otpRepository.countBy({
email,
created_at: MoreThan(tenMinutesAgo),
});
};

public static verifyOTP = async (email: string, code: string) => {
const otpRepository = await dataSource.getRepository(Otp);
const tenMinutesAgo = new Date().getTime() - 10 * 60 * 1000;
Expand All @@ -144,6 +167,8 @@ export default class Authentication {
created_at: MoreThan(tenMinutesAgo),
});

await this.saveLoginAttempt(email);

if (otpCode?.id) {
await otpRepository.update(otpCode?.id, { used: true });
}
Expand Down
2 changes: 1 addition & 1 deletion src/modules/logs/service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export class LogsService {
static findAll = async (): Promise<Teacher[]> => {
const userRepository = await dataSource.getRepository(Log);

return userRepository.find();
return userRepository.find({ take: 50 });
};

static create = async (user: User, description: string) => {
Expand Down
6 changes: 5 additions & 1 deletion src/modules/user/controller/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ export default class UserController {
throw new Error("You can not do that.");
}

await UserService.updateAdmin(user_id, newUser);
await UserService.updateAdmin(
user_id,
newUser,
user_id === currentUser.id
);

return res.status(HTTP_STATUS_OK).send({});
} catch (error) {
Expand Down
3 changes: 3 additions & 0 deletions src/modules/user/entity/user.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ export class User {
@Column({ nullable: true })
region_id?: string;

@Column({ default: false })
force_logout?: boolean;

@ManyToOne(() => Region, (region) => region.id)
@JoinColumn({ name: "region_id" })
region?: Region;
Expand Down
5 changes: 3 additions & 2 deletions src/modules/user/service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ export class UserService {

static updateAdmin = async (
user_id: User["id"],
newUser: Partial<User>
newUser: Partial<User>,
force_logout = false
): Promise<void> => {
const userRepository = dataSource.getRepository(User);

Expand All @@ -52,6 +53,7 @@ export class UserService {
name,
email,
role,
force_logout,
region_id: role === "admin" ? null : region_id,
});
};
Expand All @@ -72,7 +74,6 @@ export class UserService {
static removeAdmin = async (id: User["id"]): Promise<void> => {
const userRepository = dataSource.getRepository(User);
await userRepository.delete({ id });
return;
};

private static sendAdminWelcome = async (user: User) => {
Expand Down

0 comments on commit ba28a17

Please sign in to comment.