Files
WYF-koubo/scripts/ssh_patch_3002.py
T
2026-06-19 18:45:55 +08:00

210 lines
9.1 KiB
Python

import paramiko
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('152.136.232.83', port=22, username='root', password='Jianhua105', timeout=10)
def run(cmd):
print(f"\n>>> {cmd[:120]}")
stdin, stdout, stderr = client.exec_command(cmd, timeout=20)
out = stdout.read().decode('utf-8', errors='replace').strip()
err = stderr.read().decode('utf-8', errors='replace').strip()
if out: print(out[-600:])
if err: print(f"ERR: {err[-200:]}")
return out
# Backup
run("cp /www/wwwroot/ipzhinengti/server.js /www/wwwroot/ipzhinengti/server.js.bak.update")
run("cp /www/wwwroot/ipzhinengti/public/admin.html /www/wwwroot/ipzhinengti/public/admin.html.bak.update")
# === Patch 1: server.js - add UPDATE_COS keys to publicKeys and compute update_url ===
patch_server = r'''const fs = require('fs');
const filePath = '/www/wwwroot/ipzhinengti/server.js';
let content = fs.readFileSync(filePath, 'utf-8');
if (content.includes('UPDATE_COS_BUCKET')) {
console.log('SKIP: already patched');
process.exit(0);
}
// 1. Add UPDATE_COS keys to publicKeys array
const marker1 = " 'cloud_beauty_enabled'";
const replacement1 = marker1 + ",\n 'UPDATE_COS_BUCKET',\n 'UPDATE_COS_REGION',\n 'UPDATE_COS_PATH'";
content = content.replace(marker1, replacement1);
// 2. Replace the res.json to add update_url computation
const marker2 = "res.json({ success: true, config })";
const replacement2 = `const cosBucket = config.UPDATE_COS_BUCKET || ''
const cosRegion = config.UPDATE_COS_REGION || ''
const updatePath = config.UPDATE_COS_PATH || 'updates'
let updateUrl = ''
if (cosBucket && cosRegion) {
updateUrl = 'https://' + cosBucket + '.cos.' + cosRegion + '.myqcloud.com/' + updatePath
}
res.json({ success: true, config, update_url: updateUrl })`;
content = content.replace(marker2, replacement2);
fs.writeFileSync(filePath, content, 'utf-8');
console.log('OK: patched server.js');
'''
sftp = client.open_sftp()
with sftp.open('/tmp/patch_server.js', 'w') as f:
f.write(patch_server)
sftp.close()
run("node /tmp/patch_server.js")
run("node --check /www/wwwroot/ipzhinengti/server.js 2>&1")
# === Patch 2: admin.html - add UPDATE_COS config section ===
patch_admin = r'''const fs = require('fs');
const filePath = '/www/wwwroot/ipzhinengti/public/admin.html';
let content = fs.readFileSync(filePath, 'utf-8');
if (content.includes('UPDATE_COS_BUCKET')) {
console.log('SKIP: already patched');
process.exit(0);
}
// 1. Add to CONFIG_KEYS array
const keysMarker = "'cloud_beauty_enabled'";
content = content.replace(keysMarker, keysMarker + ", 'UPDATE_COS_BUCKET', 'UPDATE_COS_REGION', 'UPDATE_COS_PATH'");
// 2. Add save values
const saveMarker = "cloud_beauty_enabled: document.getElementById('cfg_cloud_beauty_enabled').checked ? 'true' : 'false',";
const saveReplacement = saveMarker + "\n UPDATE_COS_BUCKET: document.getElementById('cfg_UPDATE_COS_BUCKET').value,\n UPDATE_COS_REGION: document.getElementById('cfg_UPDATE_COS_REGION').value,\n UPDATE_COS_PATH: document.getElementById('cfg_UPDATE_COS_PATH').value,";
content = content.replace(saveMarker, saveReplacement);
// 3. Add HTML section after cloud_beauty section
const htmlMarker = "document.getElementById('cfg_cloud_beauty_enabled').checked = config.cloud_beauty_enabled === 'true';";
const htmlSection = htmlMarker + `
document.getElementById('cfg_UPDATE_COS_BUCKET').value = config.UPDATE_COS_BUCKET || '';
document.getElementById('cfg_UPDATE_COS_REGION').value = config.UPDATE_COS_REGION || '';
document.getElementById('cfg_UPDATE_COS_PATH').value = config.UPDATE_COS_PATH || '';`;
content = content.replace(htmlMarker, htmlSection);
// 4. Add form HTML - find the closing tag after cloud_beauty section
const formMarker = "<label>\\u542f\\u7528\\u4e91\\u7f8e\\u989c</label>";
const formSection = formMarker + `</div>
</div>
<h3 style="grid-column:1/-1;margin:15px 0 8px;padding-bottom:8px;border-bottom:1px solid #e2e8f0;">\\u81ea\\u52a8\\u66f4\\u65b0 COS \\u914d\\u7f6e</h3>
<div class="form-group"><label>\\u66f4\\u65b0\\u6876\\u540d</label><input type="text" id="cfg_UPDATE_COS_BUCKET" placeholder="xiazaigengxin-1417293730"></div>
<div class="form-group"><label>\\u5730\\u57df</label><input type="text" id="cfg_UPDATE_COS_REGION" placeholder="ap-guangzhou"></div>
<div class="form-group"><label>\\u66f4\\u65b0\\u8def\\u5f84</label><input type="text" id="cfg_UPDATE_COS_PATH" placeholder="updates"></div>
</div>
</div>
</div>
</div>
</body>
</html>`;
// Actually, let's find a better insertion point - the last form-group before save button
// Simpler: just append before the save button div
fs.writeFileSync(filePath, content, 'utf-8');
console.log('OK: patched admin.html');
'''
# Actually the admin.html patch is complex, let me use a simpler approach
# Just add the form fields after the cloud_beauty section
patch_admin2 = r'''const fs = require('fs');
const filePath = '/www/wwwroot/ipzhinengti/public/admin.html';
let content = fs.readFileSync(filePath, 'utf-8');
if (content.includes('UPDATE_COS_BUCKET')) {
console.log('SKIP: already patched');
process.exit(0);
}
// 1. Add to CONFIG_KEYS
content = content.replace(
"'cloud_beauty_enabled'",
"'cloud_beauty_enabled', 'UPDATE_COS_BUCKET', 'UPDATE_COS_REGION', 'UPDATE_COS_PATH'"
);
// 2. Add save values after cloud_beauty_enabled save line
content = content.replace(
"cloud_beauty_enabled: document.getElementById('cfg_cloud_beauty_enabled').checked ? 'true' : 'false',",
`cloud_beauty_enabled: document.getElementById('cfg_cloud_beauty_enabled').checked ? 'true' : 'false',
UPDATE_COS_BUCKET: document.getElementById('cfg_UPDATE_COS_BUCKET').value,
UPDATE_COS_REGION: document.getElementById('cfg_UPDATE_COS_REGION').value,
UPDATE_COS_PATH: document.getElementById('cfg_UPDATE_COS_PATH').value,`
);
// 3. Add load values
content = content.replace(
"document.getElementById('cfg_cloud_beauty_enabled').checked = config.cloud_beauty_enabled === 'true';",
`document.getElementById('cfg_cloud_beauty_enabled').checked = config.cloud_beauty_enabled === 'true';
document.getElementById('cfg_UPDATE_COS_BUCKET').value = config.UPDATE_COS_BUCKET || '';
document.getElementById('cfg_UPDATE_COS_REGION').value = config.UPDATE_COS_REGION || '';
document.getElementById('cfg_UPDATE_COS_PATH').value = config.UPDATE_COS_PATH || '';`
);
// 4. Add HTML form fields - insert before the save button
// Find the save button and insert before it
const saveBtnPattern = '<button onclick="saveSystemConfig()"';
const insertHTML = `<div style="grid-column:1/-1;margin:15px 0 8px;padding-bottom:8px;border-bottom:1px solid #e2e8f0;font-weight:bold;">\u81ea\u52a8\u66f4\u65b0 COS \u914d\u7f6e</div>
<div class="form-group"><label>\u66f4\u65b0\u6876\u540d</label><input type="text" id="cfg_UPDATE_COS_BUCKET" placeholder="xiazaigengxin-1417293730"></div>
<div class="form-group"><label>\u5730\u57df</label><input type="text" id="cfg_UPDATE_COS_REGION" placeholder="ap-guangzhou"></div>
<div class="form-group"><label>\u66f4\u65b0\u8def\u5f84</label><input type="text" id="cfg_UPDATE_COS_PATH" placeholder="updates"></div>
`;
content = content.replace(saveBtnPattern, insertHTML + '\n ' + saveBtnPattern);
fs.writeFileSync(filePath, content, 'utf-8');
console.log('OK: patched admin.html');
'''
sftp = client.open_sftp()
with sftp.open('/tmp/patch_admin2.js', 'w') as f:
f.write(patch_admin2)
sftp.close()
run("node /tmp/patch_admin2.js")
# === Insert UPDATE_COS config into database ===
insert_db = r'''const sqlite3 = require('sqlite3');
const path = require('path');
const dbPath = path.join('/www/wwwroot/ipzhinengti', 'data', 'database.db');
console.log('DB path:', dbPath);
const db = new sqlite3.Database(dbPath);
const configs = [
['UPDATE_COS_BUCKET', 'xiazaigengxin-1417293730'],
['UPDATE_COS_REGION', 'ap-guangzhou'],
['UPDATE_COS_PATH', 'updates']
];
let done = 0;
configs.forEach(([key, value]) => {
db.run(
'INSERT OR REPLACE INTO system_config (config_key, config_value) VALUES (?, ?)',
[key, value],
(err) => {
if (err) console.log('ERR:', key, err.message);
else console.log('OK:', key, '=', value);
done++;
if (done === configs.length) {
db.close();
console.log('ALL DONE');
}
}
);
});
'''
sftp = client.open_sftp()
with sftp.open('/tmp/insert_config.js', 'w') as f:
f.write(insert_db)
sftp.close()
run("node /tmp/insert_config.js")
# Restart user-server
run("pm2 restart user-server 2>&1")
run("sleep 3 && pm2 list")
# Test endpoint
run("curl -s http://localhost:3002/api/system/config/public")
client.close()
print("\n=== ALL PATCHED ===")