🔒 feat: Implement Granular File Storage Strategies and Access Control Middleware

This commit is contained in:
“Praneeth 2025-07-25 16:50:18 +02:00 committed by Danny Avila
parent 74e029e78f
commit ff54cbffd9
No known key found for this signature in database
GPG key ID: BF31EEB2C5CA0956
13 changed files with 269 additions and 210 deletions

View file

@ -86,6 +86,7 @@ const AppService = async (app) => {
const turnstileConfig = loadTurnstileConfig(config, configDefaults);
const defaultLocals = {
config,
ocr,
paths,
memory,

View file

@ -133,6 +133,9 @@ describe('AppService', () => {
expect(process.env.CDN_PROVIDER).toEqual('testStrategy');
expect(app.locals).toEqual({
config: expect.objectContaining({
fileStrategy: 'testStrategy',
}),
socialLogins: ['testLogin'],
fileStrategy: 'testStrategy',
interfaceConfig: expect.objectContaining({
@ -775,6 +778,7 @@ describe('AppService updating app.locals and issuing warnings', () => {
expect(app.locals).toBeDefined();
expect(app.locals.paths).toBeDefined();
expect(app.locals.config).toEqual({});
expect(app.locals.fileStrategy).toEqual(FileSources.local);
expect(app.locals.socialLogins).toEqual(defaultSocialLogins);
expect(app.locals.balance).toEqual(
@ -807,6 +811,7 @@ describe('AppService updating app.locals and issuing warnings', () => {
expect(app.locals).toBeDefined();
expect(app.locals.paths).toBeDefined();
expect(app.locals.config).toEqual(customConfig);
expect(app.locals.fileStrategy).toEqual(customConfig.fileStrategy);
expect(app.locals.socialLogins).toEqual(customConfig.registration.socialLogins);
expect(app.locals.balance).toEqual(customConfig.balance);

View file

@ -31,6 +31,7 @@ const { loadAuthValues } = require('~/server/services/Tools/credentials');
const { checkCapability } = require('~/server/services/Config');
const { LB_QueueAsyncCall } = require('~/server/utils/queue');
const { getStrategyFunctions } = require('./strategies');
const { getFileStrategy } = require('~/server/utils/getFileStrategy');
const { determineFileType } = require('~/server/utils');
const { logger } = require('~/config');
@ -319,7 +320,7 @@ const processFileURL = async ({ fileStrategy, userId, URL, fileName, basePath, c
*/
const processImageFile = async ({ req, res, metadata, returnFile = false }) => {
const { file } = req;
const source = req.app.locals.fileStrategy;
const source = getFileStrategy(req.app.locals, { isImage: true });
const { handleImageUpload } = getStrategyFunctions(source);
const { file_id, temp_file_id, endpoint } = metadata;
@ -365,7 +366,7 @@ const processImageFile = async ({ req, res, metadata, returnFile = false }) => {
* @returns {Promise<{ filepath: string, filename: string, source: string, type: string}>}
*/
const uploadImageBuffer = async ({ req, context, metadata = {}, resize = true }) => {
const source = req.app.locals.fileStrategy;
const source = getFileStrategy(req.app.locals, { isImage: true });
const { saveBuffer } = getStrategyFunctions(source);
let { buffer, width, height, bytes, filename, file_id, type } = metadata;
if (resize) {
@ -595,7 +596,8 @@ const processAgentFileUpload = async ({ req, res, metadata }) => {
// Dual storage pattern for RAG files: Storage + Vector DB
let storageResult, embeddingResult;
const source = req.app.locals.fileStrategy;
const isImageFile = file.mimetype.startsWith('image');
const source = getFileStrategy(req.app.locals, { isImage: isImageFile });
if (tool_resource === EToolResources.file_search) {
// FIRST: Upload to Storage for permanent backup (S3/local/etc.)
@ -763,7 +765,7 @@ const processOpenAIImageOutput = async ({ req, buffer, file_id, filename, fileEx
type: mime.getType(fileExt),
createdAt: formattedDate,
updatedAt: formattedDate,
source,
source: getFileStrategy(req.app.locals, { isImage: true }),
context: FileContext.assistants_output,
file_id,
filename,
@ -904,7 +906,7 @@ async function saveBase64Image(
}
const image = await resizeImageBuffer(inputBuffer, effectiveResolution, endpoint);
const source = req.app.locals.fileStrategy;
const source = getFileStrategy(req.app.locals, { isImage: true });
const { saveBuffer } = getStrategyFunctions(source);
const filepath = await saveBuffer({
userId: req.user.id,

View file

@ -270,8 +270,12 @@ const getStrategyFunctions = (fileSource) => {
return azureMistralOCRStrategy();
} else if (fileSource === FileSources.vertexai_mistral_ocr) {
return vertexMistralOCRStrategy();
} else if (fileSource === FileSources.text) {
return localStrategy(); // Text files use local strategy
} else {
throw new Error('Invalid file source');
throw new Error(
`Invalid file source: ${fileSource}. Available sources: ${Object.values(FileSources).join(', ')}`,
);
}
};