diff --git a/.github/workflows/openapi.yml b/.github/workflows/openapi.yml new file mode 100644 index 00000000..5ecdd866 --- /dev/null +++ b/.github/workflows/openapi.yml @@ -0,0 +1,32 @@ +name: Generate OpenAPI Specification + +on: + workflow_dispatch: + +jobs: + generate-openapi: + name: Generate OpenAPI JSON + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Generate OpenAPI specification + run: npm run generate:openapi + + - name: Upload OpenAPI artifact + uses: actions/upload-artifact@v4 + with: + name: openapi-spec + path: openapi.json + retention-days: 90 diff --git a/.github/workflows/translate.yml b/.github/workflows/translate.yml deleted file mode 100644 index 7c9db568..00000000 --- a/.github/workflows/translate.yml +++ /dev/null @@ -1,437 +0,0 @@ -name: Auto Translate - -on: - workflow_dispatch: - -permissions: - contents: write - pull-requests: write - -jobs: - translate-zh: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t zh --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-zh - path: src/locales/zh.json - continue-on-error: true - - translate-ru: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t ru --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-ru - path: src/locales/ru.json - continue-on-error: true - - translate-pt: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t pt --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-pt - path: src/locales/pt.json - continue-on-error: true - - translate-fr: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t fr --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-fr - path: src/locales/fr.json - continue-on-error: true - - translate-es: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t es --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-es - path: src/locales/es.json - continue-on-error: true - - translate-de: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t de --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-de - path: src/locales/de.json - continue-on-error: true - - translate-hi: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t hi --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-hi - path: src/locales/hi.json - continue-on-error: true - - translate-bn: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t bn --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-bn - path: src/locales/bn.json - continue-on-error: true - - translate-ja: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t ja --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-ja - path: src/locales/ja.json - continue-on-error: true - - translate-vi: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t vi --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-vi - path: src/locales/vi.json - continue-on-error: true - - translate-tr: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t tr --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-tr - path: src/locales/tr.json - continue-on-error: true - - translate-ko: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t ko --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-ko - path: src/locales/ko.json - continue-on-error: true - - translate-it: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t it --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-it - path: src/locales/it.json - continue-on-error: true - - translate-he: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t he --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-he - path: src/locales/he.json - continue-on-error: true - - translate-ar: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t ar --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-ar - path: src/locales/ar.json - continue-on-error: true - - translate-pl: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t pl --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-pl - path: src/locales/pl.json - continue-on-error: true - - translate-nl: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t nl --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-nl - path: src/locales/nl.json - continue-on-error: true - - translate-sv: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t sv --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-sv - path: src/locales/sv.json - continue-on-error: true - - translate-id: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t id --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-id - path: src/locales/id.json - continue-on-error: true - - translate-th: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t th --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-th - path: src/locales/th.json - continue-on-error: true - - translate-uk: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t uk --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-uk - path: src/locales/uk.json - continue-on-error: true - - translate-cs: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t cs --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-cs - path: src/locales/cs.json - continue-on-error: true - - translate-ro: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t ro --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-ro - path: src/locales/ro.json - continue-on-error: true - - translate-el: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t el --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-el - path: src/locales/el.json - continue-on-error: true - - translate-nb: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "20" - - run: npx i18n-auto-translation -k ${{ secrets.GOOGLE_TRANSLATE_API_KEY }} -d "src/locales" -f en -t nb --maxLinesPerRequest 1 - - uses: actions/upload-artifact@v4 - with: - name: translations-nb - path: src/locales/nb.json - continue-on-error: true - - create-pr: - needs: - [ - translate-zh, - translate-ru, - translate-pt, - translate-fr, - translate-es, - translate-de, - translate-hi, - translate-bn, - translate-ja, - translate-vi, - translate-tr, - translate-ko, - translate-it, - translate-he, - translate-ar, - translate-pl, - translate-nl, - translate-sv, - translate-id, - translate-th, - translate-uk, - translate-cs, - translate-ro, - translate-el, - translate-nb, - ] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - token: ${{ secrets.GHCR_TOKEN }} - - - name: Download all artifacts - uses: actions/download-artifact@v4 - with: - path: translations-temp - - - name: Move translations to src/locales - run: | - cp translations-temp/translations-zh/zh.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-ru/ru.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-pt/pt.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-fr/fr.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-es/es.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-de/de.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-hi/hi.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-bn/bn.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-ja/ja.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-vi/vi.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-tr/tr.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-ko/ko.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-it/it.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-he/he.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-ar/ar.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-pl/pl.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-nl/nl.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-sv/sv.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-id/id.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-th/th.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-uk/uk.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-cs/cs.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-ro/ro.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-el/el.json src/locales/ 2>/dev/null || true - cp translations-temp/translations-nb/nb.json src/locales/ 2>/dev/null || true - rm -rf translations-temp - - - name: Create Pull Request - uses: peter-evans/create-pull-request@v6 - with: - token: ${{ secrets.GHCR_TOKEN }} - commit-message: "chore: auto-translate to multiple languages" - branch: translations-update - delete-branch: true - title: "chore: Update translations for all languages" diff --git a/openapi.json b/openapi.json deleted file mode 100644 index 8c8c0a50..00000000 --- a/openapi.json +++ /dev/null @@ -1,2305 +0,0 @@ -{ - "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" } - } - } - } - } - } - } - } - } - } -} diff --git a/package-lock.json b/package-lock.json index 1c9d6013..bee9039d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,6 +34,7 @@ "@tailwindcss/vite": "^4.1.14", "@types/bcryptjs": "^2.4.6", "@types/cookie-parser": "^1.4.9", + "@types/cytoscape": "^3.21.9", "@types/jszip": "^3.4.0", "@types/multer": "^2.0.0", "@types/qrcode": "^1.5.5", @@ -56,6 +57,7 @@ "cmdk": "^1.1.1", "cookie-parser": "^1.4.7", "cors": "^2.8.5", + "cytoscape": "^3.33.1", "dotenv": "^17.2.0", "drizzle-orm": "^0.44.3", "express": "^5.1.0", @@ -72,6 +74,7 @@ "node-fetch": "^3.3.2", "qrcode": "^1.5.4", "react": "^19.1.0", + "react-cytoscapejs": "^2.0.0", "react-dom": "^19.1.0", "react-h5-audio-player": "^3.10.1", "react-hook-form": "^7.60.0", @@ -122,11 +125,60 @@ "husky": "^9.1.7", "lint-staged": "^16.2.3", "prettier": "3.6.2", + "swagger-jsdoc": "^6.2.8", "typescript": "~5.9.2", "typescript-eslint": "^8.40.0", "vite": "^7.1.5" } }, + "node_modules/@apidevtools/json-schema-ref-parser": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz", + "integrity": "sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.6", + "call-me-maybe": "^1.0.1", + "js-yaml": "^4.1.0" + } + }, + "node_modules/@apidevtools/openapi-schemas": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", + "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/@apidevtools/swagger-methods": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", + "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@apidevtools/swagger-parser": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz", + "integrity": "sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@apidevtools/json-schema-ref-parser": "^9.0.6", + "@apidevtools/openapi-schemas": "^2.0.4", + "@apidevtools/swagger-methods": "^3.0.2", + "@jsdevtools/ono": "^7.1.3", + "call-me-maybe": "^1.0.1", + "z-schema": "^5.0.1" + }, + "peerDependencies": { + "openapi-types": ">=7" + } + }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", @@ -2619,6 +2671,13 @@ "url": "https://opencollective.com/js-sdsl" } }, + "node_modules/@jsdevtools/ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", + "dev": true, + "license": "MIT" + }, "node_modules/@lezer/common": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.3.0.tgz", @@ -5228,6 +5287,12 @@ "@types/node": "*" } }, + "node_modules/@types/cytoscape": { + "version": "3.21.9", + "resolved": "https://registry.npmjs.org/@types/cytoscape/-/cytoscape-3.21.9.tgz", + "integrity": "sha512-JyrG4tllI6jvuISPjHK9j2Xv/LTbnLekLke5otGStjFluIyA9JjgnvgZrSBsp8cEDpiTjwgZUZwpPv8TSBcoLw==", + "license": "MIT" + }, "node_modules/@types/d3-array": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", @@ -6958,6 +7023,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/call-me-maybe": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", + "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", + "dev": true, + "license": "MIT" + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -7776,6 +7848,15 @@ "integrity": "sha512-cjrsQufETwxjvwZbYbKBCJNvmQ2++G9AvT45zDi7NXL9k2PdVcs2h0jQz96J6G4TMKRCcEsoJ+QTgQD00Igtjw==", "license": "MIT" }, + "node_modules/cytoscape": { + "version": "3.33.1", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz", + "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, "node_modules/d3-array": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", @@ -8304,6 +8385,19 @@ "license": "MIT", "optional": true }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/dompurify": { "version": "3.1.7", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.7.tgz", @@ -12195,6 +12289,14 @@ "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", "license": "MIT" }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead.", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -12207,6 +12309,14 @@ "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", "license": "MIT" }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.isinteger": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", @@ -14068,6 +14178,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/openapi-types": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", + "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -15109,6 +15227,19 @@ "node": ">=0.10.0" } }, + "node_modules/react-cytoscapejs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/react-cytoscapejs/-/react-cytoscapejs-2.0.0.tgz", + "integrity": "sha512-t3SSl1DQy7+JQjN+8QHi1anEJlM3i3aAeydHTsJwmjo/isyKK7Rs7oCvU6kZsB9NwZidzZQR21Vm2PcBLG/Tjg==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "cytoscape": "^3.2.19", + "react": ">=15.0.0" + } + }, "node_modules/react-dom": { "version": "19.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", @@ -16717,6 +16848,95 @@ "node": ">=8" } }, + "node_modules/swagger-jsdoc": { + "version": "6.2.8", + "resolved": "https://registry.npmjs.org/swagger-jsdoc/-/swagger-jsdoc-6.2.8.tgz", + "integrity": "sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "6.2.0", + "doctrine": "3.0.0", + "glob": "7.1.6", + "lodash.mergewith": "^4.6.2", + "swagger-parser": "^10.0.3", + "yaml": "2.0.0-1" + }, + "bin": { + "swagger-jsdoc": "bin/swagger-jsdoc.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/swagger-jsdoc/node_modules/commander": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz", + "integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/swagger-jsdoc/node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/swagger-jsdoc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/swagger-jsdoc/node_modules/yaml": { + "version": "2.0.0-1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.0.0-1.tgz", + "integrity": "sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/swagger-parser": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.3.tgz", + "integrity": "sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@apidevtools/swagger-parser": "10.0.3" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/tailwind-merge": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz", @@ -17566,6 +17786,16 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, + "node_modules/validator": { + "version": "13.15.26", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.26.tgz", + "integrity": "sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -18120,6 +18350,38 @@ "integrity": "sha512-YHDIOAqgRpfl1Ois9HcB8UFtWOxK8KJrV5TXpImj4BKYP1rWT04f/fMM9tQ9SYZlBKukT7NR+9wcI3UpB5BMDQ==", "license": "MIT" }, + "node_modules/z-schema": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.5.tgz", + "integrity": "sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "validator": "^13.7.0" + }, + "bin": { + "z-schema": "bin/z-schema" + }, + "engines": { + "node": ">=8.0.0" + }, + "optionalDependencies": { + "commander": "^9.4.1" + } + }, + "node_modules/z-schema/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, "node_modules/zod": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz", diff --git a/package.json b/package.json index 47a8de68..1e8098b1 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "build": "vite build && tsc -p tsconfig.node.json", "build:backend": "tsc -p tsconfig.node.json", "dev:backend": "tsc -p tsconfig.node.json && node ./dist/backend/backend/starter.js", + "generate:openapi": "tsc -p tsconfig.node.json && node ./dist/backend/backend/swagger.js", "preview": "vite preview", "electron:dev": "concurrently \"npm run dev\" \"powershell -c \\\"Start-Sleep -Seconds 5\\\" && electron .\"", "build:win-portable": "npm run build && electron-builder --win --dir", @@ -144,6 +145,7 @@ "husky": "^9.1.7", "lint-staged": "^16.2.3", "prettier": "3.6.2", + "swagger-jsdoc": "^6.2.8", "typescript": "~5.9.2", "typescript-eslint": "^8.40.0", "vite": "^7.1.5" diff --git a/src/backend/database/routes/users.ts b/src/backend/database/routes/users.ts index 192fa2dd..4ae24f40 100644 --- a/src/backend/database/routes/users.ts +++ b/src/backend/database/routes/users.ts @@ -2656,3 +2656,5 @@ router.post("/totp/verify-login", async (req, res) => { return res.status(500).json({ error: "TOTP verification failed" }); } }); + +export default router; diff --git a/src/backend/swagger.ts b/src/backend/swagger.ts new file mode 100644 index 00000000..cd30ad91 --- /dev/null +++ b/src/backend/swagger.ts @@ -0,0 +1,145 @@ +import swaggerJSDoc from "swagger-jsdoc"; +import path from "path"; +import { fileURLToPath } from "url"; +import { promises as fs } from "fs"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const projectRoot = path.join(__dirname, "..", "..", ".."); + +const swaggerOptions: swaggerJSDoc.Options = { + definition: { + openapi: "3.0.3", + info: { + title: "Termix API", + version: "0.0.0", + description: "Termix Backend API Reference", + }, + servers: [ + { + url: "http://localhost:30001", + description: "Main database and authentication server", + }, + { + url: "http://localhost:30003", + description: "SSH tunnel management server", + }, + { + url: "http://localhost:30004", + description: "SSH file manager server", + }, + { + url: "http://localhost:30005", + description: "Server statistics and monitoring server", + }, + { + url: "http://localhost:30006", + description: "Dashboard server", + }, + { + url: "http://localhost:30007", + description: "Docker management server", + }, + ], + components: { + securitySchemes: { + bearerAuth: { + type: "http", + scheme: "bearer", + bearerFormat: "JWT", + }, + }, + schemas: { + Error: { + type: "object", + properties: { + error: { type: "string" }, + details: { type: "string" }, + }, + }, + }, + }, + security: [ + { + bearerAuth: [], + }, + ], + tags: [ + { + name: "Alerts", + description: "System alerts and notifications management", + }, + { + name: "Credentials", + description: "SSH credential management", + }, + { + name: "Network Topology", + description: "Network topology visualization and management", + }, + { + name: "RBAC", + description: "Role-based access control for host sharing", + }, + { + name: "Snippets", + description: "Command snippet management", + }, + { + name: "Terminal", + description: "Terminal command history", + }, + { + name: "Users", + description: "User management and authentication", + }, + { + name: "Dashboard", + description: "Dashboard statistics and activity", + }, + { + name: "Docker", + description: "Docker container management", + }, + { + name: "SSH Tunnels", + description: "SSH tunnel connection management", + }, + { + name: "Server Stats", + description: "Server status monitoring and metrics collection", + }, + { + name: "File Manager", + description: "SSH file management operations", + }, + ], + }, + apis: [ + path.join(projectRoot, "src", "backend", "database", "routes", "*.ts"), + path.join(projectRoot, "src", "backend", "dashboard.ts"), + path.join(projectRoot, "src", "backend", "ssh", "*.ts"), + ], +}; + +async function generateOpenAPISpec() { + try { + const swaggerSpec = swaggerJSDoc(swaggerOptions); + + const outputPath = path.join(projectRoot, "openapi.json"); + + await fs.writeFile( + outputPath, + JSON.stringify(swaggerSpec, null, 2), + "utf-8", + ); + } catch (error) { + console.error("Failed to generate OpenAPI specification:", error); + process.exit(1); + } +} + +generateOpenAPISpec(); + +export { swaggerOptions, generateOpenAPISpec };