Skip to content
This repository has been archived by the owner on Apr 19, 2023. It is now read-only.

Commit

Permalink
✨ Add approve subnet endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
AnandChowdhary committed Oct 30, 2020
1 parent 24afea0 commit 2c892e8
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 10 deletions.
21 changes: 18 additions & 3 deletions src/modules/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
TotpLoginDto,
VerifyEmailDto,
} from './auth.dto';
import { TokenResponse } from './auth.interface';
import { AuthService } from './auth.service';
import { Public } from './public.decorator';

Expand All @@ -29,7 +30,7 @@ export class AuthController {
@Body() data: LoginDto,
@Ip() ip: string,
@Headers('User-Agent') userAgent: string,
): Promise<{ accessToken: string }> {
): Promise<TokenResponse> {
return this.authService.login(
ip,
userAgent,
Expand Down Expand Up @@ -62,7 +63,7 @@ export class AuthController {
@Ip() ip: string,
@Headers('User-Agent') userAgent: string,
@Body('token') refreshToken: string,
): Promise<{ accessToken: string }> {
): Promise<TokenResponse> {
return this.authService.refresh(ip, userAgent, refreshToken);
}

Expand All @@ -76,6 +77,20 @@ export class AuthController {
return this.authService.logout(refreshToken);
}

@Post('approve-subnet')
@RateLimit({
points: 5,
duration: 60,
errorMessage: 'Wait for 60 seconds before trying to logout again',
})
async approveSubnet(
@Ip() ip: string,
@Headers('User-Agent') userAgent: string,
@Body('token') token: string,
): Promise<TokenResponse> {
return this.authService.approveSubnet(ip, userAgent, token);
}

@Post('resend-email-verification')
@RateLimit({
points: 1,
Expand Down Expand Up @@ -131,7 +146,7 @@ export class AuthController {
@Body() data: TotpLoginDto,
@Ip() ip: string,
@Headers('User-Agent') userAgent: string,
): Promise<{ accessToken: string }> {
): Promise<TokenResponse> {
return this.authService.loginWithTotp(ip, userAgent, data.token, data.code);
}
}
5 changes: 5 additions & 0 deletions src/modules/auth/auth.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ export interface AccessTokenClaims {
scopes: string[];
}

export interface TokenResponse {
accessToken: string;
refreshToken: string;
}

export interface AccessTokenParsed {
id: number;
scopes: string[];
Expand Down
25 changes: 18 additions & 7 deletions src/modules/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,25 @@ import { JwtService } from '@nestjs/jwt';
import { Authenticator } from '@otplib/core';
import { emails, users } from '@prisma/client';
import { compare, hash } from 'bcrypt';
import anonymize from 'ip-anonymize';
import { authenticator } from 'otplib';
import qrcode from 'qrcode';
import { safeEmail } from 'src/helpers/safe-email';
import { ApprovedSubnetsService } from '../approved-subnets/approved-subnets.service';
import { EmailService } from '../email/email.service';
import { GeolocationService } from '../geolocation/geolocation.service';
import { Expose } from '../prisma/prisma.interface';
import { PrismaService } from '../prisma/prisma.service';
import { PwnedService } from '../pwned/pwned.service';
import {
APPROVE_SUBNET_TOKEN,
EMAIL_VERIFY_TOKEN,
PASSWORD_RESET_TOKEN,
TWO_FACTOR_TOKEN,
APPROVE_SUBNET_TOKEN,
} from '../tokens/tokens.constants';
import { TokensService } from '../tokens/tokens.service';
import { RegisterDto } from './auth.dto';
import { AccessTokenClaims } from './auth.interface';
import anonymize from 'ip-anonymize';
import { GeolocationService } from '../geolocation/geolocation.service';
import { ApprovedSubnetsService } from '../approved-subnets/approved-subnets.service';
import { AccessTokenClaims, TokenResponse } from './auth.interface';

@Injectable()
export class AuthService {
Expand Down Expand Up @@ -184,7 +184,11 @@ export class AuthService {
return { queued: true };
}

async refresh(ipAddress: string, userAgent: string, token: string) {
async refresh(
ipAddress: string,
userAgent: string,
token: string,
): Promise<TokenResponse> {
if (!token) throw new UnprocessableEntityException();
const session = await this.prisma.sessions.findFirst({
where: { token },
Expand Down Expand Up @@ -215,6 +219,13 @@ export class AuthService {
});
}

async approveSubnet(ipAddress: string, userAgent: string, token: string) {
if (!token) throw new UnprocessableEntityException();
const id = this.tokensService.verify<number>(APPROVE_SUBNET_TOKEN, token);
await this.approvedSubnetsService.approveNewSubnet(id, ipAddress);
return this.loginResponse(ipAddress, userAgent, id);
}

/** Get the two-factor authentication QR code */
async getTotpQrCode(userId: number) {
const secret = randomStringGenerator();
Expand Down Expand Up @@ -359,7 +370,7 @@ export class AuthService {
ipAddress: string,
userAgent: string,
id: number,
) {
): Promise<TokenResponse> {
const token = randomStringGenerator();
await this.prisma.sessions.create({
data: { token, ipAddress, userAgent, user: { connect: { id } } },
Expand Down

0 comments on commit 2c892e8

Please sign in to comment.