rename to prism

This commit is contained in:
lone-cloud 2026-01-31 02:00:29 -08:00
parent 34c1406e84
commit 1d25469687
27 changed files with 65 additions and 1646 deletions

View file

@ -14,8 +14,8 @@
# RATE_LIMIT=100 # RATE_LIMIT=100
# Optional: Device name shown in Signal app's linked devices list # Optional: Device name shown in Signal app's linked devices list
# Default: SUP # Default: PRISM
# DEVICE_NAME=What SUP # DEVICE_NAME=What PRISM
# Optional: Enable verbose logging # Optional: Enable verbose logging
# Default: false # Default: false
@ -32,4 +32,4 @@
# PROTON_IMAP_PASSWORD=bridge-generated-password # PROTON_IMAP_PASSWORD=bridge-generated-password
# PROTON_BRIDGE_HOST=protonmail-bridge # PROTON_BRIDGE_HOST=protonmail-bridge
# PROTON_BRIDGE_PORT=143 # PROTON_BRIDGE_PORT=143
# PROTON_SUP_TOPIC=Proton Mail # PROTON_PRISM_TOPIC=Proton Mail

View file

@ -7,7 +7,7 @@ on:
env: env:
REGISTRY: ghcr.io REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository_owner }}/sup IMAGE_NAME: ${{ github.repository_owner }}/prism
jobs: jobs:
build: build:

2
.gitignore vendored
View file

@ -1,4 +1,4 @@
node_modules/ node_modules/
signal-cli signal-cli
.env .env
sup prism

View file

