Skip to content
Draft
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
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ jobs:
- web-app-ai-image-alt-text-sidebar
- web-app-chat-with-file
- ai-llm-proxy
- jitsi-admin-proxy
- web-app-version-changelog
- web-app-group-management
- web-app-file-comments
Expand Down
320 changes: 320 additions & 0 deletions ARCHAEOLOGY.md

Large diffs are not rendered by default.

269 changes: 269 additions & 0 deletions DECISIONS.md

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ services:
- ./packages/web-app-vim-nav/dist:/web/apps/vim-nav
- ./packages/web-app-ai-smart-collections-nav/dist:/web/apps/ai-smart-collections-nav
- ./packages/web-app-ai-folder-readme-generator/dist:/web/apps/ai-folder-readme-generator
- ./packages/web-app-jitsi-conference/dist:/web/apps/jitsi-conference
- ./packages/web-app-jitsi-conference/tests/config/manifest.json:/web/apps/jitsi-conference/manifest.json
depends_on:
- traefik

Expand All @@ -83,6 +85,29 @@ services:
depends_on:
- traefik

jitsi-admin-proxy:
build:
context: ./packages/jitsi-admin-proxy
dockerfile: Dockerfile
extra_hosts:
- host.docker.internal:${DOCKER_HOST:-host-gateway}
environment:
OCIS_URL: 'https://host.docker.internal:9200'
JITSI_ADMIN_URL: '${JITSI_ADMIN_URL:-}'
JITSI_ADMIN_API_KEY: '${JITSI_ADMIN_API_KEY:-}'
JITSI_ADMIN_SERVER: '${JITSI_ADMIN_SERVER:-}'
PORT: '3031'
labels:
traefik.enable: true
traefik.http.routers.jitsi-admin-proxy.tls: true
traefik.http.routers.jitsi-admin-proxy.rule: Host(`host.docker.internal`) && PathPrefix(`/jitsi-admin-proxy`)
traefik.http.routers.jitsi-admin-proxy.entrypoints: ocis
traefik.http.routers.jitsi-admin-proxy.middlewares: jitsi-admin-proxy-strip,cors
traefik.http.middlewares.jitsi-admin-proxy-strip.stripPrefix.prefixes: /jitsi-admin-proxy
traefik.http.services.jitsi-admin-proxy.loadbalancer.server.port: 3031
depends_on:
- traefik

# tika is required for the photo and search extensions
tika:
image: apache/tika:latest-full
Expand Down
12 changes: 12 additions & 0 deletions packages/jitsi-admin-proxy/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM node:24.16.0-alpine3.24 AS build
RUN corepack enable && corepack prepare pnpm@latest --activate
WORKDIR /app
COPY package.json tsconfig.json ./
COPY src ./src
RUN pnpm install --ignore-scripts && pnpm build

FROM node:24.16.0-alpine3.24
WORKDIR /app
COPY --from=build /app/dist ./dist
EXPOSE 3031
CMD ["node", "dist/index.js"]
44 changes: 44 additions & 0 deletions packages/jitsi-admin-proxy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# jitsi-admin-proxy

Server-side sidecar for the `jitsi-conference` extension's "Call all Space members" feature (see
`../web-app-jitsi-conference/README.md`). It exists because jitsi-admin's room-provisioning API
(`/api/v1/room`, `/api/v1/user`) authenticates with a static, per-server API key rather than a
forwarded end-user token (see `DECISIONS.md`, D3) — a browser extension cannot hold that key
itself, so this proxy holds it instead and only ever accepts requests from an already-authenticated
oCIS user.

## What it does

1. Rejects any request whose `Origin` header doesn't match `OCIS_URL` (mandatory server-side check
per `CLAUDE.md` — CORS headers alone are not sufficient).
2. Validates the caller's oCIS OIDC bearer token against oCIS's own `/userinfo` endpoint.
3. Creates a room in jitsi-admin (owned by the calling user's email) and invites each supplied
participant by email — jitsi-admin sends the invitation emails itself, so this proxy never needs
to talk to any oCIS notification API.
4. Returns `{ roomCreated, invited, failed }` so the caller can show the user which invites, if any,
didn't go through.

## Configuration (environment variables)

| Variable | Required | Description |
|---|---|---|
| `OCIS_URL` | yes | Base URL of the oCIS instance; used both for the origin check and OIDC discovery. |
| `JITSI_ADMIN_URL` | yes | Base URL of the jitsi-admin instance. |
| `JITSI_ADMIN_API_KEY` | yes | The registered `Server`'s API key in jitsi-admin — a service credential, never a user token. |
| `JITSI_ADMIN_SERVER` | yes | Identifies which jitsi-admin `Server` (registered Jitsi/LiveKit backend) new rooms are created on. |
| `PORT` | no | Listen port, defaults to `3031`. |
| `ROOM_DURATION_MINUTES` | no | Duration passed to jitsi-admin when creating a room, defaults to `60`. |
| `MAX_PARTICIPANTS` | no | Hard cap on participants per request, defaults to `50`. |
| `RATE_LIMIT_RPM` | no | Requests per user per rolling minute, defaults to `10`. |
| `REQUEST_TIMEOUT_MS` | no | Timeout for the jitsi-admin API calls, defaults to `15000`. |

## A caveat worth reading before deploying this

The exact field names used when calling jitsi-admin's `/api/v1/room` and `/api/v1/user` (`name`,
`email`, `server`, `start`, `duration`, `room`) are a best-effort reconstruction from reading
H2-invent/jitsi-admin's Symfony controller source (see `../../ARCHAEOLOGY.md` §1.1) — this proxy has
not been exercised against a live jitsi-admin instance. Before relying on this in production, verify
the request/response contract against your jitsi-admin version (its Wiki's `API-Endpoints` page is
the best starting point) and adjust `src/index.ts`'s `createJitsiAdminRoom`/
`inviteJitsiAdminParticipant` functions if it doesn't match — they're deliberately kept small and
isolated for exactly this reason.
23 changes: 23 additions & 0 deletions packages/jitsi-admin-proxy/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "jitsi-admin-proxy",
"version": "0.1.0",
"private": true,
"description": "Server-side proxy for the jitsi-conference extension — validates oCIS auth and provisions jitsi-admin rooms with the operator's Server API key",
"license": "Apache-2.0",
"type": "module",
"scripts": {
"build": "tsc",
"dev": "node --watch dist/index.js",
"start": "node dist/index.js",
"test:unit": "vitest run",
"test:e2e": "echo 'No E2E tests for jitsi-admin-proxy'"
},
"engines": {
"node": ">=18"
},
"devDependencies": {
"@types/node": "^24.13.3",
"typescript": "^5.4.0",
"vitest": "4.1.10"
}
}
Loading