diff --git a/.env.example b/.env.example
deleted file mode 100644
index fe59135e0b990e56e126a0b5fc14206f0371892d..0000000000000000000000000000000000000000
--- a/.env.example
+++ /dev/null
@@ -1,35 +0,0 @@
-# shellcheck disable
-HOME_DOMAIN=local.test
-ADMIN_EMAIL=
-USER_ID="1000"
-GROUP_ID="1000"
-
-APP_ROOT=./.apps
-STORE_ROOT=/Volumes
-CLOVER_ROOT=/Volumes/clover
-MEDIA_ROOT=/Volumes/media
-TORRENT_TEMP=
-
-MAILER_ADDRESS=smtp.example.com
-MAILER_USERNAME=me@paperclover.net
-MAILER_PASSWORD=
-
-KEYCLOAK_ADMIN_PASSWORD=
-FORWARD_AUTH_KEY=
-
-POSTGRES_PASSWORD=
-POSTGRES_PASSWORD_AUTHELIA=
-POSTGRES_PASSWORD_FORGEJO=
-POSTGRES_PASSWORD_DAWARICH=
-POSTGRES_PASSWORD_LLDAP=
-
-CLOVER_SOT_KEY=
-
-ANUBIS_PRIVATE_KEY=
-
-FORGEJO_SERVER_LFS_JWT_SECRET=
-FORGEJO_OAUTH2_JWT_SECRET=
-FORGEJO_OPENID_SECRET=
-FORGEJO_SECURITY_SECRET_KEY=
-FORGEJO_SECURITY_INTERNAL_TOKEN=(jwt)
-
diff --git a/compose.yaml b/compose.yaml
index cbf2de42df4967ce6b2e82b3b6bf0025d413eb98..d9c55d826946a8f2aa88d9ee1e5a4b1045391a8b 100755
--- a/compose.yaml
+++ b/compose.yaml
@@ -152,7 +152,7 @@ services:
image: code.forgejo.org/forgejo/forgejo:13
entrypoint: ["/bin/sh", "/custom/init/entry.sh"]
ports:
- - 22:22
+ - 40243:22
- 40244:3000 # port used for forgejo-runner
environment:
USER_UID: "$USER_ID"
@@ -173,7 +173,6 @@ services:
- "/etc/timezone:/etc/timezone:ro"
- "/etc/localtime:/etc/localtime:ro"
- ./config/forgejo/public:/custom/public:ro
- - ./config/forgejo/templates:/custom/templates:ro
- ./config/forgejo/init:/custom/init:ro
labels:
net.paperclover.list.name: Clover Git Forge
@@ -387,8 +386,8 @@ services:
context: config/postgres/
dockerfile: Dockerfile
args:
- USER_ID: $USER_ID
- GROUP_ID: $GROUP_ID
+ USER_ID: "$USER_ID"
+ GROUP_ID: "$GROUP_ID"
pull_policy: build
restart: unless-stopped
user: "$USER_ID:$GROUP_ID"
@@ -397,6 +396,7 @@ services:
POSTGRES_PASSWORD_FORGEJO: "${POSTGRES_PASSWORD_FORGEJO:?}"
POSTGRES_PASSWORD_KEYCLOAK: "${POSTGRES_PASSWORD_KEYCLOAK:?}"
POSTGRES_PASSWORD_DAWARICH: "${POSTGRES_PASSWORD_DAWARICH:?}"
+ POSTGRES_PASSWORD_EVIL_FORGEJO: "${POSTGRES_PASSWORD_EVIL_FORGEJO:?}"
volumes:
- "${APP_ROOT}/pg_data:/var/lib/postgresql/data/"
healthcheck:
@@ -583,6 +583,65 @@ services:
net.paperclover.list.domain: dns
net.paperclover.list.priority: 9
net.paperclover.list.access: personal
+ # evil inc temporary infrastructure
+ evil-forgejo: # port 3000
+ container_name: evil-forgejo
+ image: code.forgejo.org/forgejo/forgejo:13
+ entrypoint: ["/bin/sh", "/custom/init/entry.sh"]
+ ports:
+ - 22666:22
+ - 40666:3000 # port used for forgejo-runner
+ environment:
+ USER_UID: "$USER_ID"
+ USER_GID: "$GROUP_ID"
+ FORGEJO_CUSTOM: "/custom"
+ MAILER_ADDRESS: "${MAILER_ADDRESS}"
+ MAILER_USERNAME: "${MAILER_USERNAME}"
+ MAILER_PASSWORD: "${MAILER_PASSWORD}"
+ FORGEJO_SERVER_LFS_JWT_SECRET: "${EVIL_FORGEJO_SERVER_LFS_JWT_SECRET}"
+ FORGEJO_OAUTH2_JWT_SECRET: "${EVIL_FORGEJO_OAUTH2_JWT_SECRET}"
+ FORGEJO_SECURITY_SECRET_KEY: "${EVIL_FORGEJO_SECURITY_SECRET_KEY}"
+ FORGEJO_SECURITY_INTERNAL_TOKEN: "${EVIL_FORGEJO_SECURITY_INTERNAL_TOKEN}"
+ POSTGRES_PASSWORD_EVIL_FORGEJO: "${POSTGRES_PASSWORD_EVIL_FORGEJO:?}"
+ restart: unless-stopped
+ volumes:
+ - "${APP_ROOT}/evil-infra/forgejo:/data:rw"
+ - "/etc/timezone:/etc/timezone:ro"
+ - "/etc/localtime:/etc/localtime:ro"
+ - ./config/evil-infra/forgejo/public:/custom/public:ro
+ - ./config/evil-infra/forgejo/init:/custom/init:ro
+ depends_on:
+ postgres:
+ condition: service_healthy
+ evil-forgejo-anubis:
+ condition: service_started
+ evil-forgejo-anubis:
+ container_name: evil-forgejo-anubis
+ image: ghcr.io/techarohq/anubis:latest
+ user: "${USER_ID:?}:${GROUP_ID:?}"
+ restart: unless-stopped
+ environment:
+ BIND: :80
+ TARGET: http://evil-forgejo:3000
+ COOKIE_DOMAIN: "evil.inc"
+ ED25519_PRIVATE_KEY_HEX: "${ANUBIS_PRIVATE_KEY:?}"
+ COOKIE_PREFIX: "anubis_v1"
+ DIFFICULTY: 5
+ evil-forgejo-runner:
+ container_name: evil-forgejo-runner
+ image: code.forgejo.org/forgejo/runner:12
+ links:
+ - docker-in-docker
+ depends_on:
+ docker-in-docker:
+ condition: service_started
+ environment:
+ DOCKER_HOST: tcp://docker-in-docker:2375
+ user: "$USER_ID:$GROUP_ID"
+ volumes:
+ - "${APP_ROOT}/evil-infra/forgejo-runner:/data"
+ restart: unless-stopped
+ command: forgejo-runner daemon
secrets:
openvpn-credentials:
diff --git a/config/Caddyfile b/config/Caddyfile
index 89c3962d0758111dd635566c0333b20c1ffd94e3..79dfb86b96fddc902b7bb6ddf7f7c6b9ce774e9d 100644
--- a/config/Caddyfile
+++ b/config/Caddyfile
@@ -190,6 +190,17 @@ sync.{$HOME_DOMAIN} {
import reverse_proxy_auth "http://syncthing:8384" admin
}
+# evil inc temporary infrastructure
+git.evil.inc {
+ tls {
+ on_demand
+ }
+ reverse_proxy "http://evil-forgejo-anubis" {
+ header_up X-Real-Ip {remote_host}
+ header_up X-Http-Version {http.request.proto}
+ }
+}
+
# redirections
paperclover.dev {
redir "https://git.paperclover.net{uri}"
diff --git a/config/evil-infra/forgejo/init/app.ini b/config/evil-infra/forgejo/init/app.ini
new file mode 100755
index 0000000000000000000000000000000000000000..f4cad2fe47696215da94930dec98a470ef0eb3dd
--- /dev/null
+++ b/config/evil-infra/forgejo/init/app.ini
@@ -0,0 +1,115 @@
+APP_NAME="evil inc"
+APP_SLOGAL="be evil. take control back."
+RUN_MODE=prod
+RUN_USER=git
+WORK_PATH=/data/work
+
+[repository]
+MAX_CREATION_LIMIT=20000
+ROOT=/data/git/repositories
+DEFAULT_CLOSE_ISSUES_VIA_COMMITS_IN_ANY_BRANCH=true
+DEFAULT_REPO_UNITS=repo.code,repo.issues,repo.pulls
+DISABLE_STARS=true
+DEFAULT_BRANCH=master
+
+[repository.local]
+LOCAL_COPY_PATH=/data/work/tmp/local-repo
+
+[repository.upload]
+TEMP_PATH=/data/work/uploads
+
+[ui]
+EXPLORE_PAGING_NUM=100
+ISSUE_PAGING_NUM=500
+MEMBERS_PAGING_NUM=100
+THEMES=evil
+DEFAULT_THEME=evil
+
+[server]
+APP_DATA_PATH=/data/work
+DOMAIN=git.evil.inc
+SSH_DOMAIN=git.evil.inc
+HTTP_PORT=3000
+ROOT_URL=https://git.evil.inc
+DISABLE_SSH=false
+SSH_PORT=22
+SSH_LISTEN_PORT=22
+LFS_JWT_SECRET=$FORGEJO_SERVER_LFS_JWT_SECRET
+LFS_START_SERVER=true
+OFFLINE_MODE=true
+LANDING_PAGE=/evil
+
+[database]
+DB_TYPE=postgres
+HOST=postgres:5432
+NAME=evil-forgejo
+USER=evil-forgejo
+PASSWD=$POSTGRES_PASSWORD_EVIL_FORGEJO
+LOG_SQL=false
+SCHEMA=
+SSL_MODE=disable
+
+[indexer]
+ISSUE_INDEXER_PATH=/data/work/indexers/issues.bleve
+
+[session]
+PROVIDER_CONFIG=/data/work/sessions
+PROVIDER=file
+
+[picture]
+AVATAR_UPLOAD_PATH=/data/work/avatars
+REPOSITORY_AVATAR_UPLOAD_PATH=/data/work/repo-avatars
+
+[admin]
+DISABLE_REGULAR_ORG_CREATION=true
+
+[attachment]
+PATH=/data/work/attachments
+
+[log]
+MODE=console
+LEVEL=info
+ROOT_PATH=/data/work/log
+
+[security]
+INSTALL_LOCK=true
+REVERSE_PROXY_LIMIT=1
+REVERSE_PROXY_TRUSTED_PROXIES=*
+PASSWORD_HASH_ALGO=pbkdf2_hi
+SECRET_KEY=$FORGEJO_SECURITY_SECRET_KEY
+INTERNAL_TOKEN=$FORGEJO_SECURITY_INTERNAL_TOKEN
+
+[service]
+ENABLE_INTERNAL_SIGNIN=true
+DISABLE_REGISTRATION=false
+ALLOW_ONLY_EXTERNAL_REGISTRATION=true
+SHOW_REGISTRATION_BUTTON=false
+REQUIRE_SIGNIN_VIEW=false
+REGISTER_EMAIL_CONFIRM=true
+ENABLE_NOTIFY_MAIL=true
+DEFAULT_KEEP_EMAIL_PRIVATE=false
+DEFAULT_ALLOW_CREATE_ORGANIZATION=true
+DEFAULT_ENABLE_TIMETRACKING=false
+
+[lfs]
+PATH = /data/git/lfs
+
+[mailer]
+ENABLED=true
+; TODO: get evil mailing credentials. we likely will not need this
+; for a while and can just use clover's email. its not that deep
+FROM=noreply.evil-git@paperclover.net
+PROTOCOL=smtps
+SMTP_PORT=465
+SMTP_ADDR=$MAILER_ADDRESS
+USER=$MAILER_USERNAME
+PASSWD=$MAILER_PASSWORD
+
+[repository.pull-request]
+DEFAULT_MERGE_STYLE=squash
+
+[repository.signing]
+DEFAULT_TRUST_MODEL=committer
+
+[oauth2]
+JWT_SECRET=$FORGEJO_OAUTH2_JWT_SECRET
diff --git a/config/evil-infra/forgejo/init/entry.sh b/config/evil-infra/forgejo/init/entry.sh
new file mode 100644
index 0000000000000000000000000000000000000000..ee9fdd8d1e535ad8569118e858f04fa244b119e1
--- /dev/null
+++ b/config/evil-infra/forgejo/init/entry.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+set -e
+
+mkdir -p /custom/conf
+envsubst /custom/conf/app.ini
+chmod 444 /custom/conf/app.ini
+
+CADDY_IP="$(getent hosts caddy | awk '{print $1}')"
+echo "${CADDY_IP} git.evil.inc" >>/etc/hosts
+
+exec /usr/bin/entrypoint /usr/bin/s6-svscan /etc/s6
diff --git a/config/evil-infra/forgejo/public/assets/css/theme-evil.css b/config/evil-infra/forgejo/public/assets/css/theme-evil.css
new file mode 100755
index 0000000000000000000000000000000000000000..96b463e99e5fcbb3c6e735d913c195901b2a8b00
--- /dev/null
+++ b/config/evil-infra/forgejo/public/assets/css/theme-evil.css
@@ -0,0 +1,136 @@
+@import "theme-forgejo-light.css";
+@import "theme-forgejo-dark.css" (prefers-color-scheme: dark);
+
+:root {
+ --f: 5;
+ --l: 4;
+ --steel-900: lch(from #10161d l calc(c * var(--f)) 320);
+ --steel-850: lch(from #131a21 l calc(c * var(--f)) 320);
+ --steel-800: lch(from #171e26 l calc(c * var(--f)) 320);
+ --steel-750: lch(from #1d262f l calc(c * var(--f)) 320);
+ --steel-700: lch(from #242d38 l calc(c * var(--f)) 320);
+ --steel-650: lch(from #2b3642 l calc(c * var(--f)) 320);
+ --steel-600: lch(from #374351 l calc(c * var(--f)) 320);
+ --steel-550: lch(from #445161 l calc(c * var(--f)) 320);
+ --steel-500: lch(from #515f70 l calc(c * var(--f)) 320);
+ --steel-450: lch(from #5f6e80 l calc(c * var(--f)) 320);
+ --steel-400: lch(from #6d7d8f l calc(c * var(--f)) 320);
+ --steel-350: lch(from #7c8c9f l calc(c * var(--f)) 320);
+ --steel-300: lch(from #8c9caf l calc(c * var(--f)) 320);
+ --steel-250: lch(from #9dadc0 l calc(c * var(--f)) 320);
+ --steel-200: lch(from #aebed0 l calc(c * var(--f)) 320);
+ --steel-150: lch(from #c0cfe0 l calc(c * var(--f)) 320);
+ --steel-100: lch(from #d2e0f0 l calc(c * var(--f)) 320);
+ --zinc-50: lch(from #fafafa l calc(c * var(--f)) 320);
+ --zinc-100: lch(from #f4f4f5 l calc(c * var(--f)) 320);
+ --zinc-150: lch(from #ececee l calc(c * var(--f)) 320);
+ --zinc-200: lch(from #e4e4e7 l calc(c * var(--f)) 320);
+ --zinc-250: lch(from #dcdce0 l calc(c * var(--f)) 320);
+ --zinc-300: lch(from #d4d4d8 l calc(c * var(--f)) 320);
+ --zinc-350: lch(from #babac1 l calc(c * var(--f)) 320);
+ --zinc-400: lch(from #a1a1aa l calc(c * var(--f)) 320);
+ --zinc-450: lch(from #898992 l calc(c * var(--f)) 320);
+ --zinc-500: lch(from #71717a l calc(c * var(--f)) 320);
+ --zinc-550: lch(from #61616a l calc(c * var(--f)) 320);
+ --zinc-600: lch(from #52525b l calc(c * var(--f)) 320);
+ --zinc-650: lch(from #484850 l calc(c * var(--f)) 320);
+ --zinc-700: lch(from #3f3f46 l calc(c * var(--f)) 320);
+ --zinc-750: lch(from #333338 l calc(c * var(--f)) 320);
+ --zinc-800: lch(from #27272a l calc(c * var(--f)) 320);
+ --zinc-850: lch(from #1f1f23 l calc(c * var(--f)) 320);
+ --zinc-900: lch(from #18181b l calc(c * var(--f)) 320);
+ --color-primary: #b734cf;
+ --color-primary-contrast: lch(from var(--color-primary) 95% 0 h);
+ --color-primary-dark-1: lch(from var(--color-primary) l c h);
+ --color-primary-dark-2: lch(from var(--color-primary) calc(l * 0.85) c h);
+ --color-primary-dark-3: lch(from var(--color-primary) calc(l * 0.85) c h);
+ --color-primary-dark-4: lch(from var(--color-primary) calc(l * 0.72) c h);
+ --color-primary-dark-5: lch(from var(--color-primary) calc(l * 0.72) c h);
+ --color-primary-dark-6: lch(from var(--color-primary) calc(l * 0.72) c h);
+ --color-primary-dark-7: lch(from var(--color-primary) calc(l * 0.72) c h);
+ --color-primary-light-1: lch(from var(--color-primary) calc(l * 1.15) c h);
+ --color-primary-light-2: lch(from var(--color-primary) calc(l * 1.28) c h);
+ --color-primary-light-3: lch(from var(--color-primary) calc(l * 1.48) c h);
+ --color-primary-light-4: lch(from var(--color-primary) calc(l * 1.68) c h);
+ --color-primary-light-5: lch(from var(--color-primary) calc(l * 1.82) calc(c * 0.6) h);
+ --color-primary-light-6: lch(from var(--color-primary) calc(l * 1.92) calc(c * 0.3) h);
+ --color-primary-light-7: lch(from var(--color-primary) calc(l * 1.98) calc(c * 0.15) h);
+ --color-primary-alpha-10: lch(from var(--color-primary) l c h / 0.1);
+ --color-primary-alpha-20: lch(from var(--color-primary) l c h / 0.2);
+ --color-primary-alpha-30: lch(from var(--color-primary) l c h / 0.3);
+ --color-primary-alpha-40: lch(from var(--color-primary) l c h / 0.4);
+ --color-primary-alpha-50: lch(from var(--color-primary) l c h / 0.5);
+ --color-primary-alpha-60: lch(from var(--color-primary) l c h / 0.6);
+ --color-primary-alpha-70: lch(from var(--color-primary) l c h / 0.7);
+ --color-primary-alpha-80: lch(from var(--color-primary) l c h / 0.8);
+ --color-primary-alpha-90: lch(from var(--color-primary) l c h / 0.9);
+ --color-active: lch(from #e2e2e5 l calc(c * var(--f) + var(--l)) 320);
+}
+@media (not (prefers-color-scheme: dark)) {
+ :root {
+ --color-secondary-alpha-10: lch(from #d4d4d819 l calc(c * var(--f) + var(--l)) h);
+ --color-secondary-alpha-20: lch(from #d4d4d833 l calc(c * var(--f) + var(--l)) h);
+ --color-secondary-alpha-30: lch(from #d4d4d84b l calc(c * var(--f) + var(--l)) h);
+ --color-secondary-alpha-40: lch(from #d4d4d866 l calc(c * var(--f) + var(--l)) h);
+ --color-secondary-alpha-50: lch(from #d4d4d880 l calc(c * var(--f) + var(--l)) h);
+ --color-secondary-alpha-60: lch(from #d4d4d899 l calc(c * var(--f) + var(--l)) h);
+ --color-secondary-alpha-70: lch(from #d4d4d8b3 l calc(c * var(--f) + var(--l)) h);
+ --color-secondary-alpha-80: lch(from #d4d4d8cc l calc(c * var(--f) + var(--l)) h);
+ --color-secondary-alpha-90: lch(from #d4d4d8e1 l calc(c * var(--f) + var(--l)) h);
+ --color-body: lch(from #fff l calc(c * var(--f) + var(--l)) h);
+ --color-text-dark: lch(from #000 l calc(c * var(--f) + var(--l)) h);
+ --color-input-background: lch(from #fff l calc(c * var(--f) + var(--l)) h);
+ --color-input-toggle-background: lch(from #fff l calc(c * var(--f) + var(--l)) h);
+ --color-header-wrapper-transparent: lch(from #d2e0f000 l calc(c * var(--f) + var(--l)) h);
+ --color-light-border: lch(from #0000001d l calc(c * var(--f) + var(--l)) h);
+ --color-hover: lch(from #e4e4e4aa l calc(c * var(--f) + var(--l)) h);
+ --color-active: lch(from #e2e2e5 l calc(c * var(--f) + var(--l)) 320);
+ --color-markup-table-row: lch(from #ffffff06 l calc(c * var(--f) + var(--l)) h);
+ --color-shadow: lch(from #00000060 l calc(c * var(--f) + var(--l)) h);
+ --color-text-focus: lch(from #fff l calc(c * var(--f) + var(--l)) h);
+ --color-reaction-bg: lch(from #0000000a l calc(c * var(--f) + var(--l)) h);
+ --color-tooltip-text: lch(from #ffffff l calc(c * var(--f) + var(--l)) h);
+ --color-tooltip-bg: lch(from #000000f0 l calc(c * var(--f) + var(--l)) h);
+ --color-label-bg: lch(from #cacaca7b l calc(c * var(--f) + var(--l)) h);
+ --color-label-hover-bg: lch(from #cacacaa0 l calc(c * var(--f) + var(--l)) h);
+ --color-label-active-bg: lch(from #cacacaff l calc(c * var(--f) + var(--l)) h);
+ --color-label-bg-alt: lch(from #cacacaff l calc(c * var(--f) + var(--l)) h);
+ --color-overlay-backdrop: lch(from #080808c0 l calc(c * var(--f) + var(--l)) h);
+ --checkerboard-color-1: lch(from #ffffff l calc(c * var(--f) + var(--l)) h);
+ --checkerboard-color-2: lch(from #e5e5e5 l calc(c * var(--f) + var(--l)) h);
+ }
+}
+@media (prefers-color-scheme: dark) {
+ :root {
+ --f: 0.75;
+ --color-primary: #E286F3;
+ }
+}
+
+.organization.profile:has(.overflow-menu-items>a[href="/evil"]) {
+ .org-avatar, .org-title {
+ clip: rect(1px, 1px, 1px, 1px);
+ clip-path: inset(50%);
+ height: 1px;
+ width: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ }
+ #org-info .render-content p {
+ display: none;
+ }
+ .org-header::before {
+ content: " ";
+ height: 60px;
+ width: 215px;
+ margin-left: 10px;
+ margin-bottom: 10px;
+ background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCAxNDUzIDQwNiI+PHBhdGggZmlsbD0iIzIwMTQyMiIgZD0iTTQ2IDQ2YzIgMTctNyAxMzUtMiAxNDBzMTI1LTQgMTQyLTJjMjYgNSAyNiA0MS0xIDQ1LTE3IDItMTM2LTgtMTQxLTMtNCA0IDUgMTA1IDMgMTE5IDE0LTQgMjktNiA0My03IDIzLTEgODgtNCAxMDggMCAyMiA0IDI0IDM5LTEgNDQtMzAgNi03NCAwLTEwNyAzLTI3IDItODYgMjYtODgtMTgtMi00MiAxNC05OSA2LTE0MiAwLTQtNi03LTctMTItNC0xOSA1LTE3IDctMjYgOC0zOC0xMS0xNDQgMi0xNzFDMTQgOSAyMCA1IDI4IDRjMTktMyAxMjQtNSAxNDEtMSAyMyA1IDE4IDQzLTMgNDNINDZabTEwMzYgMTc2Yy0xNS0xMC0zMyAzNC0zNyA0NC01IDE0LTEwIDMxLTEzIDQ2cy02IDU3LTExIDY3Yy0xMCAyMC00MSAxNC00My0xMi0xLTE3IDAtMTQxIDQtMTUxIDQtMTMgMjItMTUgMzMtOGw3IDljMSAwIDEyLTE5IDE2LTIyIDQ2LTUxIDc4IDMgMTAzIDQwIDE5IDI4IDc4IDExNCA4OCAxNDAgNyAyMS0xMCAzOC0yOSAyOS05LTUtMzctNjAtNDUtNzNsLTczLTEwOVptMzI2LTEwMWMyNS0xIDMyIDMwIDEwIDM5LTM0IDE0LTU4IDgtOTEgMzgtNjggNjAtMTIgMTIzIDU0IDE0NiAxOCA2IDY3IDkgNzEgMjcgMTAgNDUtODUgMTItMTAzIDUtMTUyLTY0LTExNS0yMDkgMjktMjQ4IDctMiAyMy03IDMwLTdaTTYzNiA1YzcgNyA1IDQyIDQgNTMgMCA3OC04IDE1Ni02IDIzNCAwIDI0IDkgNjYgNSA4Ni0zIDE5LTMxIDIxLTM0LTEtNC0yNiA1LTcwIDUtMTAwIDEtNzgtMTQtMTg0LTUtMjU4IDItMTYgMTktMjYgMzEtMTRaTTMxMyAzMTBjMjEtMzIgMzQtNzAgNTktOTkgMTAtMTEgMzItMzYgNDgtMjQgMjQgMTktMTMgMzgtMjMgNDgtMjAgMjMtMzkgNTctNTAgODYtNSAxMS0xNyA1Ni0yMyA2MS0xMyAxMC0yNiAzLTMyLTExLTktMTctNDQtMTIwLTQ3LTEzNy0zLTI1IDIzLTM2IDM2LTE5czIwIDc0IDMyIDk1Wm0xNzAtMTEzYzEyLTEyIDMyLTQgMzQgMTIgNSAyOC0xIDg0LTEgMTE3IDAgMTQgNyA1Mi00IDYyLTggNy0yMiA3LTI5LTItMTEtMTEtMy02OC0zLTg1IDAtMjctNi03MC0xLTk1IDAtMyAyLTYgNC05Wm0xNS01MmEyMSAyMSAwIDEgMCAwLTQyIDIxIDIxIDAgMCAwIDAgNDJaIi8+PHBhdGggZmlsbD0iI0UxODZGNCIgZD0iTTk1MSA0MGMyMyAyMS0xIDUzLTE2IDcwLTEzIDE1LTQ1IDUyLTY0IDUxLTYgMC00Ni0yMi01My0yNy0zOS0yNy0zNS0xMDIgMjctODkgOCAyIDI4IDE1IDMwIDE1IDMtMSAxMi0xNSAxNy0xOCAxNC0xMSA0NS0xNSA1OS0yWiIvPjxwYXRoIGZpbGw9IiMyMDE0MjIiIGQ9Ik04NjAgMzg3Yy0zLTQtNS05LTYtMTQtMy0yMi0zLTE1NSAwLTE3NiA0LTI0IDM3LTI1IDQwIDIgMyAyMCAzIDE1NiAwIDE3NS0yIDE3LTIyIDI0LTM0IDEzWiIvPjwvc3ZnPg);
+ @media (prefers-color-scheme: dark) {
+ background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCAxNDUzIDQwNiI+PHBhdGggZD0iTTQ2IDQ2YzIgMTctNyAxMzUtMiAxNDBzMTI1LTQgMTQyLTJjMjYgNSAyNiA0MS0xIDQ1LTE3IDItMTM2LTgtMTQxLTMtNCA0IDUgMTA1IDMgMTE5IDE0LTQgMjktNiA0My03IDIzLTEgODgtNCAxMDggMCAyMiA0IDI0IDM5LTEgNDQtMzAgNi03NCAwLTEwNyAzLTI3IDItODYgMjYtODgtMTgtMi00MiAxNC05OSA2LTE0MiAwLTQtNi03LTctMTItNC0xOSA1LTE3IDctMjYgOC0zOC0xMS0xNDQgMi0xNzFDMTQgOSAyMCA1IDI4IDRjMTktMyAxMjQtNSAxNDEtMSAyMyA1IDE4IDQzLTMgNDNINDZabTEwMzYgMTc2Yy0xNS0xMC0zMyAzNC0zNyA0NC01IDE0LTEwIDMxLTEzIDQ2cy02IDU3LTExIDY3Yy0xMCAyMC00MSAxNC00My0xMi0xLTE3IDAtMTQxIDQtMTUxIDQtMTMgMjItMTUgMzMtOGw3IDljMSAwIDEyLTE5IDE2LTIyIDQ2LTUxIDc4IDMgMTAzIDQwIDE5IDI4IDc4IDExNCA4OCAxNDAgNyAyMS0xMCAzOC0yOSAyOS05LTUtMzctNjAtNDUtNzNsLTczLTEwOVptMzI2LTEwMWMyNS0xIDMyIDMwIDEwIDM5LTM0IDE0LTU4IDgtOTEgMzgtNjggNjAtMTIgMTIzIDU0IDE0NiAxOCA2IDY3IDkgNzEgMjcgMTAgNDUtODUgMTItMTAzIDUtMTUyLTY0LTExNS0yMDkgMjktMjQ4IDctMiAyMy03IDMwLTdaTTYzNiA1YzcgNyA1IDQyIDQgNTMgMCA3OC04IDE1Ni02IDIzNCAwIDI0IDkgNjYgNSA4Ni0zIDE5LTMxIDIxLTM0LTEtNC0yNiA1LTcwIDUtMTAwIDEtNzgtMTQtMTg0LTUtMjU4IDItMTYgMTktMjYgMzEtMTRaTTMxMyAzMTBjMjEtMzIgMzQtNzAgNTktOTkgMTAtMTEgMzItMzYgNDgtMjQgMjQgMTktMTMgMzgtMjMgNDgtMjAgMjMtMzkgNTctNTAgODYtNSAxMS0xNyA1Ni0yMyA2MS0xMyAxMC0yNiAzLTMyLTExLTktMTctNDQtMTIwLTQ3LTEzNy0zLTI1IDIzLTM2IDM2LTE5czIwIDc0IDMyIDk1Wm0xNzAtMTEzYzEyLTEyIDMyLTQgMzQgMTIgNSAyOC0xIDg0LTEgMTE3IDAgMTQgNyA1Mi00IDYyLTggNy0yMiA3LTI5LTItMTEtMTEtMy02OC0zLTg1IDAtMjctNi03MC0xLTk1IDAtMyAyLTYgNC05Wm0xNS01MmEyMSAyMSAwIDEgMCAwLTQyIDIxIDIxIDAgMCAwIDAgNDJaIiBmaWxsPSIjZTZkYmU3Ii8+PHBhdGggZmlsbD0iI0UxODZGNCIgZD0iTTk1MSA0MGMyMyAyMS0xIDUzLTE2IDcwLTEzIDE1LTQ1IDUyLTY0IDUxLTYgMC00Ni0yMi01My0yNy0zOS0yNy0zNS0xMDIgMjctODkgOCAyIDI4IDE1IDMwIDE1IDMtMSAxMi0xNSAxNy0xOCAxNC0xMSA0NS0xNSA1OS0yWiIvPjxwYXRoIGQ9Ik04NjAgMzg3Yy0zLTQtNS05LTYtMTQtMy0yMi0zLTE1NSAwLTE3NiA0LTI0IDM3LTI1IDQwIDIgMyAyMCAzIDE1NiAwIDE3NS0yIDE3LTIyIDI0LTM0IDEzWiIgZmlsbD0iI2U2ZGJlNyIvPjwvc3ZnPg);
+
+ }
+ }
+}
diff --git a/config/evil-infra/forgejo/public/assets/img/apple-touch-icon.png b/config/evil-infra/forgejo/public/assets/img/apple-touch-icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..e36c65b9ddde8a87650e731cbfb9be7658750de9
Binary files /dev/null and b/config/evil-infra/forgejo/public/assets/img/apple-touch-icon.png differ
diff --git a/config/evil-infra/forgejo/public/assets/img/avatar_default.png b/config/evil-infra/forgejo/public/assets/img/avatar_default.png
new file mode 100644
index 0000000000000000000000000000000000000000..e5826b20abcdd5f50018f00781b5af612e420793
Binary files /dev/null and b/config/evil-infra/forgejo/public/assets/img/avatar_default.png differ
diff --git a/config/evil-infra/forgejo/public/assets/img/favicon.png b/config/evil-infra/forgejo/public/assets/img/favicon.png
new file mode 100644
index 0000000000000000000000000000000000000000..0d6b8cb661a5b12954f3336bfc39cda87b8b9f38
Binary files /dev/null and b/config/evil-infra/forgejo/public/assets/img/favicon.png differ
diff --git a/config/evil-infra/forgejo/public/assets/img/favicon.svg b/config/evil-infra/forgejo/public/assets/img/favicon.svg
new file mode 100644
index 0000000000000000000000000000000000000000..fbab2c55fa0646f4f56b29aaf0de4f15def9a16a
--- /dev/null
+++ b/config/evil-infra/forgejo/public/assets/img/favicon.svg
@@ -0,0 +1,14 @@
+
diff --git a/config/evil-infra/forgejo/public/assets/img/logo.png b/config/evil-infra/forgejo/public/assets/img/logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..c60882e000aff0359156e3d7d655437aaf445052
Binary files /dev/null and b/config/evil-infra/forgejo/public/assets/img/logo.png differ
diff --git a/config/evil-infra/forgejo/public/assets/img/logo.svg b/config/evil-infra/forgejo/public/assets/img/logo.svg
new file mode 100644
index 0000000000000000000000000000000000000000..fbab2c55fa0646f4f56b29aaf0de4f15def9a16a
--- /dev/null
+++ b/config/evil-infra/forgejo/public/assets/img/logo.svg
@@ -0,0 +1,14 @@
+
diff --git a/config/postgres/init.sh b/config/postgres/init.sh
index d318d7d6446c7cacc1d46c414dba6a6ef7dbef65..e985a98aa5419846b7dbb977667ef561bdc6660a 100755
--- a/config/postgres/init.sh
+++ b/config/postgres/init.sh
@@ -45,6 +45,7 @@ ensure_db_user "clover" "$POSTGRES_PASSWORD"
ensure_db_user "keycloak" "$POSTGRES_PASSWORD_KEYCLOAK"
ensure_db_user "dawarich" "$POSTGRES_PASSWORD_DAWARICH"
ensure_db_user "forgejo" "$POSTGRES_PASSWORD_FORGEJO"
+ensure_db_user "evil-forgejo" "$POSTGRES_PASSWORD_EVIL_FORGEJO"
printf "Everything is ready!"
diff --git a/generate-env.sh b/generate-env.sh
new file mode 100644
index 0000000000000000000000000000000000000000..df4ddbee2211f4859e22bdfa4b471945d697adb2
--- /dev/null
+++ b/generate-env.sh
@@ -0,0 +1,67 @@
+#!/bin/sh
+set -e
+
+FILE=${1:-.env}
+if [ -f "$FILE" ]; then
+ printf '\033[33mwarning: %d exists\033[0m\n' "$FILE"
+ exit 1
+fi
+
+printf "generating...\n"
+
+template() {
+ add "HOME_DOMAIN" "local.test"
+ add "ADMIN_EMAIL" ""
+ add "USER_ID" "$(id -u)"
+ add "GROUP_ID" "$(id -g)"
+
+ section "storage"
+ add "APP_ROOT" "./.apps"
+ add "STORE_ROOT" "./.apps/store"
+ add "CLOVER_ROOT" ""
+ add "MEDIA_ROOT" ""
+ add "TORRENT_TEMP" ""
+
+ section "mailing"
+ add "MAILER_ADDRESS" ""
+ add "MAILER_USERNAME" ""
+ add "MAILER_PASSWORD" ""
+
+ section "authentication"
+ add "KEYCLOAK_ADMIN_PASSWORD" "$(secret 12)"
+
+ section "postgres"
+ add "POSTGRES_PASSWORD" "$(secret 32)"
+ add "POSTGRES_PASSWORD_KEYCLOAK" "$(secret 32)"
+ add "POSTGRES_PASSWORD_FORGEJO" "$(secret 32)"
+ add "POSTGRES_PASSWORD_DAWARICH" "$(secret 32)"
+ add "POSTGRES_PASSWORD_EVIL_FORGEJO" "$(secret 32)"
+
+ section "misc keys"
+ add "ANUBIS_PRIVATE_KED" "$(secret 32)"
+ add "FORWARD_AUTH_KED" "$(secret 32)"
+ add "CLOVER_SOT_KEY" ""
+
+ section "forgejo"
+ add "FORGEJO_SERVER_LFS_JWT_SECRET" "$(forgejo generate secret LFS_JWT_SECRET)"
+ add "FORGEJO_OAUTH2_JWT_SECRET" "$(forgejo generate secret JWT_SECRET)"
+ add "FORGEJO_SECURITY_SECRET_KEY" "$(forgejo generate secret SECRET_KEY)"
+ add "FORGEJO_SECURITY_INTERNAL_TOKEN" "$(forgejo generate secret INTERNAL_TOKEN)"
+
+ section "evil infra"
+ add "EVIL_FORGEJO_SERVER_LFS_JWT_SECRET" "$(forgejo generate secret LFS_JWT_SECRET)"
+ add "EVIL_FORGEJO_OAUTH2_JWT_SECRET" "$(forgejo generate secret JWT_SECRET)"
+ add "EVIL_FORGEJO_SECURITY_SECRET_KEY" "$(forgejo generate secret SECRET_KEY)"
+ add "EVIL_FORGEJO_SECURITY_INTERNAL_TOKEN" "$(forgejo generate secret INTERNAL_TOKEN)"
+}
+
+secret() { openssl rand -base64 "$1" | tr -d '\n=/' | cut -c1-"$1"; }
+section() { printf '\n# %s\n' "$1" >>"$FILE"; }
+add() {
+ printf '%s=%s\n' "$1" "${2:-}" >>"$FILE"
+}
+forgejo() {
+ docker run --rm code.forgejo.org/forgejo/forgejo:13 forgejo "$@"
+}
+
+template