Compare commits

..

No commits in common. "d4a9519cbfb8d8f945e062b147dc4703c6d09262" and "3f61a16324ce5223a1eb47e26304558d45c3d0b4" have entirely different histories.

8 changed files with 31 additions and 149 deletions

View File

@ -4,27 +4,22 @@
"enabled": false "enabled": false
}, },
"linter": { "linter": {
"enabled": false, "enabled": true,
"rules": { "rules": {
"recommended": true, "recommended": true,
"performance": { "performance": {
"recommended": true "recommended": true
}, },
"security": { "security": {
"recommended": true "recommended": true
} }
} }
}, },
"formatter": { "formatter": {
"enabled": true, "enabled": true,
"indentStyle": "space", "indentStyle": "space",
"indentWidth": 2, "indentWidth": 2,
"lineWidth": 80, "lineWidth": 80,
"formatWithErrors": false "formatWithErrors": false
},
"javascript": {
"parser": {
"unsafeParameterDecoratorsEnabled": true
}
} }
} }

View File

@ -24,9 +24,6 @@
"@nestjs/core": "^10.0.0", "@nestjs/core": "^10.0.0",
"@nestjs/platform-express": "^10.0.0", "@nestjs/platform-express": "^10.0.0",
"@prisma/client": "^5.10.2", "@prisma/client": "^5.10.2",
"argon2": "^0.40.1",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"reflect-metadata": "^0.2.0", "reflect-metadata": "^0.2.0",
"rxjs": "^7.8.1" "rxjs": "^7.8.1"
}, },

View File

@ -1,43 +0,0 @@
/*
Warnings:
- You are about to drop the `Bookmark` table. If the table is not empty, all the data it contains will be lost.
- You are about to drop the `User` table. If the table is not empty, all the data it contains will be lost.
*/
-- DropTable
DROP TABLE `Bookmark`;
-- DropTable
DROP TABLE `User`;
-- CreateTable
CREATE TABLE `users` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,
`email` VARCHAR(191) NOT NULL,
`hash` VARCHAR(191) NOT NULL,
`firstName` VARCHAR(191) NULL,
`lastName` VARCHAR(191) NULL,
UNIQUE INDEX `users_id_key`(`id`),
UNIQUE INDEX `users_email_key`(`email`),
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `bookmarks` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,
`title` VARCHAR(191) NOT NULL,
`description` VARCHAR(191) NULL,
`link` VARCHAR(191) NOT NULL,
`userId` INTEGER NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- AddForeignKey
ALTER TABLE `bookmarks` ADD CONSTRAINT `bookmarks_userId_fkey` FOREIGN KEY (`userId`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;

View File

@ -14,18 +14,15 @@ datasource db {
} }
model User { model User {
id Int @id @unique @default(autoincrement()) id Int @id @default(autoincrement())
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
email String @unique email String
hash String hash String
firstName String? firstName String?
lastName String? lastName String?
@@map("users")
bookmarks Bookmark[]
} }
model Bookmark { model Bookmark {
@ -36,9 +33,4 @@ model Bookmark {
title String title String
description String? description String?
link String link String
userId Int
user User @relation(fields: [userId], references: [id])
@@map("bookmarks")
} }

View File

@ -4,15 +4,17 @@ import { AuthDto } from "./dto";
@Controller('auth') @Controller('auth')
export class AuthController { export class AuthController {
constructor(private authService: AuthService) {} constructor(private authService: AuthService) {}
@Post("register") @Post('signup')
async signup(@Body() dto: AuthDto) { signup(@Body() dto: AuthDto) {
return await this.authService.register(dto); console.log({dto});
} return this.authService.signup()
}
@Post("login") @Post('signin')
async signin(@Body() dto: AuthDto) { signin(@Body() dto: AuthDto) {
return await this.authService.login(dto); console.log({dto});
} return this.authService.signin()
}
} }

View File

@ -1,60 +1,17 @@
import { ForbiddenException, Injectable } from "@nestjs/common"; import { Injectable } from "@nestjs/common";
import { PrismaService } from "src/prisma/prisma.service"; import { PrismaService } from "src/prisma/prisma.service";
import { AuthDto } from "./dto";
import * as argon from "argon2";
import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library";
@Injectable({}) @Injectable({})
export class AuthService { export class AuthService {
constructor(private prisma: PrismaService) {} constructor(private prisma: PrismaService) {
async login(dto: AuthDto) {
const User = await this.prisma.user.findUnique({
where: {
email: dto.email,
},
});
if (!User) {
console.warn(`ACCESS: Refused login for "${dto.email}" (email not used)`);
throw new ForbiddenException("Credential(s) invalid.");
} }
const pwMatches = await argon.verify(User.hash, dto.password); signin() {
if (!pwMatches) { return {response: "Sign IN"}
console.warn(
`ACCESS: Refused login for "${dto.email}" (invalid password)`,
);
throw new ForbiddenException("Credential(s) invalid.");
} }
delete User.hash; signup() {
console.info(`ACCESS: Granted login for "${dto.email}"`); return {response: "Sign UP"}
return User;
}
async register(dto: AuthDto) {
const userPasswordHash = await argon.hash(dto.password);
try {
const User = await this.prisma.user.create({
data: {
email: dto.email,
hash: userPasswordHash,
},
select: {
id: true,
email: true,
firstName: true,
lastName: true,
},
});
//delete User.hash;
return User;
} catch (error) {
if (error instanceof PrismaClientKnownRequestError) {
if (error.code === "P2002") {
throw new ForbiddenException("Credential(s) taken.");
}
}
} }
}
} }

View File

@ -1,16 +1,4 @@
import { IsEmail, IsNotEmpty, IsStrongPassword } from "class-validator"; export interface AuthDto {
email: string,
export class AuthDto { password: string
@IsEmail()
@IsNotEmpty()
email: string;
@IsStrongPassword({
minLength: 8,
minLowercase: 1,
minUppercase: 1,
minNumbers: 1,
minSymbols: 1,
})
password: string;
} }

View File

@ -1,14 +1,8 @@
import { NestFactory } from '@nestjs/core'; import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module'; import { AppModule } from './app.module';
import { ValidationPipe } from "@nestjs/common";
async function bootstrap() { async function bootstrap() {
const app = await NestFactory.create(AppModule); const app = await NestFactory.create(AppModule);
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
}),
);
await app.listen(3333); await app.listen(3333);
} }
bootstrap(); bootstrap();