@ -1,8 +1,8 @@
<div align="center"> <div align="center">
<img src="assets/sup.webp" alt="SUP Icon" width="120" height="120" /> <img src="assets/prism.webp" alt="PRISM Icon" width="120" height="120" />
# SUP # PRISM
**Self-hosted notification gateway using Signal and Webhooks for transport** **Self-hosted notification gateway using Signal and Webhooks for transport**
@ -12,18 +12,18 @@
<!-- markdownlint-enable MD033 --> <!-- markdownlint-enable MD033 -->
SUP is a self-hosted notification gateway that receives HTTP requests and routes them through Signal groups or custom webhooks. Route notifications through Signal to avoid exposing unique network fingerprints, or forward them to your own webhook endpoints for custom handling. PRISM is a self-hosted notification gateway that receives HTTP requests and routes them through Signal groups or custom webhooks. Route notifications through Signal to avoid exposing unique network fingerprints, or forward them to your own webhook endpoints for custom handling.
## How? ## How?
SUP accepts notifications via HTTP POST requests and routes them based on your configured delivery method: PRISM accepts notifications via HTTP POST requests and routes them based on your configured delivery method:
- **Signal groups**: Uses [signal-cli](https://github.com/AsamK/signal-cli) to create a Signal group for each app and send notifications as messages - **Signal groups**: Uses [signal-cli](https://github.com/AsamK/signal-cli) to create a Signal group for each app and send notifications as messages
- **Webhook forwarding**: Forwards notifications to your own webhook URL (useful for UnifiedPush distributors, ntfy, or custom handlers) - **Webhook forwarding**: Forwards notifications to your own webhook URL (useful for UnifiedPush distributors, ntfy, or custom handlers)
Each endpoint can be independently configured to use either delivery method through the admin UI. Each endpoint can be independently configured to use either delivery method through the admin UI.
For the optional Proton Mail integration, SUP requires a server that runs Proton's official [proton-bridge](https://github.com/ProtonMail/proton-bridge). SUP's docker compose process will run an image from [protonmail-bridge-docker](https://github.com/shenxn/protonmail-bridge-docker). Once authenticated, the communication between SUP and proton-bridge will be over IMAP. For the optional Proton Mail integration, PRISM requires a server that runs Proton's official [proton-bridge](https://github.com/ProtonMail/proton-bridge). PRISM's docker compose process will run an image from [protonmail-bridge-docker](https://github.com/shenxn/protonmail-bridge-docker). Once authenticated, the communication between PRISM and proton-bridge will be over IMAP.
## Setup ## Setup
@ -39,7 +39,7 @@ To receive Proton Mail notifications via Signal:
```bash ```bash
# Download docker-compose.yml # Download docker-compose.yml
curl -L -O https://raw.githubusercontent.com/lone-cloud/sup/master/docker-compose.yml curl -L -O https://raw.githubusercontent.com/lone-cloud/prism/master/docker-compose.yml
docker compose run --rm protonmail-bridge init docker compose run --rm protonmail-bridge init
``` ```
@ -75,20 +75,20 @@ Your phone will now receive Signal notifications when Proton Mail receives new e
Note that the bridge will first need to sync all of your old emails before you can start getting new email notifications which may take a while, but this is a one-time setup. Note that the bridge will first need to sync all of your old emails before you can start getting new email notifications which may take a while, but this is a one-time setup.
### 2. Install SUP Server ### 2. Install PRISM Server
```bash ```bash
# Download docker-compose.yml # Download docker-compose.yml
curl -L -O https://raw.githubusercontent.com/lone-cloud/sup/master/docker-compose.yml curl -L -O https://raw.githubusercontent.com/lone-cloud/prism/master/docker-compose.yml
# Download .env.example (optional) # Download .env.example (optional)
curl -L -O https://raw.githubusercontent.com/lone-cloud/sup/master/server/.env.example curl -L -O https://raw.githubusercontent.com/lone-cloud/prism/master/server/.env.example
# Configure SUP server through environment variables (optional) # Configure PRISM server through environment variables (optional)
cp .env.example .env cp .env.example .env
nano .env nano .env
# Start SUP server # Start PRISM server
docker compose up -d docker compose up -d
``` ```
@ -125,8 +125,8 @@ For local development, install Bun and signal-cli:
# Install Bun (use your package manager and this is a backup) # Install Bun (use your package manager and this is a backup)
curl -fsSL https://bun.sh/install | bash curl -fsSL https://bun.sh/install | bash
git clone https://github.com/lone-cloud/sup.git git clone https://github.com/lone-cloud/prism.git
cd sup cd prism
bun install bun install
cd server cd server
@ -151,7 +151,7 @@ docker compose -f docker-compose.dev.yml up protonmail-bridge
Receive Signal notifications when new emails arrive in your Proton Mail inbox. Receive Signal notifications when new emails arrive in your Proton Mail inbox.
SUP monitors a Proton Mail account via the local bridge and forwards email alerts through Signal. This relies on the same technology that a third-party email client like Thunderbird would be using to integrate with Proton Mail. PRISM monitors a Proton Mail account via the local bridge and forwards email alerts through Signal. This relies on the same technology that a third-party email client like Thunderbird would be using to integrate with Proton Mail.
### Home Assistant Alerts ### Home Assistant Alerts
@ -160,26 +160,26 @@ Add a rest notification configuration (eg. add to configuration.yaml) to Home As
```bash ```bash
notify: notify:
- platform: rest - platform: rest
name: SUP name: PRISM
resource: "http://<Your SUP server network IP>/Home Assistant" resource: "http://<Your PRISM server network IP>/Home Assistant"
method: POST method: POST
headers: headers:
Authorization: !secret sup_basic_auth Authorization: !secret prism_basic_auth
``` ```
Note how Home Assistant is also a self-hosted server. As such, it is advisable to turn on `ALLOW_INSECURE_HTTP` environment variable for SUP and to refer to it by its LAN IP address. Note how Home Assistant is also a self-hosted server. As such, it is advisable to turn on `ALLOW_INSECURE_HTTP` environment variable for PRISM and to refer to it by its LAN IP address.
Add the Base64 version of your API_KEY environment variable secret to your secrets.yaml. This secret must be prepended by a colon and the simplest way to get this value is to run `btoa(':<API_KEY>')` in your browser's console. Add the Base64 version of your API_KEY environment variable secret to your secrets.yaml. This secret must be prepended by a colon and the simplest way to get this value is to run `btoa(':<API_KEY>')` in your browser's console.
```bash ```bash
sup_basic_auth: "Basic <Base64 Hash value>" prism_basic_auth: "Basic <Base64 Hash value>"
``` ```
Reboot your Home Assistant system and you'll then be able to send Signal notifications to yourself by using this notify sup action. Reboot your Home Assistant system and you'll then be able to send Signal notifications to yourself by using this notify prism action.
## Monitoring ## Monitoring
The health of the system can be viewed in the same admin UI used for linking Signal. SUP uses [basic access authentication](https://en.wikipedia.org/wiki/Basic_access_authentication) - provide your `API_KEY` as the password (username can be anything). The health of the system can be viewed in the same admin UI used for linking Signal. PRISM uses [basic access authentication](https://en.wikipedia.org/wiki/Basic_access_authentication) - provide your `API_KEY` as the password (username can be anything).
For API-based monitoring, call `/api/health` which returns JSON: For API-based monitoring, call `/api/health` which returns JSON:
@ -189,11 +189,9 @@ For API-based monitoring, call `/api/health` which returns JSON:
## Architecture ## Architecture
![SUP Architecture](assets/SUP%20Architecture.webp) PRISM consists of two services that **MUST run together on the same machine**:
SUP consists of two services that **MUST run together on the same machine**: - **prism** (Bun): Receives webhooks, sends Signal messages via signal-cli. Optional: monitors Proton Mail IMAP
- **sup** (Bun): Receives webhooks, sends Signal messages via signal-cli. Optional: monitors Proton Mail IMAP
- **protonmail-bridge** (Official Proton, optional): Decrypts Proton Mail emails, runs local IMAP server - **protonmail-bridge** (Official Proton, optional): Decrypts Proton Mail emails, runs local IMAP server
All services communicate over a private Docker network with no external exposure except Signal protocol. **Separating these services across multiple machines would expose plaintext IMAP traffic and compromise security.** All services communicate over a private Docker network with no external exposure except Signal protocol. **Separating these services across multiple machines would expose plaintext IMAP traffic and compromise security.**

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

BIN
assets/prism.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

View file

@ -3,7 +3,7 @@
"configVersion": 1, "configVersion": 1,
"workspaces": { "workspaces": {
"": { "": {
"name": "sup", "name": "prism",
"dependencies": { "dependencies": {
"chalk": "5.6.2", "chalk": "5.6.2",
"hono": "4.11.7", "hono": "4.11.7",

View file

@ -1,6 +1,6 @@
services: services:
server: server:
container_name: sup-server container_name: prism-server
build: build:
context: . context: .
dockerfile: server/Dockerfile dockerfile: server/Dockerfile
@ -15,10 +15,10 @@ services:
- PROTON_IMAP_PASSWORD=${PROTON_IMAP_PASSWORD:-} - PROTON_IMAP_PASSWORD=${PROTON_IMAP_PASSWORD:-}
- PROTON_BRIDGE_HOST=protonmail-bridge - PROTON_BRIDGE_HOST=protonmail-bridge
- PROTON_BRIDGE_PORT=${PROTON_BRIDGE_PORT:-143} - PROTON_BRIDGE_PORT=${PROTON_BRIDGE_PORT:-143}
- PROTON_SUP_TOPIC=${PROTON_SUP_TOPIC:-Proton Mail} - PROTON_PRISM_TOPIC=${PROTON_PRISM_TOPIC:-Proton Mail}
volumes: volumes:
- signal-data:/root/.local/share/signal-cli - signal-data:/root/.local/share/signal-cli
- sup-data:/root/.local/share/sup - prism-data:/root/.local/share/prism
restart: unless-stopped restart: unless-stopped
protonmail-bridge: protonmail-bridge:
@ -34,5 +34,5 @@ services:
volumes: volumes:
signal-data: signal-data:
sup-data: prism-data:
proton-bridge-data: proton-bridge-data:

View file

@ -1,7 +1,7 @@
services: services:
server: server:
container_name: sup-server container_name: prism-server
image: ghcr.io/lone-cloud/sup:latest image: ghcr.io/lone-cloud/prism:latest
ports: ports:
- '8080:8080' - '8080:8080'
environment: environment:
@ -14,10 +14,10 @@ services:
- PROTON_IMAP_PASSWORD=${PROTON_IMAP_PASSWORD:-} - PROTON_IMAP_PASSWORD=${PROTON_IMAP_PASSWORD:-}
- PROTON_BRIDGE_HOST=protonmail-bridge - PROTON_BRIDGE_HOST=protonmail-bridge
- PROTON_BRIDGE_PORT=${PROTON_BRIDGE_PORT:-143} - PROTON_BRIDGE_PORT=${PROTON_BRIDGE_PORT:-143}
- PROTON_SUP_TOPIC=${PROTON_SUP_TOPIC:-Proton Mail} - PROTON_PRISM_TOPIC=${PROTON_PRISM_TOPIC:-Proton Mail}
volumes: volumes:
- signal-data:/root/.local/share/signal-cli - signal-data:/root/.local/share/signal-cli
- sup-data:/root/.local/share/sup - prism-data:/root/.local/share/prism
restart: unless-stopped restart: unless-stopped
protonmail-bridge: protonmail-bridge:
@ -31,5 +31,5 @@ services:
volumes: volumes:
signal-data: signal-data:
sup-data: prism-data:
proton-bridge-data: proton-bridge-data:

View file

@ -1,5 +1,5 @@
{ {
"name": "sup", "name": "prism",
"version": "0.2.0", "version": "0.2.0",
"description": "Privacy-preserving push notifications using Signal as transport", "description": "Privacy-preserving push notifications using Signal as transport",
"private": true, "private": true,
@ -11,12 +11,12 @@
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/lone-cloud/sup" "url": "https://github.com/lone-cloud/prism"
}, },
"scripts": { "scripts": {
"postinstall": "bun run scripts/install-signal-cli.ts || true", "postinstall": "bun run scripts/install-signal-cli.ts || true",
"start": "bun run server/index.ts", "start": "bun run server/index.ts",
"build": "bun build --compile server/index.ts --outfile server/sup", "build": "bun build --compile server/index.ts --outfile server/prism",
"check": "tsc --noEmit && biome check .", "check": "tsc --noEmit && biome check .",
"fix": "biome check --write --unsafe .", "fix": "biome check --write --unsafe .",
"release": "bun run scripts/release.ts" "release": "bun run scripts/release.ts"

View file

@ -26,14 +26,14 @@ try {
Pull the latest version: Pull the latest version:
\`\`\`bash \`\`\`bash
docker pull ghcr.io/lone-cloud/sup:${version} docker pull ghcr.io/lone-cloud/prism:${version}
\`\`\`" --generate-notes`; \`\`\`" --generate-notes`;
console.log(` console.log(`
Release ${version} complete! Release ${version} complete!
Once CI completes, images will be available: Once CI completes, images will be available:
docker pull ghcr.io/lone-cloud/sup:${version} docker pull ghcr.io/lone-cloud/prism:${version}
`); `);
} catch (error) { } catch (error) {
console.error('Release failed:', error); console.error('Release failed:', error);

View file

@ -7,7 +7,7 @@ RUN bun install --frozen-lockfile
COPY server ./server COPY server ./server
RUN bun build --compile server/index.ts --outfile sup RUN bun build --compile server/index.ts --outfile prism
FROM debian:13.3-slim FROM debian:13.3-slim
@ -34,7 +34,7 @@ RUN ARCH=$(uname -m) && \
rm /tmp/libsignal_jni_aarch64.so; \ rm /tmp/libsignal_jni_aarch64.so; \
fi fi
COPY --from=builder /app/sup /usr/local/bin/sup COPY --from=builder /app/prism /usr/local/bin/prism
COPY --from=builder /app/server/public /public COPY --from=builder /app/server/public /public
ENV PATH="/usr/local/signal-cli/bin:${PATH}" ENV PATH="/usr/local/signal-cli/bin:${PATH}"
@ -42,4 +42,4 @@ ENV LD_LIBRARY_PATH="/usr/local/signal-cli/lib:${LD_LIBRARY_PATH}"
EXPOSE 8080 EXPOSE 8080
CMD ["sup"] CMD ["prism"]

View file

@ -4,15 +4,15 @@ export const VERBOSE_LOGGING = Bun.env.VERBOSE_LOGGING === 'true';
export const ALLOW_INSECURE_HTTP = Bun.env.ALLOW_INSECURE_HTTP === 'true'; export const ALLOW_INSECURE_HTTP = Bun.env.ALLOW_INSECURE_HTTP === 'true';
export const RATE_LIMIT = Number.parseInt(Bun.env.RATE_LIMIT || '100', 10); export const RATE_LIMIT = Number.parseInt(Bun.env.RATE_LIMIT || '100', 10);
export const DEVICE_NAME = Bun.env.DEVICE_NAME || 'SUP'; export const DEVICE_NAME = Bun.env.DEVICE_NAME || 'PRISM';
export const SUP_ENDPOINT_PREFIX = `[${DEVICE_NAME}:`; export const PRISM_ENDPOINT_PREFIX = `[${DEVICE_NAME}:`;
export const PROTON_IMAP_USERNAME = Bun.env.PROTON_IMAP_USERNAME; export const PROTON_IMAP_USERNAME = Bun.env.PROTON_IMAP_USERNAME;
export const PROTON_IMAP_PASSWORD = Bun.env.PROTON_IMAP_PASSWORD; export const PROTON_IMAP_PASSWORD = Bun.env.PROTON_IMAP_PASSWORD;
export const PROTON_BRIDGE_HOST = Bun.env.PROTON_BRIDGE_HOST || 'protonmail-bridge'; export const PROTON_BRIDGE_HOST = Bun.env.PROTON_BRIDGE_HOST || 'protonmail-bridge';
export const PROTON_BRIDGE_PORT = Number.parseInt(Bun.env.PROTON_BRIDGE_PORT || '143', 10); export const PROTON_BRIDGE_PORT = Number.parseInt(Bun.env.PROTON_BRIDGE_PORT || '143', 10);
export const PROTON_SUP_TOPIC = Bun.env.PROTON_SUP_TOPIC || 'Proton Mail'; export const PROTON_PRISM_TOPIC = Bun.env.PROTON_PRISM_TOPIC || 'Proton Mail';
export const IMAP_INBOX = 'INBOX'; export const IMAP_INBOX = 'INBOX';
export const IMAP_SEEN_FLAG = '\\Seen'; export const IMAP_SEEN_FLAG = '\\Seen';

View file

@ -7,7 +7,7 @@ export const SIGNAL_CLI_SOCKET = '/tmp/signal-cli.sock';
export const SIGNAL_CLI_DATA_DIR = `${HOME}/.local/share/signal-cli`; export const SIGNAL_CLI_DATA_DIR = `${HOME}/.local/share/signal-cli`;
export const SIGNAL_CLI_DATA = `${HOME}/.local/share/signal-cli/data`; export const SIGNAL_CLI_DATA = `${HOME}/.local/share/signal-cli/data`;
export const SUP_DB = `${HOME}/.local/share/sup/store.db`; export const PRISM_DB = `${HOME}/.local/share/prism/store.db`;
const PUBLIC_DIR_LOCAL = `${import.meta.dir}/../public`; const PUBLIC_DIR_LOCAL = `${import.meta.dir}/../public`;
export const PUBLIC_DIR = (await Bun.file(`${PUBLIC_DIR_LOCAL}/favicon.webp`).exists()) export const PUBLIC_DIR = (await Bun.file(`${PUBLIC_DIR_LOCAL}/favicon.webp`).exists())

View file

@ -94,7 +94,7 @@ const server = Bun.serve({
idleTimeout: 30, idleTimeout: 30,
}); });
logInfo(`\nSUP running on:`); logInfo(`\nPRISM running on:`);
logInfo(` Local: http://localhost:${server.port}`); logInfo(` Local: http://localhost:${server.port}`);
const lanIP = getLanIP(); const lanIP = getLanIP();

View file

@ -10,7 +10,7 @@ import {
PROTON_BRIDGE_PORT, PROTON_BRIDGE_PORT,
PROTON_IMAP_PASSWORD, PROTON_IMAP_PASSWORD,
PROTON_IMAP_USERNAME, PROTON_IMAP_USERNAME,
PROTON_SUP_TOPIC, PROTON_PRISM_TOPIC,
} from '@/constants/config'; } from '@/constants/config';
import { sendNotification as sendChannelNotification } from '@/modules/notifications'; import { sendNotification as sendChannelNotification } from '@/modules/notifications';
import { logError, logInfo, logSuccess, logVerbose, logWarn } from '@/utils/log'; import { logError, logInfo, logSuccess, logVerbose, logWarn } from '@/utils/log';
@ -124,7 +124,7 @@ export async function startProtonMonitor() {
const uid = await uidPromise; const uid = await uidPromise;
await sendChannelNotification(`${ENDPOINT_PREFIX_PROTON}${PROTON_SUP_TOPIC}`, { await sendChannelNotification(`${ENDPOINT_PREFIX_PROTON}${PROTON_PRISM_TOPIC}`, {
title: from, title: from,
message: subject, message: subject,
actions: [ actions: [

View file

@ -1,5 +1,7 @@
import { Database } from 'bun:sqlite'; import { Database } from 'bun:sqlite';
import { SUP_DB } from '@/constants/paths'; import { mkdirSync } from 'node:fs';
import { dirname } from 'node:path';
import { PRISM_DB } from '@/constants/paths';
import type { NotificationChannel } from '@/types/notifications'; import type { NotificationChannel } from '@/types/notifications';
type EndpointMapping = { type EndpointMapping = {
@ -10,7 +12,8 @@ type EndpointMapping = {
upEndpoint: string | null; upEndpoint: string | null;
}; };
const db = new Database(SUP_DB); mkdirSync(dirname(PRISM_DB), { recursive: true });
const db = new Database(PRISM_DB);
db.run(` db.run(`
CREATE TABLE IF NOT EXISTS mappings ( CREATE TABLE IF NOT EXISTS mappings (

Binary file not shown.

Before

Width:  |  Height:  |  Size: 950 B

After

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

View file

@ -2,7 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>SUP Admin</title> <title>PRISM Admin</title>
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#8159b8"> <meta name="theme-color" content="#8159b8">
<link rel="icon" type="image/webp" href="/favicon.webp"> <link rel="icon" type="image/webp" href="/favicon.webp">

View file

@ -1,6 +1,6 @@
{ {
"name": "SUP Admin", "name": "PRISM Admin",
"short_name": "SUP", "short_name": "PRISM",
"description": "Notification gateway admin panel", "description": "Notification gateway admin panel",
"start_url": "/", "start_url": "/",
"display": "standalone", "display": "standalone",

View file

@ -26,7 +26,7 @@ admin.use(
'*', '*',
basicAuth({ basicAuth({
verifyUser: (_, password, c) => verifyApiKey(password, c), verifyUser: (_, password, c) => verifyApiKey(password, c),
realm: 'SUP Admin - Username: any, Password: API_KEY', realm: 'PRISM Admin - Username: any, Password: API_KEY',
}), }),
); );

View file

@ -10,7 +10,7 @@ ntfy.use(
'*', '*',
basicAuth({ basicAuth({
verifyUser: (_, password) => verifyApiKey(password), verifyUser: (_, password) => verifyApiKey(password),
realm: 'SUP ntfy - Username: any, Password: API_KEY', realm: 'PRISM ntfy - Username: any, Password: API_KEY',
}), }),
); );

View file

@ -10,7 +10,7 @@ protonMail.use(
'*', '*',
basicAuth({ basicAuth({
verifyUser: (_, password, c) => verifyApiKey(password, c), verifyUser: (_, password, c) => verifyApiKey(password, c),
realm: 'SUP Proton Mail - Username: any, Password: API_KEY', realm: 'PRISM Proton Mail - Username: any, Password: API_KEY',
}), }),
); );

View file

@ -11,7 +11,7 @@ webhook.use(
'*', '*',
basicAuth({ basicAuth({
verifyUser: (_, password) => verifyApiKey(password), verifyUser: (_, password) => verifyApiKey(password),
realm: 'SUP Webhook - Username: any, Password: API_KEY', realm: 'PRISM Webhook - Username: any, Password: API_KEY',
}), }),
); );