build-container / build (push) Successful in 7m4s
- Music: a card with art, seek bar and controls above the albums, artists and playlists - Signal: chime, optional desktop notification when the app is in the background, (n) in the tab title, app badge; Settings -> Signal alerts (per device) - README, player test stand-in updated Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
109 lines
12 KiB
Markdown
109 lines
12 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 Music tab shows a Now Playing card with the controls above the albums, artists and playlists; 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.
|
|
- **Signal**: your Signal chats inside the app, **on desktop-class screens only** (a window at least 900 px wide with a mouse or trackpad; phones and touch tablets don't
|
|
see it). Besides the Signal tab there is a chat button on **every** screen that opens a panel over whatever you are doing (close it with the x; the
|
|
expand button opens the full page). New messages get your attention with a toast, a chime, the unread count in the browser tab title and on the installed app's icon, and
|
|
(if you switch it on in Settings -> Signal alerts) a desktop notification when the app is in the background; sound and notifications are saved per device. It talks to your account through the community `signal-cli-rest-api` bridge, which is one more *linked device* of your account
|
|
(like Signal Desktop; not an official Signal product). The `signal` container in `docker-compose.yml` runs it; remove that service and the hub's `SIGNAL_API_URL` line to skip Signal.
|
|
First time: open the Signal tab, then on your phone Signal -> Settings -> Linked devices -> Link new device and scan the code. You can send and receive text, photos,
|
|
files, voice messages (played, not recorded), replies, reactions, groups and read receipts; there are no calls. Only messages from after linking appear (Signal does
|
|
not copy older ones to a new device) and they are kept in `/data/signal`. The link keys live in the `nehub-signal` volume (a Docker *volume*, not a host folder: the bridge runs as user 1000 and a root-owned host folder gives "permission denied"; if you do want a folder, `chown -R 1000:1000` it first): whoever gets into your server can read your chats,
|
|
so only give the **Signal** tab to people you would trust with your Signal (it is one shared account, admins always have it). Signal drops a linked device that is
|
|
not connected for about a month; the hub stays connected, so this only matters if the stack is switched off.
|
|
- **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 can open a full webmail inside the app (the shortcut cards are the default page; the **Open webmail** button there opens it, and the envelope button in
|
|
the webmail goes back), 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 default Mail page is 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
|