diff --git a/idp/src/auth/auth.module.ts b/idp/src/auth/auth.module.ts index 6604f78..a3e6c06 100644 --- a/idp/src/auth/auth.module.ts +++ b/idp/src/auth/auth.module.ts @@ -1,6 +1,5 @@ import { Module } from '@nestjs/common'; import { AuthController } from './auth.controller'; -import { UsersService } from 'src/users/users.service'; import { ClientService } from 'src/client/client.service'; import { JwtModule } from '@nestjs/jwt'; import { NestjsFormDataModule } from 'nestjs-form-data'; @@ -8,9 +7,10 @@ import { LoggerModule } from 'src/core/logger.module'; import { ConfigModule, ConfigService } from '@nestjs/config'; import { DatabaseModule } from 'src/core/database/database.module'; import { MailModule } from 'src/application/mail/mail.module'; +import { SecureModule } from 'src/core/secure/secure.module'; @Module({ - providers: [UsersService, ClientService], + providers: [ClientService], controllers: [AuthController], imports: [ JwtModule.registerAsync({ @@ -25,6 +25,7 @@ import { MailModule } from 'src/application/mail/mail.module'; LoggerModule, DatabaseModule, MailModule, + SecureModule, ], }) export class AuthModule {} diff --git a/idp/src/core/database/database.module.ts b/idp/src/core/database/database.module.ts index 982bb47..3a7769e 100644 --- a/idp/src/core/database/database.module.ts +++ b/idp/src/core/database/database.module.ts @@ -17,6 +17,8 @@ import { AuthorizationCodeRepository, Role, RoleRepository, + ActivityLog, + ActivityLogRepository, } from 'src/model'; const ENTITIES = [ @@ -28,6 +30,7 @@ const ENTITIES = [ SessionKey, Log, ResetPwCode, + ActivityLog, ]; const REPOSITORIES = [ UserRepository, @@ -38,6 +41,7 @@ const REPOSITORIES = [ LogRepository, ResetPwCodeRepository, RoleRepository, + ActivityLogRepository, ]; @Module({ diff --git a/idp/src/model/entity/activity-log.entity.ts b/idp/src/model/entity/activity-log.entity.ts new file mode 100644 index 0000000..98f2d8e --- /dev/null +++ b/idp/src/model/entity/activity-log.entity.ts @@ -0,0 +1,77 @@ +import { Injectable } from '@nestjs/common'; +import { + Entity, + Column, + PrimaryGeneratedColumn, + Repository, + DataSource, + Between, +} from 'typeorm'; + +@Entity() +export class ActivityLog { + @PrimaryGeneratedColumn() + id: number; + + @Column({ type: 'date', default: null }) + date: Date; + + @Column({ default: 0, type: 'int' }) + loginCounter: number; + + @Column({ default: 0, type: 'int' }) + accessTokensVerifies: number; + + @Column({ default: 0, type: 'int' }) + accessTokenRefresh: number; +} + +@Injectable() +export class ActivityLogRepository extends Repository { + constructor(dataSource: DataSource) { + super(ActivityLog, dataSource.createEntityManager()); + } + + async logAccessTokenVerification(): Promise { + const entity = await this.getTodaysActivityLog(); + entity.accessTokensVerifies += 1; + return this.save(entity); + } + + async logLogin(): Promise { + const entity = await this.getTodaysActivityLog(); + entity.loginCounter += 1; + return this.save(entity); + } + + async logGetNewAccessTokenWithRefresh(): Promise { + const entity = await this.getTodaysActivityLog(); + entity.accessTokenRefresh += 1; + return this.save(entity); + } + + async getTodaysActivityLog(): Promise { + const start = new Date(); + start.setHours(0); + start.setMinutes(0); + start.setSeconds(0); + start.setMilliseconds(0); + + const end = new Date(); + end.setHours(23); + end.setMinutes(59); + end.setSeconds(59); + end.setMilliseconds(999); + + let x: ActivityLog = await this.findOne({ + where: { + date: Between(start, end), + }, + }); + + if (!x) { + x = this.create({ date: new Date() }); + } + return x; + } +} diff --git a/idp/src/model/entity/index.ts b/idp/src/model/entity/index.ts index 1a8afb7..814f748 100644 --- a/idp/src/model/entity/index.ts +++ b/idp/src/model/entity/index.ts @@ -6,3 +6,4 @@ export * from './role.entity'; export * from './session-key.entity'; export * from './user.entity'; export * from './auth-code.entity'; +export * from './activity-log.entity'; diff --git a/idp/src/users/users.service.ts b/idp/src/users/users.service.ts index b295dc5..a3d39ac 100644 --- a/idp/src/users/users.service.ts +++ b/idp/src/users/users.service.ts @@ -15,6 +15,7 @@ import { Client, AuthorizationCodeRepository, AuthorizationCode, + ActivityLogRepository, } from 'src/model'; @Injectable() @@ -28,6 +29,7 @@ export class UsersService { private logger: CustomLogger, private resetPwRepo: ResetPwCodeRepository, private mailService: MailService, + private activityRepo: ActivityLogRepository, ) {} async createUser(userDto: CreateUserDto): Promise { const hashedPassword = await bcrypt.hash(userDto.password, 10); @@ -79,7 +81,7 @@ export class UsersService { user, }); const session = await this.sessionRepo.save(s); - + this.activityRepo.logLogin(); return { code: token.code, session_key: session.id }; } @@ -229,12 +231,15 @@ export class UsersService { access_token: token, expires_in: pay.exp - pay.iat, }; + + this.activityRepo.logGetNewAccessTokenWithRefresh(); return result; } - verifyAccessToken(token: string) { + async verifyAccessToken(token: string) { try { const decoded = this.jwtService.verify(token); + this.activityRepo.logAccessTokenVerification(); return decoded; } catch (e) { this.logger.error(`Token ${token} is invalid. Error: ${e.message}`);