Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.vscode/
.gitignore
.git
README.md
config.example.json

6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ config.json
blocklist.json

proxy.db
proxy.db-journal
proxy.db-journal
redis/
docker-compose.yml
data/

28 changes: 28 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
ARG NODE_TAG=node:21-bullseye

FROM --platform=$BUILDPLATFORM $NODE_TAG AS base

ADD . /app
WORKDIR /app

# Enable yarn and install system packages
RUN corepack enable && apt install -y libssl1.1

FROM base AS builder

# Resolve packages
RUN --mount=type=cache,target=/root/.yarn YARN_CACHE_FOLDER=/root/.yarn yarn install

# Build sources
RUN yarn docker:build

FROM base AS prod

# Resolve packages, without devDependencies
RUN --mount=type=cache,target=/root.yarn YARN_CACHE_FOLDER=/root.yarn yarn install --production

COPY --from=builder /app/dist /app/dist
ENV VERSION "docker"

CMD [ "yarn", "docker:start" ]

54 changes: 54 additions & 0 deletions docker-compose_example.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
version: '3.8'
networks:
external:
internal:
internal: true

services:
# You can configure reverse proxy to establish https connection
# Consider, use caddy
# caddy:
# networks:
# - external
# - internal
# ports:
# - 80:80
# ...

webhook-proxy:
links:
- webhook-proxy-redis:redis
depends_on:
webhook-proxy-redis:
condition: service_healthy
build: .
restart: unless-stopped
networks:
- external
- internal
environment:
PORT: 80
TRUST_PROXY: false
AUTO_BLOCK: false
QUEUE_ENABLED: false
QUEUE_RABBITMQ: "amqp://localhost"
QUEUE_QUEUE: "webhook-proxy"
REDIS: "redis://redis"
ABUSE_THRESHOLD: 12
ports:
- 80:80
volumes:
- ./data:/data

webhook-proxy-redis:
image: redis:7-alpine
restart: unless-stopped
networks:
- internal
volumes:
- ./redis:/data
healthcheck:
test: "redis-cli ping"
interval: 10s
retries: 20

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
{
"scripts": {
"update": "git pull && yarn && yarn build && pm2 reload webhook-proxy webhook-proxy-processor || true",
"build": "prisma migrate deploy && prisma generate && rimraf dist && tsc",
"start": "yarn build && node dist"
"build": "DATABASE_URL=file:./proxy.db prisma migrate deploy && prisma generate && rimraf dist && tsc",
"docker:build": "prisma generate && rimraf dist && tsc",
"docker:start": "DATABASE_URL=file:/data/proxy.db prisma migrate deploy && DATABASE_URL=file:/data/proxy.db node dist",
"start": "yarn build && DATABASE_URL=file:./proxy.db node dist"
},
"dependencies": {
"@prisma/client": "^3.14.0",
Expand Down
5 changes: 2 additions & 3 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

datasource db {
provider = "sqlite"
url = "file:./proxy.db"
url = env("DATABASE_URL")
}

generator client {
Expand All @@ -12,7 +12,6 @@ generator client {

model BannedWebhook {
id String @id

reason String
}

Expand All @@ -31,4 +30,4 @@ model BannedGame {

model WebhooksSeen {
id String @id
}
}
38 changes: 35 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { robloxRanges } from './robloxRanges';
import 'express-async-errors';
import { setup } from './rmq';

const VERSION = (() => {
const VERSION = process.env.VERSION || (() => {
const rev = fs.readFileSync('.git/HEAD').toString().trim();
if (rev.indexOf(':') === -1) {
return rev;
Expand All @@ -33,11 +33,11 @@ const VERSION = (() => {
})();

const app = Express();
const config = JSON.parse(fs.readFileSync('./config.json', 'utf8')) as {
let config = {} as {
port: number;
trustProxy: boolean;
autoBlock: boolean;
queue: {
queue?: {
enabled: boolean;
rabbitmq: string;
queue: string;
Expand All @@ -46,6 +46,38 @@ const config = JSON.parse(fs.readFileSync('./config.json', 'utf8')) as {
abuseThreshold: number;
};

if (fs.existsSync('./config.json')) {
config = JSON.parse(fs.readFileSync('./config.json', 'utf8'));
}

function parseConfigBoolean(value:string|any):boolean {
if (value === "1") return true;
if (value === "0") return false;
if (value.toLowerCase() === "true") return true;
if (value.toLowerCase() === "false") return false;
if (value.toLowerCase() === "yes") return true;
if (value.toLowerCase() === "no") return false;
if (value.toLowerCase() === "y") return true;
if (value.toLowerCase() === "n") return false;
}

// Read configuration from env variable
for (const envItem of [
[ 'PORT', (value:string) => { config.port = parseInt(value) } ],
[ 'TRUST_PROXY', (value:string) => { config.trustProxy = parseConfigBoolean(value) } ],
[ 'AUTO_BLOCK', (value:string) => { config.autoBlock = parseConfigBoolean(value) } ],
[ 'QUEUE_ENABLED', (value:string) => { (config.queue ?? ( config.queue = {} as typeof config["queue"] )).enabled = parseConfigBoolean(value) } ],
[ 'QUEUE_RABBITMQ', (value:string) => { (config.queue ?? ( config.queue = {} as typeof config["queue"] )).rabbitmq = value } ],
[ 'QUEUE_QUEUE', (value:string) => { (config.queue ?? ( config.queue = {} as typeof config["queue"] )).queue = value } ],
[ 'REDIS', (value:string) => { config.redis = value } ],
[ 'ABUSE_THRESHOLD', (value:string) => { config.abuseThreshold = parseInt(value) } ],
] as Array<[string, (value:string)=>undefined ]>) {
const value = process.env[envItem[0]];
if (value !== undefined) {
envItem[1](value);
}
}

const db = new PrismaClient();
const redis = new Redis(config.redis);
beforeShutdown(async () => {
Expand Down