Apps for ShareOS, the alternative NAS firmware for the D-Link DNS-320L, DNS-320 and DNS-325. ShareOS shows them under APPS → Store and installs them with one click – the same way it offers firmware updates.
Deutsch weiter unten.
This repository takes web apps only (HTML/CSS/JS that run in the browser and use the app SDK). System apps – native programs and services (daemons) for the box – are submitted to the ShareOS repository, folder
sysapps/, which has an example of each kind. See System apps and services.
38 web apps. Most save their data in the personal folder of the signed-in
account on the box (permission files, ShareOS.fs) and fall back to the
browser's storage without it.
Files and office
| App | What it does |
|---|---|
| Webpad | Text editor in the style of Notepad++; opens and saves files on the box or on your computer, takes files from other apps |
| ShareCommander | Two-pane file manager in the style of Total Commander for the folders of the box and the browser file system (shared with WebTerm): ZIP, multi-rename, preview, bridges to Webpad and WinWeb Player |
| SheetOS | Small spreadsheet with formulas; opens and saves CSV files of the box |
| ShareNotes | Sticky notes in colour with an edit dialog and search; every note is a file in your personal folder on the box |
| TaskBoard | Kanban board for tasks; columns stack on phones |
| DailyLog | Diary and bullet journal with a calendar |
| BoxScan | Document scanner and receipt archive with the phone camera and image filters |
| TinyPDF | PDF viewer (pdf.js) with a drawn signature placed on the page and saved as a new PDF |
| ExpenseTracker | Expenses and budget on the go, CSV export |
Media
| App | What it does |
|---|---|
| WinWeb Player | Audio and video player in retro style with equalizer and visualizer; plays music and videos from your area on the box (streamed, with seeking) or from your computer |
| MediaTranscoder | Converts media on the box with FFmpeg (system app ffmpeg): audio to MP3/M4A/Opus/FLAC/WAV, videos into another container without re-encoding, cut out parts; jobs run in the background |
| BeatBox Studio | 16-step drum sequencer with synthesizer; projects (.beatbox) and WAV loops on the box, sends loops to WinWeb Player |
| PhotoDrop | Upload photos from the phone straight to the box, with a gallery |
| ShareAudio | Voice memos and audio recordings saved on the box |
Network and system
| App | What it does |
|---|---|
| Transmission | BitTorrent client by @SamuelSilvaG: every user has their own Transmission service (system app transmission-daemon), downloads into their folders |
| NetTunnel | VPN for the box (OpenVPN, system app openvpn): as client import profiles and connect; as server reach home from anywhere with a ready-made profile per device; admins only, shown inside ShareOS |
| Tailscale | WireGuard-based mesh VPN client by @SamuelSilvaG: secure zero-config remote access to your box, files (SMB) and web apps from anywhere – connects the box through the ShareOS system app tailscaled (admins, ShareOS 0.2.0-beta.8+) |
| autobrr | Download automation for IRC announces and RSS feeds by @SamuelSilvaG: filters releases in real time and sends torrents to Transmission (admins, ShareOS 0.2.0-beta.9+) |
| SpeedCheck | Latency, jitter and transfer rate between your device and the box (at home, over VPN), with a log |
| HomePing | Reachability of your homelab, checked from the box: ping, port or web address, automatically, with a history per host (admins, permission netcheck) |
| SysMon | System monitor and task manager of the box: CPU, memory, temperature, fan, drives and every process live; end processes (admins, permission sysinfo) |
| DockerDeck | Docker containers of your servers through their Docker API: state, stacks, ports, start/stop/restart, log with CPU and memory (admins, permission docker) |
| TuyaPulse | Local Tuya smart-home devices without the cloud: find them, switch them, power readings (protocol 3.3/3.4; admins, permission tuya) |
Security
| App | What it does |
|---|---|
| ShareVault | Password and 2FA (TOTP) manager, encrypted with AES-GCM in the browser; categories with examples and your own |
| KeyKeeper | SSH keys, API tokens and SSL certificates of your homelab, encrypted with a master password |
| PassphraseGen | Diceware passphrases with WebCrypto, with a history |
Development
| App | What it does |
|---|---|
| WebTerm | Terminal with tabs, a virtual file system, a JavaScript sandbox and a bridge to Webpad; views log files of the box |
| DevBox | Developer toolbox: JSON, Base64/URL/hex, checksums (also of files of the box), regex, diff, JWT |
| API-Pilot | REST and GraphQL client in the style of Postman: headers, auth, JSON/GraphQL/form bodies, history, cURL/fetch code; saves responses on the box or opens them in Webpad |
| ShareSnippets | Code and text snippets: commands, configs, templates |
Everyday life
| App | What it does |
|---|---|
| ShareFeed | RSS and news reader with offline cache (uses the internet) |
| ShareStash | Bookmarks and read-later list in the style of Pocket / Raindrop |
| RecipeVault | Cookbook with portion scaler and shopping list |
| PackList | Packing lists for travel, camping and shopping with progress |
| HabitGrid | Habit tracker with monthly heatmap and streaks |
| PillClock | Medication schedule and vital signs (blood pressure, pulse, weight) |
| SmartBudget | Electricity, gas and energy costs from meter readings, with projections |
| VehicleLog | Mileage log, fuel and charging with consumption, CSV export |
| QuickUnit | Unit and currency converter, offline, with favourites |
apps/<id>/app.json manifest
apps/<id>/files/ the app: entry file (index.html), icon, assets
apps/<id>/CHANGELOG.md release notes per version (optional)
A push to main runs GitHub Actions:
- every manifest is checked (
tools/build.py --check), - each app is packed into
<id>-<version>.sapp(tar.gz, reproducible) with a.sha256, - a version that has no release yet becomes the release
<id>-v<version>(versions with a-, e.g.1.1.0-beta.1, are pre-releases = beta channel), - the catalog
index.jsonis rebuilt and attached to the releasecatalog.
ShareOS downloads only …/releases/download/catalog/index.json, checks the
SHA-256 of a package before installing it and serves web apps from their own
port (8081) – another origin than the admin interface, so an app cannot use the
admin login.
To release a new version: change the app, raise version in app.json, add a
section to CHANGELOG.md, push.
To withdraw an app from the store, move its folder out of apps/ (e.g. to
examples/): the catalog lists only apps that have a folder in apps/; its
releases stay on GitHub.
{
"id": "webpad", // a-z, 0-9, -; same as the folder name
"name": "Webpad",
"version": "1.0.0",
"publisher": "UniqueDroid",
"description": { "de": "…", "en": "…" },
"type": "webapp", // later also "native" (programs for the box)
"entry": "index.html", // in files/
"icon": "icon.svg", // in files/ (SVG or PNG)
"category": "tools", // tools, media, office, network, system …
"license": "GPL-2.0-only", // SPDX name; apps by UniqueDroid are GPL-2.0-only like ShareOS
"homepage": "https://…",
"min_shareos": "0.1.0", // also met by the betas of 0.1.0; name a beta if you need one ("0.1.0-beta.7")
"permissions": ["cron"], // see below; ShareOS refuses unknown ones
"requires": ["transmission-daemon"], // apps it needs: installed from the store first (ShareOS 0.2.0-beta.4+)
"jobs": [ // scheduled tasks, need "cron" (ShareOS 0.1.0-beta.7+)
{ "id": "cleanup", // a-z, 0-9, -; max. 24 characters
"name": "Clean up",
"command": "jobs/cleanup.sh", // in files/, run with /bin/sh
"schedule": "0 3 * * *", // cron time, at most every 5 minutes
"timeout": 300 } // seconds, 10 … 3600 (default 300)
],
"window": { "width": 1100, "height": 760 }, // own window of this size (ShareOS 0.1.0-beta.9+)
"opens": [ // file types it opens from the file browser (beta.9+)
{ "ext": [".txt", ".md"], // lower case, with dot
"mode": "edit", // "edit" may save back, "view" only reads
"label": { "de": "Bearbeiten", "en": "Edit" } }
]
}| Permission | What the app may do |
|---|---|
embed |
Be shown as a page inside the ShareOS interface instead of its own window – for apps that only have settings (ShareOS 0.1.0-beta.9+). |
torrent |
Control the signed-in user's own Transmission service through ShareOS.torrent.rpc(method, args) (needs files; ShareOS 0.2.0-beta.4+ with the system app transmission-daemon). Every user has their own service; folders are <root>/<path> like ShareOS.fs, and the box passes only what a remote control needs (no scripts, no other places). |
media |
Media jobs with FFmpeg on the box through ShareOS.media (needs files; ShareOS 0.2.0-beta.5+ with the system app ffmpeg). |
vpn |
The box as an OpenVPN client through ShareOS.vpn (list, status, log, importProfile, set, remove, connect, disconnect; needs files; ShareOS 0.2.0-beta.6+ with the system app openvpn). Admin accounts only – a VPN changes the network of the whole box. The box cleans every profile on import (no scripts, plugins, file references). |
tailscale |
Remote access with Tailscale through ShareOS.tailscale (status, up({authKey}), login, down, logout, ping(ip), log; without a key up answers with auth_url, the sign-in link; needs files; ShareOS 0.2.0-beta.7+, system app tailscaled since 0.2.0-beta.8). Admin accounts only – it changes the network of the whole box. |
autobrr |
The box's autobrr (download automation, system app autobrr) through ShareOS.autobrr (status, start, set({enabled, ui, account}), password, accounts, log, api(method, path, body) – autobrr's REST API with the key of ShareOS; needs files; ShareOS 0.2.0-beta.9+). One autobrr for the whole box, admin accounts only. Found torrents go to the Transmission of the chosen account through autobrr's action Watch dir with the folder status().drop. |
sysinfo |
The box's values through ShareOS.sysinfo – info() (CPU from two samples, memory, temperature, fan, load, network, drives with use and standby), processes() (user, memory, CPU ticks, command line), kill(pid, signal) (never init, kernel threads or what keeps ShareOS running); needs files; ShareOS 0.2.0-beta.11+. Admin accounts only. |
netcheck |
Checks from the box through ShareOS.netcheck.check([{kind: 'ping', host, count}, {kind: 'tcp', host, port}, {kind: 'http', url}]) – up to 32 side by side with short time limits; one result per check {ok, ms, error, …} (also .ping(), .tcp(), .http()); needs files; ShareOS 0.2.0-beta.11+. Admin accounts only. |
tuya |
Tuya smart-home devices on the home network without the cloud through ShareOS.tuya – discover(seconds) (their announcements on UDP 6666/6667: {ip, id, product, version}), status({ip, id, key, version}) (data points) and set(device, {"1": true}) over TCP 6668 with the device's local key, protocol 3.3 and 3.4; the app keeps devices and keys; needs files; ShareOS 0.2.0-beta.11+. Admin accounts only. |
docker |
Docker hosts of the homelab through their Docker Engine API (http://host:2375 / https://host:2376) via ShareOS.docker – hosts(), setHost(), removeHost(), version, info, images, containers, inspect, stats, logs (plain text), `action(host, id, 'start' |
status |
One short chip in the header of the ShareOS interface through ShareOS.status.set({ text, state, ttl }) / .clear() (needs files; ShareOS 0.2.0-beta.6+): max. 24 characters, state ok/warn/err/info, gone after ttl seconds (max. 600) unless set again; only the account that opened the app sees it. |
notify |
Messages through the box's notification service (System → Messages, e-mail, push). In a scheduled task: shareos-app-notify <info|warn|error> <key> <title> [text] and shareos-app-notify clear <key> – sent when the task has finished, at most 10 per run. In the browser: ShareOS.notify.send(level, key, title, text) / .clear(key) (needs files, admin accounts only). The same key is one message (counted, sent again after 24 h at most); key 1–32 characters A-Z a-z 0-9 . _ -, title ≤ 100 characters (the app's name is put in front), text ≤ 1000; at most 20 messages an hour per app. ShareOS 0.2.0-beta.12+. |
files |
Read, change and delete the files the signed-in user reaches in the file browser (his personal folder; admins: all volumes and USB drives), with his rights, while the app is open – through ShareOS.fs (ShareOS 0.1.0-beta.11+). For file managers and editors that save on the box. Accounts without "Dateien" get one private folder of the app instead (root app, private: true, ShareOS 0.2.0-beta.9+). Admins get their personal folder as the first root, marked home: true (root: home/root on the apps drive; ShareOS 0.2.0-beta.10+) – pick `roots.find(r => r.home) |
cron |
Run its jobs on a schedule (at most 5, at most every 5 minutes). Each job runs as the app's own user app-<id> (no login, no access to the users' files) in the app's data folder, with nice and the time limit; the output (max. 64 KB) appears under APPS → Tasks. The admin can change or switch off every schedule there; a changed schedule stays across updates. |
Environment of a job: APP_ID, APP_DIR (the installed files, read-only for
the job), APP_DATA = HOME = working directory (the only writable place).
The install dialog shows the permissions before the app is installed.
Note: job scripts live in files/ and can be fetched over the app web server
like any other file – keep secrets in APP_DATA, not in the script.
The apps web server serves two files for every app – same address, works offline:
<link rel="stylesheet" href="/_shareos/theme.css">
<script src="/_shareos/app.js"></script>
<body class="sos-app">
<div class="sos-titlebar">My app <span class="sos-title-file" id="file"></span></div>
<nav id="menu"></nav>
<main class="sos-main">…</main>
<div class="sos-statusbar"><span>Ready</span><span>UTF-8</span></div>
</body>- Look: CSS variables
--sos-bg,--sos-panel,--sos-bar,--sos-line,--sos-accent,--sos-text,--sos-muted… for light/dark and the user's accent colour (set on<html data-theme data-accent>; ShareOS passes the user's look in the URL and updates it live). Building blocks:.sos-titlebar,.sos-menubar,.sos-toolbar,.sos-statusbar,.sos-btn,.sos-input,.sos-dialog, styled scroll bars. - Menu bar like Notepad++:
ShareOS.menu(document.getElementById('menu'), [{ label: 'Datei', items: [{ label: 'Speichern', kbd: 'Ctrl+S', action: save }, '-', …] }, { label: 'Bearbeiten', items: […] }, { label: 'Ansicht', items: […] }])– mouse and keyboard, shortcuts included. - Opened file: when the user opens a file from the ShareOS file browser,
ShareOS.fileis set:await ShareOS.file.info()(name, mode),await ShareOS.file.text()/.blob(),await ShareOS.file.save(data)(modeeditonly),ShareOS.file.url(address of the content for<audio>/<video>; ShareOS 0.1.0-beta.11+; byte ranges for seeking). The app gets a ticket for exactly this file and the user's rights – nothing else on the box. - Messages between apps:
ShareOS.emit(type, data)/ShareOS.on(type, fn)(BroadcastChannelshareos,{type, data, from}; every app hears them, so no secrets). Used by the apps here:open-file{to, name, path, content, readonly}→file-saved{to, path, name, content}(Webpad),open-media{to, name, blob|url}(WinWeb Player),ping/pong/app-ready(is an app open?). The browser file system of WebTerm and ShareCommander is shared under the keyshareos.vfs. - Folders of the box (permission
files, ShareOS 0.1.0-beta.11+):ShareOS.fs.roots(),.list(root, path),.mkdir,.rename,.copy/.move(root, path, names, destRoot, dest),.remove,.open(root, path, name, {write, create})(a file likeShareOS.file). Exactly the folders the signed-in user reaches in the file browser, with his rights, while the app is open (ShareOS passes a grant in the URL when it opens the app). - File dialog of the box (ShareOS 0.2.0-beta.1+):
await ShareOS.fs.pick({ title, ext: ['.mp3'], multiple, save, name })shows the user's folders and returns[{root, path, name}](withsave: the chosen folder and file name) ornull; thenShareOS.fs.open(…). CheckShareOS.fs && ShareOS.fs.pickbefore showing the button. - Storage per account (ShareOS 0.2.0-beta.1+): all apps share one web origin, so ShareOS passes the account (
?user=) and the SDK keepslocalStorageand IndexedDB of the accounts apart (ShareOS.user). Load/_shareos/app.jsbefore the app's own scripts. This separates accounts in one browser but does not protect against someone with the browser's developer tools – private data belongs on the box (ShareOS.fs), where the box checks the user's rights. - Open another app (ShareOS 0.2.0-beta.2+):
ShareOS.openApp(id, {width, height})opens it in its own window (the one ShareOS uses for it) with look, language and account; returns the window ornull(pop-up blocked). ShareOS.onTheme(fn),ShareOS.embedded(true inside the ShareOS interface).- Colours: use the theme variables for every colour and do not define
--sos-*in your own:root(that overrides the user's look).tools/retheme.py <app>moves an existing dark design onto the theme. - Language:
ShareOS.langis the language of the interface. The apps here are written in German and translated bysos-i18n.js(a copy oflib/sos-i18n.js, loaded after/_shareos/app.js): it loadsi18n/<lang>.json(elsei18n/en.json) and translates every text node,placeholder/title/aria-label/alt, canvas text andalert/confirm/prompt– also what the app renders later;sosT(text)for anything else. Format:{"exact": {"German": "English"}, "patterns": [["^regex$", "with $1"]], "words": [["regex", "replacement"]]}.tools/i18n.py sync <app>adds the script,tools/i18n.py extract <app> <todo.json>lists the texts not translated yet,tools/i18n.py apply <app> <todo.json> <lines.txt>stores one translation per line;tools/i18n.py checkruns in CI.
Webpad loads the SDK first whenever ShareOS opened it (it passes ?user=), so it still works as a plain HTML file anywhere.
Rules for web apps: the app itself (HTML, scripts, styles, fonts, icons) is
inside files/ – no CDN for the app's own code, so it starts on a box without
internet. Apps may use the internet when they need it (online services,
streams, maps, sync …): then set "internet": true in app.json; the store
shows "uses the internet" (ShareOS 0.1.0-beta.12+, older versions ignore it).
No symbolic links, at most 40 MB.
Not here – in the ShareOS repository.
System apps ("type": "system") are native programs for the box – nano,
htop, strace, iperf3, FFmpeg – and services (daemons) such as Tailscale,
OpenVPN, Transmission or the media server. They need the firmware's
toolchain, so they are built in ShareOS (sysapps/<id>/) and attached to its
releases as .sapp. The catalog lists them too (every version once, from the
newest firmware release that has it; refreshed every 3 hours), so the store
installs them like any other app. tools/build.py refuses "type": "system".
sysapps/README.md
in ShareOS explains both kinds with an example each:
- a program (
tree): buildroot package +sysapps/<id>/(app.json,pack.json,icon.svg); - a service (
mosquitto): the same plus"service": { "control": … }inapp.jsonand the controller/usr/sbin/shareos-<control>in the firmware, which ShareOS uses to start the daemon at boot and stop it on removal (ShareOS 0.2.0-beta.9+). A package never starts a service by itself.
A web app that needs one names it in "requires": installing the app installs
the system app first, and the store warns before removing a system app an
installed app needs. A web app for a service (e.g. Tailscale, NetTunnel,
Transmission) talks to it only through the app SDK and a permission of
ShareOS (tailscale, vpn, torrent …) – not through its own ports or
interfaces on the box. Plan a new service? Open an issue or pull request
in ShareOS for the system app and its controller first; the web app comes
here once ShareOS has it. A web app whose service does not exist yet cannot be
installed (its "requires" is not in the store) and is not merged.
- Upload: APPS → Store → Install package takes a
.sappfile (tools/build.pybuilds one). It is marked as “own / not verified”. - Own catalog: fork this repository (or use the same layout), run the workflow, then add
https://github.com/<you>/<repo>/releases/download/catalog/index.jsonunder APPS → Sources.
Build locally: tools/build.py → dist/.
The apps by UniqueDroid are licensed under the GNU General Public License
version 2 (GPL-2.0-only), like ShareOS – see COPYING. Apps by
other publishers keep their own license, named in their app.json
(Transmission: GPL-2.0-or-later, Tailscale: BSD-3-Clause). Bundled third-party
code keeps its license too (e.g. CodeMirror and crypto-js in Webpad: MIT).
Apps für ShareOS. Sie erscheinen unter APPS → Store und werden mit einem Klick installiert – genauso wie Firmware-Updates angeboten werden.
- Jede App liegt in
apps/<id>/mitapp.json(Name, Version, Herausgeber, Beschreibung, Typ, Startdatei, Symbol) und dem Ordnerfiles/. - Ein Push auf
mainbaut die Pakete (.sapp+ SHA-256), legt für neue Versionen ein Release<id>-v<version>an (mit-in der Version = Beta) und erneuert den Katalogindex.jsonim Releasecatalog. - Neue Version: App ändern,
versioninapp.jsonerhöhen, Abschnitt inCHANGELOG.md, pushen. - Berechtigungen:
"permissions": ["cron"]erlaubt geplante Aufgaben (jobsinapp.json, Skript ausfiles/, Zeitplan im Cron-Format, höchstens alle 5 Minuten, max. 5). Sie laufen als eigener Benutzerapp-<id>nur im Datenordner der App; der Admin kann Zeitpläne unter APPS → Aufgaben ändern oder abschalten. Ab ShareOS 0.1.0-beta.7. - Fenster und Dateien (ab ShareOS 0.1.0-beta.9):
"window"legt die Fenstergröße fest,"opens"die Dateitypen, die die App aus dem Dateibrowser öffnet (editdarf zurückspeichern). Die Berechtigungembedzeigt eine reine Einstellungs-App direkt in ShareOS an. Mit der Berechtigungfiles(ab ShareOS 0.1.0-beta.11) arbeitet eine App mit den Ordnern der Box – mit den Rechten des angemeldeten Benutzers (ShareOS.fs). Für Aussehen, Menüleiste (Datei | Bearbeiten | Ansicht), geöffnete Datei und Nachrichten zwischen Apps gibt es/_shareos/theme.cssund/_shareos/app.js(siehe oben). Farben nur über die Theme-Variablen (kein eigenes--sos-*im:root, sonst überschreibt die App das Aussehen des Benutzers). Übersetzungen: die Apps sind deutsch geschrieben,sos-i18n.jsübersetzt sie miti18n/<sprache>.json(sonsti18n/en.json) in die Sprache der Oberfläche – Werkzeug:tools/i18n.py(siehe oben). - Speicher je Konto (ab ShareOS 0.2.0-beta.1): Das SDK trennt
localStorageund IndexedDB der Apps nach Konto – dafür/_shareos/app.jsvor den eigenen Skripten laden. Private Daten gehören auf die Box (ShareOS.fs, DateidialogShareOS.fs.pick). - Web-Apps bringen ihren eigenen Code mit (kein CDN für Skripte, Styles, Schriften), damit sie auch auf einer Box ohne Internet starten. Internet nutzen dürfen sie, wenn sie es brauchen (Online-Dienste, Streams, Karten, Sync …): dann
"internet": trueinapp.jsonsetzen – der Store zeigt „Nutzt das Internet“ (ab ShareOS 0.1.0-beta.12, ältere Versionen ignorieren das Feld). - Ordner der Box: Apps legen ihre Daten im persönlichen Ordner ab (
roots.find(r => r.home) || roots[0]). Admins bekommen ab ShareOS 0.2.0-beta.10 ebenfalls einen persönlichen Ordner als ersten Eintrag (root:home/rootauf dem Apps-Laufwerk), damit nichts oben auf dem Laufwerk landet. - Lizenz: Die Apps von UniqueDroid stehen wie ShareOS unter der GNU GPL Version 2 (
GPL-2.0-only, siehe COPYING); Apps anderer Herausgeber behalten ihre Lizenz ausapp.json. - Eigene Apps:
.sappunter APPS → Store hochladen (gilt als „eigene/ungeprüft“) oder einen eigenen Katalog unter APPS → Quellen eintragen. - Hier nur Web-Apps. System-Apps (Programme und Dienste für die Box, z. B. Tailscale, OpenVPN, Transmission) werden im ShareOS-Repository unter
sysapps/eingereicht – dort gibt es je ein Beispiel für ein Programm (tree) und einen Dienst (mosquitto, mit"service"inapp.jsonund der Steuerungshareos-<control>in der Firmware). Eine Web-App für einen Dienst kommt erst hierher, wenn ShareOS den Dienst hat; sie spricht ihn nur über das SDK und eine Berechtigung an.
examples/notes-demo/ is a complete small app with the SDK: title bar,
menu bar (Datei | Bearbeiten | Ansicht), status bar, opened file and saving.
It is not in the store; tools/build.py examples/notes-demo builds its
.sapp (APPS → Store → Install package), or copy it as a start for an own app.