UNPKG

ssh-terminal

Version:

SSH Terminal component based on xterm.js for multiple frontend frameworks

577 lines (470 loc) 16.3 kB
# Vue SSH Terminal Vue SSH Terminal là một component dựa trên [xterm.js](https://github.com/xtermjs/xterm.js) để sử dụng trong nhiều frontend khác nhau, cho phép kết nối SSH thông qua WebSocket. ## Tính năng - **🆔 Computing ID Authentication**: Kết nối thông qua LongVan Computing ID - **🔒 Zero Password**: Không cần biết SSH password, server tự động lấy credentials - **🌐 WebSocket Connection**: Kết nối SSH thông qua WebSocket an toàn - **🎯 Zero Configuration**: Chỉ cần Computing ID và User Token - **🔧 Multi-Framework**: Hỗ trợ Vue 2, Vue 3, và Web Component - **🎨 Customizable**: Tùy chỉnh giao diện terminal (font, theme, cursor) - **📱 Responsive**: Tự động resize terminal khi thay đổi kích thước cửa sổ ### 🔒 Tính Năng Bảo Mật Nâng Cao (v2.0+) - **🔐 Mandatory RSA Encryption**: Bắt buộc mã hóa passwords - không hỗ trợ plaintext - **🚫 Legacy Auth Disabled**: Hoàn toàn loại bỏ plaintext authentication - **✅ Input Validation**: Xác thực nghiêm ngặt tất cả đầu vào - **🔍 Secure Logging**: Không log thông tin nhạy cảm ra console - **📏 Message Size Validation**: Kiểm tra kích thước message để tránh DoS - **🛡️ Error Sanitization**: Thông báo lỗi không tiết lộ thông tin hệ thống - **🔒 Credentials Protection**: Credentials không lộ trong DOM attributes - **🧹 Input Sanitization**: Làm sạch dữ liệu đầu vào - **⚡ Fail-Fast Security**: Ngắt kết nối ngay khi encryption fails ### 🚀 Universal Environment Support (v2.5+) - **🌐 Production-Ready Compatibility**: Hoạt động hoàn hảo trên mọi HTTP và HTTPS environments - **🔧 Advanced Dual Encryption**: Web Crypto API (HTTPS) + micro-rsa-dsa-dh (HTTP) với real RSA-OAEP - **🎨 Professional Clean UI**: Giao diện production-ready, ẩn connection logs mặc định - **📦 Zero-Dependency Deployment**: Tích hợp sẵn tất cả crypto libraries, không cần external CDN - **⚡ Intelligent Detection**: Tự động chọn phương thức mã hóa tối ưu cho từng environment - **🛡️ Enterprise Security**: Real encryption trong mọi môi trường, không có mock implementations ### 🚀 Tính Năng Khác - **Production Bundle**: Web component ~372KB (bao gồm enterprise-grade crypto libraries) - **Auto-reconnection**: Tự động kết nối lại khi mất connection với exponential backoff - **Connection stability**: Heartbeat mechanism để maintain WebSocket connection - **Consistent CSS approach**: Tất cả components sử dụng external CSS files ## Cài đặt ```bash npm install ssh-terminal ``` > **⚠️ Lưu ý quan trọng**: Tất cả components đều yêu cầu import CSS file riêng để hiển thị đúng. ## 🚀 Quick Start ### Computing ID (Recommended) Cách nhanh nhất để kết nối với LongVan Computing instances: #### Vue 2 ```vue <template> <SSHTerminal :computing-id="computingId" :user-token="userToken" :websocket-url="websocketUrl" /> </template> <script> import { SSHTerminal } from 'ssh-terminal/vue2'; import 'ssh-terminal/dist/vue2/ssh-terminal-vue2.css'; export default { components: { SSHTerminal }, data() { return { computingId: '20.5109.3964', userToken: 'your-longvan-token', websocketUrl: 'wss://ssh-proxy.dev.longvan.vn' }; } }; </script> ``` #### Vue 3 ```vue <template> <SSHTerminal :computing-id="computingId" :user-token="userToken" :websocket-url="websocketUrl" /> </template> <script setup> import { ref } from 'vue'; import { SSHTerminal } from 'ssh-terminal/vue3'; import 'ssh-terminal/dist/vue3/ssh-terminal-vue3.css'; const computingId = ref('20.5109.3964'); const userToken = ref('your-longvan-token'); const websocketUrl = ref('wss://ssh-proxy.dev.longvan.vn'); </script> ``` #### JavaScript thuần ```html <!DOCTYPE html> <html> <head> <script type="module"> import { SSHTerminalElement } from 'ssh-terminal'; if (!customElements.get('ssh-terminal')) { customElements.define('ssh-terminal', SSHTerminalElement); } </script> </head> <body> <ssh-terminal id="terminal"></ssh-terminal> <script> const terminal = document.getElementById('terminal'); // Cấu hình Computing ID terminal.setConfig({ computingId: '20.5109.3964', userToken: 'your-longvan-token', wsUrl: 'wss://ssh-proxy.dev.longvan.vn' }); // Lắng nghe sự kiện terminal.addEventListener('ready', () => { console.log('Connected to computing instance'); }); </script> </body> </html> ``` ## Sử dụng ### Vue 3 ```vue <template> <div class="terminal-container"> <!-- Computing ID Authentication --> <SSHTerminal :computing-id="computingId" :user-token="userToken" :websocket-url="websocketUrl" :options="options" @ready="onTerminalReady" /> </div> </template> <script setup> import { ref } from 'vue'; import { SSHTerminal } from 'ssh-terminal/vue3'; import 'ssh-terminal/dist/vue3/ssh-terminal-vue3.css'; // Computing ID authentication const computingId = ref('20.5109.3964'); const userToken = ref('your-longvan-token'); const websocketUrl = ref('wss://ssh-proxy.dev.longvan.vn'); const options = ref({ fontSize: 14, theme: { background: '#1e1e1e', foreground: '#f0f0f0' } }); function onTerminalReady(terminal) { // Terminal connected to computing instance console.log('Connected to computing:', computingId.value); } </script> <style> .terminal-container { width: 100%; height: 500px; } </style> ``` ### Web Component ```bash npm install ssh-terminal ``` ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>SSH Terminal - Computing ID</title> <script type="module"> import { SSHTerminalElement } from 'ssh-terminal'; if (!customElements.get('ssh-terminal')) { customElements.define('ssh-terminal', SSHTerminalElement); } </script> <style> .terminal-container { width: 800px; height: 500px; margin: 20px auto; } </style> </head> <body> <div class="terminal-container"> <!-- Computing ID Authentication --> <ssh-terminal id="terminal"></ssh-terminal> </div> <script> // 🆔 Set Computing ID configuration const terminal = document.getElementById('terminal'); terminal.setConfig({ computingId: '20.5109.3964', userToken: 'your-longvan-token', wsUrl: 'wss://ssh-proxy.dev.longvan.vn' }); terminal.addEventListener('ready', (event) => { console.log('Connected to computing instance'); }); </script> </body> </html> ``` #### Sử dụng trực tiếp từ CDN (không cần npm) ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>SSH Terminal Example</title> <!-- Sử dụng từ unpkg CDN --> <script src="https://unpkg.com/ssh-terminal@2.1.2/dist/web-component/ssh-terminal.umd.js"></script> <!-- Hoặc sử dụng từ jsDelivr --> <!-- <script src="https://cdn.jsdelivr.net/npm/ssh-terminal@2.1.2/dist/web-component/ssh-terminal.umd.js"></script> --> <!-- Lưu ý: Web component tự động inject CSS vào shadow DOM, không cần import CSS riêng --> <!-- Các phần tử helper của xterm.js sẽ được giữ trong shadow DOM của web component --> <style> .terminal-container { width: 800px; height: 500px; margin: 20px auto; } </style> </head> <body> <div class="terminal-container"> <!-- ✅ Secure way (v2.0+) --> <ssh-terminal id="terminal" ws-url="wss://ssh-proxy.dev.longvan.vn"></ssh-terminal> </div> <script> // 🆔 Set Computing ID configuration const terminal = document.getElementById('terminal'); terminal.setConfig({ computingId: '20.5109.3964', userToken: 'your-longvan-token', wsUrl: 'wss://ssh-proxy.dev.longvan.vn' }); terminal.addEventListener('ready', (event) => { console.log('Connected to computing instance'); }); </script> </body> </html> ``` #### Tải xuống và sử dụng trực tiếp Bạn cũng có thể tải xuống file sau và sử dụng trực tiếp: - `ssh-terminal.umd.js` (CSS được inject tự động) ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>SSH Terminal Example</title> <script src="path/to/ssh-terminal.umd.js"></script> <!-- CSS được inject tự động vào shadow DOM --> <style> .terminal-container { width: 800px; height: 500px; margin: 20px auto; } </style> </head> <body> <div class="terminal-container"> <!-- ✅ Secure way (v2.0+) --> <ssh-terminal id="terminal"></ssh-terminal> </div> <script> // 🆔 Set Computing ID configuration const terminal = document.getElementById('terminal'); terminal.setConfig({ computingId: '20.5109.3964', userToken: 'your-longvan-token', wsUrl: 'wss://ssh-proxy.dev.longvan.vn' }); terminal.addEventListener('ready', (event) => { console.log('Connected to computing instance'); }); </script> </body> </html> ``` ## 🔧 Framework Integration ### Nuxt 2 #### Plugin Setup Tạo file `plugins/ssh-terminal.client.js`: ```javascript import Vue from 'vue' import { Vue2SSHTerminal } from 'ssh-terminal/vue2' // Register component globally (CSS tự động inject) Vue.component('SSHTerminal', Vue2SSHTerminal) ``` Đăng ký plugin trong `nuxt.config.js`: ```javascript export default { plugins: [ { src: '~/plugins/ssh-terminal.client.js', mode: 'client' } ] } ``` #### Sử dụng trong component ```vue <template> <div class="terminal-container"> <SSHTerminal :computing-id="computingId" :user-token="userToken" :websocket-url="websocketUrl" @ready="onTerminalReady" @error="onTerminalError" /> </div> </template> <script> export default { data() { return { computingId: '20.5109.3964', userToken: 'your-longvan-token', websocketUrl: 'wss://ssh-proxy.dev.longvan.vn' } }, methods: { onTerminalReady(terminal) { console.log('✅ Terminal ready!') }, onTerminalError(error) { console.error('❌ Terminal error:', error) } } } </script> <style scoped> .terminal-container { width: 100%; height: 500px; } </style> ``` ## 🆔 Computing ID Authentication Kết nối SSH thông qua LongVan Computing ID - không cần biết SSH credentials. ### Flow hoạt động: 1. **Client gửi Computing ID + User Token** (encrypted) 2. **Server query LongVan GraphQL API** để lấy SSH credentials 3. **Automatic SSH connection** với credentials từ API 4. **Terminal ready** - zero password approach ### Ví dụ sử dụng: ```javascript // Mặc định: Clean UI (không hiển thị connection logs) terminal.setConfig({ computingId: '20.5109.3964', userToken: 'your-longvan-token', wsUrl: 'wss://ssh-proxy.dev.longvan.vn' }); // Debug mode: Hiển thị connection logs terminal.setConfig({ computingId: '20.5109.3964', userToken: 'your-longvan-token', wsUrl: 'wss://ssh-proxy.dev.longvan.vn' }, { showConnectionLogs: true }); ``` ### Ưu điểm: - ✅ **Zero password approach** - không cần biết SSH credentials - ✅ **Tự động lấy thông tin từ LongVan GraphQL API** - ✅ **Token-based authentication** - ✅ **Secure encryption cho user token** - ✅ **Seamless user experience** ## API ### Props (Vue Components) | Prop | Kiểu dữ liệu | Bắt buộc | Validation | Mô tả | |------|--------------|----------|------------|-------| | computingId | String | Có | Valid computing ID format | LongVan Computing instance ID | | userToken | String | Có | Valid token format | LongVan user authentication token | | websocketUrl | String | Có | Valid WebSocket URL | URL của SSH Terminal server | | options | Object | Không | - | Các tùy chọn cho terminal | ### Web Component Methods (v2.0+) #### `setConfig(config)` **Secure method** để set Computing ID configuration: ```javascript terminal.setConfig({ computingId: '20.5109.3964', userToken: 'your-longvan-token', wsUrl: 'wss://ssh-proxy.dev.longvan.vn' }); ``` **Parameters:** - `config.computingId` (String, required): LongVan Computing instance ID - `config.userToken` (String, required): LongVan user authentication token (auto-encrypted with RSA) - `config.wsUrl` (String, required): SSH Terminal server WebSocket URL **Security Notes:** - User token is automatically encrypted with RSA before transmission - No plaintext credentials are ever sent over the network - Server validates all inputs before processing ### Events | Event | Tham số | Mô tả | |-------|---------|-------| | ready | terminal | Được gọi khi terminal đã sẵn sàng, trả về đối tượng terminal | | error | { message, code } | Được gọi khi có lỗi xảy ra (authentication, connection, etc.) | | close | { code, reason } | Được gọi khi connection bị đóng | | computing-connected | { computingId, host, username } | Được gọi khi Computing ID authentication thành công (v2.0+) | ### Terminal Options | Option | Kiểu dữ liệu | Mặc định | Mô tả | |--------|--------------|----------|-------| | fontSize | Number | 14 | Kích thước font | | fontFamily | String | 'Menlo, Monaco, "Courier New", monospace' | Font family | | theme | Object | { background: '#000000', foreground: '#ffffff', ... } | Theme cho terminal | | cursorBlink | Boolean | true | Bật/tắt nhấp nháy con trỏ | | cursorStyle | String | 'block' | Kiểu con trỏ ('block', 'underline', 'bar') | | scrollback | Number | 1000 | Số dòng lưu trong bộ nhớ để cuộn lại | | reconnection | Object | {...} | Cấu hình auto-reconnection | | reconnection.enabled | Boolean | true | Bật/tắt auto-reconnection | | reconnection.maxAttempts | Number | 5 | Số lần thử kết nối lại tối đa | | reconnection.heartbeatInterval | Number | 30000 | Khoảng thời gian ping (ms) | ## 🐛 Troubleshooting ### Vue Version Compatibility Issues **Error:** `TypeError: (0 , vue__WEBPACK_IMPORTED_MODULE_4__.openBlock) is not a function` **Cause:** Using Vue 3 APIs in Vue 2 environment or vice versa. **Solution:** Use the correct version-specific import: ```javascript // ✅ For Vue 2 projects import { SSHTerminal } from 'ssh-terminal/vue2'; import 'ssh-terminal/dist/vue2/ssh-terminal-vue2.css'; // ✅ For Vue 3 projects import { SSHTerminal } from 'ssh-terminal/vue3'; import 'ssh-terminal/dist/vue3/ssh-terminal-vue3.css'; // ❌ Avoid generic import if you have version conflicts import { Vue2SSHTerminal, Vue3SSHTerminal } from 'ssh-terminal'; ``` ### Container Element Required Error **Error:** `Error: Container element is required` **Cause:** Terminal container element is not available when `createTerminal` is called. **Solution:** Ensure the container element exists in DOM: ```javascript // ✅ Wait for element to be available onMounted(() => { const container = terminalContainer.value; if (container) { initTerminal(); } }); // ✅ For Web Component, use setConfig() after element is connected const terminal = document.getElementById('terminal'); if (terminal) { terminal.setConfig({ computingId: '20.5109.3964', userToken: 'your-longvan-token', wsUrl: 'wss://ssh-proxy.dev.longvan.vn' }); } ``` ### CSS Not Loading **Problem:** Terminal appears but styling is broken. **Solution:** Make sure to import the CSS file: ```javascript // For Vue 2 import 'ssh-terminal/dist/vue2/ssh-terminal-vue2.css'; // For Vue 3 import 'ssh-terminal/dist/vue3/ssh-terminal-vue3.css'; // For generic build import 'ssh-terminal/dist/ssh-terminal.css'; ``` ## Đóng góp Mọi đóng góp đều được chào đón! Vui lòng tạo issue hoặc pull request trên GitHub. ## Giấy phép MIT