feat(core-api): harden signed urls and llm rate limits
This commit is contained in:
@@ -6,9 +6,11 @@ import { requireAuth, requirePolicy } from '../middleware/auth.js';
|
||||
import { createSignedUrlSchema } from '../contracts/core/create-signed-url.js';
|
||||
import { invokeLlmSchema } from '../contracts/core/invoke-llm.js';
|
||||
import { invokeVertexModel } from '../services/llm.js';
|
||||
import { generateReadSignedUrl, uploadToGcs } from '../services/storage.js';
|
||||
import { checkLlmRateLimit } from '../services/llm-rate-limit.js';
|
||||
import { generateReadSignedUrl, uploadToGcs, validateFileUriAccess } from '../services/storage.js';
|
||||
|
||||
const DEFAULT_MAX_FILE_BYTES = 10 * 1024 * 1024;
|
||||
const DEFAULT_MAX_SIGNED_URL_SECONDS = 900;
|
||||
const ALLOWED_FILE_TYPES = new Set(['application/pdf', 'image/jpeg', 'image/jpg', 'image/png']);
|
||||
|
||||
const upload = multer({
|
||||
@@ -105,10 +107,25 @@ async function handleCreateSignedUrl(req, res, next) {
|
||||
try {
|
||||
const payload = parseBody(createSignedUrlSchema, req.body || {});
|
||||
const expiresInSeconds = payload.expiresInSeconds || 300;
|
||||
const maxSignedUrlSeconds = Number.parseInt(
|
||||
process.env.MAX_SIGNED_URL_SECONDS || `${DEFAULT_MAX_SIGNED_URL_SECONDS}`,
|
||||
10
|
||||
);
|
||||
if (expiresInSeconds > maxSignedUrlSeconds) {
|
||||
throw new AppError('VALIDATION_ERROR', `expiresInSeconds must be <= ${maxSignedUrlSeconds}`, 400);
|
||||
}
|
||||
|
||||
const signed = useMockSignedUrl()
|
||||
? mockSignedUrl(payload.fileUri, expiresInSeconds)
|
||||
? (() => {
|
||||
validateFileUriAccess({
|
||||
fileUri: payload.fileUri,
|
||||
actorUid: req.actor.uid,
|
||||
});
|
||||
return mockSignedUrl(payload.fileUri, expiresInSeconds);
|
||||
})()
|
||||
: await generateReadSignedUrl({
|
||||
fileUri: payload.fileUri,
|
||||
actorUid: req.actor.uid,
|
||||
expiresInSeconds,
|
||||
});
|
||||
|
||||
@@ -124,6 +141,12 @@ async function handleCreateSignedUrl(req, res, next) {
|
||||
async function handleInvokeLlm(req, res, next) {
|
||||
try {
|
||||
const payload = parseBody(invokeLlmSchema, req.body || {});
|
||||
const rateLimit = checkLlmRateLimit({ uid: req.actor.uid });
|
||||
if (!rateLimit.allowed) {
|
||||
throw new AppError('RATE_LIMITED', 'Too many model requests. Please retry shortly.', 429, {
|
||||
retryAfterSeconds: rateLimit.retryAfterSeconds,
|
||||
});
|
||||
}
|
||||
|
||||
const startedAt = Date.now();
|
||||
if (process.env.LLM_MOCK === 'false') {
|
||||
|
||||
Reference in New Issue
Block a user