Switch to presigned url strategy for S3
This commit is contained in:
parent
c6ea1d3949
commit
82851c66c7
@ -7,10 +7,10 @@ const VERCEL_BLOB_HOSTNAME = VERCEL_BLOB_STORE_ID
|
||||
: undefined;
|
||||
|
||||
const AWS_S3_HOSTNAME =
|
||||
process.env.NEXT_PUBLIC_S3_BUCKET &&
|
||||
process.env.NEXT_PUBLIC_S3_REGION
|
||||
process.env.NEXT_PUBLIC_AWS_S3_BUCKET &&
|
||||
process.env.NEXT_PUBLIC_AWS_S3_REGION
|
||||
// eslint-disable-next-line max-len
|
||||
? `${process.env.NEXT_PUBLIC_S3_BUCKET}.s3.${process.env.NEXT_PUBLIC_S3_REGION}.amazonaws.com`
|
||||
? `${process.env.NEXT_PUBLIC_AWS_S3_BUCKET}.s3.${process.env.NEXT_PUBLIC_AWS_S3_REGION}.amazonaws.com`
|
||||
: undefined;
|
||||
|
||||
const createRemotePattern = (hostname) => hostname
|
||||
|
||||
20
src/app/api/aws-s3/presigned-url/[key]/route.ts
Normal file
20
src/app/api/aws-s3/presigned-url/[key]/route.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { auth } from '@/auth';
|
||||
import { awsS3GetSignedUploadUrl } from '@/services/blob/aws-s3';
|
||||
|
||||
export const runtime = 'edge';
|
||||
|
||||
export async function GET(
|
||||
_: Request,
|
||||
{ params: { key } }: { params: { key: string } },
|
||||
) {
|
||||
const session = await auth();
|
||||
if (session?.user && key) {
|
||||
const url = await awsS3GetSignedUploadUrl(key);
|
||||
return new Response(
|
||||
url,
|
||||
{ headers: { 'content-type': 'text/plain' } },
|
||||
);
|
||||
} else {
|
||||
return new Response('Unauthorized request', { status: 401 });
|
||||
}
|
||||
}
|
||||
@ -19,6 +19,6 @@ export async function GET() {
|
||||
photos: photos.map(formatPhotoForApi),
|
||||
});
|
||||
} else {
|
||||
return Response.json({ message: 'API is disabled' });
|
||||
return new Response('API access disabled', { status: 404 });
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,24 +6,20 @@ import {
|
||||
ListObjectsCommand,
|
||||
PutObjectCommand,
|
||||
} from '@aws-sdk/client-s3';
|
||||
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
||||
|
||||
const S3_BUCKET = process.env.NEXT_PUBLIC_S3_BUCKET ?? '';
|
||||
const S3_REGION = process.env.NEXT_PUBLIC_S3_REGION ?? '';
|
||||
const S3_UPLOAD_ACCESS_KEY =
|
||||
process.env.NEXT_PUBLIC_S3_UPLOAD_ACCESS_KEY ?? '';
|
||||
const S3_UPLOAD_SECRET_ACCESS_KEY =
|
||||
process.env.NEXT_PUBLIC_S3_UPLOAD_SECRET_ACCESS_KEY ?? '';
|
||||
const S3_ADMIN_ACCESS_KEY =
|
||||
process.env.S3_ADMIN_ACCESS_KEY;
|
||||
const S3_ADMIN_SECRET_ACCESS_KEY =
|
||||
process.env.S3_ADMIN_SECRET_ACCESS_KEY;
|
||||
const S3_BUCKET = process.env.NEXT_PUBLIC_AWS_S3_BUCKET ?? '';
|
||||
const S3_REGION = process.env.NEXT_PUBLIC_AWS_S3_REGION ?? '';
|
||||
const S3_ACCESS_KEY = process.env.AWS_S3_ACCESS_KEY ?? '';
|
||||
const S3_SECRET_ACCESS_KEY = process.env.AWS_S3_SECRET_ACCESS_KEY ?? '';
|
||||
|
||||
const API_PATH_PRESIGNED_URL = '/api/aws-s3/presigned-url';
|
||||
|
||||
const client = () => new S3Client({
|
||||
region: S3_REGION,
|
||||
credentials: {
|
||||
// Fall back on upload credentials when admin credentials aren't available
|
||||
accessKeyId: S3_ADMIN_ACCESS_KEY ?? S3_UPLOAD_ACCESS_KEY,
|
||||
secretAccessKey: S3_ADMIN_SECRET_ACCESS_KEY ?? S3_UPLOAD_SECRET_ACCESS_KEY,
|
||||
accessKeyId: S3_ACCESS_KEY,
|
||||
secretAccessKey: S3_SECRET_ACCESS_KEY,
|
||||
},
|
||||
});
|
||||
|
||||
@ -37,22 +33,30 @@ const urlForKey = (key?: string) => `${AWS_S3_BASE_URL}/${key}`;
|
||||
|
||||
const generateBlobId = () => generateNanoid(16);
|
||||
|
||||
// Runs on server
|
||||
export const awsS3GetSignedUploadUrl = async (Key: string) =>
|
||||
getSignedUrl(
|
||||
client(),
|
||||
new PutObjectCommand({ Bucket: S3_BUCKET, Key, ACL: 'public-read' }),
|
||||
{ expiresIn: 3600 }
|
||||
);
|
||||
|
||||
// Runs on client
|
||||
export const awsS3UploadFromClient = async (
|
||||
file: File | Blob,
|
||||
fileName: string,
|
||||
extension: string,
|
||||
addRandomSuffix?: boolean,
|
||||
) => {
|
||||
const Key = addRandomSuffix
|
||||
const key = addRandomSuffix
|
||||
? `${fileName}-${generateBlobId()}.${extension}`
|
||||
: `${fileName}.${extension}`;
|
||||
return client().send(new PutObjectCommand({
|
||||
Bucket: S3_BUCKET,
|
||||
Key,
|
||||
Body: file,
|
||||
ACL: 'public-read',
|
||||
}))
|
||||
.then(() => urlForKey(Key));
|
||||
|
||||
const url = await fetch(`${API_PATH_PRESIGNED_URL}/${key}`)
|
||||
.then((response) => response.text());
|
||||
|
||||
return fetch(url, { method: 'PUT', body: file })
|
||||
.then(() => urlForKey(key));
|
||||
};
|
||||
|
||||
export const awsS3Copy = async (
|
||||
|
||||
@ -13,7 +13,7 @@ import {
|
||||
awsS3UploadFromClient,
|
||||
isUrlFromAwsS3,
|
||||
} from './aws-s3';
|
||||
import { HAS_AWS_S3_STORAGE_CLIENT, HAS_AWS_S3_STORAGE } from '@/site/config';
|
||||
import { HAS_AWS_S3_STORAGE, HAS_AWS_S3_STORAGE_CLIENT } from '@/site/config';
|
||||
|
||||
const PREFIX_UPLOAD = 'upload';
|
||||
const PREFIX_PHOTO = 'photo';
|
||||
|
||||
@ -35,17 +35,15 @@ export const HAS_VERCEL_BLOB =
|
||||
(process.env.BLOB_READ_WRITE_TOKEN ?? '').length > 0;
|
||||
|
||||
// STORAGE: AWS S3
|
||||
// Includes separate check for client-side usage, i.e., uploading,
|
||||
// Includes separate check for client-side usage,
|
||||
// i.e., uploading, url construction
|
||||
export const HAS_AWS_S3_STORAGE_CLIENT =
|
||||
(process.env.NEXT_PUBLIC_S3_BUCKET ?? '').length > 0 &&
|
||||
(process.env.NEXT_PUBLIC_S3_REGION ?? '').length > 0 &&
|
||||
(process.env.NEXT_PUBLIC_S3_UPLOAD_ACCESS_KEY ?? '').length > 0 &&
|
||||
(process.env.NEXT_PUBLIC_S3_UPLOAD_SECRET_ACCESS_KEY ?? '').length > 0;
|
||||
(process.env.NEXT_PUBLIC_AWS_S3_BUCKET ?? '').length > 0 &&
|
||||
(process.env.NEXT_PUBLIC_AWS_S3_REGION ?? '').length > 0;
|
||||
export const HAS_AWS_S3_STORAGE =
|
||||
HAS_AWS_S3_STORAGE_CLIENT &&
|
||||
(process.env.S3_ADMIN_ACCESS_KEY ?? '').length > 0 &&
|
||||
(process.env.S3_ADMIN_SECRET_ACCESS_KEY ?? '').length > 0;
|
||||
|
||||
(process.env.AWS_S3_ACCESS_KEY ?? '').length > 0 &&
|
||||
(process.env.AWS_S3_SECRET_ACCESS_KEY ?? '').length > 0;
|
||||
|
||||
// SETTINGS
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user