feat: add share_key for Samba password, sync smbpasswd on startup

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
stswangzhiping
2026-05-04 14:17:28 +08:00
parent 4be305d0e2
commit f8789876f5
3 changed files with 47 additions and 1 deletions

View File

@@ -7,6 +7,7 @@ require('../lib/systemd-env');
const path = require('path'); const path = require('path');
const { exec } = require('child_process'); const { exec } = require('child_process');
const { ClawClient } = require('../lib/client'); const { ClawClient } = require('../lib/client');
const config = require('../lib/config');
const log = require('../lib/logger'); const log = require('../lib/logger');
const { pollSms } = require('../drivers/sim/sms-reader'); const { pollSms } = require('../drivers/sim/sms-reader');
@@ -17,6 +18,16 @@ exec(`bash "${bindScript}"`, (err, stdout, stderr) => {
else log.info('clawd', `bind-quectel-serial: ok`); else log.info('clawd', `bind-quectel-serial: ok`);
}); });
// 同步 Samba 共享密码idempotent失败不影响主流程
const cfg = config.load();
if (cfg.share_key) {
const shareKey = cfg.share_key.replace(/'/g, "'\\''");
exec(`printf '%s\\n%s\\n' '${shareKey}' '${shareKey}' | smbpasswd -a sts -s 2>/dev/null`, (err) => {
if (err) log.warn('clawd', `smbpasswd sync failed (samba not installed?): ${err.message}`);
else log.info('clawd', 'smbpasswd synced for user sts');
});
}
let smsTimer = null; let smsTimer = null;
let smsPolling = false; let smsPolling = false;

View File

@@ -377,6 +377,7 @@ class ClawClient {
token: this._cfg.token ?? null, token: this._cfg.token ?? null,
version: CLAWD_VERSION, version: CLAWD_VERSION,
ssh_secret_key: this._cfg.ssh_secret_key ?? null, ssh_secret_key: this._cfg.ssh_secret_key ?? null,
share_key: this._cfg.share_key ?? null,
headscale_joined: headscale.isInstalled() && headscale.isJoined(this._cfg.headscale_server || 'https://hs.claw.cutos.ai'), headscale_joined: headscale.isInstalled() && headscale.isJoined(this._cfg.headscale_server || 'https://hs.claw.cutos.ai'),
local_ip: getLocalIps(), local_ip: getLocalIps(),
local_networks: getLocalNetworks(), local_networks: getLocalNetworks(),

View File

@@ -20,6 +20,7 @@ const DEFAULTS = {
/** 云端已激活:用于启动/重连时立即点亮 alarmpwr不等首包 connected */ /** 云端已激活:用于启动/重连时立即点亮 alarmpwr不等首包 connected */
activated: false, activated: false,
ssh_secret_key: null, ssh_secret_key: null,
share_key: null,
headscale_server: 'https://hs.claw.cutos.ai', headscale_server: 'https://hs.claw.cutos.ai',
}; };
@@ -28,6 +29,33 @@ function _generateSshSecretKey() {
return 'sk-' + bytes.toString('hex'); 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() { function load() {
let cfg; let cfg;
try { try {
@@ -41,10 +69,16 @@ function load() {
} }
if (!cfg) cfg = Object.assign({}, DEFAULTS); if (!cfg) cfg = Object.assign({}, DEFAULTS);
let dirty = false;
if (!cfg.ssh_secret_key) { if (!cfg.ssh_secret_key) {
cfg.ssh_secret_key = _generateSshSecretKey(); cfg.ssh_secret_key = _generateSshSecretKey();
save(cfg); dirty = true;
} }
if (!cfg.share_key) {
cfg.share_key = _generateShareKey();
dirty = true;
}
if (dirty) save(cfg);
return cfg; return cfg;
} }