From 72d2c8d0ce5080ebf697df2acc97f77bec1ad102 Mon Sep 17 00:00:00 2001 From: chaos-zhu Date: Sat, 16 May 2026 15:47:38 +0800 Subject: [PATCH] test: add mobile ssh payload shaping --- server/app/controller/mobile.js | 47 ++++++++++++++++++++++ server/test/test-mobile-ssh-payload.js | 54 ++++++++++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 server/app/controller/mobile.js create mode 100644 server/test/test-mobile-ssh-payload.js diff --git a/server/app/controller/mobile.js b/server/app/controller/mobile.js new file mode 100644 index 0000000..c5da02c --- /dev/null +++ b/server/app/controller/mobile.js @@ -0,0 +1,47 @@ +const { RSADecryptAsync } = require('../utils/encrypt') +const { encryptJsonForMobile } = require('../utils/mobile-crypto') + +function toMobileSshPayload(hostId, name, authInfo) { + const { host, port, username, authType } = authInfo + if (!['password', 'privateKey'].includes(authType)) { + throw new Error(`unsupported mobile ssh auth type: ${ authType || 'empty' }`) + } + + return { + hostId, + name, + host, + port: Number(port || 22), + username, + authType, + password: authType === 'password' ? authInfo.password || '' : '', + privateKey: authType === 'privateKey' ? authInfo.privateKey || '' : '', + passphrase: authType === 'privateKey' ? authInfo.passphrase || '' : '' + } +} + +async function getMobileSshConnection({ request, res }) { + try { + const { hostId, encryptedKey } = request.body || {} + if (!hostId || !encryptedKey) { + return res.fail({ msg: 'missing params: hostId or encryptedKey' }) + } + + const tempKeyText = await RSADecryptAsync(encryptedKey) + const tempKey = Buffer.from(tempKeyText, 'base64') + const { getConnectionOptions } = require('../socket/terminal') + const { authInfo, name } = await getConnectionOptions(hostId) + const payload = toMobileSshPayload(hostId, name, authInfo) + const data = encryptJsonForMobile(payload, tempKey) + + return res.success({ data, msg: 'success' }) + } catch (error) { + logger.error('getMobileSshConnection error:', error.message) + return res.fail({ msg: error.message || 'mobile ssh connection failed' }) + } +} + +module.exports = { + getMobileSshConnection, + toMobileSshPayload +} diff --git a/server/test/test-mobile-ssh-payload.js b/server/test/test-mobile-ssh-payload.js new file mode 100644 index 0000000..8e3ffd4 --- /dev/null +++ b/server/test/test-mobile-ssh-payload.js @@ -0,0 +1,54 @@ +const assert = require('assert') +const { toMobileSshPayload } = require('../app/controller/mobile') + +function testPasswordPayload() { + const payload = toMobileSshPayload('h1', 'prod', { + host: '10.0.0.2', + port: 22, + username: 'root', + authType: 'password', + password: 'p@ss' + }) + + assert.deepStrictEqual(payload, { + hostId: 'h1', + name: 'prod', + host: '10.0.0.2', + port: 22, + username: 'root', + authType: 'password', + password: 'p@ss', + privateKey: '', + passphrase: '' + }) +} + +function testPrivateKeyPayload() { + const payload = toMobileSshPayload('h2', 'keyhost', { + host: '10.0.0.3', + port: 2222, + username: 'ubuntu', + authType: 'privateKey', + privateKey: 'KEY', + passphrase: 'phrase' + }) + + assert.strictEqual(payload.authType, 'privateKey') + assert.strictEqual(payload.privateKey, 'KEY') + assert.strictEqual(payload.password, '') + assert.strictEqual(payload.passphrase, 'phrase') +} + +function testRejectsUnsupportedAuth() { + assert.throws(() => toMobileSshPayload('h3', 'unsupported', { + host: '10.0.0.4', + port: 22, + username: 'root', + authType: 'keyboard' + }), /unsupported mobile ssh auth type/) +} + +testPasswordPayload() +testPrivateKeyPayload() +testRejectsUnsupportedAuth() +console.log('test-mobile-ssh-payload passed')