Each type of file upload has its own configuration and they all stay at:
frontend/src/security/storage.ts
backend/src/security/storage.ts
/** * Storage permissions. * * @id - Used to identify the rule on permissions and upload. * @folder - Folder where the files will be saved * @maxSizeInBytes - Max allowed size in bytes * @bypassWritingPermissions - Does not validate if the user has permission to write * @publicRead - The file can be publicly accessed via the URL without the need for a signed token */exportdefaultclassStorage {staticgetvalues() {return { userAvatarsProfiles: { id:'userAvatarsProfiles', folder:'user/avatars/profile/:userId', maxSizeInBytes:10*1024*1024, bypassWritingPermissions:true, publicRead:true, }, settingsLogos: { id:'settingsLogos', folder:'tenant/:tenantId/settings/logos', maxSizeInBytes:10*1024*1024, publicRead:true, }, settingsBackgroundImages: { id:'settingsBackgroundImages', folder:'tenant/:tenantId/settings/backgroundImages', maxSizeInBytes:10*1024*1024, publicRead:true, }, productPhotos: { id:'productPhotos', folder:'tenant/:tenantId/product/photos', maxSizeInBytes:1000000, }, orderAttachments: { id:'orderAttachments', folder:'tenant/:tenantId/order/attachments', maxSizeInBytes:1000000, }, }; }}
id: Used to identify the rule on permissions and upload.
folder: Folder where the files will be saved. It accepts two parameters, :userId and:tenantId, that, when saved, are replaced by their real value.
maxSizeInBytes: Max allowed size in bytes.
bypassWritingPermissions: Does not validate if the user has permission to write. This is usually when the user id is on the path, so they only access their folder.
publicRead: The file can be publicly accessed via the URL without the need for a signed token.
Credentials
For Amazon S3 and Google Cloud Storage, the uploaded files do not pass through the backend. The backend creates credentials that allow the frontend to submit directly to the file storage provider.
Before sending the credentials to the frontend, the backend validates if the user has all the needed permissions.
import PermissionChecker from'../../services/user/permissionChecker';import Storage from'../../security/storage';import FileStorage from'../../services/file/fileStorage';import ApiResponseHandler from'../apiResponseHandler';import Error403 from'../../errors/Error403';exportdefaultasync (req, res) => {try {constpermissionChecker=newPermissionChecker(req);constfilename=req.query.filename;conststorageId=req.query.storageId;if (!req.currentUser ||!req.currentUser.id) {thrownewError403(); }if (!req.currentTenant ||!req.currentTenant.id) {thrownewError403(); }// The config storage has the information on where// to store the file and the max sizeconstconfig=Storage.values[storageId];if (!config) {thrownewError403(); }if (// Some permissions are related to the user itself,// not related to any entity, that's why there is a bypass permissions!config.bypassWritingPermissions &&!permissionChecker.hasStorage(storageId) ) {thrownewError403(); }// The private URL is the path related to the bucket/file system folderlet privateUrl =`${config.folder}/${filename}`; privateUrl =privateUrl.replace(':tenantId',req.currentTenant.id, ); privateUrl =privateUrl.replace(':userId',req.currentUser.id, );constmaxSizeInBytes=config.maxSizeInBytes;constpublicRead=Boolean(config.publicRead);constdownloadUrl=awaitFileStorage.downloadUrl( privateUrl, publicRead, );/** * Upload Credentials has the URL and the fields to be sent * to the upload server. */constuploadCredentials=awaitFileStorage.uploadCredentials( privateUrl, maxSizeInBytes, publicRead, );awaitApiResponseHandler.success(req, res, { privateUrl, downloadUrl, uploadCredentials, }); } catch (error) {awaitApiResponseHandler.error(req, res, error); }};
Localhost
The localhost is a bit different from the Amazon S3 and Google Cloud Storage. Instead of generating a provider's token, it uses the JWT token of the current application to pass it to another endpoint that only validates this token and handles the upload to the localhost server.
Frontend
The frontend builds the upload form using the credentials created by the backend.