webgate 0.1.0__tar.gz → 0.2.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.
Files changed (83) hide show
  1. {webgate-0.1.0 → webgate-0.2.0}/.dockerignore +1 -1
  2. webgate-0.2.0/CHANGELOG.md +69 -0
  3. {webgate-0.1.0 → webgate-0.2.0}/Dockerfile +1 -1
  4. {webgate-0.1.0 → webgate-0.2.0}/PKG-INFO +77 -7
  5. {webgate-0.1.0 → webgate-0.2.0}/README.md +76 -6
  6. webgate-0.2.0/ROADMAP.md +79 -0
  7. webgate-0.2.0/docs/screenshots/access-control.png +0 -0
  8. webgate-0.2.0/docs/screenshots/audit.png +0 -0
  9. webgate-0.2.0/docs/screenshots/edit-access-control.png +0 -0
  10. webgate-0.2.0/docs/screenshots/editor.png +0 -0
  11. webgate-0.2.0/docs/screenshots/login.png +0 -0
  12. webgate-0.2.0/docs/screenshots/new-server-form.png +0 -0
  13. webgate-0.2.0/docs/screenshots/sftp-restricted.png +0 -0
  14. webgate-0.2.0/docs/screenshots/sftp.png +0 -0
  15. webgate-0.2.0/docs/screenshots/site-manager.png +0 -0
  16. webgate-0.2.0/docs/screenshots/split-view.png +0 -0
  17. webgate-0.2.0/docs/screenshots/ssh-disabled.png +0 -0
  18. webgate-0.2.0/docs/screenshots/terminal.png +0 -0
  19. webgate-0.2.0/docs/screenshots/users.png +0 -0
  20. {webgate-0.1.0 → webgate-0.2.0}/pyproject.toml +1 -1
  21. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/app.py +3 -1
  22. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/config.py +5 -0
  23. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/db/engine.py +16 -1
  24. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/files/routes.py +95 -13
  25. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/files/sftp_service.py +29 -0
  26. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/servers/models.py +17 -1
  27. webgate-0.2.0/src/webgate/servers/monitor.py +117 -0
  28. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/servers/routes.py +31 -0
  29. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/servers/service.py +26 -0
  30. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/static/index.html +276 -142
  31. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/terminal/routes.py +4 -0
  32. {webgate-0.1.0 → webgate-0.2.0}/uv.lock +1 -1
  33. webgate-0.1.0/CHANGELOG.md +0 -27
  34. webgate-0.1.0/docs/screenshots/editor.png +0 -0
  35. webgate-0.1.0/docs/screenshots/login.png +0 -0
  36. webgate-0.1.0/docs/screenshots/sftp.png +0 -0
  37. webgate-0.1.0/docs/screenshots/site-manager.png +0 -0
  38. webgate-0.1.0/docs/screenshots/terminal.png +0 -0
  39. {webgate-0.1.0 → webgate-0.2.0}/.github/workflows/docs.yml +0 -0
  40. {webgate-0.1.0 → webgate-0.2.0}/.gitignore +0 -0
  41. {webgate-0.1.0 → webgate-0.2.0}/Dockerfile.ssh-demo +0 -0
  42. {webgate-0.1.0 → webgate-0.2.0}/LICENSE +0 -0
  43. {webgate-0.1.0 → webgate-0.2.0}/VERSION +0 -0
  44. {webgate-0.1.0 → webgate-0.2.0}/compose.dev.yml +0 -0
  45. {webgate-0.1.0 → webgate-0.2.0}/compose.yml +0 -0
  46. {webgate-0.1.0 → webgate-0.2.0}/docs/api/auth.md +0 -0
  47. {webgate-0.1.0 → webgate-0.2.0}/docs/api/files.md +0 -0
  48. {webgate-0.1.0 → webgate-0.2.0}/docs/api/servers.md +0 -0
  49. {webgate-0.1.0 → webgate-0.2.0}/docs/api/terminal.md +0 -0
  50. {webgate-0.1.0 → webgate-0.2.0}/docs/changelog.md +0 -0
  51. {webgate-0.1.0 → webgate-0.2.0}/docs/getting-started/installation.md +0 -0
  52. {webgate-0.1.0 → webgate-0.2.0}/docs/getting-started/quickstart.md +0 -0
  53. {webgate-0.1.0 → webgate-0.2.0}/docs/guide/files.md +0 -0
  54. {webgate-0.1.0 → webgate-0.2.0}/docs/guide/servers.md +0 -0
  55. {webgate-0.1.0 → webgate-0.2.0}/docs/guide/split.md +0 -0
  56. {webgate-0.1.0 → webgate-0.2.0}/docs/guide/terminal.md +0 -0
  57. {webgate-0.1.0 → webgate-0.2.0}/docs/guide/users.md +0 -0
  58. {webgate-0.1.0 → webgate-0.2.0}/docs/index.md +0 -0
  59. {webgate-0.1.0 → webgate-0.2.0}/mkdocs.yml +0 -0
  60. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/__init__.py +0 -0
  61. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/__main__.py +0 -0
  62. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/audit/__init__.py +0 -0
  63. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/audit/models.py +0 -0
  64. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/audit/service.py +0 -0
  65. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/auth/__init__.py +0 -0
  66. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/auth/models.py +0 -0
  67. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/auth/routes.py +0 -0
  68. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/auth/service.py +0 -0
  69. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/db/__init__.py +0 -0
  70. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/files/__init__.py +0 -0
  71. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/files/models.py +0 -0
  72. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/files/pool.py +0 -0
  73. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/servers/__init__.py +0 -0
  74. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/servers/crypto.py +0 -0
  75. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/terminal/__init__.py +0 -0
  76. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/terminal/ssh_session.py +0 -0
  77. {webgate-0.1.0 → webgate-0.2.0}/src/webgate/terminal/ws_handler.py +0 -0
  78. {webgate-0.1.0 → webgate-0.2.0}/tests/__init__.py +0 -0
  79. {webgate-0.1.0 → webgate-0.2.0}/tests/conftest.py +0 -0
  80. {webgate-0.1.0 → webgate-0.2.0}/tests/test_auth.py +0 -0
  81. {webgate-0.1.0 → webgate-0.2.0}/tests/test_files.py +0 -0
  82. {webgate-0.1.0 → webgate-0.2.0}/tests/test_servers.py +0 -0
  83. {webgate-0.1.0 → webgate-0.2.0}/tests/test_terminal.py +0 -0
