change way auth keys behave

This commit is contained in:
rubikscraft
2022-09-07 09:48:52 +02:00
parent a19d0bab25
commit 08af514758
6 changed files with 38 additions and 26 deletions

View File

@@ -1,6 +1,6 @@
import { Injectable, Logger } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { JwtDataSchema } from 'picsur-shared/dist/dto/jwt.dto';
import { JwtData, JwtDataSchema } from 'picsur-shared/dist/dto/jwt.dto';
import { EUser } from 'picsur-shared/dist/entities/user.entity';
import { AsyncFailable, Fail, FT } from 'picsur-shared/dist/types';
@@ -11,8 +11,8 @@ export class AuthManagerService {
constructor(private readonly jwtService: JwtService) {}
async createToken(user: EUser): AsyncFailable<string> {
const jwtData = {
user,
const jwtData: JwtData = {
uid: user.id,
};
// Validate to be sure, this makes client experience better

View File

@@ -1,6 +1,8 @@
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-strategy';
import { EUser } from 'picsur-shared/dist/entities/user.entity';
import { EUserBackend2EUser } from '../../../models/transformers/user.transformer';
import { GuestService } from '../guest.service';
import { ReqType } from './reqtype';
@@ -26,7 +28,7 @@ export class GuestStrategy extends PassportStrategy(
}
// Return the guest user created by the guestservice
override async validate(payload: any) {
return await this.guestService.getGuestUser();
override async validate(payload: any): Promise<EUser> {
return EUserBackend2EUser(await this.guestService.getGuestUser());
}
}

View File

@@ -3,12 +3,18 @@ import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy as JwtPassportStrategy } from 'passport-jwt';
import { JwtDataSchema } from 'picsur-shared/dist/dto/jwt.dto';
import { EUser } from 'picsur-shared/dist/entities/user.entity';
import { ThrowIfFailed } from 'picsur-shared/dist/types';
import { UserDbService } from '../../../collections/user-db/user-db.service';
import { EUserBackend2EUser } from '../../../models/transformers/user.transformer';
@Injectable()
export class JwtStrategy extends PassportStrategy(JwtPassportStrategy, 'jwt') {
private readonly logger = new Logger(JwtStrategy.name);
constructor(@Inject('JWT_SECRET') jwtSecret: string) {
constructor(
@Inject('JWT_SECRET') jwtSecret: string,
private readonly usersService: UserDbService,
) {
// This will validate the jwt token itself
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
@@ -24,7 +30,11 @@ export class JwtStrategy extends PassportStrategy(JwtPassportStrategy, 'jwt') {
return false;
}
const backendUser = ThrowIfFailed(
await this.usersService.findOne(result.data.uid),
);
// And return the user
return result.data.user;
return EUserBackend2EUser(backendUser);
}
}

View File

@@ -2,7 +2,14 @@ import { ExecutionContext, Injectable, Logger } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
import { EUser, EUserSchema } from 'picsur-shared/dist/entities/user.entity';
import { Fail, Failable, FT, HasFailed } from 'picsur-shared/dist/types';
import {
AsyncFailable,
Fail,
Failable,
FT,
HasFailed,
ThrowIfFailed,
} from 'picsur-shared/dist/types';
import { makeUnique } from 'picsur-shared/dist/util/unique';
import { UserDbService } from '../../../collections/user-db/user-db.service';
import { Permissions } from '../../../models/constants/permissions.const';
@@ -34,9 +41,10 @@ export class MainAuthGuard extends AuthGuard(['apikey', 'jwt', 'guest']) {
);
}
const user = await this.validateUser(
context.switchToHttp().getRequest().user,
);
const unsafeUser: EUser = context.switchToHttp().getRequest().user;
const user = ThrowIfFailed(await this.validateUser(unsafeUser));
if (!user.id) {
throw Fail(
FT.Internal,
@@ -62,6 +70,7 @@ export class MainAuthGuard extends AuthGuard(['apikey', 'jwt', 'guest']) {
}
context.switchToHttp().getRequest().userPermissions = userPermissions;
context.switchToHttp().getRequest().user = user;
if (permissions.every((permission) => userPermissions.includes(permission)))
return true;
@@ -100,10 +109,10 @@ export class MainAuthGuard extends AuthGuard(['apikey', 'jwt', 'guest']) {
return permissions;
}
private async validateUser(user: EUser): Promise<EUser> {
private async validateUser(user: EUser): AsyncFailable<EUser> {
const result = EUserSchema.safeParse(user);
if (!result.success) {
throw Fail(
return Fail(
FT.Internal,
undefined,
`Invalid user object, where it should always be valid: ${result.error}`,

View File

@@ -53,15 +53,6 @@ export class UserService {
const apikey = await this.key.get();
if (!apikey) return;
const user = await this.extractUser(apikey);
if (HasFailed(user)) {
this.logger.error(user.getReason());
await this.logout();
return;
}
this.userSubject.next(user);
const fetchedUser = await this.fetchUser();
if (HasFailed(fetchedUser)) {
this.logger.error(fetchedUser.getReason());
@@ -137,7 +128,7 @@ export class UserService {
}
// This extracts the available userdata from the jwt token
private async extractUser(token: string): AsyncFailable<EUser> {
private async extractUserID(token: string): AsyncFailable<string> {
let decoded: any;
try {
decoded = jwt_decode(token);
@@ -151,7 +142,7 @@ export class UserService {
return Fail(FT.UsrValidation, 'Invalid token data');
}
return result.data.user;
return result.data.uid;
}
// This actually fetches up to date information from the server

View File

@@ -1,8 +1,8 @@
import { z } from 'zod';
import { EUserSchema } from '../entities/user.entity';
import { IsEntityID } from '../validators/entity-id.validator';
export const JwtDataSchema = z.object({
user: EUserSchema.required(),
uid: IsEntityID(),
iat: z.number().int().optional(),
exp: z.number().int().optional(),
});