98 lines
2.8 KiB
JavaScript
98 lines
2.8 KiB
JavaScript
'use strict';
|
|
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const { getConfigDir } = require('./platform-paths');
|
|
|
|
// 生产环境用 /etc/clawd/,开发环境用 ~/.clawd/
|
|
const CONFIG_DIR = getConfigDir();
|
|
|
|
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
|
|
const DEFAULTS = {
|
|
server: 'wss://claw.cutos.ai/ws',
|
|
claw_id: null,
|
|
token: null,
|
|
heartbeat_interval: 30, // 秒
|
|
/** 云端已激活:用于启动/重连时立即点亮 alarm(pwr),不等首包 connected */
|
|
activated: false,
|
|
ssh_secret_key: null,
|
|
share_key: null,
|
|
headscale_server: 'https://hs.claw.cutos.ai',
|
|
};
|
|
|
|
function _generateSshSecretKey() {
|
|
const bytes = require('crypto').randomBytes(16);
|
|
return 'sk-' + bytes.toString('hex');
|
|
}
|
|
|
|
/**
|
|
* 生成可读性好的 Samba 共享密码,格式:xxxxxx-xxxxxx-xxxxXX(三段各6字符,连字符分隔)。
|
|
* 最后一段包含至少1个大写字母和1个数字,其余为小写字母。
|
|
* 示例:juqhuf-hykgyh-mykGi3
|
|
*/
|
|
function _generateShareKey() {
|
|
const crypto = require('crypto');
|
|
const lower = 'abcdefghijklmnopqrstuvwxyz';
|
|
const upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
const digits = '0123456789';
|
|
|
|
function rndChars(chars, n) {
|
|
const bytes = crypto.randomBytes(n);
|
|
return Array.from(bytes).map(b => chars[b % chars.length]).join('');
|
|
}
|
|
|
|
const g1 = rndChars(lower, 6);
|
|
const g2 = rndChars(lower, 6);
|
|
// 第三段:4个小写 + 1个大写 + 1个数字,随机打乱顺序
|
|
const g3raw = (rndChars(lower, 4) + rndChars(upper, 1) + rndChars(digits, 1)).split('');
|
|
for (let i = g3raw.length - 1; i > 0; i--) {
|
|
const j = crypto.randomBytes(1)[0] % (i + 1);
|
|
[g3raw[i], g3raw[j]] = [g3raw[j], g3raw[i]];
|
|
}
|
|
return `${g1}-${g2}-${g3raw.join('')}`;
|
|
}
|
|
|
|
function load() {
|
|
let cfg;
|
|
try {
|
|
if (fs.existsSync(CONFIG_FILE)) {
|
|
const raw = fs.readFileSync(CONFIG_FILE, 'utf8');
|
|
cfg = Object.assign({}, DEFAULTS, JSON.parse(raw));
|
|
}
|
|
} catch (e) {
|
|
const log = require('./logger');
|
|
log.error('config', '读取配置失败,使用默认值:', e.message);
|
|
}
|
|
if (!cfg) cfg = Object.assign({}, DEFAULTS);
|
|
|
|
let dirty = false;
|
|
if (!cfg.ssh_secret_key) {
|
|
cfg.ssh_secret_key = _generateSshSecretKey();
|
|
dirty = true;
|
|
}
|
|
if (!cfg.share_key) {
|
|
cfg.share_key = _generateShareKey();
|
|
dirty = true;
|
|
}
|
|
if (dirty) save(cfg);
|
|
|
|
return cfg;
|
|
}
|
|
|
|
function save(data) {
|
|
try {
|
|
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
fs.writeFileSync(CONFIG_FILE, JSON.stringify(data, null, 2), 'utf8');
|
|
} catch (e) {
|
|
const log = require('./logger');
|
|
log.error('config', '写入配置失败:', e.message);
|
|
}
|
|
}
|
|
|
|
function getConfigPath() {
|
|
return CONFIG_FILE;
|
|
}
|
|
|
|
module.exports = { load, save, getConfigPath };
|