Files
hub/README.md
T
nmemmertandClaude Sonnet 5.5 7823bbcb03
build-container / build (push) Successful in 6m58s
Webmail is now Cypht (several accounts in one place) instead of Roundcube
- cypht/: official Cypht 2.13.0 on a SQLite file, served under /webmail/; workflow builds git.necloud.us/nate/hub-cypht
- the hub passes /webmail/ through behind the passkey sign-in and signs in to Cypht for you (CYPHT_PASSWORD)
- provider sign-in pages (Google, Microsoft) open in the whole window and return to the Mail tab; other links open in a new tab
- Gmail / Outlook.com / Office365 OAuth settings (Microsoft permissions patched to the current ones)
- Roundcube removed; README, compose and webmail tests updated

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-21 09:28:50 -04:00

98 lines
10 KiB
Markdown

# NE Hub
One installable web app (PWA) for Seafile, OnlyOffice and your four webmail accounts.
Mobile-first; bottom tabs on phones, side rail on iPad and desktop (tuned for 12.9" at 1024 and 1366 wide). On a tablet or computer the menu collapses to icons (button at the bottom of the rail) or hides completely (the menu button at the top, or Ctrl/Cmd+B); the choice is remembered on that device.
## Configure
cp .env.example .env # set ONLYOFFICE_JWT_SECRET (same value as the Document Server) and PUBLIC_URL
`PUBLIC_URL` must be an address the OnlyOffice server can reach (not localhost): it posts saved edits back there.
## Run
docker compose up -d --build # http://localhost:8080
# or: node server.js
Put it behind your reverse proxy with HTTPS (needed for "Add to Home Screen" and the service worker),
e.g. hub.necloud.us. Settings: `SEAFILE_URL`, `ONLYOFFICE_URL` env vars in docker-compose.yml.
## What each part does
- **Files**: signs in with your Seafile account, browses libraries, uploads, creates folders, downloads, deletes.
The server proxies `/sf/*` to Seafile because Seafile sends no CORS headers. Token lives in the browser only.
Office files open in Seafile's own OnlyOffice integration.
- **Edit here**: opens docs inside the app via OnlyOffice. The server signs each editor config with the JWT secret and saves edits back to Seafile.
- **Sign-in**: the whole app sits behind a passkey (WebAuthn). First run: open the site and enter the setup code (`HUB_SETUP_CODE`, or the one printed in the server log) to create a passkey; add more devices from Settings. Passkeys and the session secret live in `/data` (a Docker volume).
- **People**: you (the admin) add people in Settings -> People, choose which tabs each may use (Files, Office, Music, Audiobooks, Podcast, Podcast Admin, Mail,
Calendar, Tasks, Search; Home and Settings are always on), and give them a one-time invite code to create their own passkey. Everyone's tasks, NE Hub events,
settings, iCloud connection, calendar links and Plex sign-in are private to them (`/data/users/<id>/`). Limits are enforced by the server, not just hidden.
You can change a person's tabs, sign them out everywhere, turn them off, or delete them and their data. An existing single-user install becomes the admin
automatically on first start (the original files are left in place as a backup).
- **Files**: a Finder/Explorer-style browser. Tap **Select** (or long-press on a phone, Cmd/Ctrl-click or Shift-click on a computer) to pick several items and
Move, Copy (to any folder in any library, with a New folder button in the picker) or Delete them together. Rename checks for clashes, sort by name/date/size/kind
(folders stay on top), filter a folder, right-click for the item menu, and keys: Ctrl/Cmd-A, Delete, F2, Enter, Esc. **Drag files or whole folders from your computer
onto the page** (or onto a folder in the list) to upload; uploads show progress, retry on a bad connection, and can be cancelled. **Drag items onto a folder or a
breadcrumb** to move them (hold Alt/Option to copy). **Drag a single file out to your desktop** to download it (Chrome and Edge only; browsers cannot drag out folders
or several files). Also share links, image/PDF/video/audio preview, and New document/spreadsheet/presentation.
- **Calendar**: month grid and agenda. Add, edit and delete events:
- **NE Hub calendar**: events you create are stored in `/data/events.json` and published as a private subscribe link
(Manage calendars -> copy link) so Outlook, Google or Apple Calendar can show them (read-only there).
- **iCloud (two-way)**: connect with an Apple ID and an *app-specific password* (appleid.apple.com). Credentials are
encrypted in `/data/icloud.json`; only `*.icloud.com` is contacted. Edits keep alarms and attendees intact.
- **ICS links** (Google secret address, Outlook/M365 published calendar) are read-only.
- **Tasks**: to-do lists stored in NE Hub (`/data/tasks.json`), with due dates, notes and completion. If the connected iCloud
account exposes reminder lists over CalDAV they appear too and sync both ways. Apple hides Reminders lists that were upgraded
for iOS 13+, so for most accounts only NE Hub lists are available.
- **Settings sync**: your preferences (mail addresses, audiobooks sign-in (encrypted), Plex library, Office save location, calendar/task views, recent files) are saved on the server in `/data/settings.json` and shared by every device. The Seafile sign-in token is saved there too (encrypted), so Settings shows Seafile as signed in on every device. Only the music queue stays in the browser.
- **Search**: libraries, file names (scans libraries if Seafile has no search index) and Plex artists/albums/tracks.
- **Music**: Plex player. Sign in goes through plex.tv (no password handled), the server proxies your Plex server and adds the token itself, and a mini player keeps playing as you move between tabs; the current and next two tracks are downloaded in full so changing songs is instant and a slow or lost connection does not stop playback; the queue (play next / add to queue) and position are remembered.
- **Audiobooks**: embeds audiobooks.necloud.us in a frame that keeps playing while you use other tabs, with reload, full screen and open-in-new-tab buttons.
Back-door sign-in: set `AUDIOBOOKS_LOGIN_LINK` to the site's secret link (the key is part of it). The frame loads `/api/audiobooks/enter`, which checks
the person may use the Audiobooks tab and redirects to that link, so the key stays in the server's environment and never appears in the app's page,
script or logs. Anyone holding the link is signed in there with full access, so keep it out of the repo and `.env` backups. Or set `AUDIOBOOKS_SSO_SECRET`
(and optionally `AUDIOBOOKS_SSO_URL`, default `<AUDIOBOOKS_URL>/sso`) for short-lived signed links: `?token=<body>.<sig>`, where `body` is base64url JSON
`{u, id, exp, n}` and `sig` is the base64url HMAC-SHA256 of `body`. Without either, the plain site opens and the saved username can be copied.
- **Podcast** and **Podcast Admin**: launchers that open `PODCAST_URL` (a home-network address) and `VERSE_URL` in their own tabs.
- **Office**: embeds onlyoffice.necloud.us in a frame, with an "open in new tab" fallback if it blocks framing.
- **Mail**: Cypht comes with the project (a second container in `docker-compose.yml`), so the Mail tab is a full webmail inside the app, built for **several
accounts at once** (iCloud, Gmail, Outlook.com, Office365, Yahoo, Fastmail and others are presets, plus any IMAP server) with combined views of them all.
The hub passes `/webmail/` through to it, so it is not exposed to the internet, sits behind your passkey sign-in and shares the hub's address (which is what
lets it be framed). Set `CYPHT_PASSWORD` (any password you choose; required) in `.env` or your stack; the hub uses it to sign in to Cypht for you, so you
never see a second login. Then, once, in the Mail tab: **Add an E-mail Account**, pick the provider, and follow the steps (iCloud, Yahoo and most others: your
address and an **app password**, e.g. appleid.apple.com -> App-Specific Passwords; Gmail needs 2-step verification, then Google account -> App passwords).
Everything is kept in the `nehub-cypht` volume. Everyone who has the Mail tab shares this one Cypht account; for separate mailboxes give only the people who
should share it the tab, or run `docker exec <cypht container> php /usr/local/share/cypht/scripts/create_account.php <name> <password>` and sign in as that person in Cypht
(the automatic sign-in is then skipped by logging out of Cypht once). The envelope button in the Mail toolbar still opens the Gmail / Outlook.com / Microsoft 365 /
iCloud web shortcuts, and Settings -> Mail apps chooses which of those cards show.
**Sign in with Google or Microsoft instead of app passwords** (optional): create an OAuth app and put its ID and secret in the environment of the `cypht` service
(`GMAIL_CLIENT_ID` / `GMAIL_CLIENT_SECRET` from console.cloud.google.com, with `<your hub address>/webmail/?page=home` as the authorized redirect URI;
`OUTLOOK_CLIENT_ID` / `OUTLOOK_CLIENT_SECRET` for a personal Outlook.com account and `OFFICE365_CLIENT_ID` / `OFFICE365_CLIENT_SECRET` plus `M365_TENANT` for a work
or school account, from a Microsoft Entra app registration with the same redirect URI and the delegated permissions `IMAP.AccessAsUser.All`, `SMTP.Send`, `offline_access`).
Set `PUBLIC_URL` (your hub address) so the redirect address is right. The provider's sign-in page cannot be shown inside a frame, so that step opens in the whole
window and returns you to the Mail tab. The Gmail and Microsoft sign-ins have not been tried against the real providers; the Microsoft ones use a patched permission
list because Cypht's own preset asks for a retired one. To use a webmail you run elsewhere instead, set `WEBMAIL_URL` (it must allow being framed:
no `X-Frame-Options`, and `Content-Security-Policy: frame-ancestors https://<your hub address>`). With neither, Mail is just the shortcut cards.
## Install on iPhone / iPad (PWA)
Open the site in **Safari** (it must be the `https://` address), tap **Share -> Add to Home Screen**. The home-screen app has proper
icons (iPhone, iPad), a splash screen for each iPhone and iPad size (including iPad Pro 12.9"), and opens full screen without Safari's bars.
iOS keeps a separate sign-in for the home-screen app, so sign in once inside it with your passkey; it then stays signed in
(`SESSION_DAYS`, default 180, renewed whenever you use it). Regenerate the artwork with `python3 tools/make-icons.py` (needs Pillow).
## Build and deploy with Gitea
`.gitea/workflows/build.yml` builds the container on every push to `main` (and `v*` tags) and pushes it to
`git.necloud.us/nate/hub` (tags: `latest`, short commit sha, git tag), and the webmail container from `cypht/` (the official Cypht plus the hub's settings) to
`git.necloud.us/nate/hub-cypht`. amd64 (x86) only.
One-time setup in Gitea: create an access token with the **write:package** scope, then add it to the repo under
Settings -> Actions -> Secrets as `REGISTRY_TOKEN` (optionally `REGISTRY_USER`). The runner needs Docker.
On the server:
cp .env.example .env # fill in secrets, PUBLIC_URL, CYPHT_PASSWORD (choose one), etc.
docker compose pull && docker compose up -d
docker compose logs hub | grep "Setup code" # first sign-in: create your passkey