@@ -13,6 +13,6 @@ CLAUDE.md
13
13
  CLAUDE.local.md
14
14
  .env
15
15
  docs/
16
- README.md
16
+ ROADMAP.md
17
17
  *.png
18
18
  .playwright-cli/
@@ -0,0 +1,69 @@
1
+ # Changelog
2
+
3
+ ## v0.2.0 (2026-04-09)
4
+
5
+ ### Features
6
+
7
+ - **SFTP read-only mode** -- per-server flag to allow browse and download only, blocking all write operations (upload, write, mkdir, rename, delete, chmod)
8
+ - **Server status monitoring** -- background task checks SSH connectivity every 60 seconds; online/offline indicator (green/red dot) on server dashboard
9
+ - **Dark/light theme toggle** -- user preference saved in localStorage; CSS custom properties for full theme support; terminal and editor adapt to theme
10
+ - **Keyboard shortcuts** -- Escape closes modals, Ctrl+1 goes to Site Manager, Ctrl+N opens New Server
11
+ - **Drag & drop upload progress** -- visual progress bar with percentage during file uploads
12
+ - **Folder download as ZIP** -- right-click a directory in SFTP browser to download it as a ZIP archive
13
+ - **Lightweight DB migrations** -- automatic ALTER TABLE for new columns on existing databases
14
+
15
+ ### Details
16
+
17
+ - New server model field: `sftp_read_only` (bool, default false)
18
+ - New file: `servers/monitor.py` — ServerMonitor class with asyncio background task
19
+ - New API endpoints: `GET /api/servers/status`, `GET /api/servers/{id}/status`
20
+ - New API endpoint: `GET /api/files/{id}/download-zip?path=`
21
+ - Config settings: `monitor_interval`, `monitor_timeout`, `monitor_concurrency`
22
+ - CSS variables for theming: `--bg-primary`, `--text-primary`, `--accent`, etc.
23
+ - Terminal theme switches between dark (Tokyo Night) and light on toggle
24
+
25
+ ---
26
+
27
+ ## v0.1.1 (2026-04-08)
28
+
29
+ ### Features
30
+
31
+ - **Per-server SSH/SFTP toggles** -- admin can enable or disable SSH terminal and SFTP file browser independently for each server
32
+ - **SFTP path restrictions** -- admin can configure allowed directory paths per server; users are restricted to only those directories and their subdirectories (empty list = unrestricted)
33
+
34
+ ### Details
35
+
36
+ - New server model fields: `ssh_enabled` (bool), `sftp_enabled` (bool), `sftp_allowed_paths` (JSON list of paths)
37
+ - SSH disabled servers return WebSocket close code 4003
38
+ - SFTP disabled servers return HTTP 403
39
+ - Path restriction enforced on all SFTP operations (ls, read, write, upload, download, mkdir, rename, delete, chmod)
40
+ - Rename operations validate both source and destination paths against allowed paths
41
+ - All existing tests continue to pass (34 tests)
42
+
43
+ ---
44
+
45
+ ## v0.1.0 (2026-04-08)
46
+
47
+ First public release.
48
+
49
+ ### Features
50
+
51
+ - SSH web terminal (xterm.js + asyncssh WebSocket bridge)
52
+ - SFTP file browser (directory listing, upload, download, rename, delete, mkdir, chmod)
53
+ - In-browser text editor (CodeMirror 6 with oneDark theme)
54
+ - PDF and image preview (PDF, PNG, JPG, GIF, SVG, WebP)
55
+ - Server registry with groups, tags, and encrypted credentials (Fernet)
56
+ - Quick Connect toolbar for one-off SSH connections
57
+ - Admin/user role system with group-based access control
58
+ - Default admin account with forced password change on first login
59
+ - User management panel (create, delete, assign groups)
60
+ - Multi-tab split pane (terminal + file browser side by side)
61
+ - File search/filter within SFTP listings
62
+ - Server import/export (JSON) from the UI
63
+ - Session persistence across page reloads
64
+ - Rate limiting on auth endpoints (slowapi)
65
+ - Audit log (admin-viewable action history)
66
+ - SFTP connection pool (reuse per server, 5 min TTL)
67
+ - Modern dark UI (GitHub-inspired theme)
68
+ - Docker multi-stage build with demo SSH container
69
+ - 34 automated tests
@@ -4,7 +4,7 @@ FROM python:3.13-slim AS builder
4
4
  WORKDIR /app
