Files
Kuddev bf2ed9af9b feat(mobile): integrate remote terminal, SSH and reader workflows (#343)
Integrate the Android client with native desktop pairing, remote terminal and SSH/SFTP sessions, keyboard controls, file reading and Agent conversations. Preserve authenticated connection ownership and per-device input permissions.

Validation: all ten required GitHub checks passed, including five native test platforms and both macOS release workspace checks.
2026-09-29 20:09:00 +08:00

33 lines
2.4 KiB
JavaScript

import { randomBytes } from 'node:crypto';
import { mkdirSync, writeFileSync, readFileSync, existsSync } from 'node:fs';
import path from 'node:path';
import { createInvitation } from './invite.mjs';
const urlIndex = process.argv.indexOf('--url');
const nameIndex = process.argv.indexOf('--name');
const outputIndex = process.argv.indexOf('--output');
if (urlIndex < 0) throw new Error('Usage: node init.mjs --url wss://relay.example.com --name MyPC --output private');
const url = new URL(process.argv[urlIndex + 1]);
if (url.protocol !== 'wss:' || url.port || url.username || url.password || url.search || url.hash || !['/', ''].includes(url.pathname)) throw new Error('Use wss://your-domain on port 443 with no path or credentials');
const directory = path.resolve(outputIndex < 0 ? 'private' : process.argv[outputIndex + 1]);
const name = nameIndex < 0 ? 'Pebrel PC' : process.argv[nameIndex + 1];
const id = randomBytes(12).toString('hex');
const device = { id, desktopToken: randomBytes(32).toString('base64url'), mobileToken: randomBytes(32).toString('base64url') };
mkdirSync(directory, { recursive: true, mode: 0o700 });
const serverFile = path.join(directory, 'relay.config.json');
const server = existsSync(serverFile) ? JSON.parse(readFileSync(serverFile, 'utf8')) : { devices: [] };
if (!Array.isArray(server.devices) || server.devices.length >= 64) throw new Error('configure_at_most_64_devices');
server.devices.push(device);
writeFileSync(serverFile, JSON.stringify(server, null, 2) + '\n', { mode: 0o600 });
writeFileSync(path.join(directory, `computer-${id}.json`), JSON.stringify({ url: url.origin.replace('https:', 'wss:'), device: id, token: device.desktopToken, name }, null, 2), { flag: 'wx', mode: 0o600 });
const invitation = createInvitation({ url: url.toString(), device: id, token: device.mobileToken, name });
writeFileSync(path.join(directory, `phone-${id}.txt`), JSON.stringify(invitation), { flag: 'wx', mode: 0o600 });
const envFile = path.resolve('.env');
if (!existsSync(envFile)) {
const uid = process.getuid?.() ?? 1000;
const gid = process.getgid?.() ?? 1000;
writeFileSync(envFile, `PEBREL_RELAY_DOMAIN=${url.host}\nPEBREL_RELAY_UID=${uid}\nPEBREL_RELAY_GID=${gid}\n`, { flag: 'wx', mode: 0o600 });
}
console.log(`Created relay.config.json, computer-${id}.json and phone-${id}.txt in ${directory}`);
console.log('Keep these credentials private. Import the phone file in the Android app; copy only the computer file to the desktop.');