Skip to content

Commit

Permalink
Proxifie les fichiers uploadés pour utiliser le même domaine que l'ap…
Browse files Browse the repository at this point in the history
…plication (#721)

* proxy /uploads requests to S3 container

* proxy front requests on /uploads to backend

* add proxy config to nginx config

* api doesnt send image url

* construct example image urls on frontend
  • Loading branch information
hissalht authored Jun 5, 2024
1 parent eb17af1 commit 212ac1b
Show file tree
Hide file tree
Showing 16 changed files with 97 additions and 43 deletions.
1 change: 1 addition & 0 deletions confiture-rest-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"bcrypt": "^5.1.0",
"class-transformer": "^0.5.1",
"class-validator": "^0.13.2",
"express-http-proxy": "^2.0.0",
"got": "^11.8.5",
"handlebars": "^4.7.7",
"joi": "^17.6.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
Warnings:
- You are about to drop the column `thumbnailUrl` on the `StoredFile` table. All the data in the column will be lost.
- You are about to drop the column `url` on the `StoredFile` table. All the data in the column will be lost.
*/
-- AlterTable
ALTER TABLE "StoredFile" DROP COLUMN "thumbnailUrl",
DROP COLUMN "url";
5 changes: 1 addition & 4 deletions confiture-rest-api/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,10 @@ model AuditTrace {
model StoredFile {
id Int @id @default(autoincrement())
originalFilename String
url String
size Int
// S3 storage key
// S3 storage keys
key String
thumbnailUrl String
thumbnailKey String
criterionResult CriterionResult? @relation(fields: [criterionResultId], references: [id], onDelete: Cascade, onUpdate: Cascade)
Expand Down
13 changes: 4 additions & 9 deletions confiture-rest-api/src/audits/audit.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -477,9 +477,6 @@ export class AuditService {
)
]);

const publicUrl = this.fileStorageService.getPublicUrl(key);
const thumbnailUrl = this.fileStorageService.getPublicUrl(thumbnailKey);

const storedFile = await this.prisma.storedFile.create({
data: {
criterionResult: {
Expand All @@ -495,10 +492,7 @@ export class AuditService {
key,
originalFilename: file.originalname,
size: file.size,
url: publicUrl,

thumbnailKey,
thumbnailUrl
thumbnailKey
}
});

Expand Down Expand Up @@ -929,8 +923,9 @@ export class AuditService {
userImpact: r.userImpact,
quickWin: r.quickWin,
exampleImages: r.exampleImages.map((img) => ({
url: img.url,
filename: img.originalFilename
filename: img.originalFilename,
key: img.key,
thumbnailKey: img.thumbnailKey
}))
}))
};
Expand Down
6 changes: 4 additions & 2 deletions confiture-rest-api/src/audits/dto/audit-report.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,10 @@ class ReportCriterionResult {
}

class ExampleImage {
/** @example "https://example.com/mon-image.jpg" */
url: string;
/** @example "mon-image.jpg" */
filename: string;
/** @example "audit/xxxx/my-image.jpg" */
key: string;
/** @example "audit/xxxx/my-image_thumbnail.jpg" */
thumbnailKey: string;
}
2 changes: 1 addition & 1 deletion confiture-rest-api/src/audits/file-storage.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export class FileStorageService {
}

getPublicUrl(key: string): string {
return `${this.config.get("S3_VIRTUAL_HOST")}${key}`;
return `${this.config.get("FRONT_BASE_URL")}/${key}}`;
}

