mirror of
https://github.com/lone-cloud/prism
synced 2026-06-03 08:43:10 -07:00
rename to prism
This commit is contained in:
parent
8d25ab7bf2
commit
1360dae681
27 changed files with 65 additions and 1646 deletions
|
|
@ -14,8 +14,8 @@
|
|||
# RATE_LIMIT=100
|
||||
|
||||
# Optional: Device name shown in Signal app's linked devices list
|
||||
# Default: SUP
|
||||
# DEVICE_NAME=What SUP
|
||||
# Default: PRISM
|
||||
# DEVICE_NAME=What PRISM
|
||||
|
||||
# Optional: Enable verbose logging
|
||||
# Default: false
|
||||
|
|
@ -32,4 +32,4 @@
|
|||
# PROTON_IMAP_PASSWORD=bridge-generated-password
|
||||
# PROTON_BRIDGE_HOST=protonmail-bridge
|
||||
# PROTON_BRIDGE_PORT=143
|
||||
# PROTON_SUP_TOPIC=Proton Mail
|
||||
# PROTON_PRISM_TOPIC=Proton Mail
|
||||
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
|
|
@ -7,7 +7,7 @@ on:
|
|||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository_owner }}/sup
|
||||
IMAGE_NAME: ${{ github.repository_owner }}/prism
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
|
|
|||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,4 +1,4 @@
|
|||
node_modules/
|
||||
signal-cli
|
||||
.env
|
||||
sup
|
||||
prism
|
||||
|
|
|
|||
48
README.md
48
README.md
|
|
@ -1,8 +1,8 @@
|
|||
<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**
|
||||
|
||||
|
|
@ -12,18 +12,18 @@
|
|||
|
||||
<!-- 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?
|
||||
|
||||
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
|
||||
- **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.
|
||||
|
||||
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
|
||||
|
||||
|
|
@ -39,7 +39,7 @@ To receive Proton Mail notifications via Signal:
|
|||
|
||||
```bash
|
||||
# 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
|
||||
```
|
||||
|
|
@ -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.
|
||||
|
||||
### 2. Install SUP Server
|
||||
### 2. Install PRISM Server
|
||||
|
||||
```bash
|
||||
# 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)
|
||||
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
|
||||
nano .env
|
||||
|
||||
# Start SUP server
|
||||
# Start PRISM server
|
||||
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)
|
||||
curl -fsSL https://bun.sh/install | bash
|
||||
|
||||
git clone https://github.com/lone-cloud/sup.git
|
||||
cd sup
|
||||
git clone https://github.com/lone-cloud/prism.git
|
||||
cd prism
|
||||
|
||||
bun install
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
|
|
@ -160,26 +160,26 @@ Add a rest notification configuration (eg. add to configuration.yaml) to Home As
|
|||
```bash
|
||||
notify:
|
||||
- platform: rest
|
||||
name: SUP
|
||||
resource: "http://<Your SUP server network IP>/Home Assistant"
|
||||
name: PRISM
|
||||
resource: "http://<Your PRISM server network IP>/Home Assistant"
|
||||
method: POST
|
||||
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.
|
||||
|
||||
```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
|
||||
|
||||
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:
|
||||
|
||||
|
|
@ -189,11 +189,9 @@ For API-based monitoring, call `/api/health` which returns JSON:
|
|||
|
||||
## Architecture
|
||||
|
||||

|
||||
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**:
|
||||
|
||||
- **sup** (Bun): Receives webhooks, sends Signal messages via signal-cli. Optional: monitors Proton Mail IMAP
|
||||
- **prism** (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
|
||||
|
||||
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
BIN
assets/prism.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
BIN
assets/sup.webp
BIN
assets/sup.webp
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB |
2
bun.lock
2
bun.lock
|
|
@ -3,7 +3,7 @@
|
|||
"configVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "sup",
|
||||
"name": "prism",
|
||||
"dependencies": {
|
||||
"chalk": "5.6.2",
|
||||
"hono": "4.11.7",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
services:
|
||||
server:
|
||||
container_name: sup-server
|
||||
container_name: prism-server
|
||||
build:
|
||||
context: .
|
||||
dockerfile: server/Dockerfile
|
||||
|
|
@ -15,10 +15,10 @@ services:
|
|||
- PROTON_IMAP_PASSWORD=${PROTON_IMAP_PASSWORD:-}
|
||||
- PROTON_BRIDGE_HOST=protonmail-bridge
|
||||
- PROTON_BRIDGE_PORT=${PROTON_BRIDGE_PORT:-143}
|
||||
- PROTON_SUP_TOPIC=${PROTON_SUP_TOPIC:-Proton Mail}
|
||||
- PROTON_PRISM_TOPIC=${PROTON_PRISM_TOPIC:-Proton Mail}
|
||||
volumes:
|
||||
- signal-data:/root/.local/share/signal-cli
|
||||
- sup-data:/root/.local/share/sup
|
||||
- prism-data:/root/.local/share/prism
|
||||
restart: unless-stopped
|
||||
|
||||
protonmail-bridge:
|
||||
|
|
@ -34,5 +34,5 @@ services:
|
|||
|
||||
volumes:
|
||||
signal-data:
|
||||
sup-data:
|
||||
prism-data:
|
||||
proton-bridge-data:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
services:
|
||||
server:
|
||||
container_name: sup-server
|
||||
image: ghcr.io/lone-cloud/sup:latest
|
||||
container_name: prism-server
|
||||
image: ghcr.io/lone-cloud/prism:latest
|
||||
ports:
|
||||
- '8080:8080'
|
||||
environment:
|
||||
|
|
@ -14,10 +14,10 @@ services:
|
|||
- PROTON_IMAP_PASSWORD=${PROTON_IMAP_PASSWORD:-}
|
||||
- PROTON_BRIDGE_HOST=protonmail-bridge
|
||||
- PROTON_BRIDGE_PORT=${PROTON_BRIDGE_PORT:-143}
|
||||
- PROTON_SUP_TOPIC=${PROTON_SUP_TOPIC:-Proton Mail}
|
||||
- PROTON_PRISM_TOPIC=${PROTON_PRISM_TOPIC:-Proton Mail}
|
||||
volumes:
|
||||
- signal-data:/root/.local/share/signal-cli
|
||||
- sup-data:/root/.local/share/sup
|
||||
- prism-data:/root/.local/share/prism
|
||||
restart: unless-stopped
|
||||
|
||||
protonmail-bridge:
|
||||
|
|
@ -31,5 +31,5 @@ services:
|
|||
|
||||
volumes:
|
||||
signal-data:
|
||||
sup-data:
|
||||
prism-data:
|
||||
proton-bridge-data:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "sup",
|
||||
"name": "prism",
|
||||
"version": "0.2.0",
|
||||
"description": "Privacy-preserving push notifications using Signal as transport",
|
||||
"private": true,
|
||||
|
|
@ -11,12 +11,12 @@
|
|||
"license": "AGPL-3.0-or-later",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/lone-cloud/sup"
|
||||
"url": "https://github.com/lone-cloud/prism"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "bun run scripts/install-signal-cli.ts || true",
|
||||
"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 .",
|
||||
"fix": "biome check --write --unsafe .",
|
||||
"release": "bun run scripts/release.ts"
|
||||
|
|
|
|||
|
|
@ -26,14 +26,14 @@ try {
|
|||
|
||||
Pull the latest version:
|
||||
\`\`\`bash
|
||||
docker pull ghcr.io/lone-cloud/sup:${version}
|
||||
docker pull ghcr.io/lone-cloud/prism:${version}
|
||||
\`\`\`" --generate-notes`;
|
||||
|
||||
console.log(`
|
||||
✨ Release ${version} complete!
|
||||
|
||||
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) {
|
||||
console.error('Release failed:', error);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ RUN bun install --frozen-lockfile
|
|||
|
||||
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
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ RUN ARCH=$(uname -m) && \
|
|||
rm /tmp/libsignal_jni_aarch64.so; \
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
CMD ["sup"]
|
||||
CMD ["prism"]
|
||||
|
|
|
|||
|
|
@ -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 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_PASSWORD = Bun.env.PROTON_IMAP_PASSWORD;
|
||||
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_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_SEEN_FLAG = '\\Seen';
|
||||
|
|
|
|||
|
|
@ -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 = `${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`;
|
||||
export const PUBLIC_DIR = (await Bun.file(`${PUBLIC_DIR_LOCAL}/favicon.webp`).exists())
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ const server = Bun.serve({
|
|||
idleTimeout: 30,
|
||||
});
|
||||
|
||||
logInfo(`\nSUP running on:`);
|
||||
logInfo(`\nPRISM running on:`);
|
||||
logInfo(` Local: http://localhost:${server.port}`);
|
||||
|
||||
const lanIP = getLanIP();
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {
|
|||
PROTON_BRIDGE_PORT,
|
||||
PROTON_IMAP_PASSWORD,
|
||||
PROTON_IMAP_USERNAME,
|
||||
PROTON_SUP_TOPIC,
|
||||
PROTON_PRISM_TOPIC,
|
||||
} from '@/constants/config';
|
||||
import { sendNotification as sendChannelNotification } from '@/modules/notifications';
|
||||
import { logError, logInfo, logSuccess, logVerbose, logWarn } from '@/utils/log';
|
||||
|
|
@ -124,7 +124,7 @@ export async function startProtonMonitor() {
|
|||
|
||||
const uid = await uidPromise;
|
||||
|
||||
await sendChannelNotification(`${ENDPOINT_PREFIX_PROTON}${PROTON_SUP_TOPIC}`, {
|
||||
await sendChannelNotification(`${ENDPOINT_PREFIX_PROTON}${PROTON_PRISM_TOPIC}`, {
|
||||
title: from,
|
||||
message: subject,
|
||||
actions: [
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
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';
|
||||
|
||||
type EndpointMapping = {
|
||||
|
|
@ -10,7 +12,8 @@ type EndpointMapping = {
|
|||
upEndpoint: string | null;
|
||||
};
|
||||
|
||||
const db = new Database(SUP_DB);
|
||||
mkdirSync(dirname(PRISM_DB), { recursive: true });
|
||||
const db = new Database(PRISM_DB);
|
||||
|
||||
db.run(`
|
||||
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 |
|
|
@ -2,7 +2,7 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>SUP Admin</title>
|
||||
<title>PRISM Admin</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#8159b8">
|
||||
<link rel="icon" type="image/webp" href="/favicon.webp">
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "SUP Admin",
|
||||
"short_name": "SUP",
|
||||
"name": "PRISM Admin",
|
||||
"short_name": "PRISM",
|
||||
"description": "Notification gateway admin panel",
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ admin.use(
|
|||
'*',
|
||||
basicAuth({
|
||||
verifyUser: (_, password, c) => verifyApiKey(password, c),
|
||||
realm: 'SUP Admin - Username: any, Password: API_KEY',
|
||||
realm: 'PRISM Admin - Username: any, Password: API_KEY',
|
||||
}),
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ ntfy.use(
|
|||
'*',
|
||||
basicAuth({
|
||||
verifyUser: (_, password) => verifyApiKey(password),
|
||||
realm: 'SUP ntfy - Username: any, Password: API_KEY',
|
||||
realm: 'PRISM ntfy - Username: any, Password: API_KEY',
|
||||
}),
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ protonMail.use(
|
|||
'*',
|
||||
basicAuth({
|
||||
verifyUser: (_, password, c) => verifyApiKey(password, c),
|
||||
realm: 'SUP Proton Mail - Username: any, Password: API_KEY',
|
||||
realm: 'PRISM Proton Mail - Username: any, Password: API_KEY',
|
||||
}),
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ webhook.use(
|
|||
'*',
|
||||
basicAuth({
|
||||
verifyUser: (_, password) => verifyApiKey(password),
|
||||
realm: 'SUP Webhook - Username: any, Password: API_KEY',
|
||||
realm: 'PRISM Webhook - Username: any, Password: API_KEY',
|
||||
}),
|
||||
);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue