mirror of
https://gitlab.dit.htwk-leipzig.de/htwk-software/htwkalender.git
synced 2025-08-06 11:49:14 +02:00
Merge branch '19-rate-limiting' into 'main'
Resolve "rate limiting" Closes #19 See merge request ekresse/htwkalender!20
This commit is contained in:
@@ -29,3 +29,26 @@ COPY --chown=$USER:$USER --from=build /htwkalender ./
|
|||||||
EXPOSE 8090
|
EXPOSE 8090
|
||||||
|
|
||||||
ENTRYPOINT ["./htwkalender", "serve"]
|
ENTRYPOINT ["./htwkalender", "serve"]
|
||||||
|
|
||||||
|
|
||||||
|
FROM golang:1.21.6 AS dev
|
||||||
|
|
||||||
|
# Set the Current Working Directory inside the container
|
||||||
|
WORKDIR /htwkalender
|
||||||
|
|
||||||
|
# Copy go mod and sum files
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
# Copy the source from the current directory to the Working Directory inside the container
|
||||||
|
COPY *.go ./
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Build the Go app
|
||||||
|
RUN CGO_ENABLED=1 GOOS=linux go build -o /htwkalender
|
||||||
|
|
||||||
|
# Expose port 8090 to the outside world
|
||||||
|
EXPOSE 8090
|
||||||
|
|
||||||
|
# Entry point
|
||||||
|
ENTRYPOINT ["./htwkalender", "serve"]
|
@@ -5,13 +5,13 @@ services:
|
|||||||
build:
|
build:
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
context: ./backend
|
context: ./backend
|
||||||
target: prod
|
target: dev # prod
|
||||||
command: "--http=0.0.0.0:8090 --dir=/htwkalender/data/pb_data"
|
command: "--http=0.0.0.0:8090 --dir=/htwkalender/data/pb_data"
|
||||||
# open port 8090
|
|
||||||
ports:
|
ports:
|
||||||
- "8090:8090"
|
- "8090:8090"
|
||||||
volumes:
|
volumes:
|
||||||
- pb_data:/htwkalender/data
|
- pb_data:/htwkalender/data # for production with volume
|
||||||
|
# - ./backend/pb_data:/pb_data # for development with bind mount from project directory
|
||||||
|
|
||||||
htwkalender-frontend:
|
htwkalender-frontend:
|
||||||
build:
|
build:
|
||||||
@@ -22,6 +22,8 @@ services:
|
|||||||
# open port 8000
|
# open port 8000
|
||||||
ports:
|
ports:
|
||||||
- "8000:8000"
|
- "8000:8000"
|
||||||
|
volumes:
|
||||||
|
- ./frontend/src:/app/src
|
||||||
|
|
||||||
rproxy:
|
rproxy:
|
||||||
image: bitnami/nginx:1.25
|
image: bitnami/nginx:1.25
|
||||||
|
@@ -1,22 +1,24 @@
|
|||||||
import { Module } from "../model/module.ts";
|
import { Module } from "../model/module.ts";
|
||||||
|
|
||||||
export async function createIndividualFeed(modules: Module[]): Promise<string> {
|
export async function createIndividualFeed(modules: Module[]): Promise<string> {
|
||||||
let token = "";
|
try {
|
||||||
|
const response = await fetch("/api/createFeed", {
|
||||||
await fetch("/api/createFeed", {
|
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify(modules),
|
body: JSON.stringify(modules),
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
return response.json();
|
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
token = response;
|
|
||||||
});
|
});
|
||||||
return token;
|
|
||||||
|
if (response.status === 429 || response.status === 500 || response.status != 200) {
|
||||||
|
return Promise.reject(response.statusText);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await response.json();
|
||||||
|
} catch (error) {
|
||||||
|
// Catch possible errors and return an unfilled promise
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FeedResponse {
|
interface FeedResponse {
|
||||||
|
@@ -8,6 +8,7 @@ import ModuleTemplateDialog from "./ModuleTemplateDialog.vue";
|
|||||||
import { onlyWhitespace } from "../helpers/strings.ts";
|
import { onlyWhitespace } from "../helpers/strings.ts";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { Module } from "@/model/module.ts";
|
import { Module } from "@/model/module.ts";
|
||||||
|
import { useToast } from "primevue/usetoast";
|
||||||
const { t } = useI18n({ useScope: "global" });
|
const { t } = useI18n({ useScope: "global" });
|
||||||
|
|
||||||
const store = moduleStore();
|
const store = moduleStore();
|
||||||
@@ -33,10 +34,26 @@ const columns = computed(() => [
|
|||||||
{ field: "Reminder", header: t("renameModules.reminder") },
|
{ field: "Reminder", header: t("renameModules.reminder") },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
async function finalStep() {
|
async function finalStep() {
|
||||||
const token: string = await createIndividualFeed(store.getAllModules());
|
const createFeed: Promise<string>= createIndividualFeed(store.getAllModules());
|
||||||
|
|
||||||
|
// Check if createFeed Promise is resolved
|
||||||
|
createFeed.then(async (token: string) => {
|
||||||
tokenStore().setToken(token);
|
tokenStore().setToken(token);
|
||||||
await router.push("/calendar-link");
|
await router.push("/calendar-link");
|
||||||
|
});
|
||||||
|
|
||||||
|
// if createFeed Promise is rejected
|
||||||
|
createFeed.catch(() => {
|
||||||
|
toast.add({
|
||||||
|
severity: "error",
|
||||||
|
summary: t("renameModules.error"),
|
||||||
|
detail: t("renameModules.TooManyRequests"),
|
||||||
|
life: 3000,
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@@ -110,7 +110,9 @@
|
|||||||
"reminder": "Erinnerung",
|
"reminder": "Erinnerung",
|
||||||
"enableAllNotifications": "Alle Benachrichtigungen aktivieren",
|
"enableAllNotifications": "Alle Benachrichtigungen aktivieren",
|
||||||
"subTitle": "Konfigurieren Sie die ausgewählten Module nach Ihren Wünschen.",
|
"subTitle": "Konfigurieren Sie die ausgewählten Module nach Ihren Wünschen.",
|
||||||
"nextStep": "Speichern"
|
"nextStep": "Speichern",
|
||||||
|
"error": "Fehler",
|
||||||
|
"TooManyRequests": "Zu viele Anfragen um einen Kalender zu erstellen. Bitte versuchen Sie es später erneut."
|
||||||
},
|
},
|
||||||
"moduleTemplateDialog": {
|
"moduleTemplateDialog": {
|
||||||
"explanationOne": "Hier können Module nach Wunsch umbenannt werden, welche dann als Anzeigename im Kalender dargestellt werden.",
|
"explanationOne": "Hier können Module nach Wunsch umbenannt werden, welche dann als Anzeigename im Kalender dargestellt werden.",
|
||||||
|
@@ -110,7 +110,9 @@
|
|||||||
"reminder": "reminder",
|
"reminder": "reminder",
|
||||||
"enableAllNotifications": "enable all notifications",
|
"enableAllNotifications": "enable all notifications",
|
||||||
"subTitle": "configure your selected modules to your liking",
|
"subTitle": "configure your selected modules to your liking",
|
||||||
"nextStep": "save"
|
"nextStep": "save",
|
||||||
|
"error": "error",
|
||||||
|
"TooManyRequests": "too many requests for creating a calendar in a short time"
|
||||||
},
|
},
|
||||||
"moduleTemplateDialog": {
|
"moduleTemplateDialog": {
|
||||||
"explanationOne": "Here you can rename your modules to your liking. This will be the name of the event in your calendar.",
|
"explanationOne": "Here you can rename your modules to your liking. This will be the name of the event in your calendar.",
|
||||||
|
@@ -21,6 +21,8 @@ http {
|
|||||||
map $request_method $cache_bypass {
|
map $request_method $cache_bypass {
|
||||||
default 0;
|
default 0;
|
||||||
POST 1;
|
POST 1;
|
||||||
|
PUT 1;
|
||||||
|
DELETE 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
client_body_temp_path /opt/bitnami/nginx/tmp/client_temp;
|
client_body_temp_path /opt/bitnami/nginx/tmp/client_temp;
|
||||||
@@ -36,6 +38,31 @@ http {
|
|||||||
proxy_cache_use_stale timeout updating;
|
proxy_cache_use_stale timeout updating;
|
||||||
proxy_ignore_headers Cache-Control Expires Set-Cookie;
|
proxy_ignore_headers Cache-Control Expires Set-Cookie;
|
||||||
|
|
||||||
|
proxy_buffering on;
|
||||||
|
proxy_buffers 8 16k;
|
||||||
|
proxy_buffer_size 16k;
|
||||||
|
proxy_busy_buffers_size 64k;
|
||||||
|
proxy_temp_file_write_size 64k;
|
||||||
|
proxy_max_temp_file_size 1024m;
|
||||||
|
|
||||||
|
geo $admin {
|
||||||
|
default 1;
|
||||||
|
10.0.0.0/8 0; # Private Network
|
||||||
|
192.168.0.0/24 0; # Localhost Network
|
||||||
|
141.57.0.0/16 0; # HTWK Leipzig Network
|
||||||
|
172.18.0.0/24 0; # Docker Internal Network
|
||||||
|
}
|
||||||
|
|
||||||
|
map $admin $limit_key {
|
||||||
|
0 "";
|
||||||
|
1 $binary_remote_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Limit the number of requests per IP
|
||||||
|
limit_req_zone $limit_key zone=feed:20m rate=10r/m;
|
||||||
|
limit_req_zone $limit_key zone=createFeed:10m rate=1r/m;
|
||||||
|
limit_req_zone $limit_key zone=modules:10m rate=3r/m;
|
||||||
|
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
server_name frontend;
|
server_name frontend;
|
||||||
@@ -65,10 +92,91 @@ http {
|
|||||||
proxy_cache_lock on;
|
proxy_cache_lock on;
|
||||||
proxy_cache_use_stale timeout updating;
|
proxy_cache_use_stale timeout updating;
|
||||||
add_header X-Proxy-Cache $upstream_cache_status;
|
add_header X-Proxy-Cache $upstream_cache_status;
|
||||||
|
limit_req zone=modules burst=5 nodelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/rooms {
|
||||||
|
proxy_pass http://htwkalender-backend:8090;
|
||||||
|
client_max_body_size 20m;
|
||||||
|
proxy_connect_timeout 600s;
|
||||||
|
proxy_read_timeout 600s;
|
||||||
|
proxy_send_timeout 600s;
|
||||||
|
send_timeout 600s;
|
||||||
|
proxy_cache_bypass 0;
|
||||||
|
proxy_no_cache 0;
|
||||||
|
proxy_cache mcache; # mcache=RAM
|
||||||
|
proxy_cache_valid 200 301 302 30m;
|
||||||
|
proxy_cache_valid 403 404 5m;
|
||||||
|
proxy_cache_lock on;
|
||||||
|
proxy_cache_use_stale timeout updating;
|
||||||
|
add_header X-Proxy-Cache $upstream_cache_status;
|
||||||
|
limit_req zone=modules burst=5 nodelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/schedule {
|
||||||
|
proxy_pass http://htwkalender-backend:8090;
|
||||||
|
client_max_body_size 20m;
|
||||||
|
proxy_connect_timeout 600s;
|
||||||
|
proxy_read_timeout 600s;
|
||||||
|
proxy_send_timeout 600s;
|
||||||
|
send_timeout 600s;
|
||||||
|
proxy_cache_bypass 0;
|
||||||
|
proxy_no_cache 0;
|
||||||
|
proxy_cache mcache; # mcache=RAM
|
||||||
|
proxy_cache_valid 200 301 302 30m;
|
||||||
|
proxy_cache_valid 403 404 5m;
|
||||||
|
proxy_cache_lock on;
|
||||||
|
proxy_cache_use_stale timeout updating;
|
||||||
|
add_header X-Proxy-Cache $upstream_cache_status;
|
||||||
|
limit_req zone=modules burst=5 nodelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/courses {
|
||||||
|
proxy_pass http://htwkalender-backend:8090;
|
||||||
|
client_max_body_size 20m;
|
||||||
|
proxy_connect_timeout 600s;
|
||||||
|
proxy_read_timeout 600s;
|
||||||
|
proxy_send_timeout 600s;
|
||||||
|
send_timeout 600s;
|
||||||
|
proxy_cache_bypass 0;
|
||||||
|
proxy_no_cache 0;
|
||||||
|
proxy_cache mcache; # mcache=RAM
|
||||||
|
proxy_cache_valid 200 301 302 30m;
|
||||||
|
proxy_cache_valid 403 404 5m;
|
||||||
|
proxy_cache_lock on;
|
||||||
|
proxy_cache_use_stale timeout updating;
|
||||||
|
add_header X-Proxy-Cache $upstream_cache_status;
|
||||||
|
limit_req zone=modules burst=5 nodelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/feed {
|
||||||
|
proxy_pass http://htwkalender-backend:8090;
|
||||||
|
client_max_body_size 2m;
|
||||||
|
proxy_connect_timeout 600s;
|
||||||
|
proxy_read_timeout 600s;
|
||||||
|
proxy_send_timeout 600s;
|
||||||
|
send_timeout 600s;
|
||||||
|
limit_req zone=feed burst=10 nodelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/createFeed {
|
||||||
|
limit_req zone=createFeed nodelay;
|
||||||
|
# return limit request error
|
||||||
|
limit_req_status 429;
|
||||||
|
proxy_pass http://htwkalender-backend:8090;
|
||||||
|
client_max_body_size 2m;
|
||||||
|
proxy_connect_timeout 600s;
|
||||||
|
proxy_read_timeout 600s;
|
||||||
|
proxy_send_timeout 600s;
|
||||||
|
send_timeout 600s;
|
||||||
}
|
}
|
||||||
|
|
||||||
location /_ {
|
location /_ {
|
||||||
proxy_pass http://htwkalender-backend:8090;
|
proxy_pass http://htwkalender-backend:8090;
|
||||||
|
# if user is not 0 in admin list, return 404
|
||||||
|
if ($admin) {
|
||||||
|
return 404 "Not Found";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
|
Reference in New Issue
Block a user