async deleteStoredFile(key: string) {
Expand Down
2 changes: 2 additions & 0 deletions confiture-rest-api/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { NestFactory } from "@nestjs/core";
import { SwaggerModule, DocumentBuilder } from "@nestjs/swagger";
import type { NestExpressApplication } from "@nestjs/platform-express";
import morgan from "morgan";
import proxy from "express-http-proxy";

import { AppModule } from "./app.module";

Expand All @@ -17,6 +18,7 @@ async function bootstrap() {

app.useBodyParser("json", { limit: "500kb" });
app.use(morgan(process.env.NODE_ENV !== "production" ? "dev" : "common"));
app.use("/uploads", proxy(process.env.S3_VIRTUAL_HOST));

app.setGlobalPrefix("/api");
app.useGlobalPipes(new ValidationPipe({ whitelist: true }));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ server {
# auth_basic off;
# allow all;
#}

location / {

# This is due to nginx and the try_files behavior below, it will always
Expand All @@ -49,9 +48,9 @@ server {

# This seperate location is so the no cache policy only applies to the index and nothing else.
location @index {
add_header Cache-Control no-cache;
expires 0;
try_files /index.html =404;
add_header Cache-Control no-cache;
expires 0;
try_files /index.html =404;
}

# # reverse proxy for backend
Expand All @@ -70,18 +69,36 @@ server {
# proxy_pass $upstream_backend;
proxy_pass http://backend:8085;

proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
proxy_set_header CLIENT_IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_read_timeout 900;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
proxy_set_header CLIENT_IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_read_timeout 900;
proxy_buffers 16 16k;
proxy_buffer_size 16k;

# rewrite /api(.*) $1 break;

}

location /uploads/ {
if ($request_method !~ ^(OPTIONS|GET|HEAD)$ ) {
return 405;
}

proxy_pass http://backend:8085;

proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
proxy_set_header CLIENT_IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;

proxy_read_timeout 900;
proxy_buffers 16 16k;
proxy_buffer_size 16k;
}

}

5 changes: 3 additions & 2 deletions confiture-web-app/public/_redirects
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/api/* https://confiture-api.herokuapp.com/api/:splat 200
/* /index.html 200
/api/* https://confiture-api.herokuapp.com/api/:splat 200
/uploads/* https://confiture-api.herokuapp.com/uploads/:splat 200
/* /index.html 200
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import LazyAccordion from "./LazyAccordion.vue";
import MarkdownHelpButton from "./MarkdownHelpButton.vue";
import { RadioColor } from "../ui/Radio.vue";
import RadioGroup from "../ui/RadioGroup.vue";
import { getUploadUrl } from "../../utils";
const props = defineProps<{
id: string;
Expand Down Expand Up @@ -162,13 +163,13 @@ const isOffline = useIsOffline();
<img
width="50"
height="50"
:src="image.thumbnailUrl"
:src="getUploadUrl(image.thumbnailKey)"
alt=""
loading="lazy"
/>
<a
class="fr-link"
:href="image.url"
:href="getUploadUrl(image.key)"
target="_blank"
rel="noreferrer noopener"
>
Expand Down
21 changes: 15 additions & 6 deletions confiture-web-app/src/components/report/ReportErrors.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { formatStatus, formatUserImpact, pluralize } from "../../utils";
import CriteriumTestsAccordion from "../audit/CriteriumTestsAccordion.vue";
import LazyAccordion from "../audit/LazyAccordion.vue";
import MarkdownRenderer from "../ui/MarkdownRenderer.vue";
import { getUploadUrl } from "../../utils";
const report = useReportStore();
Expand Down Expand Up @@ -516,15 +517,19 @@ function getPage(pageId: number | string) {
>
<a
v-for="example in line"
:key="example.url"
:key="example.key"
class="fr-col-md-6 fr-col-12 image-link"
:href="example.url"
:href="getUploadUrl(example.key)"
target="_blank"
>
<span class="sr-only">
Ouvrir l’image dans une nouvelle fenêtre
</span>
<img style="width: 100%" :src="example.url" alt="" />
<img
style="width: 100%"
:src="getUploadUrl(example.key)"
alt=""
/>
</a>
</div>
</div>
Expand Down Expand Up @@ -636,15 +641,19 @@ function getPage(pageId: number | string) {
>
<a
v-for="example in line"
:key="example.url"
:key="example.key"
class="fr-col-md-6 fr-col-12 image-link"
:href="example.url"
:href="getUploadUrl(example.key)"
target="_blank"
>
<span class="sr-only">
Ouvrir l’image dans une nouvelle fenêtre
</span>
<img style="width: 100%" :src="example.url" alt="" />
<img
style="width: 100%"
:src="getUploadUrl(example.key)"
alt=""
/>
</a>
</div>
</div>
Expand Down
3 changes: 2 additions & 1 deletion confiture-web-app/src/types/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ export interface AuditReport {
results: Array<
Omit<CriteriumResult, "exampleImages"> & {
exampleImages: {
url: string;
key: string;
thumbnailKey: string;
filename: string;
}[];
}
Expand Down
5 changes: 2 additions & 3 deletions confiture-web-app/src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,8 @@ export interface ExampleImage {
id: number;
originalFilename: string;
size: number;
url: string;

thumbnailUrl: string;
key: string;
thumbnailKey: string;
}

export interface CriteriumResult {
Expand Down
4 changes: 4 additions & 0 deletions confiture-web-app/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,3 +231,7 @@ export function waitForElement(selector: string): Promise<Element> {
});
});
}

export function getUploadUrl(key: string): string {
return `/uploads/${key}`;
}
3 changes: 2 additions & 1 deletion confiture-web-app/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ export default defineConfig({
],
server: {
proxy: {
"/api": "http://localhost:4000"
"/api": "http://localhost:4000",
"/uploads": "http://localhost:4000"
},
port: 3000
}
Expand Down
18 changes: 16 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3736,7 +3736,7 @@ debug@4, [email protected], debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
dependencies:
ms "2.1.2"

debug@^3.1.0:
debug@^3.0.1, debug@^3.1.0:
version "3.2.7"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
Expand Down Expand Up @@ -4069,6 +4069,11 @@ es-module-lexer@^1.2.1:
resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.4.1.tgz#41ea21b43908fe6a287ffcbe4300f790555331f5"
integrity sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==

es6-promise@^4.1.1:
version "4.2.8"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==

esbuild@^0.18.10:
version "0.18.20"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6"
Expand Down Expand Up @@ -4348,6 +4353,15 @@ expand-template@^2.0.3:
resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c"
integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==

express-http-proxy@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/express-http-proxy/-/express-http-proxy-2.0.0.tgz#c47f4d8b53e8d9c2b9a2f1d158eedf6eb84828a5"
integrity sha512-TXxcPFTWVUMSEmyM6iX2sT/JtmqhqngTq29P+eXTVFdtxZrTmM8THUYK59rUXiln0FfPGvxEpGRnVrgvHksXDw==
dependencies:
debug "^3.0.1"
es6-promise "^4.1.1"
raw-body "^2.3.0"

[email protected]:
version "4.18.2"
resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59"
Expand Down Expand Up @@ -6990,7 +7004,7 @@ [email protected]:
iconv-lite "0.4.24"
unpipe "1.0.0"

[email protected]:
[email protected], raw-body@^2.3.0:
version "2.5.2"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
Expand Down

0 comments on commit 212ac1b

Please sign in to comment.