Files
us-api/src/kv/kv.controller.ts
2024-04-04 17:43:27 -06:00

157 lines
3.9 KiB
TypeScript

import {
Controller,
Get,
Post,
Req,
Body,
Param,
HttpException,
Patch,
UseInterceptors,
UploadedFile,
} from '@nestjs/common';
import { KvService } from './kv.service';
import { Request } from 'express';
import { ApiQuery, ApiTags } from '@nestjs/swagger';
import { FileInterceptor } from '@nestjs/platform-express';
@Controller('kv')
@ApiTags('kv')
export class KvController {
constructor(private readonly kvService: KvService) { }
@Get(':namespace/:key/metadata')
@ApiQuery({ name: 'namespace', required: true })
@ApiQuery({ name: 'key', required: true })
async getMetadata(
@Param('namespace') namespace: string,
@Param('key') key: string,
@Req() request: Request,
): Promise<object> {
if (!request.headers['x-secret-key']) {
throw new HttpException("Missing 'X-Secret-Key' header", 403);
}
try {
return await this.kvService.queryObjectMetadata(
namespace,
key,
request.headers['x-secret-key'] as string,
);
} catch (e) {
throw new HttpException(e.message, 403);
}
}
@Get(':namespace/:key')
async get(
@Param('namespace') namespace: string,
@Param('key') key: string,
@Req() request: Request,
): Promise<string> {
if (request.headers['x-secret-key']) {
try {
return (
await this.kvService.getWithSecretKey(
namespace,
key,
request.headers['x-secret-key'] as string,
)
).toString();
} catch (e) {
throw new HttpException(e.message, 403);
}
}
try {
return (await this.kvService.get(namespace, key)).toString();
} catch (e) {
throw new HttpException(e.message, 403);
}
}
@Post(':namespace/:key')
@UseInterceptors(FileInterceptor('file'))
async create(
@Param('namespace') namespace: string,
@Param('key') key: string,
@Req() request: Request,
@Body() body: object | string,
@UploadedFile('file') file: Express.Multer.File,
) {
const secretKey =
(request.headers['x-secret-key'] as string | undefined) ?? '';
const publicFlag = request.headers['x-public'] === 'true';
if (secretKey) {
return await this.kvService.set(
namespace,
key,
file === undefined
? typeof body === 'object'
? Buffer.from(JSON.stringify(body))
: Buffer.from(body)
: file.buffer,
secretKey,
{
public: publicFlag,
mimeType:
file?.mimetype ?? request.headers['content-type'] ?? 'text/plain',
},
);
}
return 'No secret key provided within X-Secret-Key header';
}
@Post(':namespace/:key/share')
async share(
@Param('namespace') namespace: string,
@Param('key') key: string,
@Req() request: Request,
@Body() body: { expiry?: number },
) {
const secretKey =
(request.headers['x-secret-key'] as string | undefined) ?? '';
if (secretKey) {
return {
expiry: body.expiry,
namespace,
key,
url: await this.kvService.shareFile(
namespace,
key,
secretKey,
body.expiry,
),
};
}
}
@Post(':namespace')
async claimNamespace(
@Param('namespace') namespace: string,
@Req() request: Request,
) {
try {
return await this.kvService.claimNamespace(namespace);
} catch (e) {
throw new HttpException(e.message, 403);
}
}
@Patch(':namespace/secretKey')
async rotateSecretKey(
@Param('namespace') namespace: string,
@Req() request: Request,
) {
if (!request.headers['x-secret-key']) {
throw new HttpException("Missing 'X-Secret-Key' header", 403);
}
try {
return await this.kvService.rotateSecretKey(
namespace,
request.headers['x-secret-key'] as string,
);
} catch (e) {
throw new HttpException(e.message, 403);
}
}
}