Initial commit: Prism messenger with Expo + NestJS + GraphQL + PostgreSQL

This commit is contained in:
Bivekich
2025-08-06 02:19:37 +03:00
commit 6fb83334d6
56 changed files with 24295 additions and 0 deletions

View File

@ -0,0 +1,21 @@
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { AuthService } from './auth.service';
import { AuthResolver } from './auth.resolver';
import { JwtStrategy } from './strategies/jwt.strategy';
import { UsersModule } from '../users/users.module';
@Module({
imports: [
UsersModule,
PassportModule,
JwtModule.register({
secret: process.env.JWT_SECRET || 'secret',
signOptions: { expiresIn: process.env.JWT_EXPIRATION || '7d' },
}),
],
providers: [AuthService, AuthResolver, JwtStrategy],
exports: [AuthService],
})
export class AuthModule {}

View File

@ -0,0 +1,34 @@
import { Resolver, Mutation, Args, ObjectType, Field } from '@nestjs/graphql';
import { AuthService } from './auth.service';
import { User } from '../users/entities/user.entity';
@ObjectType()
class AuthResponse {
@Field()
access_token: string;
@Field(() => User)
user: User;
}
@Resolver()
export class AuthResolver {
constructor(private authService: AuthService) {}
@Mutation(() => AuthResponse)
async login(
@Args('username') username: string,
@Args('password') password: string,
) {
return this.authService.login(username, password);
}
@Mutation(() => AuthResponse)
async register(
@Args('username') username: string,
@Args('email') email: string,
@Args('password') password: string,
) {
return this.authService.register(username, email, password);
}
}

View File

@ -0,0 +1,43 @@
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { UsersService } from '../users/users.service';
import * as bcrypt from 'bcrypt';
import { User } from '../users/entities/user.entity';
@Injectable()
export class AuthService {
constructor(
private usersService: UsersService,
private jwtService: JwtService,
) {}
async validateUser(username: string, password: string): Promise<User | null> {
const user = await this.usersService.findByUsername(username);
if (user && await bcrypt.compare(password, user.password)) {
return user;
}
return null;
}
async login(username: string, password: string) {
const user = await this.validateUser(username, password);
if (!user) {
throw new UnauthorizedException('Неверный логин или пароль');
}
const payload = { username: user.username, sub: user.id };
return {
access_token: this.jwtService.sign(payload),
user,
};
}
async register(username: string, email: string, password: string) {
const user = await this.usersService.create(username, email, password);
const payload = { username: user.username, sub: user.id };
return {
access_token: this.jwtService.sign(payload),
user,
};
}
}

View File

@ -0,0 +1,9 @@
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';
export const CurrentUser = createParamDecorator(
(data: unknown, context: ExecutionContext) => {
const ctx = GqlExecutionContext.create(context);
return ctx.getContext().req.user;
},
);

View File

@ -0,0 +1,11 @@
import { Injectable, ExecutionContext } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { GqlExecutionContext } from '@nestjs/graphql';
@Injectable()
export class GqlAuthGuard extends AuthGuard('jwt') {
getRequest(context: ExecutionContext) {
const ctx = GqlExecutionContext.create(context);
return ctx.getContext().req;
}
}

View File

@ -0,0 +1,20 @@
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
import { UsersService } from '../../users/users.service';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private usersService: UsersService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: process.env.JWT_SECRET || 'secret',
});
}
async validate(payload: any) {
const user = await this.usersService.findOne(payload.sub);
return user;
}
}