diff --git a/.env b/.env index fbd02ad8..c22d1734 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -VERSION=1.3.1 \ No newline at end of file +VERSION=1.4.0 \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..5a2a2e8a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,56 @@ +# Contributing + +## Prerequisites + +- [Node.js](https://nodejs.org/en/download/) (built with v24) +- [NPM](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) +- [Git](https://git-scm.com/downloads) + +## Installation + +1. Clone the repository: + ```sh + git clone https://github.com/LukeGus/Termix + ``` +2. Install the dependencies: + ```sh + npm install + ``` + +## Running the development server + +Run the following commands: + +```sh +npm run dev +npx tsc -p tsconfig.node.json +node ./dist/backend/starter.js +``` + +This will start the backend and the frontend Vite server. You can access Termix by going to `http://localhost:5174/`. + +## Contributing + +1. **Fork the repository**: Click the "Fork" button at the top right of + the [repository page](https://github.com/LukeGus/Termix). +2. **Create a new branch**: + ```sh + git checkout -b feature/my-new-feature + ``` +3. **Make your changes**: Implement your feature, fix, or improvement. +4. **Commit your changes**: + ```sh + git commit -m "Add feature: my new feature" + ``` +5. **Push to your fork**: + ```sh + git push origin feature/my-new-feature + ``` +6. **Open a pull request**: Go to the original repository and create a PR with a clear description. + +## 📝 Guidelines + +- Follow the existing code style. Use Tailwind CSS with shadcn components. +- Place all API routes in the `main-axios.ts` file. Updating the `openapi.json` is unneeded. +- Include meaningful commit messages. +- Link related issues when applicable. \ No newline at end of file diff --git a/README.md b/README.md index b36e2762..72d47b80 100644 --- a/README.md +++ b/README.md @@ -37,18 +37,17 @@ Termix is an open-source, forever-free, self-hosted all-in-one server management - **Remote File Editor** - Edit files directly on remote servers with syntax highlighting, file management features (uploading, removing, renaming, deleting files) - **SSH Host Manager** - Save, organize, and manage your SSH connections with tags and folders - **Server Stats** - View CPU, memory, and HDD usage on any SSH server -- **User Authentication** - Secure user management with admin controls and OIDC support with more auth types planned +- **User Authentication** - Secure user management with admin controls and OIDC and 2FA (TOTP) support - **Modern UI** - Clean interface built with React, Tailwind CSS, and Shadcn # Planned Features - **Improved Admin Control** - Give more fine-grained control over user and admin permissions, share hosts, etc -- **More auth types** - Add 2FA, TOTP, etc -- **Theming** - Modify themeing for all tools +- **Theming** - Modify theming for all tools - **Improved Terminal Support** - Add more terminal protocols such as VNC and RDP (anyone who has experience in integrating RDP into a web-application similar to Apache Guacamole, please contact me by creating an issue) - **Mobile Support** - Support a mobile app or version of the Termix website to manage servers from your phone # Installation -Visit the Termix [Docs](https://docs.termix.site/docs) for more information on how to install Termix. Otherwise, view a sample docker-compose file here: +Visit the Termix [Docs](https://docs.termix.site/install) for more information on how to install Termix. Otherwise, view a sample docker-compose file here: ```yaml services: termix: diff --git a/openapi.json b/openapi.json new file mode 100644 index 00000000..b8d6ce05 --- /dev/null +++ b/openapi.json @@ -0,0 +1,2262 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "Termix API", + "version": "1.0.0", + "description": "Comprehensive API for Termix SSH management, file operations, tunneling, and server monitoring. This API provides endpoints for managing SSH hosts, file operations, tunnel connections, server monitoring, user management, and system alerts.", + "contact": { + "name": "Termix Development Team" + } + }, + "servers": [ + { + "url": "http://localhost:8081", + "description": "Main database and authentication server" + }, + { + "url": "http://localhost:8083", + "description": "SSH tunnel management server" + }, + { + "url": "http://localhost:8084", + "description": "SSH file manager server" + }, + { + "url": "http://localhost:8085", + "description": "Server statistics and monitoring server" + } + ], + "security": [ + { + "bearerAuth": [] + } + ], + "tags": [ + { + "name": "System", + "description": "System health, version, and release information endpoints" + }, + { + "name": "SSH Hosts", + "description": "SSH host management, creation, updates, and deletion" + }, + { + "name": "File Manager", + "description": "File manager operations including recent, pinned, and shortcuts" + }, + { + "name": "SSH File Operations", + "description": "SSH file operations like reading, writing, creating, and deleting files" + }, + { + "name": "Tunnel Management", + "description": "SSH tunnel connection, disconnection, and status management" + }, + { + "name": "Server Statistics", + "description": "Server status monitoring and metrics collection" + }, + { + "name": "User Management", + "description": "User account management and administration" + }, + { + "name": "Authentication", + "description": "User authentication, login, and password management" + }, + { + "name": "TOTP", + "description": "Two-factor authentication using TOTP (Time-based One-Time Password)" + }, + { + "name": "Alerts", + "description": "System alerts and notifications management" + } + ], + "components": { + "securitySchemes": { + "bearerAuth": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT" + } + }, + "schemas": { + "SSHHost": { + "type": "object", + "properties": { + "id": { "type": "integer" }, + "name": { "type": "string" }, + "ip": { "type": "string" }, + "port": { "type": "integer" }, + "username": { "type": "string" }, + "folder": { "type": "string" }, + "tags": { "type": "array", "items": { "type": "string" } }, + "pin": { "type": "boolean" }, + "authType": { "type": "string", "enum": ["password", "key"] }, + "password": { "type": "string" }, + "key": { "type": "string" }, + "keyPassword": { "type": "string" }, + "keyType": { "type": "string" }, + "enableTerminal": { "type": "boolean" }, + "enableTunnel": { "type": "boolean" }, + "enableFileManager": { "type": "boolean" }, + "defaultPath": { "type": "string" }, + "tunnelConnections": { "type": "array", "items": { "type": "object" } }, + "createdAt": { "type": "string", "format": "date-time" }, + "updatedAt": { "type": "string", "format": "date-time" } + }, + "required": ["id", "ip", "port", "username", "authType"] + }, + "SSHHostData": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "ip": { "type": "string" }, + "port": { "type": "integer" }, + "username": { "type": "string" }, + "folder": { "type": "string" }, + "tags": { "type": "array", "items": { "type": "string" } }, + "pin": { "type": "boolean" }, + "authType": { "type": "string", "enum": ["password", "key"] }, + "password": { "type": "string" }, + "key": { "type": "string" }, + "keyPassword": { "type": "string" }, + "keyType": { "type": "string" }, + "enableTerminal": { "type": "boolean" }, + "enableTunnel": { "type": "boolean" }, + "enableFileManager": { "type": "boolean" }, + "defaultPath": { "type": "string" }, + "tunnelConnections": { "type": "array", "items": { "type": "object" } } + }, + "required": ["ip", "port", "username", "authType"] + }, + "TunnelConfig": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "hostName": { "type": "string" }, + "sourceIP": { "type": "string" }, + "sourceSSHPort": { "type": "integer" }, + "sourceUsername": { "type": "string" }, + "sourcePassword": { "type": "string" }, + "sourceAuthMethod": { "type": "string" }, + "sourceSSHKey": { "type": "string" }, + "sourceKeyPassword": { "type": "string" }, + "sourceKeyType": { "type": "string" }, + "endpointIP": { "type": "string" }, + "endpointSSHPort": { "type": "integer" }, + "endpointUsername": { "type": "string" }, + "endpointPassword": { "type": "string" }, + "endpointAuthMethod": { "type": "string" }, + "endpointSSHKey": { "type": "string" }, + "endpointKeyPassword": { "type": "string" }, + "endpointKeyType": { "type": "string" }, + "sourcePort": { "type": "integer" }, + "endpointPort": { "type": "integer" }, + "maxRetries": { "type": "integer" }, + "retryInterval": { "type": "integer" }, + "autoStart": { "type": "boolean" }, + "isPinned": { "type": "boolean" } + }, + "required": ["name", "hostName", "sourceIP", "sourceSSHPort", "sourceUsername", "endpointIP", "endpointSSHPort", "endpointUsername", "sourcePort", "endpointPort"] + }, + "TunnelStatus": { + "type": "object", + "properties": { + "status": { "type": "string" }, + "reason": { "type": "string" }, + "errorType": { "type": "string" }, + "retryCount": { "type": "integer" }, + "maxRetries": { "type": "integer" }, + "nextRetryIn": { "type": "integer" }, + "retryExhausted": { "type": "boolean" } + } + }, + "ServerStatus": { + "type": "object", + "properties": { + "status": { "type": "string", "enum": ["online", "offline"] }, + "lastChecked": { "type": "string", "format": "date-time" } + } + }, + "ServerMetrics": { + "type": "object", + "properties": { + "cpu": { + "type": "object", + "properties": { + "percent": { "type": "number" }, + "cores": { "type": "number" }, + "load": { "type": "array", "items": { "type": "number" }, "minItems": 3, "maxItems": 3 } + } + }, + "memory": { + "type": "object", + "properties": { + "percent": { "type": "number" }, + "usedGiB": { "type": "number" }, + "totalGiB": { "type": "number" } + } + }, + "disk": { + "type": "object", + "properties": { + "percent": { "type": "number" }, + "usedHuman": { "type": "string" }, + "totalHuman": { "type": "string" } + } + }, + "lastChecked": { "type": "string", "format": "date-time" } + } + }, + "FileManagerFile": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "path": { "type": "string" }, + "type": { "type": "string", "enum": ["file", "directory"] }, + "isSSH": { "type": "boolean" }, + "sshSessionId": { "type": "string" } + }, + "required": ["name", "path"] + }, + "UserInfo": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "username": { "type": "string" }, + "is_admin": { "type": "boolean" } + }, + "required": ["id", "username", "is_admin"] + }, + "AuthResponse": { + "type": "object", + "properties": { + "token": { "type": "string" } + }, + "required": ["token"] + }, + "Error": { + "type": "object", + "properties": { + "error": { "type": "string" }, + "details": { "type": "string" } + } + } + }, + "parameters": { + "hostId": { + "name": "hostId", + "in": "query", + "description": "The ID of the SSH host", + "required": true, + "schema": { + "type": "integer" + } + }, + "sessionId": { + "name": "sessionId", + "in": "query", + "description": "The SSH session identifier", + "required": true, + "schema": { + "type": "string" + } + }, + "path": { + "name": "path", + "in": "query", + "description": "The file or directory path", + "required": true, + "schema": { + "type": "string" + } + }, + "tunnelName": { + "name": "tunnelName", + "in": "path", + "description": "The name of the tunnel", + "required": true, + "schema": { + "type": "string" + } + }, + "userId": { + "name": "userId", + "in": "path", + "description": "The user identifier", + "required": true, + "schema": { + "type": "string" + } + }, + "hostIdPath": { + "name": "id", + "in": "path", + "description": "The SSH host identifier", + "required": true, + "schema": { + "type": "integer" + } + }, + "serverIdPath": { + "name": "id", + "in": "path", + "description": "The server identifier", + "required": true, + "schema": { + "type": "integer" + } + } + }, + "responses": { + "BadRequest": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/Error" } + } + } + }, + "Unauthorized": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/Error" } + } + } + }, + "NotFound": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/Error" } + } + } + }, + "InternalServerError": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/Error" } + } + } + } + } + }, + "paths": { + "/health": { + "get": { + "summary": "Health check endpoint", + "description": "Simple health check to verify the API server is running and responsive. **Server: localhost:8081**", + "operationId": "getHealth", + "tags": ["System"], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { "type": "string", "example": "ok" } + } + } + } + } + } + } + } + }, + "/version": { + "get": { + "summary": "Get version information and check for updates", + "description": "Get version information and check for updates. **Server: localhost:8081**", + "operationId": "getVersion", + "tags": ["System"], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "status": { "type": "string", "enum": ["up_to_date", "requires_update"] }, + "version": { "type": "string" }, + "latest_release": { + "type": "object", + "properties": { + "tag_name": { "type": "string" }, + "name": { "type": "string" }, + "published_at": { "type": "string" }, + "html_url": { "type": "string" } + } + }, + "cached": { "type": "boolean" }, + "cache_age": { "type": "number" } + } + } + } + } + }, + "401": { + "description": "Version information not available", + "content": { + "text/plain": { + "schema": { "type": "string" } + } + } + } + } + } + }, + "/releases/rss": { + "get": { + "summary": "Get releases in RSS format", + "description": "Get releases in RSS format. **Server: localhost:8081**", + "operationId": "getReleasesRSS", + "tags": ["System"], + "parameters": [ + { + "name": "page", + "in": "query", + "schema": { "type": "integer", "default": 1 } + }, + { + "name": "per_page", + "in": "query", + "schema": { "type": "integer", "default": 20, "maximum": 100 } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "feed": { + "type": "object", + "properties": { + "title": { "type": "string" }, + "description": { "type": "string" }, + "link": { "type": "string" }, + "updated": { "type": "string" } + } + }, + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "integer" }, + "title": { "type": "string" }, + "description": { "type": "string" }, + "link": { "type": "string" }, + "pubDate": { "type": "string" }, + "version": { "type": "string" }, + "isPrerelease": { "type": "boolean" }, + "isDraft": { "type": "boolean" }, + "assets": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "size": { "type": "number" }, + "download_count": { "type": "number" }, + "download_url": { "type": "string" } + } + } + } + } + } + }, + "total_count": { "type": "integer" }, + "cached": { "type": "boolean" }, + "cache_age": { "type": "number" } + } + } + } + } + } + } + } + }, + "/ssh/db/host": { + "get": { + "summary": "Get all SSH hosts", + "description": "Retrieve a list of all configured SSH hosts in the system. This endpoint requires authentication and returns host information including connection details, authentication methods, and enabled features. **Server: localhost:8081**", + "operationId": "getSSHHosts", + "tags": ["SSH Hosts"], + "security": [{ "bearerAuth": [] }], + "responses": { + "200": { + "description": "Successfully retrieved SSH hosts", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { "$ref": "#/components/schemas/SSHHost" } + } + } + } + }, + "401": { "$ref": "#/components/responses/Unauthorized" } + } + }, + "post": { + "summary": "Create a new SSH host", + "description": "Create a new SSH host configuration. **Server: localhost:8081**", + "operationId": "createSSHHost", + "tags": ["SSH Hosts"], + "security": [{ "bearerAuth": [] }], + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "key": { + "type": "string", + "format": "binary", + "description": "SSH private key file (optional)" + }, + "data": { + "type": "string", + "description": "JSON string containing host data" + } + } + } + }, + "application/json": { + "schema": { "$ref": "#/components/schemas/SSHHostData" } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/SSHHost" } + } + } + }, + "400": { "$ref": "#/components/responses/BadRequest" }, + "401": { "$ref": "#/components/responses/Unauthorized" } + } + } + }, + "/ssh/db/host/{id}": { + "get": { + "summary": "Get SSH host by ID", + "description": "Get SSH host by ID. **Server: localhost:8081**", + "operationId": "getSSHHostById", + "tags": ["SSH Hosts"], + "security": [{ "bearerAuth": [] }], + "parameters": [ + { + "$ref": "#/components/parameters/hostIdPath" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/SSHHost" } + } + } + }, + "404": { "$ref": "#/components/responses/NotFound" }, + "401": { "$ref": "#/components/responses/Unauthorized" } + } + }, + "put": { + "summary": "Update SSH host", + "description": "Update SSH host configuration. **Server: localhost:8081**", + "operationId": "updateSSHHost", + "tags": ["SSH Hosts"], + "security": [{ "bearerAuth": [] }], + "parameters": [ + { + "$ref": "#/components/parameters/hostIdPath" + } + ], + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "key": { + "type": "string", + "format": "binary", + "description": "SSH private key file (optional)" + }, + "data": { + "type": "string", + "description": "JSON string containing host data" + } + } + } + }, + "application/json": { + "schema": { "$ref": "#/components/schemas/SSHHostData" } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/SSHHost" } + } + } + }, + "400": { "$ref": "#/components/responses/BadRequest" }, + "401": { "$ref": "#/components/responses/Unauthorized" }, + "404": { "$ref": "#/components/responses/NotFound" } + } + }, + "delete": { + "summary": "Delete SSH host", + "description": "Delete SSH host configuration. **Server: localhost:8081**", + "operationId": "deleteSSHHost", + "tags": ["SSH Hosts"], + "security": [{ "bearerAuth": [] }], + "parameters": [ + { + "$ref": "#/components/parameters/hostIdPath" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + }, + "401": { "$ref": "#/components/responses/Unauthorized" }, + "404": { "$ref": "#/components/responses/NotFound" } + } + } + }, + "/ssh/db/folders": { + "get": { + "summary": "Get all SSH host folders", + "description": "Get all SSH host folders. **Server: localhost:8081**", + "operationId": "getSSHFolders", + "tags": ["SSH Hosts"], + "security": [{ "bearerAuth": [] }], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { "type": "string" } + } + } + } + }, + "401": { "$ref": "#/components/responses/Unauthorized" } + } + } + }, + "/ssh/bulk-import": { + "post": { + "summary": "Bulk import SSH hosts", + "description": "Bulk import SSH hosts. **Server: localhost:8081**", + "operationId": "bulkImportSSHHosts", + "tags": ["SSH Hosts"], + "security": [{ "bearerAuth": [] }], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "hosts": { + "type": "array", + "items": { "$ref": "#/components/schemas/SSHHostData" } + } + }, + "required": ["hosts"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" }, + "success": { "type": "integer" }, + "failed": { "type": "integer" }, + "errors": { + "type": "array", + "items": { "type": "string" } + } + } + } + } + } + }, + "400": { "$ref": "#/components/responses/BadRequest" }, + "401": { "$ref": "#/components/responses/Unauthorized" } + } + } + }, + "/ssh/file_manager/recent": { + "get": { + "summary": "Get recent files for a host", + "description": "Get recent files for a host. **Server: localhost:8081**", + "operationId": "getFileManagerRecent", + "tags": ["File Manager"], + "security": [{ "bearerAuth": [] }], + "parameters": [ + { + "$ref": "#/components/parameters/hostId" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { "$ref": "#/components/schemas/FileManagerFile" } + } + } + } + }, + "401": { "$ref": "#/components/responses/Unauthorized" } + } + }, + "post": { + "summary": "Add file to recent list", + "description": "Add file to recent list. **Server: localhost:8081**", + "operationId": "addFileManagerRecent", + "tags": ["File Manager"], + "security": [{ "bearerAuth": [] }], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "path": { "type": "string" }, + "isSSH": { "type": "boolean" }, + "sshSessionId": { "type": "string" }, + "hostId": { "type": "integer" } + }, + "required": ["name", "path", "isSSH", "hostId"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + }, + "400": { "$ref": "#/components/responses/BadRequest" }, + "401": { "$ref": "#/components/responses/Unauthorized" } + } + }, + "delete": { + "summary": "Remove file from recent list", + "description": "Remove file from recent list. **Server: localhost:8081**", + "operationId": "removeFileManagerRecent", + "tags": ["File Manager"], + "security": [{ "bearerAuth": [] }], + "parameters": [ + { + "name": "name", + "in": "query", + "description": "File name", + "required": true, + "schema": { "type": "string" } + }, + { + "name": "path", + "in": "query", + "description": "File path", + "required": true, + "schema": { "type": "string" } + }, + { + "name": "isSSH", + "in": "query", + "description": "Whether this is an SSH file", + "required": true, + "schema": { "type": "boolean" } + }, + { + "name": "sshSessionId", + "in": "query", + "description": "SSH session ID", + "required": false, + "schema": { "type": "string" } + }, + { + "name": "hostId", + "in": "query", + "description": "Host ID", + "required": true, + "schema": { "type": "integer" } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + }, + "400": { "$ref": "#/components/responses/BadRequest" }, + "401": { "$ref": "#/components/responses/Unauthorized" } + } + } + }, + "/ssh/file_manager/pinned": { + "get": { + "summary": "Get pinned files for a host", + "description": "Get pinned files for a host. **Server: localhost:8081**", + "operationId": "getFileManagerPinned", + "tags": ["File Manager"], + "security": [{ "bearerAuth": [] }], + "parameters": [ + { + "$ref": "#/components/parameters/hostId" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { "$ref": "#/components/schemas/FileManagerFile" } + } + } + } + }, + "401": { "$ref": "#/components/responses/Unauthorized" } + } + }, + "post": { + "summary": "Add file to pinned list", + "description": "Add file to pinned list. **Server: localhost:8081**", + "operationId": "addFileManagerPinned", + "tags": ["File Manager"], + "security": [{ "bearerAuth": [] }], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "path": { "type": "string" }, + "isSSH": { "type": "boolean" }, + "sshSessionId": { "type": "string" }, + "hostId": { "type": "integer" } + }, + "required": ["name", "path", "isSSH", "hostId"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + }, + "400": { "$ref": "#/components/responses/BadRequest" }, + "401": { "$ref": "#/components/responses/Unauthorized" } + } + }, + "delete": { + "summary": "Remove file from pinned list", + "description": "Remove file from pinned list. **Server: localhost:8081**", + "operationId": "removeFileManagerPinned", + "tags": ["File Manager"], + "security": [{ "bearerAuth": [] }], + "parameters": [ + { + "name": "name", + "in": "query", + "description": "File name", + "required": true, + "schema": { "type": "string" } + }, + { + "name": "path", + "in": "query", + "description": "File path", + "required": true, + "schema": { "type": "string" } + }, + { + "name": "isSSH", + "in": "query", + "description": "Whether this is an SSH file", + "required": true, + "schema": { "type": "boolean" } + }, + { + "name": "sshSessionId", + "in": "query", + "description": "SSH session ID", + "required": false, + "schema": { "type": "string" } + }, + { + "name": "hostId", + "in": "query", + "description": "Host ID", + "required": true, + "schema": { "type": "integer" } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + }, + "400": { "$ref": "#/components/responses/BadRequest" }, + "401": { "$ref": "#/components/responses/Unauthorized" } + } + } + }, + "/ssh/file_manager/shortcuts": { + "get": { + "summary": "Get file shortcuts for a host", + "description": "Get file shortcuts for a host. **Server: localhost:8081**", + "operationId": "getFileManagerShortcuts", + "tags": ["File Manager"], + "security": [{ "bearerAuth": [] }], + "parameters": [ + { + "$ref": "#/components/parameters/hostId" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "path": { "type": "string" } + }, + "required": ["name", "path"] + } + } + } + } + }, + "401": { "$ref": "#/components/responses/Unauthorized" } + } + }, + "post": { + "summary": "Add file shortcut", + "description": "Add file shortcut. **Server: localhost:8081**", + "operationId": "addFileManagerShortcut", + "tags": ["File Manager"], + "security": [{ "bearerAuth": [] }], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "path": { "type": "string" }, + "isSSH": { "type": "boolean" }, + "sshSessionId": { "type": "string" }, + "hostId": { "type": "integer" } + }, + "required": ["name", "path", "isSSH", "hostId"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + }, + "400": { "$ref": "#/components/responses/BadRequest" }, + "401": { "$ref": "#/components/responses/Unauthorized" } + } + }, + "delete": { + "summary": "Remove file shortcut", + "description": "Remove file shortcut. **Server: localhost:8081**", + "operationId": "removeFileManagerShortcut", + "tags": ["File Manager"], + "security": [{ "bearerAuth": [] }], + "parameters": [ + { + "name": "name", + "in": "query", + "description": "File name", + "required": true, + "schema": { "type": "string" } + }, + { + "name": "path", + "in": "query", + "description": "File path", + "required": true, + "schema": { "type": "string" } + }, + { + "name": "isSSH", + "in": "query", + "description": "Whether this is an SSH file", + "required": true, + "schema": { "type": "boolean" } + }, + { + "name": "sshSessionId", + "in": "query", + "description": "SSH session ID", + "required": false, + "schema": { "type": "string" } + }, + { + "name": "hostId", + "in": "query", + "description": "Host ID", + "required": true, + "schema": { "type": "integer" } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + }, + "400": { "$ref": "#/components/responses/BadRequest" }, + "401": { "$ref": "#/components/responses/Unauthorized" } + } + } + }, + "/ssh/file_manager/ssh/connect": { + "post": { + "summary": "Connect to SSH server", + "description": "Connect to SSH server. **Server: localhost:8084**", + "operationId": "connectSSH", + "tags": ["SSH File Operations"], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "sessionId": { "type": "string" }, + "ip": { "type": "string" }, + "port": { "type": "integer" }, + "username": { "type": "string" }, + "password": { "type": "string" }, + "sshKey": { "type": "string" }, + "keyPassword": { "type": "string" } + }, + "required": ["sessionId", "ip", "username", "port"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + }, + "400": { "$ref": "#/components/responses/BadRequest" } + } + } + }, + "/ssh/file_manager/ssh/disconnect": { + "post": { + "summary": "Disconnect from SSH server", + "description": "Disconnect from SSH server. **Server: localhost:8084**", + "operationId": "disconnectSSH", + "tags": ["SSH File Operations"], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "sessionId": { "type": "string" } + }, + "required": ["sessionId"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + } + } + } + }, + "/ssh/file_manager/ssh/status": { + "get": { + "summary": "Get SSH connection status", + "description": "Get SSH connection status. **Server: localhost:8084**", + "operationId": "getSSHStatus", + "tags": ["SSH File Operations"], + "parameters": [ + { + "$ref": "#/components/parameters/sessionId" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connected": { "type": "boolean" } + } + } + } + } + } + } + } + }, + "/ssh/file_manager/ssh/listFiles": { + "get": { + "summary": "List files in SSH directory", + "description": "List files in SSH directory. **Server: localhost:8084**", + "operationId": "listSSHFiles", + "tags": ["SSH File Operations"], + "parameters": [ + { + "$ref": "#/components/parameters/sessionId" + }, + { + "$ref": "#/components/parameters/path" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "path": { "type": "string" }, + "type": { "type": "string", "enum": ["file", "directory"] }, + "size": { "type": "number" }, + "modified": { "type": "string" }, + "permissions": { "type": "string" } + } + } + } + } + } + } + } + } + }, + "/ssh/file_manager/ssh/readFile": { + "get": { + "summary": "Read SSH file content", + "description": "Read SSH file content. **Server: localhost:8084**", + "operationId": "readSSHFile", + "tags": ["SSH File Operations"], + "parameters": [ + { + "$ref": "#/components/parameters/sessionId" + }, + { + "$ref": "#/components/parameters/path" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "content": { "type": "string" }, + "path": { "type": "string" } + } + } + } + } + } + } + } + }, + "/ssh/file_manager/ssh/writeFile": { + "post": { + "summary": "Write content to SSH file", + "description": "Write content to SSH file. **Server: localhost:8084**", + "operationId": "writeSSHFile", + "tags": ["SSH File Operations"], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "sessionId": { "type": "string" }, + "path": { "type": "string" }, + "content": { "type": "string" } + }, + "required": ["sessionId", "path", "content"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + } + } + } + }, + "/ssh/file_manager/ssh/createFile": { + "post": { + "summary": "Create new SSH file", + "description": "Create new SSH file. **Server: localhost:8084**", + "operationId": "createSSHFile", + "tags": ["SSH File Operations"], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "sessionId": { "type": "string" }, + "path": { "type": "string" }, + "fileName": { "type": "string" }, + "content": { "type": "string" } + }, + "required": ["sessionId", "path", "fileName"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + } + } + } + }, + "/ssh/file_manager/ssh/createFolder": { + "post": { + "summary": "Create new SSH folder", + "description": "Create new SSH folder. **Server: localhost:8084**", + "operationId": "createSSHFolder", + "tags": ["SSH File Operations"], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "sessionId": { "type": "string" }, + "path": { "type": "string" }, + "folderName": { "type": "string" } + }, + "required": ["sessionId", "path", "folderName"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + } + } + } + }, + "/ssh/file_manager/ssh/deleteItem": { + "delete": { + "summary": "Delete SSH file or folder", + "description": "Delete SSH file or folder. **Server: localhost:8084**", + "operationId": "deleteSSHItem", + "tags": ["SSH File Operations"], + "parameters": [ + { + "name": "sessionId", + "in": "query", + "description": "SSH session ID", + "required": true, + "schema": { "type": "string" } + }, + { + "name": "path", + "in": "query", + "description": "File or directory path", + "required": true, + "schema": { "type": "string" } + }, + { + "name": "isDirectory", + "in": "query", + "description": "Whether the item is a directory", + "required": true, + "schema": { "type": "boolean" } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + } + } + } + }, + "/ssh/file_manager/ssh/renameItem": { + "put": { + "summary": "Rename SSH file or folder", + "description": "Rename SSH file or folder. **Server: localhost:8084**", + "operationId": "renameSSHItem", + "tags": ["SSH File Operations"], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "sessionId": { "type": "string" }, + "oldPath": { "type": "string" }, + "newName": { "type": "string" } + }, + "required": ["sessionId", "oldPath", "newName"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + } + } + } + }, + "/ssh/tunnel/status": { + "get": { + "summary": "Get all tunnel statuses", + "description": "Get all tunnel statuses. **Server: localhost:8083**", + "operationId": "getTunnelStatuses", + "tags": ["Tunnel Management"], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { "$ref": "#/components/schemas/TunnelStatus" } + } + } + } + } + } + } + }, + "/ssh/tunnel/status/{tunnelName}": { + "get": { + "summary": "Get tunnel status by name", + "description": "Get tunnel status by name. **Server: localhost:8083**", + "operationId": "getTunnelStatusByName", + "tags": ["Tunnel Management"], + "parameters": [ + { + "$ref": "#/components/parameters/tunnelName" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/TunnelStatus" } + } + } + } + } + } + }, + "/ssh/tunnel/connect": { + "post": { + "summary": "Connect to tunnel", + "description": "Connect to tunnel. **Server: localhost:8083**", + "operationId": "connectTunnel", + "tags": ["Tunnel Management"], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/TunnelConfig" } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + } + } + } + }, + "/ssh/tunnel/disconnect": { + "post": { + "summary": "Disconnect tunnel", + "description": "Disconnect tunnel. **Server: localhost:8083**", + "operationId": "disconnectTunnel", + "tags": ["Tunnel Management"], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "tunnelName": { "type": "string" } + }, + "required": ["tunnelName"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + } + } + } + }, + "/ssh/tunnel/cancel": { + "post": { + "summary": "Cancel tunnel connection", + "description": "Cancel tunnel connection. **Server: localhost:8083**", + "operationId": "cancelTunnel", + "tags": ["Tunnel Management"], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "tunnelName": { "type": "string" } + }, + "required": ["tunnelName"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + } + } + } + }, + "/status": { + "get": { + "summary": "Get all server statuses", + "description": "Get all server statuses. **Server: localhost:8085**", + "operationId": "getAllServerStatuses", + "tags": ["Server Statistics"], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { "$ref": "#/components/schemas/ServerStatus" } + } + } + } + } + } + } + }, + "/status/{id}": { + "get": { + "summary": "Get server status by ID", + "description": "Get server status by ID. **Server: localhost:8085**", + "operationId": "getServerStatusById", + "tags": ["Server Statistics"], + "parameters": [ + { + "$ref": "#/components/parameters/serverIdPath" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ServerStatus" } + } + } + } + } + } + }, + "/metrics/{id}": { + "get": { + "summary": "Get server metrics by ID", + "description": "Get server metrics by ID. **Server: localhost:8085**", + "operationId": "getServerMetricsById", + "tags": ["Server Statistics"], + "parameters": [ + { + "$ref": "#/components/parameters/serverIdPath" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ServerMetrics" } + } + } + } + } + } + }, + "/refresh": { + "post": { + "summary": "Refresh server statistics", + "description": "Refresh server statistics. **Server: localhost:8085**", + "operationId": "refreshServerStats", + "tags": ["Server Statistics"], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + } + } + } + }, + "/users/create": { + "post": { + "summary": "Create new user account", + "description": "Create new user account. **Server: localhost:8081**", + "operationId": "createUser", + "tags": ["User Management"], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "username": { "type": "string" }, + "password": { "type": "string" } + }, + "required": ["username", "password"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + }, + "400": { "$ref": "#/components/responses/BadRequest" } + } + } + }, + "/users/login": { + "post": { + "summary": "User login", + "description": "User login. **Server: localhost:8081**", + "operationId": "loginUser", + "tags": ["Authentication"], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "username": { "type": "string" }, + "password": { "type": "string" } + }, + "required": ["username", "password"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/AuthResponse" } + } + } + }, + "400": { "$ref": "#/components/responses/BadRequest" }, + "401": { "$ref": "#/components/responses/Unauthorized" } + } + } + }, + "/users/me": { + "get": { + "summary": "Get current user info", + "description": "Get current user info. **Server: localhost:8081**", + "operationId": "getUserInfo", + "tags": ["User Management"], + "security": [{ "bearerAuth": [] }], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/UserInfo" } + } + } + }, + "401": { "$ref": "#/components/responses/Unauthorized" } + } + } + }, + "/users/count": { + "get": { + "summary": "Get total user count", + "description": "Get total user count. **Server: localhost:8081**", + "operationId": "getUserCount", + "tags": ["User Management"], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "count": { "type": "integer" } + } + } + } + } + } + } + } + }, + "/users/registration-allowed": { + "get": { + "summary": "Check if user registration is allowed", + "description": "Check if user registration is allowed. **Server: localhost:8081**", + "operationId": "getRegistrationAllowed", + "tags": ["User Management"], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "allowed": { "type": "boolean" } + } + } + } + } + } + } + }, + "patch": { + "summary": "Update registration allowed status", + "description": "Update registration allowed status. **Server: localhost:8081**", + "operationId": "updateRegistrationAllowed", + "tags": ["User Management"], + "security": [{ "bearerAuth": [] }], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "allowed": { "type": "boolean" } + }, + "required": ["allowed"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + }, + "401": { "$ref": "#/components/responses/Unauthorized" } + } + } + }, + "/users/initiate-reset": { + "post": { + "summary": "Initiate password reset", + "description": "Initiate password reset. **Server: localhost:8081**", + "operationId": "initiatePasswordReset", + "tags": ["Authentication"], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "username": { "type": "string" } + }, + "required": ["username"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + } + } + } + }, + "/users/verify-reset-code": { + "post": { + "summary": "Verify password reset code", + "description": "Verify password reset code. **Server: localhost:8081**", + "operationId": "verifyPasswordResetCode", + "tags": ["Authentication"], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "username": { "type": "string" }, + "resetCode": { "type": "string" } + }, + "required": ["username", "resetCode"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "tempToken": { "type": "string" } + } + } + } + } + } + } + } + }, + "/users/complete-reset": { + "post": { + "summary": "Complete password reset", + "description": "Complete password reset. **Server: localhost:8081**", + "operationId": "completePasswordReset", + "tags": ["Authentication"], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "username": { "type": "string" }, + "tempToken": { "type": "string" }, + "newPassword": { "type": "string" } + }, + "required": ["username", "tempToken", "newPassword"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + } + } + } + }, + "/users/totp/setup": { + "post": { + "summary": "Setup TOTP authentication", + "description": "Setup TOTP authentication. **Server: localhost:8081**", + "operationId": "setupTOTP", + "tags": ["TOTP"], + "security": [{ "bearerAuth": [] }], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "secret": { "type": "string" }, + "qr_code": { "type": "string" } + } + } + } + } + }, + "401": { "$ref": "#/components/responses/Unauthorized" } + } + } + }, + "/users/totp/enable": { + "post": { + "summary": "Enable TOTP authentication", + "description": "Enable TOTP authentication. **Server: localhost:8081**", + "operationId": "enableTOTP", + "tags": ["TOTP"], + "security": [{ "bearerAuth": [] }], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "totp_code": { "type": "string" } + }, + "required": ["totp_code"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" }, + "backup_codes": { + "type": "array", + "items": { "type": "string" } + } + } + } + } + } + }, + "401": { "$ref": "#/components/responses/Unauthorized" } + } + } + }, + "/users/totp/verify-login": { + "post": { + "summary": "Verify TOTP during login", + "description": "Verify TOTP during login. **Server: localhost:8081**", + "operationId": "verifyTOTPLogin", + "tags": ["TOTP"], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "temp_token": { "type": "string" }, + "totp_code": { "type": "string" } + }, + "required": ["temp_token", "totp_code"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/AuthResponse" } + } + } + } + } + } + }, + "/alerts": { + "get": { + "summary": "Get all system alerts", + "description": "Get all system alerts. **Server: localhost:8081**", + "operationId": "getAllAlerts", + "tags": ["Alerts"], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "title": { "type": "string" }, + "message": { "type": "string" }, + "expiresAt": { "type": "string" }, + "priority": { "type": "string", "enum": ["low", "medium", "high", "critical"] }, + "type": { "type": "string", "enum": ["info", "warning", "error", "success"] }, + "actionUrl": { "type": "string" }, + "actionText": { "type": "string" } + } + } + } + } + } + } + } + } + }, + "/alerts/user/{userId}": { + "get": { + "summary": "Get alerts for specific user", + "description": "Get alerts for specific user. **Server: localhost:8081**", + "operationId": "getUserAlerts", + "tags": ["Alerts"], + "parameters": [ + { + "$ref": "#/components/parameters/userId" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "alerts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "title": { "type": "string" }, + "message": { "type": "string" }, + "expiresAt": { "type": "string" }, + "priority": { "type": "string", "enum": ["low", "medium", "high", "critical"] }, + "type": { "type": "string", "enum": ["info", "warning", "error", "success"] }, + "actionUrl": { "type": "string" }, + "actionText": { "type": "string" } + } + } + } + } + } + } + } + } + } + } + }, + "/alerts/dismiss": { + "post": { + "summary": "Dismiss an alert", + "description": "Dismiss an alert. **Server: localhost:8081**", + "operationId": "dismissAlert", + "tags": ["Alerts"], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "userId": { "type": "string" }, + "alertId": { "type": "string" } + }, + "required": ["userId", "alertId"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { "type": "string" } + } + } + } + } + } + } + } + } + } + } + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 23dc8262..1ec9298d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,8 @@ "@tailwindcss/vite": "^4.1.11", "@types/bcryptjs": "^2.4.6", "@types/multer": "^2.0.0", + "@types/qrcode": "^1.5.5", + "@types/speakeasy": "^2.0.10", "@uiw/codemirror-extensions-hyper-link": "^4.24.1", "@uiw/codemirror-extensions-langs": "^4.24.1", "@uiw/codemirror-themes": "^4.24.1", @@ -58,12 +60,14 @@ "nanoid": "^5.1.5", "next-themes": "^0.4.6", "node-fetch": "^3.3.2", + "qrcode": "^1.5.4", "react": "^19.1.0", "react-dom": "^19.1.0", "react-hook-form": "^7.60.0", "react-resizable-panels": "^3.0.3", "react-xtermjs": "^1.0.10", "sonner": "^2.0.7", + "speakeasy": "^2.0.0", "ssh2": "^1.16.0", "tailwind-merge": "^3.3.1", "tailwindcss": "^4.1.11", @@ -3782,6 +3786,15 @@ "undici-types": "~7.10.0" } }, + "node_modules/@types/qrcode": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.5.tgz", + "integrity": "sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/qs": { "version": "6.14.0", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", @@ -3835,6 +3848,15 @@ "@types/send": "*" } }, + "node_modules/@types/speakeasy": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/speakeasy/-/speakeasy-2.0.10.tgz", + "integrity": "sha512-QVRlDW5r4yl7p7xkNIbAIC/JtyOcClDIIdKfuG7PWdDT1MmyhtXSANsildohy0K+Lmvf/9RUtLbNLMacvrVwxA==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/ssh2": { "version": "1.15.5", "resolved": "https://registry.npmjs.org/@types/ssh2/-/ssh2-1.15.5.tgz", @@ -4400,6 +4422,15 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -4518,6 +4549,12 @@ "dev": true, "license": "MIT" }, + "node_modules/base32.js": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/base32.js/-/base32.js-0.0.1.tgz", + "integrity": "sha512-EGHIRiegFa62/SsA1J+Xs2tIzludPdzM064N9wjbiEgHnGnJ1V0WEpA4pEwCYT5nDvZk3ubf0shqaCS7k6xeUQ==", + "license": "MIT" + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -4771,6 +4808,15 @@ "node": ">=6" } }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001727", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz", @@ -4829,6 +4875,17 @@ "url": "https://polar.sh/cva" } }, + "node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -5062,6 +5119,15 @@ } } }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -5136,6 +5202,12 @@ "node": ">=0.3.1" } }, + "node_modules/dijkstrajs": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", + "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", + "license": "MIT" + }, "node_modules/dotenv": { "version": "17.2.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.0.tgz", @@ -5309,6 +5381,12 @@ "dev": true, "license": "ISC" }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, "node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", @@ -5994,6 +6072,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -6270,6 +6357,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -7195,6 +7291,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -7221,7 +7326,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -7265,6 +7369,15 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -7393,6 +7506,23 @@ "node": ">=6" } }, + "node_modules/qrcode": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz", + "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", + "license": "MIT", + "dependencies": { + "dijkstrajs": "^1.0.1", + "pngjs": "^5.0.0", + "yargs": "^15.3.1" + }, + "bin": { + "qrcode": "bin/qrcode" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/qs": { "version": "6.14.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", @@ -7616,6 +7746,21 @@ "node": ">= 6" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "license": "ISC" + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -7797,6 +7942,12 @@ "node": ">= 18" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -7962,6 +8113,18 @@ "node": ">=0.10.0" } }, + "node_modules/speakeasy": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/speakeasy/-/speakeasy-2.0.0.tgz", + "integrity": "sha512-lW2A2s5LKi8rwu77ewisuUOtlCydF/hmQSOJjpTqTj1gZLkNgTaYnyvfxy2WBr4T/h+9c4g8HIITfj83OkFQFw==", + "license": "MIT", + "dependencies": { + "base32.js": "0.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, "node_modules/ssh2": { "version": "1.16.0", "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.16.0.tgz", @@ -8005,6 +8168,32 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -8611,6 +8800,12 @@ "node": ">= 8" } }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "license": "ISC" + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -8621,6 +8816,20 @@ "node": ">=0.10.0" } }, + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -8657,6 +8866,12 @@ "node": ">=0.4" } }, + "node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "license": "ISC" + }, "node_modules/yallist": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", @@ -8666,6 +8881,93 @@ "node": ">=18" } }, + "node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/package.json b/package.json index b016dcb0..bfb57933 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,8 @@ "@tailwindcss/vite": "^4.1.11", "@types/bcryptjs": "^2.4.6", "@types/multer": "^2.0.0", + "@types/qrcode": "^1.5.5", + "@types/speakeasy": "^2.0.10", "@uiw/codemirror-extensions-hyper-link": "^4.24.1", "@uiw/codemirror-extensions-langs": "^4.24.1", "@uiw/codemirror-themes": "^4.24.1", @@ -62,12 +64,14 @@ "nanoid": "^5.1.5", "next-themes": "^0.4.6", "node-fetch": "^3.3.2", + "qrcode": "^1.5.4", "react": "^19.1.0", "react-dom": "^19.1.0", "react-hook-form": "^7.60.0", "react-resizable-panels": "^3.0.3", "react-xtermjs": "^1.0.10", "sonner": "^2.0.7", + "speakeasy": "^2.0.0", "ssh2": "^1.16.0", "tailwind-merge": "^3.3.1", "tailwindcss": "^4.1.11", diff --git a/src/App.tsx b/src/App.tsx index fb3e1525..2894ede1 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,10 +2,11 @@ import React, {useState, useEffect} from "react" import {LeftSidebar} from "@/ui/Navigation/LeftSidebar.tsx" import {Homepage} from "@/ui/Homepage/Homepage.tsx" import {AppView} from "@/ui/Navigation/AppView.tsx" -import {HostManager} from "@/ui/apps/Host Manager/HostManager.tsx" +import {HostManager} from "@/ui/Apps/Host Manager/HostManager.tsx" import {TabProvider, useTabs} from "@/ui/Navigation/Tabs/TabContext.tsx" import {TopNavbar} from "@/ui/Navigation/TopNavbar.tsx"; import { AdminSettings } from "@/ui/Admin/AdminSettings"; +import { UserProfile } from "@/ui/User/UserProfile.tsx"; import { Toaster } from "@/components/ui/sonner"; import { getUserInfo } from "@/ui/main-axios.ts"; @@ -86,6 +87,7 @@ function AppContent() { const showHome = currentTabData?.type === 'home'; const showSshManager = currentTabData?.type === 'ssh_manager'; const showAdmin = currentTabData?.type === 'admin'; + const showProfile = currentTabData?.type === 'profile'; return (
Use this guide to create JSON files for bulk importing SSH hosts. All examples are copyable.
- -ip - Host IP address (string)
-
- port - SSH port (number, 1-65535)
-
- username - SSH username (string)
-
- authType - "password" or "key"
-
- password - Required if authType is "password"
-
- key - SSH private key content (string) if authType is "key"
-
- keyPassword - Optional key passphrase
-
- keyType - Key type (auto, ssh-rsa, ssh-ed25519, etc.)
-
- name - Display name (string)
-
- folder - Organization folder (string)
-
- tags - Array of tag strings
-
- pin - Pin to top (boolean)
-
- enableTerminal - Show in Terminal tab (boolean, default: true)
-
- enableTunnel - Show in Tunnel tab (boolean, default: true)
-
- enableFileManager - Show in File Manager tab (boolean, default: true)
-
- defaultPath - Default directory path (string)
-
- tunnelConnections - Array of tunnel objects
-
- sourcePort - Local port (number)
-
- endpointPort - Remote port (number)
-
- endpointHost - Target host name (string)
-
- maxRetries - Retry attempts (number, default: 3)
-
- retryInterval - Retry delay in seconds (number, default: 10)
-
- autoStart - Auto-start on launch (boolean, default: false)
-
- {
- "hosts": [
- {
- "name": "Web Server",
- "ip": "192.168.1.100",
- "port": 22,
- "username": "admin",
- "authType": "password",
- "password": "your_password",
- "folder": "Production",
- "tags": ["web", "production"],
- "pin": true,
- "enableTerminal": true,
- "enableTunnel": false,
- "enableFileManager": true,
- "defaultPath": "/var/www"
- }
- ]
-}
-
-