mirror of
https://github.com/CaramelFur/Picsur.git
synced 2026-03-21 02:51:31 +01:00
add permission endpoint
This commit is contained in:
@@ -8,7 +8,7 @@ export const RequiredPermissions = (...permissions: Permissions) => {
|
||||
};
|
||||
|
||||
// Easy to read roles
|
||||
export const NoAuth = () => RequiredPermissions();
|
||||
export const NoPermissions = () => RequiredPermissions();
|
||||
|
||||
export const UseLocalAuth = (...permissions: Permissions) =>
|
||||
CombineDecorators(
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
UserInfoResponse,
|
||||
UserListResponse,
|
||||
UserLoginResponse,
|
||||
UserMePermissionsResponse,
|
||||
UserMeResponse,
|
||||
UserRegisterRequest,
|
||||
UserRegisterResponse,
|
||||
@@ -23,6 +24,7 @@ import {
|
||||
import { HasFailed } from 'picsur-shared/dist/types';
|
||||
import { UsersService } from '../../../collections/userdb/userdb.service';
|
||||
import {
|
||||
NoPermissions,
|
||||
RequiredPermissions,
|
||||
UseLocalAuth
|
||||
} from '../../../decorators/permissions.decorator';
|
||||
@@ -94,7 +96,7 @@ export class UserController {
|
||||
body.username,
|
||||
body.roles,
|
||||
);
|
||||
|
||||
|
||||
if (HasFailed(updatedUser)) {
|
||||
this.logger.warn(updatedUser.getReason());
|
||||
throw new InternalServerErrorException('Could not update user');
|
||||
@@ -133,16 +135,24 @@ export class UserController {
|
||||
@Get('me')
|
||||
@RequiredPermissions('user-view')
|
||||
async me(@Request() req: AuthFasityRequest): Promise<UserMeResponse> {
|
||||
return {
|
||||
user: req.user,
|
||||
token: await this.authService.createToken(req.user),
|
||||
};
|
||||
}
|
||||
|
||||
// You can always check your permissions
|
||||
@Get('me/permissions')
|
||||
@NoPermissions()
|
||||
async refresh(
|
||||
@Request() req: AuthFasityRequest,
|
||||
): Promise<UserMePermissionsResponse> {
|
||||
const permissions = await this.usersService.getPermissions(req.user);
|
||||
if (HasFailed(permissions)) {
|
||||
this.logger.warn(permissions.getReason());
|
||||
throw new InternalServerErrorException('Could not get permissions');
|
||||
}
|
||||
|
||||
return {
|
||||
user: req.user,
|
||||
permissions,
|
||||
newJwtToken: await this.authService.createToken(req.user),
|
||||
};
|
||||
return { permissions };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { Controller, Get } from '@nestjs/common';
|
||||
import { InfoResponse } from 'picsur-shared/dist/dto/api/info.dto';
|
||||
import { HostConfigService } from '../../../config/host.config.service';
|
||||
import { NoAuth } from '../../../decorators/permissions.decorator';
|
||||
import { NoPermissions } from '../../../decorators/permissions.decorator';
|
||||
|
||||
@Controller('api/info')
|
||||
export class InfoController {
|
||||
constructor(private hostConfig: HostConfigService) {}
|
||||
|
||||
@Get()
|
||||
@NoAuth()
|
||||
@NoPermissions()
|
||||
async getInfo(): Promise<InfoResponse> {
|
||||
return {
|
||||
demo: this.hostConfig.isDemo(),
|
||||
|
||||
@@ -3,10 +3,17 @@ import { NgModule } from '@angular/core';
|
||||
import { ApiService } from './api.service';
|
||||
import { ImageService } from './image.service';
|
||||
import { KeyService } from './key.service';
|
||||
import { PermissionService } from './permission.service';
|
||||
import { UserService } from './user.service';
|
||||
|
||||
@NgModule({
|
||||
providers: [ApiService, ImageService, UserService, KeyService],
|
||||
providers: [
|
||||
ApiService,
|
||||
ImageService,
|
||||
UserService,
|
||||
PermissionService,
|
||||
KeyService,
|
||||
],
|
||||
imports: [CommonModule],
|
||||
})
|
||||
export class ApiModule {}
|
||||
|
||||
50
frontend/src/app/api/permission.service.ts
Normal file
50
frontend/src/app/api/permission.service.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
|
||||
import { UserMePermissionsResponse } from 'picsur-shared/dist/dto/api/user.dto';
|
||||
import { Permissions } from 'picsur-shared/dist/dto/permissions';
|
||||
import { AsyncFailable, HasFailed } from 'picsur-shared/dist/types';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { ApiService } from './api.service';
|
||||
import { UserService } from './user.service';
|
||||
|
||||
@Injectable()
|
||||
export class PermissionService {
|
||||
private readonly logger = console;
|
||||
|
||||
constructor(private userService: UserService, private api: ApiService) {
|
||||
this.onUser();
|
||||
}
|
||||
|
||||
public get livePermissions() {
|
||||
return this.permissionsSubject;
|
||||
}
|
||||
|
||||
public get permissions() {
|
||||
return this.permissionsSubject.getValue();
|
||||
}
|
||||
|
||||
private permissionsSubject = new BehaviorSubject<Permissions>([]);
|
||||
|
||||
@AutoUnsubscribe()
|
||||
private onUser() {
|
||||
return this.userService.liveUser.subscribe(async (user) => {
|
||||
const permissions = await this.fetchPermissions();
|
||||
if (HasFailed(permissions)) {
|
||||
this.logger.warn(permissions.getReason());
|
||||
return;
|
||||
}
|
||||
|
||||
this.permissionsSubject.next(permissions);
|
||||
});
|
||||
}
|
||||
|
||||
private async fetchPermissions(): AsyncFailable<Permissions> {
|
||||
const got = await this.api.get(
|
||||
UserMePermissionsResponse,
|
||||
'/api/user/me/permissions'
|
||||
);
|
||||
if (HasFailed(got)) return got;
|
||||
|
||||
return got.permissions;
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,7 @@ import { validate } from 'class-validator';
|
||||
import jwt_decode from 'jwt-decode';
|
||||
import {
|
||||
UserLoginRequest,
|
||||
UserLoginResponse,
|
||||
UserMeResponse
|
||||
UserLoginResponse, UserMeResponse
|
||||
} from 'picsur-shared/dist/dto/api/user.dto';
|
||||
import { JwtDataDto } from 'picsur-shared/dist/dto/jwt.dto';
|
||||
import { EUser } from 'picsur-shared/dist/entities/user.entity';
|
||||
@@ -117,7 +116,7 @@ export class UserService {
|
||||
const got = await this.api.get(UserMeResponse, '/api/user/me');
|
||||
if (HasFailed(got)) return got;
|
||||
|
||||
this.key.set(got.newJwtToken);
|
||||
this.key.set(got.token);
|
||||
return got.user;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,14 +90,17 @@ export class UserMeResponse {
|
||||
@Type(() => EUser)
|
||||
user: EUser;
|
||||
|
||||
@IsString()
|
||||
@IsDefined()
|
||||
token: string;
|
||||
}
|
||||
|
||||
// UserMePermissions
|
||||
export class UserMePermissionsResponse {
|
||||
@IsDefined()
|
||||
@IsArray()
|
||||
@IsEnum(PermissionsList, { each: true })
|
||||
permissions: Permissions;
|
||||
|
||||
@IsString()
|
||||
@IsDefined()
|
||||
newJwtToken: string;
|
||||
}
|
||||
|
||||
// UserUpdateRoles
|
||||
|
||||
@@ -7,8 +7,8 @@ const PermissionsTuple = tuple(
|
||||
'image-upload',
|
||||
'user-login', // Ability to log in
|
||||
'user-register', // Ability to register
|
||||
'user-view', // Ability to view user info, only granted if logged in
|
||||
'user-manage',
|
||||
'user-view', // Ability to view user details and refresh token
|
||||
'role-manage',
|
||||
'syspref-manage',
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user