mirror of
https://github.com/documenso/documenso.git
synced 2025-11-13 08:13:56 +10:00
149 lines
4.0 KiB
TypeScript
149 lines
4.0 KiB
TypeScript
import {
|
|
DeleteObjectCommand,
|
|
GetObjectCommand,
|
|
PutObjectCommand,
|
|
S3Client,
|
|
} from '@aws-sdk/client-s3';
|
|
import slugify from '@sindresorhus/slugify';
|
|
import path from 'node:path';
|
|
|
|
import { env } from '@documenso/lib/utils/env';
|
|
|
|
import { ONE_HOUR, ONE_SECOND } from '../../constants/time';
|
|
import { alphaid } from '../id';
|
|
|
|
export const getPresignPostUrl = async (fileName: string, contentType: string, userId?: number) => {
|
|
const client = getS3Client();
|
|
|
|
const { getSignedUrl } = await import('@aws-sdk/s3-request-presigner');
|
|
|
|
// Get the basename and extension for the file
|
|
const { name, ext } = path.parse(fileName);
|
|
|
|
let key = `${alphaid(12)}/${slugify(name)}${ext}`;
|
|
|
|
if (userId) {
|
|
key = `${userId}/${key}`;
|
|
}
|
|
|
|
const putObjectCommand = new PutObjectCommand({
|
|
Bucket: env('NEXT_PRIVATE_UPLOAD_BUCKET'),
|
|
Key: key,
|
|
ContentType: contentType,
|
|
});
|
|
|
|
const url = await getSignedUrl(client, putObjectCommand, {
|
|
expiresIn: ONE_HOUR / ONE_SECOND,
|
|
});
|
|
|
|
return { key, url };
|
|
};
|
|
|
|
export const getAbsolutePresignPostUrl = async (key: string) => {
|
|
const client = getS3Client();
|
|
|
|
const { getSignedUrl: getS3SignedUrl } = await import('@aws-sdk/s3-request-presigner');
|
|
|
|
const putObjectCommand = new PutObjectCommand({
|
|
Bucket: env('NEXT_PRIVATE_UPLOAD_BUCKET'),
|
|
Key: key,
|
|
});
|
|
|
|
const url = await getS3SignedUrl(client, putObjectCommand, {
|
|
expiresIn: ONE_HOUR / ONE_SECOND,
|
|
});
|
|
|
|
return { key, url };
|
|
};
|
|
|
|
export const getPresignGetUrl = async (key: string) => {
|
|
if (env('NEXT_PRIVATE_UPLOAD_DISTRIBUTION_DOMAIN')) {
|
|
const distributionUrl = new URL(key, `${env('NEXT_PRIVATE_UPLOAD_DISTRIBUTION_DOMAIN')}`);
|
|
|
|
const { getSignedUrl: getCloudfrontSignedUrl } = await import('@aws-sdk/cloudfront-signer');
|
|
|
|
const url = getCloudfrontSignedUrl({
|
|
url: distributionUrl.toString(),
|
|
keyPairId: `${env('NEXT_PRIVATE_UPLOAD_DISTRIBUTION_KEY_ID')}`,
|
|
privateKey: `${env('NEXT_PRIVATE_UPLOAD_DISTRIBUTION_KEY_CONTENTS')}`,
|
|
dateLessThan: new Date(Date.now() + ONE_HOUR).toISOString(),
|
|
});
|
|
|
|
return { key, url };
|
|
}
|
|
|
|
const client = getS3Client();
|
|
|
|
const { getSignedUrl: getS3SignedUrl } = await import('@aws-sdk/s3-request-presigner');
|
|
|
|
const getObjectCommand = new GetObjectCommand({
|
|
Bucket: env('NEXT_PRIVATE_UPLOAD_BUCKET'),
|
|
Key: key,
|
|
});
|
|
|
|
const url = await getS3SignedUrl(client, getObjectCommand, {
|
|
expiresIn: ONE_HOUR / ONE_SECOND,
|
|
});
|
|
|
|
return { key, url };
|
|
};
|
|
|
|
/**
|
|
* Uploads a file to S3.
|
|
*/
|
|
export const uploadS3File = async (file: File) => {
|
|
const client = getS3Client();
|
|
|
|
// Get the basename and extension for the file
|
|
const { name, ext } = path.parse(file.name);
|
|
|
|
const key = `${alphaid(12)}/${slugify(name)}${ext}`;
|
|
|
|
const fileBuffer = await file.arrayBuffer();
|
|
|
|
const response = await client.send(
|
|
new PutObjectCommand({
|
|
Bucket: env('NEXT_PRIVATE_UPLOAD_BUCKET'),
|
|
Key: key,
|
|
Body: Buffer.from(fileBuffer),
|
|
ContentType: file.type,
|
|
}),
|
|
);
|
|
|
|
return { key, response };
|
|
};
|
|
|
|
export const deleteS3File = async (key: string) => {
|
|
const client = getS3Client();
|
|
|
|
await client.send(
|
|
new DeleteObjectCommand({
|
|
Bucket: env('NEXT_PRIVATE_UPLOAD_BUCKET'),
|
|
Key: key,
|
|
}),
|
|
);
|
|
};
|
|
|
|
const getS3Client = () => {
|
|
const NEXT_PUBLIC_UPLOAD_TRANSPORT = env('NEXT_PUBLIC_UPLOAD_TRANSPORT');
|
|
|
|
if (NEXT_PUBLIC_UPLOAD_TRANSPORT !== 's3') {
|
|
throw new Error('Invalid upload transport');
|
|
}
|
|
|
|
const hasCredentials =
|
|
env('NEXT_PRIVATE_UPLOAD_ACCESS_KEY_ID') && env('NEXT_PRIVATE_UPLOAD_SECRET_ACCESS_KEY');
|
|
|
|
return new S3Client({
|
|
endpoint: env('NEXT_PRIVATE_UPLOAD_ENDPOINT') || undefined,
|
|
forcePathStyle: env('NEXT_PRIVATE_UPLOAD_FORCE_PATH_STYLE') === 'true',
|
|
region: env('NEXT_PRIVATE_UPLOAD_REGION') || 'us-east-1',
|
|
credentials: hasCredentials
|
|
? {
|
|
accessKeyId: String(env('NEXT_PRIVATE_UPLOAD_ACCESS_KEY_ID')),
|
|
secretAccessKey: String(env('NEXT_PRIVATE_UPLOAD_SECRET_ACCESS_KEY')),
|
|
}
|
|
: undefined,
|
|
});
|
|
};
|