5
5
  COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
6
6
 
7
- COPY pyproject.toml uv.lock ./
7
+ COPY pyproject.toml uv.lock README.md ./
8
8
  RUN uv sync --frozen --no-dev --no-editable
9
9
 
10
10
  COPY src/ src/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: webgate
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Self-hosted web application for remote server management via SSH terminal and SFTP file browser
5
5
  Project-URL: Homepage, https://github.com/kalexnolasco/webgate
6
6
  Project-URL: Documentation, https://kalexnolasco.github.io/webgate/
@@ -44,11 +44,12 @@ Description-Content-Type: text/markdown
44
44
 
45
45
  # webgate
46
46
 
47
- [![Python](https://img.shields.io/badge/python-3.11+-blue?style=flat-square&logo=python&logoColor=white)](https://python.org)
47
+ [![PyPI](https://img.shields.io/pypi/v/webgate?style=flat-square)](https://pypi.org/project/webgate/)
48
+ [![Python](https://img.shields.io/pypi/pyversions/webgate?style=flat-square)](https://pypi.org/project/webgate/)
49
+ [![License](https://img.shields.io/pypi/l/webgate?style=flat-square)](https://github.com/kalexnolasco/webgate/blob/main/LICENSE)
48
50
  [![FastAPI](https://img.shields.io/badge/FastAPI-0.115+-009688?style=flat-square&logo=fastapi&logoColor=white)](https://fastapi.tiangolo.com)
49
- [![License](https://img.shields.io/badge/license-MIT-green?style=flat-square)](LICENSE)
50
51
  [![Docker](https://img.shields.io/badge/docker-ready-2496ED?style=flat-square&logo=docker&logoColor=white)](Dockerfile)
51
- [![Status](https://img.shields.io/badge/status-beta-orange?style=flat-square)]()
52
+ [![Status](https://img.shields.io/badge/status-beta-orange?style=flat-square)](https://pypi.org/project/webgate/)
52
53
  [![Tests](https://img.shields.io/badge/tests-34%20passed-brightgreen?style=flat-square)](https://github.com/kalexnolasco/webgate/actions)
53
54
  [![Docs](https://img.shields.io/badge/docs-kalexnolasco.github.io-blue?style=flat-square)](https://kalexnolasco.github.io/webgate/)
54
55
 
@@ -183,16 +184,25 @@ flowchart TB
183
184
  | **SFTP File Browser** | Directory listing, upload/download, drag & drop, rename, delete, mkdir, chmod, breadcrumb navigation |
184
185
  | **File Editor** | In-browser text editor powered by CodeMirror 6 with syntax highlighting (oneDark theme) |
185
186
  | **File Preview** | PDF viewer, image preview (PNG, JPG, GIF, SVG, WebP) directly in the browser |
186
- | **Server Registry** | Add/edit/delete servers, groups, tags, password & key auth, test connectivity, import/export |
187
+ | **Server Registry** | Add/edit/delete servers, groups, tags, password & key auth, test connectivity, import/export, per-server SSH/SFTP toggles |
187
188
  | **Quick Connect** | One-off SSH/SFTP connections without saving server config (FileZilla-style toolbar) |
188
- | **User Management** | Admin creates users and assigns server groups -- users only see what they're allowed to |
189
+ | **Access Control** | Admin creates users, assigns server groups, enables/disables SSH or SFTP per server, restricts SFTP to specific paths, read-only SFTP mode |
190
+ | **Server Monitoring** | Background SSH connectivity checks every 60s, green/red status dot on server dashboard |
191
+ | **Dark/Light Theme** | Toggle between dark and light themes, saved in localStorage, terminal adapts |
189
192
  | **Credential Security** | SSH passwords and private keys encrypted at rest with Fernet (derived from app secret) |
190
193
  | **Connection Pool** | SFTP connections are reused per server (5 min TTL), not opened/closed on every request |
194
+ | **Upload Progress** | Visual progress bar with percentage during file uploads |
195
+ | **ZIP Download** | Download entire directories as ZIP archives from the SFTP browser |
196
+ | **Keyboard Shortcuts** | Escape closes modals, Ctrl+1 Site Manager, Ctrl+N New Server |
191
197
  | **Docker Ready** | Multi-stage Dockerfile, single-command deployment, health checks, persistent volumes |
198
+ | **Responsive** | Adapts to tablet and mobile screen sizes |
192
199
  | **Zero Frontend Build** | Vanilla JS + Alpine.js, no npm/node required, all assets from CDN |
193
200
 
194
201
  ## Screenshots
195
202
 
203
+ ### Login
204
+ ![Login](docs/screenshots/login.png)
205
+
196
206
  ### Site Manager
197
207
  ![Site Manager](docs/screenshots/site-manager.png)
198
208
 
@@ -205,6 +215,24 @@ flowchart TB
205
215
  ### File Editor (CodeMirror 6)
206
216
  ![Editor](docs/screenshots/editor.png)
207
217
 
218
+ ### Split View (Terminal + SFTP)
219
+ ![Split View](docs/screenshots/split-view.png)
220
+
221
+ ### Access Control (per-server SSH/SFTP toggles + path restrictions)
222
+ ![Access Control](docs/screenshots/access-control.png)
223
+
224
+ ### SSH Disabled (button greyed out)
225
+ ![SSH Disabled](docs/screenshots/ssh-disabled.png)
226
+
227
+ ### SFTP Path Restriction in Action
228
+ ![SFTP Restricted](docs/screenshots/sftp-restricted.png)
229
+
230
+ ### User Management
231
+ ![Users](docs/screenshots/users.png)
232
+
233
+ ### Audit Log
234
+ ![Audit](docs/screenshots/audit.png)
235
+
208
236
  ## Quick Start
209
237
 
210
238
  ### Docker (recommended)
@@ -272,10 +300,13 @@ flowchart LR
272
300
  | | Admin | User |
273
301
  |---|---|---|
274
302
  | Add/edit/delete servers | Yes | No |
303
+ | Enable/disable SSH or SFTP per server | Yes | No |
304
+ | Restrict SFTP to specific paths | Yes | No |
275
305
  | Create/delete users | Yes | No |
276
306
  | Assign groups to users | Yes | No |
277
307
  | See all servers | Yes | Only servers in assigned groups |
278
- | SSH / SFTP / Test | Yes | Yes (allowed servers only) |
308
+ | SSH terminal (if enabled on server) | Yes | Yes (allowed servers only) |
309
+ | SFTP file browser (if enabled, within allowed paths) | Yes | Yes (allowed servers only) |
279
310
  | Quick Connect | Yes | Yes |
280
311
 
281
312
  ### Example workflow
@@ -417,6 +448,9 @@ All settings are configurable via environment variables with the `WEBGATE_` pref
417
448
  | `WEBGATE_MAX_UPLOAD_SIZE` | `104857600` | Max upload size (100 MB) |
418
449
  | `WEBGATE_JWT_ALGORITHM` | `HS256` | JWT algorithm |
419
450
  | `WEBGATE_JWT_EXPIRE_MINUTES` | `1440` | Token expiry (24 hours) |
451
+ | `WEBGATE_MONITOR_INTERVAL` | `60` | Server status check interval (seconds) |
452
+ | `WEBGATE_MONITOR_TIMEOUT` | `5` | SSH connect timeout for checks (seconds) |
453
+ | `WEBGATE_MONITOR_CONCURRENCY` | `10` | Max parallel status checks |
420
454
 
421
455
  ## Docker
422
456
 
@@ -516,6 +550,9 @@ uv run coverage run -m pytest tests/ -v && uv run coverage report
516
550
  - **SSH credentials encrypted at rest** with Fernet (key derived from `WEBGATE_SECRET_KEY`)
517
551
  - **JWT authentication** with configurable expiry
518
552
  - **Group-based access control** -- users only see servers in their assigned groups
553
+ - **Per-server feature control** -- admin can disable SSH or SFTP independently per server
554
+ - **SFTP path restrictions** -- admin can lock SFTP to specific directories per server
555
+ - **SFTP read-only mode** -- admin can set per-server read-only flag, blocking all write operations
519
556
  - **SFTP path traversal protection** (server-side normalization and validation)
520
557
  - **CORS configurable** per deployment
521
558
  - **No plaintext password storage** (user passwords hashed with bcrypt)
@@ -523,6 +560,8 @@ uv run coverage run -m pytest tests/ -v && uv run coverage report
523
560
 
524
561
  ## Roadmap
525
562
 
563
+ ### Completed (v0.1.x)
564
+
526
565
  - [x] SSH web terminal (xterm.js + asyncssh)
527
566
  - [x] SFTP file browser with full CRUD
528
567
  - [x] Server registry with groups and tags
@@ -541,6 +580,37 @@ uv run coverage run -m pytest tests/ -v && uv run coverage report
541
580
  - [x] Session persistence across page reloads
542
581
  - [x] Rate limiting on auth endpoints (slowapi)
543
582
  - [x] Audit log (admin-viewable action history)
583
+ - [x] Per-server SSH/SFTP toggles (admin can enable/disable each feature)
584
+ - [x] SFTP path restrictions (admin can limit access to specific directories)
585
+
586
+ ### Completed (v0.2.x)
587
+
588
+ - [x] SFTP read-only mode per server (browse and download only)
589
+ - [x] Server status monitoring (background SSH checks, green/red dot)
590
+ - [x] Dark/light theme toggle with localStorage persistence
591
+ - [x] Responsive tablet/mobile layout
592
+ - [x] Keyboard shortcuts (Escape, Ctrl+1, Ctrl+N)
593
+ - [x] Upload progress bar with percentage
594
+ - [x] Folder download as ZIP
595
+
596
+ ### Planned (v0.3.x -- Collaboration & Ops)
597
+
598
+ - [ ] Shared terminal sessions (multiple users watching the same session)
599
+ - [ ] Session recording and playback (audit/training)
600
+ - [ ] SSH command snippets/macros (saved per server or global)
601
+ - [ ] Webhook/notifications on connection events
602
+ - [ ] Two-factor authentication (TOTP)
603
+ - [ ] LDAP/Active Directory integration
604
+ - [ ] API key authentication (for automation/scripts)
605
+
606
+ ### Planned (v0.4.x -- Enterprise)
607
+
608
+ - [ ] PostgreSQL support (tested and documented)
609
+ - [ ] Multi-instance deployment with shared DB
610
+ - [ ] SSH jump host / bastion support (ProxyCommand equivalent)
611
+ - [ ] Custom branding (logo, colors, company name)
612
+ - [ ] Backup/restore UI for server registry
613
+ - [ ] Internationalization (i18n)
544
614
 
545
615
  ## Requirements
546
616
 
@@ -1,10 +1,11 @@
1
1
  # webgate
2
2
 
3
- [![Python](https://img.shields.io/badge/python-3.11+-blue?style=flat-square&logo=python&logoColor=white)](https://python.org)
3
+ [![PyPI](https://img.shields.io/pypi/v/webgate?style=flat-square)](https://pypi.org/project/webgate/)
4
+ [![Python](https://img.shields.io/pypi/pyversions/webgate?style=flat-square)](https://pypi.org/project/webgate/)
5
+ [![License](https://img.shields.io/pypi/l/webgate?style=flat-square)](https://github.com/kalexnolasco/webgate/blob/main/LICENSE)
4
6
  [![FastAPI](https://img.shields.io/badge/FastAPI-0.115+-009688?style=flat-square&logo=fastapi&logoColor=white)](https://fastapi.tiangolo.com)
5
- [![License](https://img.shields.io/badge/license-MIT-green?style=flat-square)](LICENSE)
6
7
  [![Docker](https://img.shields.io/badge/docker-ready-2496ED?style=flat-square&logo=docker&logoColor=white)](Dockerfile)
7
- [![Status](https://img.shields.io/badge/status-beta-orange?style=flat-square)]()
8
+ [![Status](https://img.shields.io/badge/status-beta-orange?style=flat-square)](https://pypi.org/project/webgate/)
8
9
  [![Tests](https://img.shields.io/badge/tests-34%20passed-brightgreen?style=flat-square)](https://github.com/kalexnolasco/webgate/actions)
9
10
  [![Docs](https://img.shields.io/badge/docs-kalexnolasco.github.io-blue?style=flat-square)](https://kalexnolasco.github.io/webgate/)
10
11
 
@@ -139,16 +140,25 @@ flowchart TB
139
140
  | **SFTP File Browser** | Directory listing, upload/download, drag & drop, rename, delete, mkdir, chmod, breadcrumb navigation |
140
141
  | **File Editor** | In-browser text editor powered by CodeMirror 6 with syntax highlighting (oneDark theme) |
141
142
  | **File Preview** | PDF viewer, image preview (PNG, JPG, GIF, SVG, WebP) directly in the browser |
142
- | **Server Registry** | Add/edit/delete servers, groups, tags, password & key auth, test connectivity, import/export |
143
+ | **Server Registry** | Add/edit/delete servers, groups, tags, password & key auth, test connectivity, import/export, per-server SSH/SFTP toggles |
143
144
  | **Quick Connect** | One-off SSH/SFTP connections without saving server config (FileZilla-style toolbar) |
144
- | **User Management** | Admin creates users and assigns server groups -- users only see what they're allowed to |
145
+ | **Access Control** | Admin creates users, assigns server groups, enables/disables SSH or SFTP per server, restricts SFTP to specific paths, read-only SFTP mode |
146
+ | **Server Monitoring** | Background SSH connectivity checks every 60s, green/red status dot on server dashboard |
147
+ | **Dark/Light Theme** | Toggle between dark and light themes, saved in localStorage, terminal adapts |
145
148
  | **Credential Security** | SSH passwords and private keys encrypted at rest with Fernet (derived from app secret) |
146
149
  | **Connection Pool** | SFTP connections are reused per server (5 min TTL), not opened/closed on every request |
150
+ | **Upload Progress** | Visual progress bar with percentage during file uploads |
151
+ | **ZIP Download** | Download entire directories as ZIP archives from the SFTP browser |
152
+ | **Keyboard Shortcuts** | Escape closes modals, Ctrl+1 Site Manager, Ctrl+N New Server |
147
153
  | **Docker Ready** | Multi-stage Dockerfile, single-command deployment, health checks, persistent volumes |
154
+ | **Responsive** | Adapts to tablet and mobile screen sizes |
148
155
  | **Zero Frontend Build** | Vanilla JS + Alpine.js, no npm/node required, all assets from CDN |
149
156
 
150
157
  ## Screenshots
151
158
 
159
+ ### Login
160
+ ![Login](docs/screenshots/login.png)
161
+
152
162
  ### Site Manager
153
163
  ![Site Manager](docs/screenshots/site-manager.png)
154
164
 
@@ -161,6 +171,24 @@ flowchart TB
161
171
  ### File Editor (CodeMirror 6)
162
172
  ![Editor](docs/screenshots/editor.png)
163
173
 
174
+ ### Split View (Terminal + SFTP)
175
+ ![Split View](docs/screenshots/split-view.png)
176
+
177
+ ### Access Control (per-server SSH/SFTP toggles + path restrictions)
178
+ ![Access Control](docs/screenshots/access-control.png)
179
+
180
+ ### SSH Disabled (button greyed out)
181
+ ![SSH Disabled](docs/screenshots/ssh-disabled.png)
182
+
183
+ ### SFTP Path Restriction in Action
184
+ ![SFTP Restricted](docs/screenshots/sftp-restricted.png)
185
+
186
+ ### User Management
187
+ ![Users](docs/screenshots/users.png)
188
+
189
+ ### Audit Log
190
+ ![Audit](docs/screenshots/audit.png)
191
+
164
192
  ## Quick Start
165
193
 
166
194
  ### Docker (recommended)
@@ -228,10 +256,13 @@ flowchart LR
228
256
  | | Admin | User |
229
257
  |---|---|---|
230
258
  | Add/edit/delete servers | Yes | No |
259
+ | Enable/disable SSH or SFTP per server | Yes | No |
260
+ | Restrict SFTP to specific paths | Yes | No |
231
261
  | Create/delete users | Yes | No |
232
262
  | Assign groups to users | Yes | No |
233
263
  | See all servers | Yes | Only servers in assigned groups |
234
- | SSH / SFTP / Test | Yes | Yes (allowed servers only) |
264
+ | SSH terminal (if enabled on server) | Yes | Yes (allowed servers only) |
265
+ | SFTP file browser (if enabled, within allowed paths) | Yes | Yes (allowed servers only) |
235
266
  | Quick Connect | Yes | Yes |
236
267
 
237
268
  ### Example workflow
@@ -373,6 +404,9 @@ All settings are configurable via environment variables with the `WEBGATE_` pref
373
404
  | `WEBGATE_MAX_UPLOAD_SIZE` | `104857600` | Max upload size (100 MB) |
374
405
  | `WEBGATE_JWT_ALGORITHM` | `HS256` | JWT algorithm |
375
406
  | `WEBGATE_JWT_EXPIRE_MINUTES` | `1440` | Token expiry (24 hours) |
407
+ | `WEBGATE_MONITOR_INTERVAL` | `60` | Server status check interval (seconds) |
408
+ | `WEBGATE_MONITOR_TIMEOUT` | `5` | SSH connect timeout for checks (seconds) |
409
+ | `WEBGATE_MONITOR_CONCURRENCY` | `10` | Max parallel status checks |
376
410
 
377
411
  ## Docker
378
412
 
@@ -472,6 +506,9 @@ uv run coverage run -m pytest tests/ -v && uv run coverage report
472
506
  - **SSH credentials encrypted at rest** with Fernet (key derived from `WEBGATE_SECRET_KEY`)
473
507
  - **JWT authentication** with configurable expiry
474
508
  - **Group-based access control** -- users only see servers in their assigned groups
509
+ - **Per-server feature control** -- admin can disable SSH or SFTP independently per server
510
+ - **SFTP path restrictions** -- admin can lock SFTP to specific directories per server
511
+ - **SFTP read-only mode** -- admin can set per-server read-only flag, blocking all write operations
475
512
  - **SFTP path traversal protection** (server-side normalization and validation)
476
513
  - **CORS configurable** per deployment
477
514
  - **No plaintext password storage** (user passwords hashed with bcrypt)
@@ -479,6 +516,8 @@ uv run coverage run -m pytest tests/ -v && uv run coverage report
479
516
 
480
517
  ## Roadmap
481
518
 
519
+ ### Completed (v0.1.x)
520
+
482
521
  - [x] SSH web terminal (xterm.js + asyncssh)
483
522
  - [x] SFTP file browser with full CRUD
484
523
  - [x] Server registry with groups and tags
@@ -497,6 +536,37 @@ uv run coverage run -m pytest tests/ -v && uv run coverage report
497
536
  - [x] Session persistence across page reloads
498
537
  - [x] Rate limiting on auth endpoints (slowapi)
499
538
  - [x] Audit log (admin-viewable action history)
539
+ - [x] Per-server SSH/SFTP toggles (admin can enable/disable each feature)
540
+ - [x] SFTP path restrictions (admin can limit access to specific directories)
541
+
542
+ ### Completed (v0.2.x)
543
+
544
+ - [x] SFTP read-only mode per server (browse and download only)
545
+ - [x] Server status monitoring (background SSH checks, green/red dot)
546
+ - [x] Dark/light theme toggle with localStorage persistence
547
+ - [x] Responsive tablet/mobile layout
548
+ - [x] Keyboard shortcuts (Escape, Ctrl+1, Ctrl+N)
549
+ - [x] Upload progress bar with percentage
550
+ - [x] Folder download as ZIP
551
+
552
+ ### Planned (v0.3.x -- Collaboration & Ops)
553
+
554
+ - [ ] Shared terminal sessions (multiple users watching the same session)
555
+ - [ ] Session recording and playback (audit/training)
556
+ - [ ] SSH command snippets/macros (saved per server or global)
557
+ - [ ] Webhook/notifications on connection events
558
+ - [ ] Two-factor authentication (TOTP)
559
+ - [ ] LDAP/Active Directory integration
560
+ - [ ] API key authentication (for automation/scripts)
561
+
562
+ ### Planned (v0.4.x -- Enterprise)
563
+
564
+ - [ ] PostgreSQL support (tested and documented)
565
+ - [ ] Multi-instance deployment with shared DB
566
+ - [ ] SSH jump host / bastion support (ProxyCommand equivalent)
567
+ - [ ] Custom branding (logo, colors, company name)
568
+ - [ ] Backup/restore UI for server registry
569
+ - [ ] Internationalization (i18n)
500
570
 
501
571
  ## Requirements
502
572
 
@@ -0,0 +1,79 @@
1
+ # Roadmap
2
+
3
+ This document tracks the development plan for **webgate**. Items are organized by release milestone.
4
+
5
+ ---
6
+
7
+ ## v0.1.0 -- Foundation (Released 2026-04-08)
8
+
9
+ - [x] SSH web terminal (xterm.js + asyncssh WebSocket bridge)
10
+ - [x] SFTP file browser (ls, upload, download, rename, delete, mkdir, chmod)
11
+ - [x] In-browser text editor (CodeMirror 6 with oneDark theme)
12
+ - [x] PDF and image preview (PDF, PNG, JPG, GIF, SVG, WebP)
13
+ - [x] Server registry with groups, tags, and encrypted credentials (Fernet)
14
+ - [x] Quick Connect toolbar for one-off SSH connections
15
+ - [x] Admin/user role system with group-based access control
16
+ - [x] Default admin account with forced password change on first login
17
+ - [x] User management panel (create, delete, assign groups)
18
+ - [x] Multi-tab split pane (terminal + file browser side by side)
19
+ - [x] SSH key management (per-server key upload with visual indicator)
20
+ - [x] File search/filter within SFTP listings
21
+ - [x] Server import/export (JSON) from the UI
22
+ - [x] Session persistence across page reloads
23
+ - [x] Rate limiting on auth endpoints (slowapi)
24
+ - [x] Audit log (admin-viewable action history)
25
+ - [x] SFTP connection pool (reuse per server, 5 min TTL)
26
+ - [x] Docker multi-stage build with demo SSH container
27
+ - [x] 34 automated tests
28
+
29
+ ## v0.1.1 -- Per-Server Access Control (Released 2026-04-08)
30
+
31
+ - [x] Per-server SSH toggle (admin can disable SSH terminal for specific servers)
32
+ - [x] Per-server SFTP toggle (admin can disable SFTP file browser for specific servers)
33
+ - [x] SFTP path restrictions (admin can limit SFTP access to specific directories per server)
34
+ - [x] Path enforcement on all SFTP operations (ls, read, write, upload, download, mkdir, rename, delete, chmod)
35
+
36
+ ---
37
+
38
+ ## v0.2.0 -- Access Refinement & UX (Released 2026-04-09)
39
+
40
+ - [x] SFTP read-only mode (per-server flag: browse/download only, block upload/write/delete/rename/mkdir/chmod)
41
+ - [x] Server status monitoring (background SSH checks every 60s, green/red dot on dashboard)
42
+ - [x] Dark/light theme toggle (CSS variables, localStorage persistence, terminal/editor adapt)
43
+ - [x] Responsive tablet layout (CSS media queries for 1024px and 768px breakpoints)
44
+ - [x] Keyboard shortcuts (Escape closes modals, Ctrl+1 Site Manager, Ctrl+N New Server)
45
+ - [x] Drag & drop upload progress bar (XHR with progress events, percentage display)
46
+ - [x] Folder download as ZIP (server-side zip compression, right-click context menu)
47
+
48
+ ## v0.3.0 -- Collaboration & Operations
49
+
50
+ | Feature | Priority | Description |
51
+ |---------|----------|-------------|
52
+ | Shared terminal sessions | High | Multiple users can watch/interact with the same SSH session in real time |
53
+ | Session recording & playback | High | Record terminal sessions for audit trail and training; replay in browser |
54
+ | SSH command snippets | Medium | Save and execute common commands per server or globally; share across team |
55
+ | Webhook notifications | Medium | Fire webhooks on events: user login, SSH connect, file upload, server added |
56
+ | Two-factor authentication (TOTP) | High | Optional TOTP (Google Authenticator, Authy) for user accounts |
57
+ | LDAP / Active Directory | Medium | Authenticate users against corporate LDAP/AD; auto-map groups |
58
+ | API key authentication | Low | Generate API keys for programmatic access (automation, scripts, CI/CD) |
59
+
60
+ ## v0.4.0 -- Enterprise & Scale
61
+
62
+ | Feature | Priority | Description |
63
+ |---------|----------|-------------|
64
+ | PostgreSQL support | High | Test, document, and CI-verify PostgreSQL as alternative to SQLite |
65
+ | Multi-instance deployment | Medium | Multiple webgate instances sharing a single database (stateless workers behind LB) |
66
+ | SSH jump host / bastion | High | Connect through a bastion/jump host to reach servers not directly reachable |
67
+ | Custom branding | Low | Configurable logo, application name, and color scheme |
68
+ | Backup/restore UI | Medium | Export/import full application state (users, servers, audit log) from admin panel |
69
+ | Internationalization (i18n) | Low | Multi-language support for the UI (starting with English and Spanish) |
70
+
71
+ ---
72
+
73
+ ## How to Contribute
74
+
75
+ Feature requests and bug reports go in [GitHub Issues](https://github.com/kalexnolasco/webgate/issues). When proposing a new feature, please include:
76
+
77
+ 1. **Use case** -- What problem does it solve?
78
+ 2. **Who benefits** -- Which type of user needs this?
79
+ 3. **Suggested approach** -- How would you implement it (optional)?
Binary file
Binary file
Binary file
Binary file
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "webgate"
3
- version = "0.1.0"
3
+ version = "0.2.0"
4
4
  description = "Self-hosted web application for remote server management via SSH terminal and SFTP file browser"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -4,7 +4,6 @@ from contextlib import asynccontextmanager
4
4
  from fastapi import FastAPI
5
5
  from fastapi.middleware.cors import CORSMiddleware
6
6
  from fastapi.staticfiles import StaticFiles
7
-
8
7
  from slowapi import _rate_limit_exceeded_handler
9
8
  from slowapi.errors import RateLimitExceeded
10
9
 
@@ -15,6 +14,7 @@ from webgate.config import settings
15
14
  from webgate.db.engine import async_session_factory, close_db, init_db
16
15
  from webgate.files.pool import sftp_pool
17
16
  from webgate.files.routes import router as files_router
17
+ from webgate.servers.monitor import server_monitor
18
18
  from webgate.servers.routes import router as servers_router
19
19
  from webgate.terminal.routes import router as terminal_router
20
20
 
@@ -25,7 +25,9 @@ async def lifespan(app: FastAPI) -> AsyncGenerator[None]:
25
25
  async with async_session_factory() as session:
26
26
  await seed_admin(session)
27
27
  await sftp_pool.start()
28
+ await server_monitor.start()
28
29
  yield
30
+ await server_monitor.stop()
29
31
  await sftp_pool.stop()
30
32
  await close_db()
31
33
 
@@ -20,6 +20,11 @@ class Settings(BaseSettings):
20
20
  jwt_algorithm: str = "HS256"
21
21
  jwt_expire_minutes: int = 1440 # 24 hours
22
22
 
23
+ # Server monitoring
24
+ monitor_interval: int = 60 # seconds between connectivity checks
25
+ monitor_timeout: int = 5 # SSH connect timeout for checks
26
+ monitor_concurrency: int = 10 # max parallel checks
27
+
23
28
  @property
24
29
  def static_dir(self) -> Path:
25
30
  return Path(__file__).parent / "static"
@@ -1,11 +1,14 @@
1
+ import logging
1
2
  from collections.abc import AsyncGenerator
2
3
 
3
- from sqlalchemy import MetaData
4
+ from sqlalchemy import MetaData, text
4
5
  from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
5
6
  from sqlalchemy.orm import DeclarativeBase
6
7
 
7
8
  from webgate.config import settings
8
9
 
10
+ logger = logging.getLogger(__name__)
11
+
9
12
  engine = create_async_engine(settings.db_url, echo=False)
10
13
  async_session_factory = async_sessionmaker(engine, expire_on_commit=False)
11
14
 
@@ -27,9 +30,21 @@ async def get_session() -> AsyncGenerator[AsyncSession]:
27
30
  yield session
28
31
 
29
32
 
33
+ _MIGRATIONS = [
34
+ "ALTER TABLE servers ADD COLUMN sftp_read_only BOOLEAN DEFAULT 0",
35
+ ]
36
+
37
+
30
38
  async def init_db() -> None:
31
39
  async with engine.begin() as conn:
32
40
  await conn.run_sync(Base.metadata.create_all)
41
+ # Lightweight migrations for columns added after initial release
42
+ for sql in _MIGRATIONS:
43
+ try:
44
+ await conn.execute(text(sql))
45
+ logger.info("Migration applied: %s", sql.split("ADD COLUMN ")[1].split()[0])
46
+ except Exception:
47
+ pass # Column already exists
33
48
 
34
49
 
35
50
  async def close_db() -> None: