synclayer 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- synclayer-0.1.0/CHANGELOG.md +14 -0
- synclayer-0.1.0/LICENSE +21 -0
- synclayer-0.1.0/MANIFEST.in +9 -0
- synclayer-0.1.0/PKG-INFO +418 -0
- synclayer-0.1.0/README.md +369 -0
- synclayer-0.1.0/pyproject.toml +85 -0
- synclayer-0.1.0/setup.cfg +4 -0
- synclayer-0.1.0/synclayer/__init__.py +13 -0
- synclayer-0.1.0/synclayer/__main__.py +4 -0
- synclayer-0.1.0/synclayer/_version.py +1 -0
- synclayer-0.1.0/synclayer/autostart.py +175 -0
- synclayer-0.1.0/synclayer/cli.py +913 -0
- synclayer-0.1.0/synclayer/client/__init__.py +0 -0
- synclayer-0.1.0/synclayer/client/api.py +283 -0
- synclayer-0.1.0/synclayer/client/config.py +224 -0
- synclayer-0.1.0/synclayer/client/sync.py +566 -0
- synclayer-0.1.0/synclayer/common/__init__.py +0 -0
- synclayer-0.1.0/synclayer/common/scan.py +40 -0
- synclayer-0.1.0/synclayer/config.py +317 -0
- synclayer-0.1.0/synclayer/deploy.py +370 -0
- synclayer-0.1.0/synclayer/desktop.py +281 -0
- synclayer-0.1.0/synclayer/devtools.py +209 -0
- synclayer-0.1.0/synclayer/gui/__init__.py +23 -0
- synclayer-0.1.0/synclayer/gui/app.py +1123 -0
- synclayer-0.1.0/synclayer/gui/icon.py +63 -0
- synclayer-0.1.0/synclayer/py.typed +0 -0
- synclayer-0.1.0/synclayer/remote.py +364 -0
- synclayer-0.1.0/synclayer/server/__init__.py +15 -0
- synclayer-0.1.0/synclayer/server/app.py +1404 -0
- synclayer-0.1.0/synclayer/server/library.py +423 -0
- synclayer-0.1.0/synclayer/server/mfa.py +407 -0
- synclayer-0.1.0/synclayer/server/quota.py +119 -0
- synclayer-0.1.0/synclayer/server/security.py +268 -0
- synclayer-0.1.0/synclayer/server/users.py +163 -0
- synclayer-0.1.0/synclayer/server/web/app.css +277 -0
- synclayer-0.1.0/synclayer/server/web/app.js +841 -0
- synclayer-0.1.0/synclayer/server/web/index.html +307 -0
- synclayer-0.1.0/synclayer/server/web/share.html +30 -0
- synclayer-0.1.0/synclayer/server/web/share.js +57 -0
- synclayer-0.1.0/synclayer/theme.py +127 -0
- synclayer-0.1.0/synclayer/tui.py +1318 -0
- synclayer-0.1.0/synclayer/vault.py +364 -0
- synclayer-0.1.0/synclayer/winservice.py +483 -0
- synclayer-0.1.0/synclayer.egg-info/PKG-INFO +418 -0
- synclayer-0.1.0/synclayer.egg-info/SOURCES.txt +47 -0
- synclayer-0.1.0/synclayer.egg-info/dependency_links.txt +1 -0
- synclayer-0.1.0/synclayer.egg-info/entry_points.txt +6 -0
- synclayer-0.1.0/synclayer.egg-info/requires.txt +27 -0
- synclayer-0.1.0/synclayer.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## 0.1.0
|
|
6
|
+
- Added a self-hosted cloud with a FastAPI server, web file manager, admin controls, MFA, and configurable storage quotas.
|
|
7
|
+
- Added multi-user accounts with private drives, folder sharing, and a Shared with me view.
|
|
8
|
+
- Added file search, recent and starred views, trash and restore, version history, protected share links, and resumable uploads.
|
|
9
|
+
- Added cross-platform clients: CLI/TUI, Python API, Windows and Linux desktop sync apps, and an Android WebView app with native upload and download support. Sync supports `.slignore`, bandwidth limits, and selective folder sync.
|
|
10
|
+
- Added multi-server support and a first-run connect screen to the desktop and Android apps, and Android camera backup.
|
|
11
|
+
- Added Docker and service deployment, desktop and Android build tools, and CI/release workflows for PyPI, GitHub Releases, container images, a Windows installer, and a Linux .deb.
|
|
12
|
+
- Added setup, contribution, support, and security documentation.
|
|
13
|
+
- Changed sync so deleting a file on a device keeps the server copy unless deletion sync is turned on.
|
|
14
|
+
- Updated repository ignore rules and platform-specific text-file handling.
|
synclayer-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Bradley Odimmasi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
synclayer-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: synclayer
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Synclayer - self-hosted cloud file manager with cross-platform sync (server, web, desktop, CLI)
|
|
5
|
+
Author: Bradley Odimmasi
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/KshRaven/synclayer
|
|
8
|
+
Project-URL: Documentation, https://github.com/KshRaven/synclayer#readme
|
|
9
|
+
Project-URL: Source, https://github.com/KshRaven/synclayer
|
|
10
|
+
Project-URL: Issues, https://github.com/KshRaven/synclayer/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/KshRaven/synclayer/blob/main/CHANGELOG.md
|
|
12
|
+
Keywords: file manager,sync,cloud storage,self-hosted,backup
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Topic :: System :: Archiving :: Backup
|
|
22
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: fastapi>=0.115
|
|
28
|
+
Requires-Dist: pillow>=10.0
|
|
29
|
+
Requires-Dist: uvicorn[standard]>=0.27
|
|
30
|
+
Requires-Dist: httpx>=0.26
|
|
31
|
+
Requires-Dist: platformdirs>=4.0
|
|
32
|
+
Requires-Dist: python-dotenv>=1.0
|
|
33
|
+
Requires-Dist: websockets>=12
|
|
34
|
+
Requires-Dist: watchdog>=4.0
|
|
35
|
+
Provides-Extra: gui
|
|
36
|
+
Requires-Dist: PySide6>=6.6; extra == "gui"
|
|
37
|
+
Provides-Extra: winservice
|
|
38
|
+
Requires-Dist: pywin32>=306; sys_platform == "win32" and extra == "winservice"
|
|
39
|
+
Provides-Extra: build
|
|
40
|
+
Requires-Dist: synclayer[gui]; extra == "build"
|
|
41
|
+
Requires-Dist: pyinstaller>=6.3; extra == "build"
|
|
42
|
+
Requires-Dist: build>=1.0; extra == "build"
|
|
43
|
+
Requires-Dist: twine>=5.0; extra == "build"
|
|
44
|
+
Provides-Extra: dev
|
|
45
|
+
Requires-Dist: synclayer[build]; extra == "dev"
|
|
46
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
47
|
+
Requires-Dist: ruff; extra == "dev"
|
|
48
|
+
Dynamic: license-file
|
|
49
|
+
|
|
50
|
+
# Synclayer
|
|
51
|
+
|
|
52
|
+
A self-hosted cloud for your files. Run the server on a machine you control, then browse, upload and
|
|
53
|
+
sync folders from a web browser, a desktop app, an Android app, the command line or Python code.
|
|
54
|
+
|
|
55
|
+
## What is included
|
|
56
|
+
|
|
57
|
+
| Part | What it does |
|
|
58
|
+
|---|---|
|
|
59
|
+
| Server | FastAPI app that stores the files and serves the web app and API. Has an admin panel (web, desktop tab and CLI). |
|
|
60
|
+
| Web app | File manager with drag and drop for files and folders, search, recent and starred views, trash, version history and share links. |
|
|
61
|
+
| Desktop app | Windows and Linux app with tray icon, notifications and launch at login. macOS works on a best-effort basis. |
|
|
62
|
+
| Terminal app | `synclayer` (or `sl`). With no arguments it opens a full-screen menu; with arguments it behaves like a normal CLI (`synclayer --help`). |
|
|
63
|
+
| Android app | WebView client for the server's web app with native upload and download handling. No background folder sync. |
|
|
64
|
+
| Python package | `import synclayer` to pull, push and sync project files from your own code. |
|
|
65
|
+
|
|
66
|
+
Other features: multiple users with private drives and per-user quotas, folder sharing between users,
|
|
67
|
+
password-protected share links, resumable uploads, `.slignore` files to exclude paths from sync, and
|
|
68
|
+
optional admin multi-factor authentication.
|
|
69
|
+
|
|
70
|
+
## Try it locally
|
|
71
|
+
|
|
72
|
+
Requires Python 3.10 or newer.
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
python3 -m venv .venv && source .venv/bin/activate # Windows: py -3 -m venv .venv, then .venv\Scripts\activate
|
|
76
|
+
pip install -e .
|
|
77
|
+
cp .env.example .env # Windows: Copy-Item .env.example .env
|
|
78
|
+
synclayer server serve
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Open `http://localhost:8787` and sign in as `admin`. If `SL_ADMIN_PASSWORD` is empty, a random password is
|
|
82
|
+
printed once on first start. Set your own later with `synclayer server passwd`. To listen on this machine
|
|
83
|
+
only, set `SL_HOST=127.0.0.1` in `.env`; the example file listens on all interfaces.
|
|
84
|
+
|
|
85
|
+
Check that it is running:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
curl --fail http://127.0.0.1:8787/api/health
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
To test from the command line, create a device token on the server and use it from a client:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
synclayer server token add sample-client
|
|
95
|
+
synclayer login --server http://127.0.0.1:8787 --token "dst_TOKEN_FROM_SERVER"
|
|
96
|
+
synclayer put ./sample.txt
|
|
97
|
+
synclayer ls
|
|
98
|
+
synclayer get sample.txt ./sample-downloaded.txt
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The token is shown once. Store it somewhere private and revoke it if the device is lost.
|
|
102
|
+
|
|
103
|
+
There is also an interactive manager that covers setup, running, building, updating, Docker, the boot
|
|
104
|
+
service and PyPI publishing: `bash scripts/manage/manage.sh` (Linux, macOS) or `scripts\manage\manage.bat` (Windows).
|
|
105
|
+
|
|
106
|
+
### Install options
|
|
107
|
+
|
|
108
|
+
| Command | You get | Typical use |
|
|
109
|
+
|---|---|---|
|
|
110
|
+
| `pip install synclayer` | server, CLI, Python package (no Qt) | servers, scripts |
|
|
111
|
+
| `pip install "synclayer[gui]"` | plus the desktop app (`synclayer-gui`) | desktops |
|
|
112
|
+
| `pip install "synclayer[winservice]"` | plus the Windows Service | Windows servers |
|
|
113
|
+
| `pip install -e ".[dev]"` / `".[build]"` | tests and lint / packaging tools | working on Synclayer |
|
|
114
|
+
|
|
115
|
+
From a checkout of this repository, use `pip install -e` in place of `pip install`.
|
|
116
|
+
|
|
117
|
+
## Hosting on your own server
|
|
118
|
+
|
|
119
|
+
The server targets Ubuntu/Debian (any systemd distribution works). Windows runs it as a real Windows
|
|
120
|
+
Service. macOS is supported as a LaunchAgent, best effort.
|
|
121
|
+
|
|
122
|
+
You need Python 3.10+, a domain whose `A` record points at the server (for HTTPS), and ports 80 and 443 open
|
|
123
|
+
(`sudo ufw allow 'Nginx Full'`). Behind a router, forward TCP 80 and 443. Only publish an `AAAA` record if
|
|
124
|
+
IPv6 and its firewall rules are set up too; Let's Encrypt validates over port 80.
|
|
125
|
+
|
|
126
|
+
### Linux: one command
|
|
127
|
+
|
|
128
|
+
From a checkout on the server:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
sudo bash scripts/install-service.sh install --nginx files.example.com --certbot you@example.com
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
This creates a `synclayer` system user, installs the app into `/opt/synclayer`, writes
|
|
135
|
+
`/etc/synclayer/synclayer.env`, installs a sandboxed systemd service that starts at boot and restarts on
|
|
136
|
+
failure, configures nginx for your domain and requests a Let's Encrypt certificate. Leave out `--nginx` and
|
|
137
|
+
`--certbot` to do it in steps. Without `--nginx` the server listens on `127.0.0.1` only; set `SL_HOST=0.0.0.0`
|
|
138
|
+
in the env file to expose port 8787 directly.
|
|
139
|
+
|
|
140
|
+
Then find the one-time admin password, or set your own:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
sudo journalctl -u synclayer-server --no-pager | grep -A4 'first start'
|
|
144
|
+
sudo synclayer server passwd
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
| Task | Command |
|
|
148
|
+
|---|---|
|
|
149
|
+
| Status, restart, logs | `sudo bash scripts/install-service.sh status` / `restart` / `logs` |
|
|
150
|
+
| Update from this checkout (or PyPI) | `sudo bash scripts/install-service.sh update` |
|
|
151
|
+
| Remove the service (files are kept) | `sudo bash scripts/install-service.sh uninstall` |
|
|
152
|
+
|
|
153
|
+
Data locations: files in `/var/lib/synclayer/files`, settings in `/var/lib/synclayer/config`, environment in
|
|
154
|
+
`/etc/synclayer/synclayer.env`.
|
|
155
|
+
|
|
156
|
+
### Linux: step by step
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
pip install synclayer
|
|
160
|
+
sudo synclayer service install --domain files.example.com
|
|
161
|
+
sudo synclayer nginx install --domain files.example.com --install-packages --certbot --email you@example.com
|
|
162
|
+
sudo synclayer service restart
|
|
163
|
+
synclayer service status
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
`synclayer nginx show --domain D` prints the nginx config without installing it, for setups you manage
|
|
167
|
+
yourself. The generated site keeps WebSocket updates working, streams uploads and downloads, and removes
|
|
168
|
+
nginx's body-size limit; the server enforces upload size and quota itself. Without root, use
|
|
169
|
+
`synclayer service install --user` for a systemd user unit (`sudo loginctl enable-linger $USER` makes it start
|
|
170
|
+
without a login).
|
|
171
|
+
|
|
172
|
+
### Windows
|
|
173
|
+
|
|
174
|
+
```powershell
|
|
175
|
+
pip install "synclayer[winservice]"
|
|
176
|
+
synclayer service install # from an Administrator prompt
|
|
177
|
+
synclayer service status | stop | start | restart | uninstall
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The service uses `SL_PORT` (8787 by default); use `--port` if something else owns it, and update clients and
|
|
181
|
+
any proxy to match. It starts automatically (delayed), restarts on failure and runs as LocalSystem. Data and
|
|
182
|
+
logs are in `%ProgramData%\Synclayer`, and its `config\` folder (signing key, tokens) is restricted to
|
|
183
|
+
Administrators, so run `synclayer server passwd` from an Administrator prompt. Settings come from a `.env` in
|
|
184
|
+
the folder you run `install` from (or `--env-file`), or from the admin panel.
|
|
185
|
+
|
|
186
|
+
If registration fails with a `pythonservice.exe` or DLL error, run
|
|
187
|
+
`python -m pywin32_postinstall -install` once as Administrator and try again. To allow other machines, set
|
|
188
|
+
`SL_HOST=0.0.0.0` and open the port:
|
|
189
|
+
`netsh advfirewall firewall add rule name="Synclayer" dir=in action=allow protocol=TCP localport=8787`.
|
|
190
|
+
The packaged `.exe` cannot host the service; use `synclayer autostart enable --server` (Task Scheduler)
|
|
191
|
+
instead. For HTTPS, put any reverse proxy in front; the config from `synclayer nginx show` works.
|
|
192
|
+
|
|
193
|
+
### Docker
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
docker compose up -d --build # http://localhost:8787
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
For HTTPS with nginx and Let's Encrypt, set `SL_DOMAIN=your.domain` and `SL_TRUST_PROXY=true` in `.env`, point
|
|
200
|
+
DNS at the server, open ports 80 and 443, then:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
docker compose --profile proxy up -d --build # nginx on :80, serves the certificate challenge
|
|
204
|
+
docker compose --profile certbot run --rm certbot certonly --webroot -w /var/www/certbot \
|
|
205
|
+
-d your.domain --email you@example.com --agree-tos --no-eff-email
|
|
206
|
+
docker compose --profile proxy down && docker compose --profile https up -d
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Renew about monthly with
|
|
210
|
+
`docker compose --profile certbot run --rm certbot renew && docker compose exec nginx nginx -s reload`.
|
|
211
|
+
On a LAN, or when TLS is handled elsewhere (Cloudflare, a load balancer), stay on `--profile proxy`.
|
|
212
|
+
|
|
213
|
+
## Configuration
|
|
214
|
+
|
|
215
|
+
Settings are `SL_*` variables (see `.env.example`). Precedence, lowest to highest: defaults, process
|
|
216
|
+
environment, `.env`, `settings.json`. The server re-reads `.env` and `settings.json` within about a second,
|
|
217
|
+
so most settings apply without a restart. Host, port, proxy mode and secret key need one.
|
|
218
|
+
|
|
219
|
+
Change settings from the web Admin panel, the desktop Admin tab, `synclayer admin set KEY VALUE` (from any
|
|
220
|
+
computer) or `synclayer server set KEY VALUE` (on the server). `synclayer server show` prints the effective values.
|
|
221
|
+
|
|
222
|
+
### Storage and limits
|
|
223
|
+
|
|
224
|
+
Files live in a per-OS data folder by default. Set `SL_STORAGE_ROOT` to move them, and
|
|
225
|
+
`SL_MOUNTS="name=/abs/path;other=/abs/path"` to expose existing server folders for syncing.
|
|
226
|
+
|
|
227
|
+
| Setting | Effect |
|
|
228
|
+
|---|---|
|
|
229
|
+
| `quota_mb` | Cap for the main storage folder. Uploads past it fail with HTTP 507. `0` means unlimited. |
|
|
230
|
+
| `min_free_mb` | Refuse writes that would leave less than this much free disk. |
|
|
231
|
+
| `max_upload_mb` | Largest single file. |
|
|
232
|
+
| `blocked_extensions` | File types that cannot be stored, for example `.exe,.php`. |
|
|
233
|
+
| `user_writes` | `false` makes everyone except the admin read-only. |
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
synclayer server set quota_mb 400
|
|
237
|
+
synclayer server usage # usage, quota, free disk, largest folders (`synclayer admin usage` from another computer)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
The quota covers the main storage folder only; `SL_MOUNTS` folders are not counted. Usage is scanned and
|
|
241
|
+
cached for about 15 seconds, so two uploads started at the same moment can overshoot by their own size.
|
|
242
|
+
|
|
243
|
+
### Users and sharing
|
|
244
|
+
|
|
245
|
+
The admin creates users from the Admin panel. Each user gets a private drive and can have their own quota.
|
|
246
|
+
A user can share a folder with another user as read-only or read-write, and create share links (optionally
|
|
247
|
+
password protected). Share links and starred items belong to the user who made them. Users cannot reach the
|
|
248
|
+
admin API. Disabling a user blocks sign-in; deleting one lets you keep or purge their data.
|
|
249
|
+
|
|
250
|
+
Devices (the desktop app, CLI, scripts) sign in with revocable tokens: `synclayer server token add NAME`.
|
|
251
|
+
Tokens can be read-only (`--read-only`).
|
|
252
|
+
|
|
253
|
+
### Multi-factor authentication
|
|
254
|
+
|
|
255
|
+
The server can require a second factor on admin password logins: authenticator-app codes (TOTP), SMS (Twilio or
|
|
256
|
+
a webhook), e-mail (SMTP) and one-time recovery codes. Configure delivery with the `sms_twilio_*`,
|
|
257
|
+
`sms_webhook_*` or `smtp_*` settings and manage factors through `/api/admin/mfa/...`. Sign-in codes by SMS or
|
|
258
|
+
e-mail use `/api/auth/mfa/send`.
|
|
259
|
+
|
|
260
|
+
The bundled web, Android, desktop, CLI and Python password logins do not yet prompt for the second factor, so
|
|
261
|
+
do not enable MFA for an account that signs in through them. Device-token authentication is unaffected.
|
|
262
|
+
|
|
263
|
+
### Security
|
|
264
|
+
|
|
265
|
+
Passwords are hashed, sessions are signed, login attempts are rate limited and paths cannot escape their
|
|
266
|
+
root. Serve over HTTPS on the internet, use a strong admin password and keep `SL_SECRET_KEY` private.
|
|
267
|
+
See [SECURITY.md](SECURITY.md) for reporting vulnerabilities.
|
|
268
|
+
|
|
269
|
+
### Backups and troubleshooting
|
|
270
|
+
|
|
271
|
+
Back up both the file data and the server configuration (settings, device tokens, signing key, MFA state).
|
|
272
|
+
Losing the configuration invalidates sessions and tokens. Locations: `/var/lib/synclayer` and
|
|
273
|
+
`/etc/synclayer/synclayer.env` on Linux, `%ProgramData%\Synclayer` on Windows, and the `synclayer-data` volume
|
|
274
|
+
(`/data/config`, `/data/files`) in Docker. The storage root may be elsewhere if you changed it. Stop the
|
|
275
|
+
service or use a filesystem snapshot while copying, and test a restore. `docker compose down -v` deletes the volumes.
|
|
276
|
+
|
|
277
|
+
If something fails, check `synclayer service status` and `synclayer service logs` (Docker: `docker compose ps`
|
|
278
|
+
and `docker compose logs`), then `/api/health`, DNS, firewall and ports 80/443. If an upload is rejected, check
|
|
279
|
+
the limits above and free disk space. If a setting seems ignored, remember that `settings.json` overrides `.env`.
|
|
280
|
+
|
|
281
|
+
## Using the apps
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
synclayer login --server https://your.domain # or: --token dst_...
|
|
285
|
+
synclayer ls | put FILE_OR_DIR [REMOTE] | get REMOTE [LOCAL] | mkdir | mv | rm
|
|
286
|
+
synclayer sync add work ~/Work --path projects/alpha # pair a local folder with a server folder
|
|
287
|
+
synclayer sync run # one pass; `synclayer daemon` keeps syncing
|
|
288
|
+
synclayer gui # desktop app; `synclayer tray --minimized` for the tray only
|
|
289
|
+
synclayer autostart enable # start the tray app at login (--server for the server)
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Sync is two-way by default; `--mode upload` makes a backup that never changes local files and `--mode download`
|
|
293
|
+
mirrors the server. If both sides changed a file, the newest copy wins and the other is saved as
|
|
294
|
+
`name.conflict-<time>.ext`. Deleting a file on a device does not delete it on the server unless you add
|
|
295
|
+
`--propagate-deletes` to that sync folder. The default local folder is `~/Synclayer`; each sync profile can use
|
|
296
|
+
another folder and another server path. Put patterns in a `.slignore` file to leave paths out of sync.
|
|
297
|
+
|
|
298
|
+
The desktop and Android apps start with no server and ask for an address on first launch. They can keep several
|
|
299
|
+
servers and switch between them, and the desktop app has a picker for the server folder of each sync folder.
|
|
300
|
+
|
|
301
|
+
The web and desktop apps both have **Account** (who you are, which server, sign in or out, device token) and
|
|
302
|
+
**Settings** (confirm before delete, date format, parallel uploads, notifications, launch at login). Admins also
|
|
303
|
+
get a shortcut to the server-wide Admin panel. CLI equivalents: `synclayer login | logout | status`.
|
|
304
|
+
|
|
305
|
+
### Desktop app
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
pip install "synclayer[gui]"
|
|
309
|
+
synclayer-gui
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
The first run adds an application-menu entry and icon (Linux: a `.desktop` file under `~/.local/share`;
|
|
313
|
+
Windows: a Start Menu shortcut you can pin) and keeps the app in the system tray when the window is closed.
|
|
314
|
+
Manage the launcher with `synclayer desktop install | uninstall | status`.
|
|
315
|
+
|
|
316
|
+
On Ubuntu, Qt needs `sudo apt install libxcb-cursor0 libegl1`, and GNOME shows tray icons only with the
|
|
317
|
+
AppIndicator extension (`sudo apt install gnome-shell-extension-appindicator`).
|
|
318
|
+
|
|
319
|
+
macOS (11+, best effort): the same commands work. The first run creates `~/Applications/Synclayer.app`,
|
|
320
|
+
`synclayer autostart enable` adds a LaunchAgent, and `synclayer service install` runs the server as a
|
|
321
|
+
LaunchAgent that starts at login (logs in `~/Library/Logs/Synclayer`). Release builds include an unsigned
|
|
322
|
+
Apple Silicon app: right-click it and choose Open the first time, or run
|
|
323
|
+
`xattr -dr com.apple.quarantine Synclayer.app`. For a server that must run before anyone logs in, use Linux.
|
|
324
|
+
|
|
325
|
+
### Android app
|
|
326
|
+
|
|
327
|
+
A WebView shell around the web app: choose a server address, use the file manager and admin panel, pick files
|
|
328
|
+
to upload and download through Android's DownloadManager. Optional camera backup uploads new photos and videos to
|
|
329
|
+
`Camera Uploads` on the active server in the background (Wi-Fi only by default, with an option to include existing
|
|
330
|
+
media). Background sync of arbitrary folders is not included (see [TODO.md](TODO.md)).
|
|
331
|
+
|
|
332
|
+
Build an APK with JDK 17, the Android SDK and Gradle, or let `synclayer dev android` download them for you:
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
bash android/build-apk.sh [https://files.example.com] # optional default server address
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
The APK is written to `dist/synclayer-<version>-android.apk`. Without a keystore it is signed with the debug
|
|
339
|
+
key, which is fine for sideloading. For your own signing, set `SL_KEYSTORE_FILE`, `SL_KEYSTORE_PASSWORD`,
|
|
340
|
+
`SL_KEY_ALIAS` and `SL_KEY_PASSWORD`.
|
|
341
|
+
|
|
342
|
+
### Python package
|
|
343
|
+
|
|
344
|
+
```python
|
|
345
|
+
import synclayer
|
|
346
|
+
|
|
347
|
+
cloud = synclayer.connect("https://your.domain", token="dst_...") # or set SL_SERVER / SL_TOKEN
|
|
348
|
+
cloud.pull("projects/alpha", "./workdir") # fetch your files on another machine
|
|
349
|
+
cloud.push("./workdir/results", "projects/alpha/results")
|
|
350
|
+
cloud.sync("./workdir", "projects/alpha") # two-way
|
|
351
|
+
watcher = cloud.watch("./workdir", "projects/alpha", interval=30) # background sync; watcher.stop()
|
|
352
|
+
cloud.write_text("notes/todo.txt", "hello"); print(cloud.read_text("notes/todo.txt"))
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
## Building and releasing
|
|
356
|
+
|
|
357
|
+
Build the desktop and CLI apps on the operating system you are targeting:
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
pip install -e ".[gui,build]"
|
|
361
|
+
python scripts/build.py --package # dist/synclayer, dist/synclayer-gui and an archive
|
|
362
|
+
python scripts/build.py --server https://your.domain # also bake in a default server address
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
Releases are automated by `scripts/pypimgr`. Add notes under `## Unreleased` in `CHANGELOG.md`, then:
|
|
366
|
+
|
|
367
|
+
```bash
|
|
368
|
+
python scripts/pypimgr/pypimgr.py check # tests, build and verify; changes nothing
|
|
369
|
+
python scripts/pypimgr/pypimgr.py release patch --push
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
This bumps `synclayer/_version.py`, stamps the changelog, builds from a clean copy, makes one commit and a
|
|
373
|
+
`vX.Y.Z` tag, and pushes. The tag starts `.github/workflows/release.yml`, which:
|
|
374
|
+
|
|
375
|
+
- builds the Windows and Linux apps, a Windows installer and a Linux `.deb` package (macOS, Linux ARM and Android
|
|
376
|
+
are best effort) and attaches them to a GitHub Release with the changelog notes;
|
|
377
|
+
- publishes to TestPyPI, then PyPI, through Trusted Publishing (no tokens);
|
|
378
|
+
- pushes the server image to `ghcr.io`.
|
|
379
|
+
|
|
380
|
+
One-time setup: add a Trusted Publisher for this repository and workflow on pypi.org and test.pypi.org
|
|
381
|
+
(environments `pypi` and `testpypi`). Optional repository variable `SL_BUILD_SERVER` bakes a default server
|
|
382
|
+
address into released apps. Android signing uses the secrets `ANDROID_KEYSTORE_BASE64`,
|
|
383
|
+
`ANDROID_KEYSTORE_PASSWORD`, `ANDROID_KEY_ALIAS` and `ANDROID_KEY_PASSWORD`; without them the APK is
|
|
384
|
+
debug-signed. Running the workflow by hand builds the apps only, with no release or PyPI upload. Check every
|
|
385
|
+
job and artifact before announcing a release. Windows and macOS builds are unsigned.
|
|
386
|
+
|
|
387
|
+
## Development
|
|
388
|
+
|
|
389
|
+
```bash
|
|
390
|
+
pip install -e ".[gui,dev,build]"
|
|
391
|
+
synclayer dev doctor # shows what is installed or missing (extras, JDK, Android SDK, Gradle)
|
|
392
|
+
python -m compileall -q synclayer scripts packaging
|
|
393
|
+
ruff check .
|
|
394
|
+
pytest -q
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
CI runs compile and import checks, Ruff and the tests on Linux and macOS with Python 3.10 and 3.12. The tests
|
|
398
|
+
cover the server API, authentication, users and sharing, trash and versions, quotas, path safety, device
|
|
399
|
+
monitoring, sync ignore rules and terminal-app helpers. They are not a full deployment or cross-device test.
|
|
400
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
401
|
+
|
|
402
|
+
### Known limitations
|
|
403
|
+
|
|
404
|
+
No per-device folder permissions, polling instead of a filesystem watcher, no block-level delta transfers, no
|
|
405
|
+
Android background sync, and incomplete MFA support in password-login clients. Deferred work and
|
|
406
|
+
clean-machine verification gaps are in [TODO.md](TODO.md).
|
|
407
|
+
|
|
408
|
+
### Repository layout
|
|
409
|
+
|
|
410
|
+
```
|
|
411
|
+
synclayer/ server/ (API, web UI, MFA) client/ (API client, sync) gui/ cli.py remote.py vault.py
|
|
412
|
+
android/ Kotlin WebView app and APK build script
|
|
413
|
+
scripts/ manage/ setup menu, pypimgr/ release tool, build.py, install-service.sh
|
|
414
|
+
packaging/ entry points for built executables, installer scripts
|
|
415
|
+
docker/ nginx templates (Dockerfile and docker-compose.yml are in the root)
|
|
416
|
+
.github/workflows/ CI and release automation
|
|
417
|
+
tests/ server, storage and client tests
|
|
418
|
+
```
|