mirror of
https://github.com/papra-hq/papra.git
synced 2025-12-20 20:29:54 -06:00
Compare commits
1 Commits
@papra/doc
...
storage-dr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ed9f34ee8 |
@@ -18,7 +18,7 @@ const { config } = await parseConfig({ env });
|
|||||||
await ensureLocalDatabaseDirectoryExists({ config });
|
await ensureLocalDatabaseDirectoryExists({ config });
|
||||||
const { db, client } = setupDatabase(config.database);
|
const { db, client } = setupDatabase(config.database);
|
||||||
|
|
||||||
const documentsStorageService = createDocumentStorageService({ config });
|
const documentsStorageService = createDocumentStorageService({ documentStorageConfig: config.documentsStorage });
|
||||||
|
|
||||||
const taskServices = createTaskServices({ config });
|
const taskServices = createTaskServices({ config });
|
||||||
const { app } = await createServer({ config, db, taskServices, documentsStorageService });
|
const { app } = await createServer({ config, db, taskServices, documentsStorageService });
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ async function createGlobalDependencies(partialDeps: Partial<GlobalDependencies>
|
|||||||
const auth = partialDeps.auth ?? getAuth({ db, config, authEmailsServices: createAuthEmailsServices({ emailsServices }), trackingServices }).auth;
|
const auth = partialDeps.auth ?? getAuth({ db, config, authEmailsServices: createAuthEmailsServices({ emailsServices }), trackingServices }).auth;
|
||||||
const subscriptionsServices = createSubscriptionsServices({ config });
|
const subscriptionsServices = createSubscriptionsServices({ config });
|
||||||
const taskServices = partialDeps.taskServices ?? createTaskServices({ config });
|
const taskServices = partialDeps.taskServices ?? createTaskServices({ config });
|
||||||
const documentsStorageService = partialDeps.documentsStorageService ?? createDocumentStorageService({ config });
|
const documentsStorageService = partialDeps.documentsStorageService ?? createDocumentStorageService({ documentStorageConfig: config.documentsStorage });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
documentsStorageService,
|
documentsStorageService,
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ describe('documents usecases', () => {
|
|||||||
organizationPlans: { isFreePlanUnlimited: true },
|
organizationPlans: { isFreePlanUnlimited: true },
|
||||||
documentsStorage: { driver: 'in-memory' },
|
documentsStorage: { driver: 'in-memory' },
|
||||||
});
|
});
|
||||||
const documentsStorageService = createDocumentStorageService({ config });
|
const documentsStorageService = createDocumentStorageService({ documentStorageConfig: config.documentsStorage });
|
||||||
|
|
||||||
const createDocument = await createDocumentCreationUsecase({
|
const createDocument = await createDocumentCreationUsecase({
|
||||||
db,
|
db,
|
||||||
@@ -93,7 +93,7 @@ describe('documents usecases', () => {
|
|||||||
documentsStorage: { driver: 'in-memory' },
|
documentsStorage: { driver: 'in-memory' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const documentsStorageService = createDocumentStorageService({ config });
|
const documentsStorageService = createDocumentStorageService({ documentStorageConfig: config.documentsStorage });
|
||||||
|
|
||||||
let documentIdIndex = 1;
|
let documentIdIndex = 1;
|
||||||
const createDocument = await createDocumentCreationUsecase({
|
const createDocument = await createDocumentCreationUsecase({
|
||||||
@@ -254,7 +254,7 @@ describe('documents usecases', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const documentsRepository = createDocumentsRepository({ db });
|
const documentsRepository = createDocumentsRepository({ db });
|
||||||
const documentsStorageService = createDocumentStorageService({ config });
|
const documentsStorageService = createDocumentStorageService({ documentStorageConfig: config.documentsStorage });
|
||||||
|
|
||||||
const createDocument = await createDocumentCreationUsecase({
|
const createDocument = await createDocumentCreationUsecase({
|
||||||
documentsStorageService,
|
documentsStorageService,
|
||||||
@@ -533,7 +533,7 @@ describe('documents usecases', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const documentsRepository = createDocumentsRepository({ db });
|
const documentsRepository = createDocumentsRepository({ db });
|
||||||
const documentsStorageService = createDocumentStorageService({ config });
|
const documentsStorageService = createDocumentStorageService({ documentStorageConfig: config.documentsStorage });
|
||||||
const taggingRulesRepository = createTaggingRulesRepository({ db });
|
const taggingRulesRepository = createTaggingRulesRepository({ db });
|
||||||
const tagsRepository = createTagsRepository({ db });
|
const tagsRepository = createTagsRepository({ db });
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { Config } from '../../config/config.types';
|
import type { Config } from '../../config/config.types';
|
||||||
|
import type { DocumentStorageConfig } from './documents.storage.types';
|
||||||
import type { StorageDriver, StorageDriverFactory, StorageServices } from './drivers/drivers.models';
|
import type { StorageDriver, StorageDriverFactory, StorageServices } from './drivers/drivers.models';
|
||||||
import { createError } from '../../shared/errors/errors';
|
import { createError } from '../../shared/errors/errors';
|
||||||
import { isNil } from '../../shared/utils';
|
import { isNil } from '../../shared/utils';
|
||||||
@@ -17,8 +18,8 @@ const storageDriverFactories = {
|
|||||||
|
|
||||||
export type DocumentStorageService = Awaited<ReturnType<typeof createDocumentStorageService>>;
|
export type DocumentStorageService = Awaited<ReturnType<typeof createDocumentStorageService>>;
|
||||||
|
|
||||||
export function createDocumentStorageService({ config }: { config: Config }): StorageServices {
|
export function createDocumentStorageService({ documentStorageConfig }: { documentStorageConfig: DocumentStorageConfig }): StorageServices {
|
||||||
const storageDriverName = config.documentsStorage.driver;
|
const storageDriverName = documentStorageConfig.driver;
|
||||||
|
|
||||||
const storageDriverFactory: StorageDriverFactory | undefined = storageDriverFactories[storageDriverName];
|
const storageDriverFactory: StorageDriverFactory | undefined = storageDriverFactories[storageDriverName];
|
||||||
|
|
||||||
@@ -31,11 +32,11 @@ export function createDocumentStorageService({ config }: { config: Config }): St
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const storageDriver = storageDriverFactory({ config });
|
const storageDriver = storageDriverFactory({ documentStorageConfig });
|
||||||
|
|
||||||
return createDocumentStorageServiceFromDriver({
|
return createDocumentStorageServiceFromDriver({
|
||||||
storageDriver,
|
storageDriver,
|
||||||
encryptionConfig: config.documentsStorage.encryption,
|
encryptionConfig: documentStorageConfig.encryption,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import type { Config } from '../../config/config.types';
|
||||||
|
|
||||||
|
export type DocumentStorageConfig = Config['documentsStorage'];
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { documentsTable } from "../documents.table";
|
||||||
|
import { DocumentStorageService } from "./documents.storage.services";
|
||||||
|
|
||||||
|
export async function migrateDocumentsStorage({db, inputDocumentStorageService, outputDocumentStorageService, logger = createLogger({ namespace: 'migrateDocumentsStorage' })}: {
|
||||||
|
db: Database;
|
||||||
|
inputDocumentStorageService: DocumentStorageService;
|
||||||
|
outputDocumentStorageService: DocumentStorageService;
|
||||||
|
logger?: Logger;
|
||||||
|
}) {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { DocumentStorageConfig } from '../../documents.storage.types';
|
||||||
import { AzuriteContainer } from '@testcontainers/azurite';
|
import { AzuriteContainer } from '@testcontainers/azurite';
|
||||||
import { describe } from 'vitest';
|
import { describe } from 'vitest';
|
||||||
import { TEST_CONTAINER_IMAGES } from '../../../../../../test/containers/images';
|
import { TEST_CONTAINER_IMAGES } from '../../../../../../test/containers/images';
|
||||||
@@ -13,11 +14,7 @@ describe('az-blob storage-driver', () => {
|
|||||||
const azuriteContainer = await new AzuriteContainer(TEST_CONTAINER_IMAGES.AZURITE).withInMemoryPersistence().start();
|
const azuriteContainer = await new AzuriteContainer(TEST_CONTAINER_IMAGES.AZURITE).withInMemoryPersistence().start();
|
||||||
const connectionString = azuriteContainer.getConnectionString();
|
const connectionString = azuriteContainer.getConnectionString();
|
||||||
|
|
||||||
const config = overrideConfig({
|
const driver = azBlobStorageDriverFactory({ documentStorageConfig: { drivers: { azureBlob: { connectionString, containerName: 'test-container' } } } as DocumentStorageConfig });
|
||||||
documentsStorage: { drivers: { azureBlob: { connectionString, containerName: 'test-container' } } },
|
|
||||||
});
|
|
||||||
|
|
||||||
const driver = azBlobStorageDriverFactory({ config });
|
|
||||||
const client = driver.getClient();
|
const client = driver.getClient();
|
||||||
await client.createContainer('test-container');
|
await client.createContainer('test-container');
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ function isAzureBlobNotFoundError(error: Error): boolean {
|
|||||||
return ('statusCode' in error && error.statusCode === 404) || ('code' in error && error.code === 'BlobNotFound');
|
return ('statusCode' in error && error.statusCode === 404) || ('code' in error && error.code === 'BlobNotFound');
|
||||||
}
|
}
|
||||||
|
|
||||||
export const azBlobStorageDriverFactory = defineStorageDriver(({ config }) => {
|
export const azBlobStorageDriverFactory = defineStorageDriver(({ documentStorageConfig }) => {
|
||||||
const { accountName, accountKey, containerName, connectionString } = config.documentsStorage.drivers.azureBlob;
|
const { accountName, accountKey, containerName, connectionString } = documentStorageConfig.drivers.azureBlob;
|
||||||
|
|
||||||
const blobServiceClient = connectionString !== undefined
|
const blobServiceClient = connectionString !== undefined
|
||||||
? BlobServiceClient.fromConnectionString(connectionString)
|
? BlobServiceClient.fromConnectionString(connectionString)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { Readable } from 'node:stream';
|
import type { Readable } from 'node:stream';
|
||||||
import type { Config } from '../../../config/config.types';
|
import type { Config } from '../../../config/config.types';
|
||||||
import type { ExtendNamedArguments, ExtendReturnPromise } from '../../../shared/types';
|
import type { ExtendNamedArguments, ExtendReturnPromise } from '../../../shared/types';
|
||||||
|
import type { DocumentStorageConfig } from '../documents.storage.types';
|
||||||
|
|
||||||
export type StorageDriver = {
|
export type StorageDriver = {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -31,7 +32,7 @@ export type StorageServices = {
|
|||||||
deleteFile: StorageDriver['deleteFile'];
|
deleteFile: StorageDriver['deleteFile'];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type StorageDriverFactory = (args: { config: Config }) => StorageDriver;
|
export type StorageDriverFactory = (args: { documentStorageConfig: DocumentStorageConfig }) => StorageDriver;
|
||||||
|
|
||||||
export function defineStorageDriver<T extends StorageDriverFactory>(factory: T) {
|
export function defineStorageDriver<T extends StorageDriverFactory>(factory: T) {
|
||||||
return factory;
|
return factory;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { Config } from '../../../../config/config.types';
|
import type { Config } from '../../../../config/config.types';
|
||||||
|
import type { DocumentStorageConfig } from '../../documents.storage.types';
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import { tmpdir } from 'node:os';
|
import { tmpdir } from 'node:os';
|
||||||
import path, { join } from 'node:path';
|
import path, { join } from 'node:path';
|
||||||
@@ -28,18 +29,10 @@ describe('storage driver', () => {
|
|||||||
createDriver: async () => {
|
createDriver: async () => {
|
||||||
const tmpDirectory = await createTmpDirectory();
|
const tmpDirectory = await createTmpDirectory();
|
||||||
|
|
||||||
const config = {
|
|
||||||
documentsStorage: {
|
|
||||||
drivers: {
|
|
||||||
filesystem: {
|
|
||||||
root: tmpDirectory,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as Config;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
driver: fsStorageDriverFactory({ config }),
|
driver: fsStorageDriverFactory({
|
||||||
|
documentStorageConfig: { drivers: { filesystem: { root: tmpDirectory } } } as DocumentStorageConfig,
|
||||||
|
}),
|
||||||
[Symbol.asyncDispose]: async () => {
|
[Symbol.asyncDispose]: async () => {
|
||||||
await deleteTmpDirectory(tmpDirectory);
|
await deleteTmpDirectory(tmpDirectory);
|
||||||
},
|
},
|
||||||
@@ -49,17 +42,7 @@ describe('storage driver', () => {
|
|||||||
|
|
||||||
describe('saveFile', () => {
|
describe('saveFile', () => {
|
||||||
test('persists the file to the filesystem', async () => {
|
test('persists the file to the filesystem', async () => {
|
||||||
const config = {
|
const fsStorageDriver = fsStorageDriverFactory({ documentStorageConfig: { drivers: { filesystem: { root: tmpDirectory } } } as DocumentStorageConfig });
|
||||||
documentsStorage: {
|
|
||||||
drivers: {
|
|
||||||
filesystem: {
|
|
||||||
root: tmpDirectory,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as Config;
|
|
||||||
|
|
||||||
const fsStorageDriver = fsStorageDriverFactory({ config });
|
|
||||||
|
|
||||||
const { storageKey } = await fsStorageDriver.saveFile({
|
const { storageKey } = await fsStorageDriver.saveFile({
|
||||||
fileStream: createReadableStream({ content: 'lorem ipsum' }),
|
fileStream: createReadableStream({ content: 'lorem ipsum' }),
|
||||||
@@ -77,17 +60,7 @@ describe('storage driver', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('an error is raised if the file already exists', async () => {
|
test('an error is raised if the file already exists', async () => {
|
||||||
const config = {
|
const fsStorageDriver = fsStorageDriverFactory({ documentStorageConfig: { drivers: { filesystem: { root: tmpDirectory } } } as DocumentStorageConfig });
|
||||||
documentsStorage: {
|
|
||||||
drivers: {
|
|
||||||
filesystem: {
|
|
||||||
root: tmpDirectory,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as Config;
|
|
||||||
|
|
||||||
const fsStorageDriver = fsStorageDriverFactory({ config });
|
|
||||||
|
|
||||||
await fsStorageDriver.saveFile({
|
await fsStorageDriver.saveFile({
|
||||||
fileStream: createReadableStream({ content: 'lorem ipsum' }),
|
fileStream: createReadableStream({ content: 'lorem ipsum' }),
|
||||||
@@ -109,17 +82,7 @@ describe('storage driver', () => {
|
|||||||
|
|
||||||
describe('getFileStream', () => {
|
describe('getFileStream', () => {
|
||||||
test('get a readable stream of a stored file', async () => {
|
test('get a readable stream of a stored file', async () => {
|
||||||
const config = {
|
const fsStorageDriver = fsStorageDriverFactory({ documentStorageConfig: { drivers: { filesystem: { root: tmpDirectory } } } as DocumentStorageConfig });
|
||||||
documentsStorage: {
|
|
||||||
drivers: {
|
|
||||||
filesystem: {
|
|
||||||
root: tmpDirectory,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as Config;
|
|
||||||
|
|
||||||
const fsStorageDriver = fsStorageDriverFactory({ config });
|
|
||||||
|
|
||||||
await fsStorageDriver.saveFile({
|
await fsStorageDriver.saveFile({
|
||||||
fileStream: createReadableStream({ content: 'lorem ipsum' }),
|
fileStream: createReadableStream({ content: 'lorem ipsum' }),
|
||||||
@@ -139,17 +102,7 @@ describe('storage driver', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('an error is raised if the file does not exist', async () => {
|
test('an error is raised if the file does not exist', async () => {
|
||||||
const config = {
|
const fsStorageDriver = fsStorageDriverFactory({ documentStorageConfig: { drivers: { filesystem: { root: tmpDirectory } } } as DocumentStorageConfig });
|
||||||
documentsStorage: {
|
|
||||||
drivers: {
|
|
||||||
filesystem: {
|
|
||||||
root: tmpDirectory,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as Config;
|
|
||||||
|
|
||||||
const fsStorageDriver = fsStorageDriverFactory({ config });
|
|
||||||
|
|
||||||
await expect(fsStorageDriver.getFileStream({ storageKey: 'org_1/text-file.txt' })).rejects.toThrow(createFileNotFoundError());
|
await expect(fsStorageDriver.getFileStream({ storageKey: 'org_1/text-file.txt' })).rejects.toThrow(createFileNotFoundError());
|
||||||
});
|
});
|
||||||
@@ -157,17 +110,7 @@ describe('storage driver', () => {
|
|||||||
|
|
||||||
describe('deleteFile', () => {
|
describe('deleteFile', () => {
|
||||||
test('deletes a stored file', async () => {
|
test('deletes a stored file', async () => {
|
||||||
const config = {
|
const fsStorageDriver = fsStorageDriverFactory({ documentStorageConfig: { drivers: { filesystem: { root: tmpDirectory } } } as DocumentStorageConfig });
|
||||||
documentsStorage: {
|
|
||||||
drivers: {
|
|
||||||
filesystem: {
|
|
||||||
root: tmpDirectory,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as Config;
|
|
||||||
|
|
||||||
const fsStorageDriver = fsStorageDriverFactory({ config });
|
|
||||||
|
|
||||||
await fsStorageDriver.saveFile({
|
await fsStorageDriver.saveFile({
|
||||||
fileStream: createReadableStream({ content: 'lorem ipsum' }),
|
fileStream: createReadableStream({ content: 'lorem ipsum' }),
|
||||||
@@ -189,17 +132,7 @@ describe('storage driver', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('when the file does not exist, an error is raised', async () => {
|
test('when the file does not exist, an error is raised', async () => {
|
||||||
const config = {
|
const fsStorageDriver = fsStorageDriverFactory({ documentStorageConfig: { drivers: { filesystem: { root: tmpDirectory } } } as DocumentStorageConfig });
|
||||||
documentsStorage: {
|
|
||||||
drivers: {
|
|
||||||
filesystem: {
|
|
||||||
root: tmpDirectory,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as Config;
|
|
||||||
|
|
||||||
const fsStorageDriver = fsStorageDriverFactory({ config });
|
|
||||||
|
|
||||||
await expect(fsStorageDriver.deleteFile({ storageKey: 'org_1/text-file.txt' })).rejects.toThrow(createFileNotFoundError());
|
await expect(fsStorageDriver.deleteFile({ storageKey: 'org_1/text-file.txt' })).rejects.toThrow(createFileNotFoundError());
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import { createFileAlreadyExistsError } from './fs.storage-driver.errors';
|
|||||||
|
|
||||||
export const FS_STORAGE_DRIVER_NAME = 'filesystem' as const;
|
export const FS_STORAGE_DRIVER_NAME = 'filesystem' as const;
|
||||||
|
|
||||||
export const fsStorageDriverFactory = defineStorageDriver(({ config }) => {
|
export const fsStorageDriverFactory = defineStorageDriver(({ documentStorageConfig }) => {
|
||||||
const { root } = config.documentsStorage.drivers.filesystem;
|
const { root } = documentStorageConfig.drivers.filesystem;
|
||||||
|
|
||||||
const getStoragePath = ({ storageKey }: { storageKey: string }) => ({ storagePath: join(root, storageKey) });
|
const getStoragePath = ({ storageKey }: { storageKey: string }) => ({ storagePath: join(root, storageKey) });
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { DocumentStorageConfig } from '../../documents.storage.types';
|
||||||
import { CreateBucketCommand } from '@aws-sdk/client-s3';
|
import { CreateBucketCommand } from '@aws-sdk/client-s3';
|
||||||
import { LocalstackContainer } from '@testcontainers/localstack';
|
import { LocalstackContainer } from '@testcontainers/localstack';
|
||||||
import { describe } from 'vitest';
|
import { describe } from 'vitest';
|
||||||
@@ -16,8 +17,8 @@ describe('s3 storage-driver', () => {
|
|||||||
const localstackContainer = await new LocalstackContainer(TEST_CONTAINER_IMAGES.LOCALSTACK).start();
|
const localstackContainer = await new LocalstackContainer(TEST_CONTAINER_IMAGES.LOCALSTACK).start();
|
||||||
const bucketName = 'test-bucket';
|
const bucketName = 'test-bucket';
|
||||||
|
|
||||||
const config = overrideConfig({
|
const driver = s3StorageDriverFactory({
|
||||||
documentsStorage: {
|
documentStorageConfig: {
|
||||||
drivers: {
|
drivers: {
|
||||||
s3: {
|
s3: {
|
||||||
accessKeyId: 'test',
|
accessKeyId: 'test',
|
||||||
@@ -28,11 +29,9 @@ describe('s3 storage-driver', () => {
|
|||||||
forcePathStyle: true,
|
forcePathStyle: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
} as DocumentStorageConfig,
|
||||||
});
|
});
|
||||||
|
|
||||||
const driver = s3StorageDriverFactory({ config });
|
|
||||||
|
|
||||||
const s3Client = driver.getClient();
|
const s3Client = driver.getClient();
|
||||||
|
|
||||||
await s3Client.send(new CreateBucketCommand({ Bucket: bucketName }));
|
await s3Client.send(new CreateBucketCommand({ Bucket: bucketName }));
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ function isS3NotFoundError(error: Error) {
|
|||||||
|| ('Code' in error && typeof error.Code === 'string' && codes.includes(error.Code));
|
|| ('Code' in error && typeof error.Code === 'string' && codes.includes(error.Code));
|
||||||
}
|
}
|
||||||
|
|
||||||
export const s3StorageDriverFactory = defineStorageDriver(({ config }) => {
|
export const s3StorageDriverFactory = defineStorageDriver(({ documentStorageConfig }) => {
|
||||||
const { accessKeyId, secretAccessKey, bucketName, region, endpoint, forcePathStyle } = config.documentsStorage.drivers.s3;
|
const { accessKeyId, secretAccessKey, bucketName, region, endpoint, forcePathStyle } = documentStorageConfig.drivers.s3;
|
||||||
|
|
||||||
const s3Client = new S3Client({
|
const s3Client = new S3Client({
|
||||||
region,
|
region,
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
import type { Logger } from '@crowlog/logger';
|
import type { Logger } from '@crowlog/logger';
|
||||||
import type { Database } from '../../../app/database/database.types';
|
import type { Database } from '../../../app/database/database.types';
|
||||||
|
import type { Config } from '../../../config/config.types';
|
||||||
import type { DocumentStorageService } from '../documents.storage.services';
|
import type { DocumentStorageService } from '../documents.storage.services';
|
||||||
import { eq, isNull } from 'drizzle-orm';
|
import { eq, isNotNull, isNull } from 'drizzle-orm';
|
||||||
import { createLogger } from '../../../shared/logger/logger';
|
import { createLogger } from '../../../shared/logger/logger';
|
||||||
import { documentsTable } from '../../documents.table';
|
import { documentsTable } from '../../documents.table';
|
||||||
|
import {
|
||||||
|
createDocumentStorageService,
|
||||||
|
|
||||||
|
} from '../documents.storage.services';
|
||||||
|
|
||||||
export async function encryptAllUnencryptedDocuments({
|
export async function encryptAllUnencryptedDocuments({
|
||||||
db,
|
db,
|
||||||
@@ -17,7 +22,12 @@ export async function encryptAllUnencryptedDocuments({
|
|||||||
deleteUnencryptedAfterEncryption?: boolean;
|
deleteUnencryptedAfterEncryption?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const documents = await db
|
const documents = await db
|
||||||
.select({ id: documentsTable.id, originalStorageKey: documentsTable.originalStorageKey, fileName: documentsTable.originalName, mimeType: documentsTable.mimeType })
|
.select({
|
||||||
|
id: documentsTable.id,
|
||||||
|
originalStorageKey: documentsTable.originalStorageKey,
|
||||||
|
fileName: documentsTable.originalName,
|
||||||
|
mimeType: documentsTable.mimeType,
|
||||||
|
})
|
||||||
.from(documentsTable)
|
.from(documentsTable)
|
||||||
.where(isNull(documentsTable.fileEncryptionKeyWrapped))
|
.where(isNull(documentsTable.fileEncryptionKeyWrapped))
|
||||||
.orderBy(documentsTable.id);
|
.orderBy(documentsTable.id);
|
||||||
@@ -34,15 +44,26 @@ export async function encryptAllUnencryptedDocuments({
|
|||||||
fileEncryptionKekVersion: null,
|
fileEncryptionKekVersion: null,
|
||||||
});
|
});
|
||||||
const newStorageKey = `${originalStorageKey}.enc`;
|
const newStorageKey = `${originalStorageKey}.enc`;
|
||||||
const { storageKey, ...encryptionFields } = await documentStorageService.saveFile({ fileStream, fileName, mimeType, storageKey: newStorageKey });
|
const { storageKey, ...encryptionFields }
|
||||||
|
= await documentStorageService.saveFile({
|
||||||
|
fileStream,
|
||||||
|
fileName,
|
||||||
|
mimeType,
|
||||||
|
storageKey: newStorageKey,
|
||||||
|
});
|
||||||
|
|
||||||
await db.update(documentsTable).set({
|
await db
|
||||||
|
.update(documentsTable)
|
||||||
|
.set({
|
||||||
...encryptionFields,
|
...encryptionFields,
|
||||||
originalStorageKey: storageKey,
|
originalStorageKey: storageKey,
|
||||||
}).where(eq(documentsTable.id, id));
|
})
|
||||||
|
.where(eq(documentsTable.id, id));
|
||||||
|
|
||||||
if (deleteUnencryptedAfterEncryption) {
|
if (deleteUnencryptedAfterEncryption) {
|
||||||
await documentStorageService.deleteFile({ storageKey: originalStorageKey });
|
await documentStorageService.deleteFile({
|
||||||
|
storageKey: originalStorageKey,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { runScriptWithDb } from './commons/run-script';
|
|||||||
await runScriptWithDb(
|
await runScriptWithDb(
|
||||||
{ scriptName: 'encrypt-all-documents' },
|
{ scriptName: 'encrypt-all-documents' },
|
||||||
async ({ db, config, logger, isDryRun }) => {
|
async ({ db, config, logger, isDryRun }) => {
|
||||||
const documentStorageService = createDocumentStorageService({ config });
|
const documentStorageService = createDocumentStorageService({ documentStorageConfig: config.documentsStorage });
|
||||||
|
|
||||||
if (!config.documentsStorage.encryption.isEncryptionEnabled) {
|
if (!config.documentsStorage.encryption.isEncryptionEnabled) {
|
||||||
logger.error('Document encryption is not enabled, skipping');
|
logger.error('Document encryption is not enabled, skipping');
|
||||||
|
|||||||
Reference in New Issue
Block a user