dsh-ssh-vault 0.0.0-stage → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +404 -0
- package/CHANGELOG.zh-CN.md +352 -0
- package/CONTRIBUTING.md +179 -0
- package/CONTRIBUTING.zh-CN.md +167 -0
- package/LICENSE +21 -0
- package/README.md +452 -2
- package/README.zh-CN.md +450 -0
- package/SECURITY.md +42 -0
- package/SECURITY.zh-CN.md +38 -0
- package/assets/banner.png +0 -0
- package/assets/icon-180.png +0 -0
- package/assets/screenshot-1.png +0 -0
- package/client.js +1134 -0
- package/cordis.patch.yml +4 -0
- package/icon.svg +11 -0
- package/index.js +1180 -0
- package/lib/background.js +65 -0
- package/lib/i18n.js +589 -0
- package/lib/locales/ssh.js +130 -0
- package/lib/platform.js +68 -0
- package/lib/ssh.js +723 -0
- package/lib/vault-api.js +417 -0
- package/lib/vault.js +397 -0
- package/locale/en.json +4 -0
- package/locale/zh.json +4 -0
- package/package.json +75 -4
- package/scripts/dhcp-reserve-kali.ps1 +81 -0
- package/scripts/make-market-icon.py +63 -0
- package/scripts/set-secret.mjs +127 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* 离线口令录入通道。
|
|
4
|
+
*
|
|
5
|
+
* 为什么需要它:插件把口令加密保存,但**录入**这一步原本必须经过工具参数,
|
|
6
|
+
* 于是口令会进入会话日志;改走 credentialRef 虽然避开了对话,落盘却是明文 YAML。
|
|
7
|
+
* 这个脚本让口令从你自己的终端直接进入加密保险库——不经过 DSH、不经过模型、
|
|
8
|
+
* 不进会话日志,也不在任何地方留下明文文件。
|
|
9
|
+
*
|
|
10
|
+
* 用法(在包目录下运行):
|
|
11
|
+
* node scripts/set-secret.mjs <alias> # 交互式录入登录口令(不回显)
|
|
12
|
+
* node scripts/set-secret.mjs <alias> --sudo # 录入 sudo 专用口令
|
|
13
|
+
* node scripts/set-secret.mjs <alias> --show # 只看状态,不修改
|
|
14
|
+
*
|
|
15
|
+
* 自检 DSH_HOME 与 Harness 不一致时(例如自定义数据目录),可在前面加
|
|
16
|
+
* DSH_HOME=<path>(PowerShell: $env:DSH_HOME='<path>')。
|
|
17
|
+
*
|
|
18
|
+
* @module dsh-ssh-vault/set-secret
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { Vault, defaultVaultDir } from '../lib/vault.js'
|
|
22
|
+
|
|
23
|
+
const argv = process.argv.slice(2)
|
|
24
|
+
const alias = argv.find((arg) => !arg.startsWith('--'))
|
|
25
|
+
const forSudo = argv.includes('--sudo')
|
|
26
|
+
const showOnly = argv.includes('--show')
|
|
27
|
+
|
|
28
|
+
if (alias === undefined) {
|
|
29
|
+
console.error('用法: node scripts/set-secret.mjs <alias> [--sudo] [--show]')
|
|
30
|
+
process.exit(2)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const dir = defaultVaultDir()
|
|
34
|
+
const vault = new Vault({ dir })
|
|
35
|
+
const record = await vault.get(alias)
|
|
36
|
+
|
|
37
|
+
if (record === undefined) {
|
|
38
|
+
const known = (await vault.list()).map((host) => host.alias)
|
|
39
|
+
console.error(`保险库中没有名为 ${alias} 的主机。${known.length > 0 ? `现有:${known.join(', ')}` : ''}`)
|
|
40
|
+
console.error(`保险库位置:${dir}`)
|
|
41
|
+
process.exit(1)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (showOnly) {
|
|
45
|
+
console.log(`alias: ${alias}`)
|
|
46
|
+
console.log(`vault: ${dir}`)
|
|
47
|
+
console.log(`auth: ${record.auth?.type ?? 'agent'}`)
|
|
48
|
+
console.log(`password: ${record.auth?.type === 'password' && record.auth.password ? 'set' : 'missing'}`)
|
|
49
|
+
console.log(`sudoPassword: ${record.sudoPassword ? 'set' : 'missing'}`)
|
|
50
|
+
console.log(`credentialRef: ${record.credentialRef ? record.credentialRef : '(none)'}`)
|
|
51
|
+
if (record.credentialRef) {
|
|
52
|
+
console.log('提示:该主机配置了 credentialRef,连接时会优先使用它;要改用保险库口令,')
|
|
53
|
+
console.log(' 可让智能体执行 ssh_hosts action=update alias=' + alias + ' credentialRef="" 。')
|
|
54
|
+
}
|
|
55
|
+
process.exit(0)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const secret = await readSecret(`请输入 ${alias} 的${forSudo ? ' sudo ' : '登录'}口令(不回显,回车确认):`)
|
|
59
|
+
|
|
60
|
+
if (secret.length === 0) {
|
|
61
|
+
console.error('口令为空,未做任何修改。')
|
|
62
|
+
process.exit(1)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (forSudo) {
|
|
66
|
+
await vault.patch(alias, { sudoPassword: secret })
|
|
67
|
+
console.log(`已把 ${alias} 的 sudo 口令加密写入保险库:${dir}`)
|
|
68
|
+
} else {
|
|
69
|
+
await vault.patch(alias, { auth: { type: 'password', password: secret } })
|
|
70
|
+
console.log(`已把 ${alias} 的登录口令加密写入保险库:${dir}`)
|
|
71
|
+
if (record.credentialRef) {
|
|
72
|
+
console.log(`注意:该主机仍配置了 credentialRef=${record.credentialRef},连接时会优先使用它。`)
|
|
73
|
+
console.log(` 要改用保险库口令,请让智能体执行 ssh_hosts action=update alias=${alias} credentialRef="" 。`)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 读取一段口令:终端下关闭回显,管道下读第一行。
|
|
79
|
+
* @param question - 显示的提示语。
|
|
80
|
+
* @returns 用户输入的口令。
|
|
81
|
+
*/
|
|
82
|
+
async function readSecret(question) {
|
|
83
|
+
if (process.stdin.isTTY === true && typeof process.stdin.setRawMode === 'function') {
|
|
84
|
+
return readHidden(question)
|
|
85
|
+
}
|
|
86
|
+
process.stdout.write(question)
|
|
87
|
+
let raw = ''
|
|
88
|
+
for await (const chunk of process.stdin) raw += chunk
|
|
89
|
+
return (raw.split(/\r?\n/)[0] ?? '').trim()
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* 关闭回显地读一行,避免口令留在终端回滚缓冲里。
|
|
94
|
+
* @param question - 显示的提示语。
|
|
95
|
+
* @returns 输入的口令。
|
|
96
|
+
*/
|
|
97
|
+
function readHidden(question) {
|
|
98
|
+
process.stdout.write(question)
|
|
99
|
+
const stdin = process.stdin
|
|
100
|
+
stdin.setRawMode(true)
|
|
101
|
+
stdin.resume()
|
|
102
|
+
return new Promise((resolve) => {
|
|
103
|
+
let value = ''
|
|
104
|
+
const onData = (chunk) => {
|
|
105
|
+
for (const char of chunk.toString('utf8')) {
|
|
106
|
+
if (char === '\r' || char === '\n') {
|
|
107
|
+
stdin.setRawMode(false)
|
|
108
|
+
stdin.pause()
|
|
109
|
+
stdin.off('data', onData)
|
|
110
|
+
process.stdout.write('\n')
|
|
111
|
+
resolve(value)
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
if (char === '\u0003') {
|
|
115
|
+
process.stdout.write('\n')
|
|
116
|
+
process.exit(130)
|
|
117
|
+
}
|
|
118
|
+
if (char === '\u007f' || char === '\b') {
|
|
119
|
+
value = value.slice(0, -1)
|
|
120
|
+
continue
|
|
121
|
+
}
|
|
122
|
+
value += char
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
stdin.on('data', onData)
|
|
126
|
+
})
|
|
127
|
+
}
|