add nginx and temporary client stuff for public url

This commit is contained in:
StarAppeal
2025-09-26 01:31:20 +02:00
parent 7b38ec1660
commit ef7c285dee
6 changed files with 74 additions and 10 deletions
+20 -3
View File
@@ -7,8 +7,6 @@ services:
restart: always restart: always
env_file: env_file:
- .env - .env
ports:
- "3000:3000"
depends_on: depends_on:
- minio - minio
networks: networks:
@@ -20,12 +18,31 @@ services:
restart: always restart: always
env_file: env_file:
- .env - .env
ports:
- "9003:9001"
volumes: volumes:
- ./minio-data:/data - ./minio-data:/data
command: server /data --console-address ":9001" command: server /data --console-address ":9001"
networks: networks:
- app-network - app-network
nginx:
image: nginx:latest
container_name: ledmatrix-proxy
restart: always
ports:
- "8080:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- backend
- minio
networks:
- app-network
networks: networks:
app-network: app-network:
driver: bridge driver: bridge
volumes:
minio-data:
+27
View File
@@ -0,0 +1,27 @@
events {}
http {
server {
listen 80;
server_name localhost;
location /api/ {
proxy_pass http://ledmatrix-backend:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location /ledmatrix/ {
proxy_pass http://ledmatrix-storage:9000;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
+8 -2
View File
@@ -1,6 +1,6 @@
import { Server } from "./server"; import { Server } from "./server";
import { config as baseConfig } from "./config/config"; import { config as baseConfig } from "./config/config";
import { S3Service } from "./services/s3Service"; import { S3ClientConfig, S3Service } from "./services/s3Service";
import { UserService } from "./services/db/UserService"; import { UserService } from "./services/db/UserService";
import { SpotifyTokenService } from "./services/spotifyTokenService"; import { SpotifyTokenService } from "./services/spotifyTokenService";
import { connectToDatabase } from "./services/db/database.service"; import { connectToDatabase } from "./services/db/database.service";
@@ -21,6 +21,7 @@ async function bootstrap() {
MINIO_ROOT_PASSWORD, MINIO_ROOT_PASSWORD,
DB_NAME, DB_NAME,
DB_CONN_STRING, DB_CONN_STRING,
MINIO_SERVER_URL,
} = process.env; } = process.env;
if (!SECRET_KEY || SECRET_KEY.length < 32) { if (!SECRET_KEY || SECRET_KEY.length < 32) {
@@ -45,11 +46,16 @@ async function bootstrap() {
throw new Error("MINIO_BUCKET_NAME environment variable is not set."); throw new Error("MINIO_BUCKET_NAME environment variable is not set.");
} }
if (!MINIO_SERVER_URL) {
throw new Error("MINIO_SERVER_URL environment variable is not set.");
}
if (!DB_NAME || !DB_CONN_STRING) { if (!DB_NAME || !DB_CONN_STRING) {
throw new Error("DB_NAME and/or DB_CONN_STRING environment variable is not set."); throw new Error("DB_NAME and/or DB_CONN_STRING environment variable is not set.");
} }
const s3ClientConfig = { const s3ClientConfig: S3ClientConfig = {
publicUrl: MINIO_SERVER_URL,
endpoint: MINIO_ENDPOINT, endpoint: MINIO_ENDPOINT,
port: parseInt(MINIO_PORT), port: parseInt(MINIO_PORT),
accessKey: MINIO_ROOT_USER, accessKey: MINIO_ROOT_USER,
+1 -3
View File
@@ -46,12 +46,10 @@ export class RestStorage {
const userId = req.payload.uuid; const userId = req.payload.uuid;
const objectKey = req.params[0]; const objectKey = req.params[0];
console.log(userId);
console.log(objectKey);
if (!objectKey || !objectKey.startsWith(`user-${userId}`)) { if (!objectKey || !objectKey.startsWith(`user-${userId}`)) {
return forbidden(res); return forbidden(res);
} }
try { try {
const expiresInSeconds = 60; const expiresInSeconds = 60;
const downloadUrl = await this.s3Service.getSignedDownloadUrl(objectKey, expiresInSeconds); const downloadUrl = await this.s3Service.getSignedDownloadUrl(objectKey, expiresInSeconds);
+12 -1
View File
@@ -16,6 +16,7 @@ export interface S3ClientConfig {
secretAccessKey: string; secretAccessKey: string;
bucket: string; bucket: string;
region?: string; region?: string;
publicUrl: string;
} }
export class S3Service { export class S3Service {
@@ -23,6 +24,7 @@ export class S3Service {
private readonly client: S3Client; private readonly client: S3Client;
private readonly bucketName: string; private readonly bucketName: string;
private readonly publicUrl: string;
private constructor(clientConfig: S3ClientConfig) { private constructor(clientConfig: S3ClientConfig) {
this.client = new S3Client({ this.client = new S3Client({
@@ -36,6 +38,7 @@ export class S3Service {
}); });
this.bucketName = clientConfig.bucket; this.bucketName = clientConfig.bucket;
this.publicUrl = clientConfig.publicUrl;
} }
public static getInstance(config?: S3ClientConfig): S3Service { public static getInstance(config?: S3ClientConfig): S3Service {
@@ -103,11 +106,19 @@ export class S3Service {
} }
async getSignedDownloadUrl(objectKey: string, expiresIn: number = 60): Promise<string> { async getSignedDownloadUrl(objectKey: string, expiresIn: number = 60): Promise<string> {
// temporary client for public url
const signingClient = new S3Client({
endpoint: this.publicUrl,
forcePathStyle: true,
region: this.client.config.region,
credentials: this.client.config.credentials,
});
const command = new GetObjectCommand({ const command = new GetObjectCommand({
Bucket: this.bucketName, Bucket: this.bucketName,
Key: objectKey, Key: objectKey,
}); });
return await getSignedUrl(this.client, command, { expiresIn }); return await getSignedUrl(signingClient, command, { expiresIn });
} }
} }
+6 -1
View File
@@ -27,6 +27,7 @@ const testConfig: S3ClientConfig = {
accessKey: "test-key", accessKey: "test-key",
secretAccessKey: "test-secret", secretAccessKey: "test-secret",
bucket: "test-bucket", bucket: "test-bucket",
publicUrl: "http://test-publicUrl",
}; };
const MockS3Client = vi.mocked(S3Client); const MockS3Client = vi.mocked(S3Client);
@@ -46,6 +47,9 @@ describe("S3Service", () => {
}) as never }) as never
); );
// @ts-ignore
S3Service.instance = undefined;
s3Service = S3Service.getInstance(testConfig); s3Service = S3Service.getInstance(testConfig);
}); });
@@ -174,10 +178,11 @@ describe("S3Service", () => {
}); });
}); });
// ignore test for now.
describe("getSignedDownloadUrl", () => { describe("getSignedDownloadUrl", () => {
it("should generate a signed URL for a given object key", async () => { it("should generate a signed URL for a given object key", async () => {
const objectKey = "user-123/image.png"; const objectKey = "user-123/image.png";
const fakeSignedUrl = "http://test-minio:9000/test-bucket/user-123/image.png?signed=true"; const fakeSignedUrl = "http://test-publicUrl/test-bucket/user-123/image.png?signed=true";
mockGetSignedUrl.mockResolvedValue(fakeSignedUrl); mockGetSignedUrl.mockResolvedValue(fakeSignedUrl);