Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add local strategy #9

Merged
merged 1 commit into from
Aug 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
365 changes: 361 additions & 4 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"@opentelemetry/sdk-node": "0.52.1",
"@prisma/client": "5.17.0",
"@quixo3/prisma-session-store": "3.1.13",
"bcrypt": "5.1.1",
"class-transformer": "0.5.1",
"class-validator": "0.14.1",
"cookie-parser": "1.4.6",
Expand Down Expand Up @@ -81,6 +82,7 @@
"@nestjs/testing": "10.3.10",
"@swc/cli": "0.4.0",
"@swc/core": "1.7.0",
"@types/bcrypt": "5.0.2",
"@types/cookie-parser": "1.4.7",
"@types/express": "4.17.21",
"@types/jest": "29.5.12",
Expand Down
3,391 changes: 3,390 additions & 1 deletion public/styles.css

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import i18n_opts from './config/i18n';
import { LoggerModule } from 'nestjs-pino';
import pinoOpts from './config/pino';
import { OpenTelemetryModule } from 'nestjs-otel';
import { CredentialsService } from './credentials/credentials.service';

@Module({
controllers: [AppController],
Expand All @@ -38,5 +39,6 @@ import { OpenTelemetryModule } from 'nestjs-otel';
UsersModule,
ValidationModule,
],
providers: [CredentialsService],
})
export class AppModule {}
2 changes: 2 additions & 0 deletions src/auth/auth.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { prismaMock } from '../../prisma/singleton';
import { I18nModule } from 'nestjs-i18n';
import i18n_opts from '@core/config/i18n';
import opts from '@core/config/app';
import { CredentialsService } from '@core/credentials/credentials.service';

describe('AuthController', () => {
let module: TestingModule;
Expand All @@ -27,6 +28,7 @@ describe('AuthController', () => {
providers: [
AuthService,
UsersService,
CredentialsService,
{ provide: PrismaService, useValue: prismaMock },
],
controllers: [AuthController],
Expand Down
13 changes: 9 additions & 4 deletions src/auth/auth.controller.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Body, Controller } from '@nestjs/common';
import { Body, Controller, Logger } from '@nestjs/common';

import { AuthService } from './auth.service';

import { ConfigService } from '@nestjs/config';
import { Config } from '@core/config/app';
import { CurrentSession } from './current-session.decorator';
import { SessionWithUserPii } from '@core/users/users.service';

import { UserAvatar } from './components/user-avatar';
import { AuthLinks } from './components/auth-links';
import { Base } from '@core/base/base.controller';
Expand All @@ -17,11 +17,14 @@ import * as P from '@core/auth/pages';
import { SignInDto } from './schemas/sign-in';
import { EmailDto } from '@core/validation/schemas';
import { MainContent } from '@core/components';
import { SessionWithUserPii } from '@core/users/users.service';

const PREFIX = 'auth' as const;
const prefix = `/${PREFIX}` as const;

@Controller(PREFIX)
export class AuthController extends Base {
logger = new Logger(AuthController.name);
constructor(
private readonly configService: ConfigService<Config>,
private readonly authService: AuthService,
Expand Down Expand Up @@ -66,7 +69,8 @@ export class AuthController extends Base {
description: 'sign in',
})
async sigInPost(@Body() signInDto: SignInDto) {
console.log(signInDto);
const user = await this.authService.localSignIn(signInDto);
this.logger.log(user);
}

@Route({
Expand All @@ -89,7 +93,8 @@ export class AuthController extends Base {
description: 'register',
})
async registerPost(@Body() signInDto: SignInDto) {
console.log(signInDto);
const user = await this.authService.localRegister(signInDto);
this.logger.log(user);
}

@Route({
Expand Down
6 changes: 4 additions & 2 deletions src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { AuthService } from './auth.service';
import { UsersModule } from '@core/users/users.module';
import { JwtModule } from '@nestjs/jwt';
import { GoogleController } from './auth.google.controller';
import { CredentialsService } from '@core/credentials/credentials.service';
import { PrismaModule } from 'nestjs-prisma';

@Module({
imports: [JwtModule, UsersModule],
imports: [JwtModule, UsersModule, PrismaModule],
controllers: [AuthController, GoogleController],
providers: [AuthService],
providers: [AuthService, CredentialsService],
})
export class AuthModule {}
2 changes: 2 additions & 0 deletions src/auth/auth.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { JwtModule } from '@nestjs/jwt';
import { UsersService } from '@core/users/users.service';
import { PrismaService } from 'nestjs-prisma';
import { prismaMock } from '../../prisma/singleton';
import { CredentialsService } from '@core/credentials/credentials.service';

describe('AuthService', () => {
let module: TestingModule;
Expand All @@ -15,6 +16,7 @@ describe('AuthService', () => {
providers: [
AuthService,
UsersService,
CredentialsService,
{ provide: PrismaService, useValue: prismaMock },
],
}).compile();
Expand Down
34 changes: 33 additions & 1 deletion src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,19 @@ import { JwtService } from '@nestjs/jwt';
import { SessionWithUserPii, UsersService } from '@core/users/users.service';
import { ValidGoogleOauthData } from './google-oauth.strategy';
import { JwtPayload } from './jwt.strategy';
import bcrypt from 'bcrypt';
import {
CredentialsService,
CredentialWithUserPii,
} from '@core/credentials/credentials.service';
import { SignInDto } from './schemas/sign-in';

@Injectable()
export class AuthService {
constructor(
private jwtService: JwtService,
private readonly usersService: UsersService,
private readonly credentialsService: CredentialsService,
) {}

generateJwt(payload: JwtPayload) {
Expand All @@ -20,6 +27,31 @@ export class AuthService {
throw new BadRequestException('Invalid user data');
}

return this.usersService.upsertOauthCredentialUser(data);
return this.credentialsService.upsertOauthCredentialUser(data);
}

async localSignIn({
email,
password,
}: SignInDto): Promise<CredentialWithUserPii> {
const credential =
await this.credentialsService.findLocalUserByEmail(email);
const valid = await bcrypt.compare(password, credential?.value || '');
if (!valid || !credential) {
throw new BadRequestException('Invalid email or password');
}
return credential;
}

async localRegister({
email,
password,
}: SignInDto): Promise<CredentialWithUserPii> {
const existing = await this.credentialsService.findLocalUserByEmail(email);
if (existing) {
throw new BadRequestException('User already exists');
}

return this.credentialsService.createLocalUser(email, password);
}
}
3 changes: 2 additions & 1 deletion src/auth/components/user-avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Link } from '@core/components';
import { PiiType } from '@core/credentials/credentials.service';
import { Translations } from '@core/i18n/i18n.utils';
import { PiiType, SessionWithUserPii } from '@core/users/users.service';
import { SessionWithUserPii } from '@core/users/users.service';

export type UserAvatarProps = Translations & {
session: SessionWithUserPii;
Expand Down
3 changes: 2 additions & 1 deletion src/auth/google-oauth.strategy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Config } from '@core/config/app';
import { PiiType } from '@core/users/users.service';
import { PiiType } from '@core/credentials/credentials.service';

import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PassportStrategy } from '@nestjs/passport';
Expand Down
19 changes: 19 additions & 0 deletions src/auth/local.strategy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './auth.service';

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super();
}

async validate(email: string, password: string): Promise<any> {
const user = await this.authService.localSignIn({ email, password });
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
Loading