yaport 0.1.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/README.md ADDED
@@ -0,0 +1,427 @@
1
+ # 丫口 (yaport)
2
+
3
+ 丫口是一个本机运行的 Web UI 和 CLI,用 SSH 读取远程机器当前监听中的 TCP/UDP 端口。
4
+
5
+ English documentation is available below: [English](#english).
6
+
7
+ ## 适合什么场景
8
+
9
+ - 快速查看远程机器的监听端口、监听地址、协议、状态、进程和 PID。
10
+ - 通过 OpenSSH alias 连接机器,例如 `ssh erya` 对应 `--host erya`。
11
+ - 通过一层或两层跳板机连接目标机器,底层使用 OpenSSH `ProxyJump`。
12
+ - 目标机器或跳板机需要 SSH 密码时,可以在 GUI 填写,也可以通过 CLI 环境变量传入。
13
+ - 面板和 CLI 都能配置连接超时、命令超时,适合慢链路或两层跳板机。
14
+ - 如果远程机器有 nginx 配置,丫口会把能匹配端口的外部入口 URL 展示在端口行里。
15
+ - 当前选中的机器会复用 OpenSSH ControlMaster 连接,降低两层跳板和密码认证的重复握手成本。
16
+
17
+ 丫口只做只读查询,不扫描网段,也不修改远程机器配置。
18
+
19
+ ## 安装
20
+
21
+ 全局安装:
22
+
23
+ ```bash
24
+ pnpm add -g yaport
25
+ ```
26
+
27
+ 也可以直接用 pnpm dlx:
28
+
29
+ ```bash
30
+ pnpm dlx yaport
31
+ ```
32
+
33
+ 本地开发运行:
34
+
35
+ ```bash
36
+ pnpm install
37
+ pnpm dev
38
+ ```
39
+
40
+ ## 启动 Web UI
41
+
42
+ ```bash
43
+ yaport
44
+ yaport --host 127.0.0.1 --port 5173
45
+ yaport --data-file .yaport/machines.json
46
+ yaport --no-open
47
+ ```
48
+
49
+ 默认行为:
50
+
51
+ - `yaport` 会启动本机 server,并自动打开网页。
52
+ - 默认监听 `127.0.0.1:5173`。
53
+ - 默认机器配置目录按顺序查找 `./.yaport`、`~/.yaport`,命中即使用其中的 `machines.json`,不合并;都不存在时创建当前目录的 `./.yaport/machines.json`。
54
+ - `--no-open` 适合脚本、agent、远程 shell,不自动打开浏览器。
55
+
56
+ ## 通过 CLI 添加机器
57
+
58
+ GUI 能添加机器,但大量机器用 CLI 更快。`add-machine` 是非交互式命令,适合 agent 和脚本使用。
59
+
60
+ OpenSSH alias,等价于 `ssh erya`:
61
+
62
+ ```bash
63
+ yaport add-machine --name Erya --host erya --json
64
+ ```
65
+
66
+ 明确指定用户和端口:
67
+
68
+ ```bash
69
+ yaport add-machine --name Prod --host 10.0.0.5 --user root --port 2222 --json
70
+ ```
71
+
72
+ 目标机器密码使用环境变量传入:
73
+
74
+ ```bash
75
+ TARGET_PASSWORD='[redacted-target-password]' yaport add-machine \
76
+ --name Prod \
77
+ --host 10.0.0.5 \
78
+ --user root \
79
+ --password-env TARGET_PASSWORD \
80
+ --json
81
+ ```
82
+
83
+ 一层跳板机:
84
+
85
+ ```bash
86
+ JUMP_PASSWORD='[redacted-jump-password]' TARGET_PASSWORD='[redacted-target-password]' yaport add-machine \
87
+ --name Prod \
88
+ --host prod.internal \
89
+ --user app \
90
+ --password-env TARGET_PASSWORD \
91
+ --connect-timeout 30 \
92
+ --command-timeout 90 \
93
+ --jump1-host jump.internal \
94
+ --jump1-user ops \
95
+ --jump1-password-env JUMP_PASSWORD \
96
+ --json
97
+ ```
98
+
99
+ 两层跳板机:
100
+
101
+ ```bash
102
+ yaport add-machine \
103
+ --name DeepTarget \
104
+ --host target.internal \
105
+ --user app \
106
+ --jump1-host jump-a.internal \
107
+ --jump1-user ops \
108
+ --jump2-host jump-b.internal \
109
+ --jump2-user edge \
110
+ --json
111
+ ```
112
+
113
+ 常用参数:
114
+
115
+ | 参数 | 说明 |
116
+ | --- | --- |
117
+ | `--name <name>` | UI 里展示的机器名称。 |
118
+ | `--host <host>` | SSH host、IP 或 OpenSSH alias。 |
119
+ | `--user <user>` | SSH 用户。OpenSSH alias 已配置时可以省略。 |
120
+ | `--port <port>` | SSH 端口。OpenSSH alias 已配置时可以省略。 |
121
+ | `--password-env <env>` | 从环境变量读取目标机器 SSH 密码。 |
122
+ | `--connect-timeout <seconds>` | SSH 连接超时。可选值:`8`、`15`、`30`、`60`。默认 `15`。 |
123
+ | `--command-timeout <seconds>` | 本机等待命令完成的总超时。可选值:`12`、`30`、`45`、`90`。默认 `45`。 |
124
+ | `--jump1-host <host>` | 第一层跳板机。 |
125
+ | `--jump2-host <host>` | 第二层跳板机。 |
126
+ | `--jumpN-user <user>` | 第 N 层跳板机 SSH 用户。 |
127
+ | `--jumpN-port <port>` | 第 N 层跳板机 SSH 端口。 |
128
+ | `--jumpN-password-env <env>` | 从环境变量读取第 N 层跳板机密码。 |
129
+ | `--json` | 输出稳定 JSON,不输出密码。 |
130
+ | `--data-file <path>` | 指定机器配置文件,跳过默认两层查找。 |
131
+
132
+ 建议:
133
+
134
+ - agent 和脚本优先使用 `--json`。
135
+ - 密码优先使用 `--password-env` 和 `--jumpN-password-env`,不要把密码直接放进命令参数。
136
+ - 使用 OpenSSH alias 时,`--user` 和 `--port` 可以留空。
137
+ - 两层跳板或密码认证握手较慢时,建议使用 `--connect-timeout 30 --command-timeout 90`。
138
+
139
+ ## 端口信息
140
+
141
+ 丫口通过本机 OpenSSH 登录远程机器,并读取:
142
+
143
+ - `ss -H -lntup`:监听中的 TCP/UDP 端口。
144
+ - `ps -ww -p <pid> -o pid=,args=`:尽量补全进程命令行。
145
+ - `nginx -T`:如果可读,推断 nginx 外部入口。
146
+
147
+ `ss` 会先执行;拿到 PID 后,`ps` 和 `nginx -T` 会并发执行。任意一个失败都不会影响端口清单。
148
+
149
+ 表格展示:
150
+
151
+ - 协议:TCP / UDP。
152
+ - 监听地址。
153
+ - 端口号。
154
+ - 状态。
155
+ - 进程名称或完整命令行。
156
+ - PID。
157
+ - 外部入口。
158
+
159
+ ## nginx 外部入口
160
+
161
+ 当 `nginx -T` 可读时,丫口会解析 `server` 配置并按端口匹配外部入口。
162
+
163
+ 规则:
164
+
165
+ - `listen 443 ssl` 或端口 `443` 展示为 `https://server_name`。
166
+ - 其他端口展示为 `http://server_name:port`。
167
+ - `server_name _`、空值、变量域名不展示。
168
+ - `nginx -T` 读不到不会影响端口清单,只显示“无外部入口”。
169
+ - nginx 来源的入口会带一个 nginx 小图标;后续可以继续支持其他来源类型。
170
+ - nginx 外部入口按机器缓存 5 分钟,包括短时间缓存读取失败,避免静默刷新时重复等待慢失败。
171
+
172
+ ## Web UI 行为
173
+
174
+ - 添加机器表单默认折叠。
175
+ - 添加机器时可以选择“连接超时”和“命令超时”。
176
+ - TCP / UDP 指标卡带开关,默认开启,用于过滤下方记录。
177
+ - “监听端口”指标卡可以按端口分组。
178
+ - “进程”指标卡可以按进程分组。
179
+ - 切换机器时按机器粒度保留上次结果,不会把上一台机器的端口展示到当前机器。
180
+ - 当前选中的机器会使用 OpenSSH `ControlMaster=auto` 和 `ControlPersist=5m`,`ss`、`ps`、`nginx -T`、手动刷新和 1 分钟自动刷新会复用同一条 SSH master connection。
181
+ - 未选中机器的后台静默刷新不启用连接复用,避免维护过多后台连接。
182
+ - 网页在前台活跃时,选中机器默认每 1 分钟静默刷新,未选中机器默认每 5 分钟静默刷新。
183
+ - 机器列表和当前选中机器会写入 `sessionStorage`,刷新页面后能先看到本地缓存,再等待 server 返回最新数据。
184
+
185
+ ## 数据与安全
186
+
187
+ - 机器配置目录默认按顺序查找 `./.yaport`、`~/.yaport`,命中即使用其中的 `machines.json`,不合并;都不存在时创建当前目录的 `./.yaport/machines.json`。
188
+ - 配置文件以 `0600` 权限写入。
189
+ - API 和 CLI JSON 输出不会返回已保存的 SSH 密码。
190
+ - 密码目前是本机明文保存;如果不想落盘,优先使用 SSH key 或 OpenSSH alias。
191
+ - 丫口只从远程机器读取端口、进程和 nginx 配置,不会写远程文件。
192
+
193
+ ## 远程机器要求
194
+
195
+ - 本机需要可用的 OpenSSH `ssh` 命令。
196
+ - 远程机器需要有 `ss` 命令。
197
+ - 进程命令行和 PID 是否完整,取决于当前 SSH 用户权限。
198
+ - nginx 外部入口依赖远程机器能执行并读取 `nginx -T`。
199
+
200
+ ## 本地开发
201
+
202
+ ```bash
203
+ pnpm install
204
+ pnpm dev
205
+ pnpm test
206
+ pnpm build
207
+ ```
208
+
209
+ 打包后的 CLI 入口:
210
+
211
+ ```bash
212
+ pnpm build
213
+ node bin/yaport.js --help
214
+ ```
215
+
216
+ ## English
217
+
218
+ Yaport is a local Web UI and CLI for reading currently listening TCP/UDP ports on remote machines through SSH.
219
+
220
+ Yaport is read-only. It does not scan networks and does not modify remote machine configuration.
221
+
222
+ ## Use Cases
223
+
224
+ - Inspect listening ports, listen addresses, protocols, states, processes, and PIDs on remote machines.
225
+ - Connect through OpenSSH aliases, for example `ssh erya` maps to `--host erya`.
226
+ - Connect through one or two jump hosts via OpenSSH `ProxyJump`.
227
+ - Support SSH passwords for both target machines and jump hosts, from the GUI or CLI environment variables.
228
+ - Configure connection and command timeouts from both the UI and CLI for slow links or two-hop jump paths.
229
+ - Infer public-facing nginx URLs and show them next to matching listening ports.
230
+ - Reuse an OpenSSH ControlMaster connection for the currently selected machine to reduce repeated handshakes on slow jump paths.
231
+
232
+ ## Installation
233
+
234
+ Install globally:
235
+
236
+ ```bash
237
+ pnpm add -g yaport
238
+ ```
239
+
240
+ Or run it with pnpm dlx:
241
+
242
+ ```bash
243
+ pnpm dlx yaport
244
+ ```
245
+
246
+ For local development:
247
+
248
+ ```bash
249
+ pnpm install
250
+ pnpm dev
251
+ ```
252
+
253
+ ## Start the Web UI
254
+
255
+ ```bash
256
+ yaport
257
+ yaport --host 127.0.0.1 --port 5173
258
+ yaport --data-file .yaport/machines.json
259
+ yaport --no-open
260
+ ```
261
+
262
+ Default behavior:
263
+
264
+ - `yaport` starts the local server and opens the Web UI automatically.
265
+ - The default bind address is `127.0.0.1:5173`.
266
+ - The default machine config directory lookup checks `./.yaport` first, then `~/.yaport`. The first hit wins and Yaport uses that directory's `machines.json`; files are not merged. If neither directory exists, Yaport creates `./.yaport/machines.json`.
267
+ - Use `--no-open` for scripts, agents, or remote shells.
268
+
269
+ ## Add Machines from the CLI
270
+
271
+ The GUI can add machines, but the CLI is faster for repeated setup. `add-machine` is non-interactive and works well from agents and scripts.
272
+
273
+ OpenSSH alias, same as `ssh erya`:
274
+
275
+ ```bash
276
+ yaport add-machine --name Erya --host erya --json
277
+ ```
278
+
279
+ Explicit user and port:
280
+
281
+ ```bash
282
+ yaport add-machine --name Prod --host 10.0.0.5 --user root --port 2222 --json
283
+ ```
284
+
285
+ Target password from an environment variable:
286
+
287
+ ```bash
288
+ TARGET_PASSWORD='[redacted-target-password]' yaport add-machine \
289
+ --name Prod \
290
+ --host 10.0.0.5 \
291
+ --user root \
292
+ --password-env TARGET_PASSWORD \
293
+ --json
294
+ ```
295
+
296
+ One jump host:
297
+
298
+ ```bash
299
+ JUMP_PASSWORD='[redacted-jump-password]' TARGET_PASSWORD='[redacted-target-password]' yaport add-machine \
300
+ --name Prod \
301
+ --host prod.internal \
302
+ --user app \
303
+ --password-env TARGET_PASSWORD \
304
+ --connect-timeout 30 \
305
+ --command-timeout 90 \
306
+ --jump1-host jump.internal \
307
+ --jump1-user ops \
308
+ --jump1-password-env JUMP_PASSWORD \
309
+ --json
310
+ ```
311
+
312
+ Two jump hosts:
313
+
314
+ ```bash
315
+ yaport add-machine \
316
+ --name DeepTarget \
317
+ --host target.internal \
318
+ --user app \
319
+ --jump1-host jump-a.internal \
320
+ --jump1-user ops \
321
+ --jump2-host jump-b.internal \
322
+ --jump2-user edge \
323
+ --json
324
+ ```
325
+
326
+ Common options:
327
+
328
+ | Option | Description |
329
+ | --- | --- |
330
+ | `--name <name>` | Display name in the UI. |
331
+ | `--host <host>` | SSH host, IP address, or OpenSSH alias. |
332
+ | `--user <user>` | SSH user. Omit it when an OpenSSH alias already defines `User`. |
333
+ | `--port <port>` | SSH port. Omit it when an OpenSSH alias already defines `Port`. |
334
+ | `--password-env <env>` | Read the target machine SSH password from an environment variable. |
335
+ | `--connect-timeout <seconds>` | SSH connection timeout. Choices: `8`, `15`, `30`, `60`. Default: `15`. |
336
+ | `--command-timeout <seconds>` | Total local command timeout. Choices: `12`, `30`, `45`, `90`. Default: `45`. |
337
+ | `--jump1-host <host>` | First jump host. |
338
+ | `--jump2-host <host>` | Second jump host. |
339
+ | `--jumpN-user <user>` | SSH user for jump host N. |
340
+ | `--jumpN-port <port>` | SSH port for jump host N. |
341
+ | `--jumpN-password-env <env>` | Read jump host N's password from an environment variable. |
342
+ | `--json` | Print deterministic JSON. Passwords are never printed. |
343
+ | `--data-file <path>` | Use a specific machine config file and skip the default two-level lookup. |
344
+
345
+ Recommendations:
346
+
347
+ - Use `--json` from agents and scripts.
348
+ - Prefer `--password-env` and `--jumpN-password-env`; avoid putting passwords directly in process arguments.
349
+ - Omit `--user` and `--port` when `--host` is an OpenSSH alias.
350
+ - For slow two-hop jump paths or password handshakes, use `--connect-timeout 30 --command-timeout 90`.
351
+
352
+ ## Port Inventory
353
+
354
+ Yaport logs in through local OpenSSH and reads:
355
+
356
+ - `ss -H -lntup`: listening TCP/UDP ports.
357
+ - `ps -ww -p <pid> -o pid=,args=`: full process command lines when available.
358
+ - `nginx -T`: nginx configuration, when readable, to infer external routes.
359
+
360
+ `ss` runs first. After PIDs are available, `ps` and `nginx -T` run concurrently. Either one may fail without breaking the port list.
361
+
362
+ The table shows:
363
+
364
+ - Protocol: TCP / UDP.
365
+ - Listen address.
366
+ - Port.
367
+ - State.
368
+ - Process name or full command line.
369
+ - PID.
370
+ - External routes.
371
+
372
+ ## nginx External Routes
373
+
374
+ When `nginx -T` is readable, Yaport parses `server` blocks and matches routes by port.
375
+
376
+ Rules:
377
+
378
+ - `listen 443 ssl` or port `443` is shown as `https://server_name`.
379
+ - Other ports are shown as `http://server_name:port`.
380
+ - `server_name _`, empty names, and variable names are ignored.
381
+ - If `nginx -T` cannot be read, the port list still works and the UI shows no external route.
382
+ - nginx routes include a small nginx source icon. Other source types can be added later.
383
+ - nginx external routes are cached per machine for 5 minutes, including short-lived failure caching, so silent refreshes do not repeatedly wait on slow config reads.
384
+
385
+ ## Web UI Behavior
386
+
387
+ - The add-machine form is collapsed by default.
388
+ - The add-machine form lets you choose connection timeout and command timeout.
389
+ - TCP and UDP metric cards include switches, both enabled by default, to filter visible records.
390
+ - The listening-port metric card can group the table by port.
391
+ - The process metric card can group the table by process.
392
+ - Switching machines keeps the selected machine's own cached result; it never shows another machine's ports as stale data.
393
+ - The selected machine uses OpenSSH `ControlMaster=auto` and `ControlPersist=5m`; `ss`, `ps`, `nginx -T`, manual refresh, and 1-minute auto refresh reuse the same SSH master connection.
394
+ - Background refreshes for unselected machines do not use connection reuse, so Yaport does not keep extra background master connections open.
395
+ - While the page is visible, the selected machine refreshes silently every 1 minute, and unselected machines refresh silently every 5 minutes.
396
+ - The machine list and selected machine ID are stored in `sessionStorage` for immediate visibility after page reload.
397
+
398
+ ## Data and Security
399
+
400
+ - Machine config directory lookup checks `./.yaport` first, then `~/.yaport`. The first hit wins and Yaport uses that directory's `machines.json`; files are not merged. If neither directory exists, Yaport creates `./.yaport/machines.json`.
401
+ - The config file is written with `0600` permissions.
402
+ - API responses and CLI JSON output never return stored SSH passwords.
403
+ - Passwords are currently stored locally in plain text. Prefer SSH keys or OpenSSH aliases if you do not want passwords on disk.
404
+ - Yaport only reads remote ports, processes, and nginx configuration. It does not write remote files.
405
+
406
+ ## Remote Requirements
407
+
408
+ - Local machine: OpenSSH `ssh`.
409
+ - Remote machine: `ss`.
410
+ - Process command lines and PIDs depend on the SSH user's permissions.
411
+ - nginx external routes require `nginx -T` to be executable and readable on the remote machine.
412
+
413
+ ## Development
414
+
415
+ ```bash
416
+ pnpm install
417
+ pnpm dev
418
+ pnpm test
419
+ pnpm build
420
+ ```
421
+
422
+ Packaged CLI entry:
423
+
424
+ ```bash
425
+ pnpm build
426
+ node bin/yaport.js --help
427
+ ```
package/bin/yaport.js ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { main } from "../dist/server/cli.js";
3
+
4
+ await main();