fix(backend): use public MinIO origin for browser uploads
This commit is contained in:
@@ -2,14 +2,90 @@ import { readFileSync } from 'node:fs';
|
||||
import { Agent as HttpsAgent } from 'node:https';
|
||||
import { Client } from 'minio';
|
||||
|
||||
const endpoint = process.env.MINIO_ENDPOINT ?? 'localhost';
|
||||
const port = Number(process.env.MINIO_PORT ?? 9000);
|
||||
const useSSL = (process.env.MINIO_USE_SSL ?? 'false').toLowerCase() === 'true';
|
||||
type MinioTarget = {
|
||||
endPoint: string;
|
||||
port: number;
|
||||
useSSL: boolean;
|
||||
origin: string;
|
||||
};
|
||||
|
||||
const parseBoolean = (value: string | undefined, fallback: boolean): boolean => {
|
||||
if (value == null || value.trim() === '') {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
return value.toLowerCase() === 'true';
|
||||
};
|
||||
|
||||
const resolveMinioTarget = ({
|
||||
origin,
|
||||
endpoint,
|
||||
port,
|
||||
useSSL,
|
||||
}: {
|
||||
origin?: string;
|
||||
endpoint?: string;
|
||||
port?: string | number;
|
||||
useSSL: boolean;
|
||||
}): MinioTarget => {
|
||||
const rawOrigin = origin?.trim();
|
||||
|
||||
if (rawOrigin) {
|
||||
const url = new URL(rawOrigin);
|
||||
const targetUseSSL = url.protocol === 'https:';
|
||||
const targetPort = Number(url.port || (targetUseSSL ? 443 : 80));
|
||||
|
||||
return {
|
||||
endPoint: url.hostname,
|
||||
port: targetPort,
|
||||
useSSL: targetUseSSL,
|
||||
origin: url.origin,
|
||||
};
|
||||
}
|
||||
|
||||
const rawEndpoint = endpoint?.trim() || 'localhost';
|
||||
|
||||
if (rawEndpoint.startsWith('http://') || rawEndpoint.startsWith('https://')) {
|
||||
const url = new URL(rawEndpoint);
|
||||
const targetUseSSL = url.protocol === 'https:';
|
||||
const targetPort = Number(url.port || (targetUseSSL ? 443 : 80));
|
||||
|
||||
return {
|
||||
endPoint: url.hostname,
|
||||
port: targetPort,
|
||||
useSSL: targetUseSSL,
|
||||
origin: url.origin,
|
||||
};
|
||||
}
|
||||
|
||||
const targetPort = Number(port ?? (useSSL ? 443 : 80));
|
||||
const includePort = !(useSSL && targetPort === 443) && !(!useSSL && targetPort === 80);
|
||||
|
||||
return {
|
||||
endPoint: rawEndpoint,
|
||||
port: targetPort,
|
||||
useSSL,
|
||||
origin: `${useSSL ? 'https' : 'http'}://${rawEndpoint}${includePort ? `:${targetPort}` : ''}`,
|
||||
};
|
||||
};
|
||||
|
||||
const accessKey = process.env.MINIO_ACCESS_KEY;
|
||||
const secretKey = process.env.MINIO_SECRET_KEY;
|
||||
const insecureSkipTlsVerify = (process.env.MINIO_INSECURE_SKIP_TLS_VERIFY ?? 'false').toLowerCase() === 'true';
|
||||
const tlsRejectUnauthorized = (process.env.MINIO_TLS_REJECT_UNAUTHORIZED ?? 'true').toLowerCase() !== 'false';
|
||||
const insecureSkipTlsVerify = parseBoolean(process.env.MINIO_INSECURE_SKIP_TLS_VERIFY, false);
|
||||
const tlsRejectUnauthorized = parseBoolean(process.env.MINIO_TLS_REJECT_UNAUTHORIZED, true);
|
||||
const minioCaCertPath = process.env.MINIO_CA_CERT_PATH?.trim();
|
||||
const internalUseSSL = parseBoolean(process.env.MINIO_USE_SSL, false);
|
||||
const internalTarget = resolveMinioTarget({
|
||||
endpoint: process.env.MINIO_ENDPOINT ?? 'localhost',
|
||||
port: process.env.MINIO_PORT ?? 9000,
|
||||
useSSL: internalUseSSL,
|
||||
});
|
||||
const publicTarget = resolveMinioTarget({
|
||||
origin: process.env.MINIO_PUBLIC_ORIGIN,
|
||||
endpoint: process.env.MINIO_PUBLIC_ENDPOINT ?? internalTarget.endPoint,
|
||||
port: process.env.MINIO_PUBLIC_PORT ?? internalTarget.port,
|
||||
useSSL: parseBoolean(process.env.MINIO_PUBLIC_USE_SSL, internalTarget.useSSL),
|
||||
});
|
||||
|
||||
if (!accessKey || !secretKey) {
|
||||
throw new Error('MINIO_ACCESS_KEY and MINIO_SECRET_KEY must be set');
|
||||
@@ -17,8 +93,9 @@ if (!accessKey || !secretKey) {
|
||||
|
||||
export const minioBucket = process.env.MINIO_BUCKET ?? 'videos';
|
||||
export const minioPresignedExpirySeconds = Number(process.env.MINIO_PRESIGNED_EXPIRY_SECONDS ?? 60 * 10);
|
||||
export const minioPublicOrigin = publicTarget.origin;
|
||||
const customCa = minioCaCertPath ? readFileSync(minioCaCertPath) : undefined;
|
||||
const transportAgent = useSSL
|
||||
const transportAgent = internalTarget.useSSL
|
||||
? new HttpsAgent({
|
||||
keepAlive: true,
|
||||
ca: customCa,
|
||||
@@ -27,14 +104,24 @@ const transportAgent = useSSL
|
||||
: undefined;
|
||||
|
||||
export const minioClient = new Client({
|
||||
endPoint: endpoint,
|
||||
port,
|
||||
useSSL,
|
||||
endPoint: internalTarget.endPoint,
|
||||
port: internalTarget.port,
|
||||
useSSL: internalTarget.useSSL,
|
||||
accessKey,
|
||||
secretKey,
|
||||
region: process.env.MINIO_REGION ?? 'us-east-1',
|
||||
transportAgent,
|
||||
});
|
||||
|
||||
export const minioPresignClient = new Client({
|
||||
endPoint: publicTarget.endPoint,
|
||||
port: publicTarget.port,
|
||||
useSSL: publicTarget.useSSL,
|
||||
accessKey,
|
||||
secretKey,
|
||||
region: process.env.MINIO_REGION ?? 'us-east-1',
|
||||
});
|
||||
|
||||
let ensureBucketPromise: Promise<void> | null = null;
|
||||
|
||||
export const ensureMinioBucket = async (): Promise<void> => {
|
||||
|
||||
Reference in New Issue
Block a user