mirror of
https://github.com/PretendoNetwork/BOSS.git
synced 2026-08-19 23:54:08 -05:00
feat: make GRPC server compatible with non-user callers
This commit is contained in:
@@ -1,16 +1,13 @@
|
||||
import { Status, ServerError } from 'nice-grpc';
|
||||
import { getTaskFileByDataID } from '@/database';
|
||||
import { hasPermission } from '@/services/grpc/boss/middleware/authentication-middleware';
|
||||
import type { AuthenticationCallContextExt } from '@/services/grpc/boss/middleware/authentication-middleware';
|
||||
import type { CallContext } from 'nice-grpc';
|
||||
import type { DeleteFileRequest } from '@pretendonetwork/grpc/boss/delete_file';
|
||||
import type { GetUserDataResponse } from '@pretendonetwork/grpc/account/get_user_data_rpc';
|
||||
import type { Empty } from '@pretendonetwork/grpc/boss/google/protobuf/empty';
|
||||
import type { AuthenticationCallContextExt } from '@/services/grpc/boss/middleware/authentication-middleware';
|
||||
|
||||
export async function deleteFile(request: DeleteFileRequest, context: CallContext & AuthenticationCallContextExt): Promise<Empty> {
|
||||
// * This is asserted in authentication middleware, we know this is never null
|
||||
const user: GetUserDataResponse = context.user!;
|
||||
|
||||
if (!user.permissions?.deleteBossFiles) {
|
||||
if (!hasPermission(context, 'deleteBossFiles')) {
|
||||
throw new ServerError(Status.PERMISSION_DENIED, 'PNID not authorized to delete files');
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
import { Status, ServerError } from 'nice-grpc';
|
||||
import { getTask } from '@/database';
|
||||
import { hasPermission } from '@/services/grpc/boss/middleware/authentication-middleware';
|
||||
import type { AuthenticationCallContextExt } from '@/services/grpc/boss/middleware/authentication-middleware';
|
||||
import type { CallContext } from 'nice-grpc';
|
||||
import type { DeleteTaskRequest } from '@pretendonetwork/grpc/boss/delete_task';
|
||||
import type { GetUserDataResponse } from '@pretendonetwork/grpc/account/get_user_data_rpc';
|
||||
import type { AuthenticationCallContextExt } from '@/services/grpc/boss/middleware/authentication-middleware';
|
||||
import type { Empty } from '@pretendonetwork/grpc/boss/google/protobuf/empty';
|
||||
|
||||
export async function deleteTask(request: DeleteTaskRequest, context: CallContext & AuthenticationCallContextExt): Promise<Empty> {
|
||||
// * This is asserted in authentication middleware, we know this is never null
|
||||
const user: GetUserDataResponse = context.user!;
|
||||
|
||||
if (!user.permissions?.deleteBossTasks) {
|
||||
if (!hasPermission(context, 'deleteBossTasks')) {
|
||||
throw new ServerError(Status.PERMISSION_DENIED, 'PNID not authorized to delete tasks');
|
||||
}
|
||||
|
||||
|
||||
@@ -2,14 +2,7 @@ import { Status, ServerError } from 'nice-grpc';
|
||||
import { getUserDataByToken } from '@/util';
|
||||
import type { ServerMiddlewareCall, CallContext } from 'nice-grpc';
|
||||
import type { GetUserDataResponse } from '@pretendonetwork/grpc/account/get_user_data_rpc';
|
||||
|
||||
const TOKEN_REQUIRED_PATHS = [
|
||||
'/boss.BOSS/RegisterTask',
|
||||
'/boss.BOSS/UpdateTask',
|
||||
'/boss.BOSS/DeleteTask',
|
||||
'/boss.BOSS/UploadFile',
|
||||
'/boss.BOSS/DeleteFile'
|
||||
];
|
||||
import type { PNIDPermissionFlags } from '@pretendonetwork/grpc/account/pnid_permission_flags';
|
||||
|
||||
export type AuthenticationCallContextExt = {
|
||||
user: GetUserDataResponse | null;
|
||||
@@ -21,19 +14,14 @@ export async function* authenticationMiddleware<Request, Response>(
|
||||
): AsyncGenerator<Response, Response | void, undefined> {
|
||||
const token: string | undefined = context.metadata.get('X-Token')?.trim();
|
||||
|
||||
if (!token && TOKEN_REQUIRED_PATHS.includes(call.method.path)) {
|
||||
throw new ServerError(Status.UNAUTHENTICATED, 'Missing or invalid authentication token');
|
||||
}
|
||||
|
||||
try {
|
||||
let user: GetUserDataResponse | null = null;
|
||||
|
||||
if (token) {
|
||||
user = await getUserDataByToken(token);
|
||||
}
|
||||
|
||||
if (!user && TOKEN_REQUIRED_PATHS.includes(call.method.path)) {
|
||||
throw new ServerError(Status.UNAUTHENTICATED, 'Missing or invalid authentication token');
|
||||
if (!user) {
|
||||
throw new ServerError(Status.UNAUTHENTICATED, 'User could not be found');
|
||||
}
|
||||
}
|
||||
|
||||
return yield* call.next(call.request, {
|
||||
@@ -52,3 +40,13 @@ export async function* authenticationMiddleware<Request, Response>(
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, message);
|
||||
}
|
||||
}
|
||||
|
||||
export function hasPermission(ctx: AuthenticationCallContextExt, perm: keyof PNIDPermissionFlags): boolean {
|
||||
if (!ctx.user) {
|
||||
return true; // Non users are always allowed
|
||||
}
|
||||
if (!ctx.user.permissions) {
|
||||
return false; // No permissions, no entry
|
||||
}
|
||||
return ctx.user.permissions[perm];
|
||||
}
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
import { ServerError, Status } from 'nice-grpc';
|
||||
import { getTask } from '@/database';
|
||||
import { Task } from '@/models/task';
|
||||
import type { CallContext } from 'nice-grpc';
|
||||
import { hasPermission } from '@/services/grpc/boss/middleware/authentication-middleware';
|
||||
import type { AuthenticationCallContextExt } from '@/services/grpc/boss/middleware/authentication-middleware';
|
||||
import type { GetUserDataResponse } from '@pretendonetwork/grpc/account/get_user_data_rpc';
|
||||
import type { CallContext } from 'nice-grpc';
|
||||
import type { RegisterTaskRequest, RegisterTaskResponse } from '@pretendonetwork/grpc/boss/register_task';
|
||||
|
||||
const BOSS_APP_ID_FILTER_REGEX = /^[A-Za-z0-9]*$/;
|
||||
|
||||
export async function registerTask(request: RegisterTaskRequest, context: CallContext & AuthenticationCallContextExt): Promise<RegisterTaskResponse> {
|
||||
// * This is asserted in authentication middleware, we know this is never null
|
||||
const user: GetUserDataResponse = context.user!;
|
||||
|
||||
if (!user.permissions?.createBossTasks) {
|
||||
if (!hasPermission(context, 'createBossTasks')) {
|
||||
throw new ServerError(Status.PERMISSION_DENIED, 'PNID not authorized to register new tasks');
|
||||
}
|
||||
|
||||
@@ -55,7 +52,7 @@ export async function registerTask(request: RegisterTaskRequest, context: CallCo
|
||||
id: taskID.slice(0, 7),
|
||||
in_game_id: taskID,
|
||||
boss_app_id: bossAppID,
|
||||
creator_pid: user.pid,
|
||||
creator_pid: context.user?.pid,
|
||||
status: 'open', // TODO - Make this configurable
|
||||
title_id: titleID,
|
||||
description: description,
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
import { Status, ServerError } from 'nice-grpc';
|
||||
import { getTaskFileByDataID } from '@/database';
|
||||
import { isValidFileNotifyCondition, isValidFileType } from '@/util';
|
||||
import { hasPermission } from '@/services/grpc/boss/middleware/authentication-middleware';
|
||||
import type { AuthenticationCallContextExt } from '@/services/grpc/boss/middleware/authentication-middleware';
|
||||
import type { CallContext } from 'nice-grpc';
|
||||
import type { UpdateFileMetadataRequest } from '@pretendonetwork/grpc/boss/update_file_metadata';
|
||||
import type { GetUserDataResponse } from '@pretendonetwork/grpc/account/get_user_data_rpc';
|
||||
import type { AuthenticationCallContextExt } from '@/services/grpc/boss/middleware/authentication-middleware';
|
||||
import type { Empty } from '@pretendonetwork/grpc/boss/google/protobuf/empty';
|
||||
|
||||
export async function updateFileMetadata(request: UpdateFileMetadataRequest, context: CallContext & AuthenticationCallContextExt): Promise<Empty> {
|
||||
// * This is asserted in authentication middleware, we know this is never null
|
||||
const user: GetUserDataResponse = context.user!;
|
||||
|
||||
if (!user.permissions?.updateBossFiles) {
|
||||
if (!hasPermission(context, 'updateBossFiles')) {
|
||||
throw new ServerError(Status.PERMISSION_DENIED, 'PNID not authorized to update file metadata');
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
import { Status, ServerError } from 'nice-grpc';
|
||||
import { getTask } from '@/database';
|
||||
import { hasPermission } from '@/services/grpc/boss/middleware/authentication-middleware';
|
||||
import type { AuthenticationCallContextExt } from '@/services/grpc/boss/middleware/authentication-middleware';
|
||||
import type { CallContext } from 'nice-grpc';
|
||||
import type { UpdateTaskRequest } from '@pretendonetwork/grpc/boss/update_task';
|
||||
import type { GetUserDataResponse } from '@pretendonetwork/grpc/account/get_user_data_rpc';
|
||||
import type { AuthenticationCallContextExt } from '@/services/grpc/boss/middleware/authentication-middleware';
|
||||
import type { Empty } from '@pretendonetwork/grpc/boss/google/protobuf/empty';
|
||||
|
||||
export async function updateTask(request: UpdateTaskRequest, context: CallContext & AuthenticationCallContextExt): Promise<Empty> {
|
||||
// * This is asserted in authentication middleware, we know this is never null
|
||||
const user: GetUserDataResponse = context.user!;
|
||||
|
||||
if (!user.permissions?.updateBossTasks) {
|
||||
if (!hasPermission(context, 'updateBossTasks')) {
|
||||
throw new ServerError(Status.PERMISSION_DENIED, 'PNID not authorized to update tasks');
|
||||
}
|
||||
|
||||
|
||||
@@ -5,18 +5,15 @@ import { getTask, getTaskFile } from '@/database';
|
||||
import { File } from '@/models/file';
|
||||
import { config } from '@/config-manager';
|
||||
import { uploadCdnFile } from '@/cdn';
|
||||
import type { CallContext } from 'nice-grpc';
|
||||
import { hasPermission } from '@/services/grpc/boss/middleware/authentication-middleware';
|
||||
import type { AuthenticationCallContextExt } from '@/services/grpc/boss/middleware/authentication-middleware';
|
||||
import type { GetUserDataResponse } from '@pretendonetwork/grpc/account/get_user_data_rpc';
|
||||
import type { CallContext } from 'nice-grpc';
|
||||
import type { UploadFileRequest, UploadFileResponse } from '@pretendonetwork/grpc/boss/upload_file';
|
||||
|
||||
const BOSS_APP_ID_FILTER_REGEX = /^[A-Za-z0-9]*$/;
|
||||
|
||||
export async function uploadFile(request: UploadFileRequest, context: CallContext & AuthenticationCallContextExt): Promise<UploadFileResponse> {
|
||||
// * This is asserted in authentication middleware, we know this is never null
|
||||
const user: GetUserDataResponse = context.user!;
|
||||
|
||||
if (!user.permissions?.uploadBossFiles) {
|
||||
if (!hasPermission(context, 'uploadBossFiles')) {
|
||||
throw new ServerError(Status.PERMISSION_DENIED, 'PNID not authorized to upload new files');
|
||||
}
|
||||
|
||||
@@ -138,7 +135,7 @@ export async function uploadFile(request: UploadFileRequest, context: CallContex
|
||||
boss_app_id: bossAppID,
|
||||
supported_countries: supportedCountries,
|
||||
supported_languages: supportedLanguages,
|
||||
creator_pid: user.pid,
|
||||
creator_pid: context.user?.pid,
|
||||
name: name,
|
||||
type: type,
|
||||
hash: contentHash,
|
||||
|
||||
Reference in New Issue
Block a user