#!/usr/bin/env node const fs = require('fs'); const path = require('path'); const https = require('https'); // 加载配置 const CONFIG_PATH = process.env.VAULTWARDEN_CONFIG_PATH || path.join(process.env.HOME || process.env.USERPROFILE, '.config', 'vaultwarden', 'config.json'); let config = { url: 'https://bit.180356.xyz', client_id: '', client_secret: '' }; if (fs.existsSync(CONFIG_PATH)) { try { config = { ...config, ...JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8')) }; } catch (e) {} } const VAULT_URL = config.url; const CLIENT_ID = config.client_id; const CLIENT_SECRET = config.client_secret; const token = null; const deviceId = 'openclaw-cli-' + require('crypto').randomUUID(); async function getToken() { const params = new URLSearchParams({ grant_type: 'client_credentials', scope: 'api', client_id: CLIENT_ID, client_secret: CLIENT_SECRET, device_identifier: deviceId, device_type: '14', device_name: 'OpenClaw CLI' }); const response = await request('/identity/connect/token', 'POST', params.toString(), false, 'application/x-www-form-urlencoded'); return response.access_token; } async function request(endpoint, method = 'GET', data = null, useAuth = true, contentType = 'application/json') { return new Promise((resolve, reject) => { const url = new URL(VAULT_URL + endpoint); const options = { hostname: url.hostname, port: url.port || 443, path: url.pathname + url.search, method: method, headers: { 'Content-Type': contentType, 'Accept': 'application/json' }, timeout: 30000 }; const req = https.request(options, (res) => { let body = ''; res.on('data', chunk => body += chunk); res.on('end', () => { try { const json = body ? JSON.parse(body) : {}; if (res.statusCode >= 200 && res.statusCode < 300) resolve(json); else reject(new Error(`HTTP ${res.statusCode}: ${json.message || body}`)); } catch (e) { reject(e); } }); }); req.on('error', reject); req.on('timeout', () => { req.destroy(); reject(new Error('超时')); }); if (data) req.write(data); req.end(); }); } async function createItem(name, password, username, notes) { const token = await getToken(); const itemData = { name: name, notes: notes, type: 1, favorite: false, login: { username: username, password: password, totp: null }, fields: [], collectionIds: [] }; return new Promise((resolve, reject) => { const url = new URL(VAULT_URL + '/api/ciphers'); const options = { hostname: url.hostname, port: url.port || 443, path: url.pathname + url.search, method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': `Bearer ${token}` }, timeout: 30000 }; const req = https.request(options, (res) => { let body = ''; res.on('data', chunk => body += chunk); res.on('end', () => { try { const json = body ? JSON.parse(body) : {}; if (res.statusCode >= 200 && res.statusCode < 300) resolve(json); else reject(new Error(`HTTP ${res.statusCode}: ${json.message || body}`)); } catch (e) { reject(e); } }); }); req.on('error', reject); req.write(JSON.stringify(itemData)); req.end(); }); } async function main() { try { console.log('\n📝 保存新项目\n'); await createItem('Test Account', 'testpassword123', 'testuser', 'Test notes'); console.log('✅ 已保存: Test Account\n'); } catch (error) { console.error('\n❌ 错误:', error.message); process.exit(1); } } main();