add nginx and temporary client stuff for public url
This commit is contained in:
+20
-3
@@ -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:
|
||||||
@@ -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
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user