@cnbcool/cnb-api-generate 2.14.2 → 2.15.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/client/lib/login.ts
CHANGED
|
@@ -16,13 +16,14 @@ export function registerLoginCommand(program: Command): void {
|
|
|
16
16
|
.command('login')
|
|
17
17
|
.description('通过 OAuth2 设备授权流登录 CNB,获取并保存 access_token')
|
|
18
18
|
.option('--client-id <string>', 'OAuth2 client_id', process.env.OAUTH2_CLIENT_ID || 'cnb_cli')
|
|
19
|
+
.option('--host <string>', '平台域名(如 cnb.cool,可带端口如 cnb.cool:8080),优先级高于 git remote 与 CNB_API_ENDPOINT')
|
|
19
20
|
.option('--debug', '打印调试信息', false)
|
|
20
21
|
.helpOption('-h, --help', '显示帮助文档')
|
|
21
22
|
.action(async (opts) => {
|
|
22
23
|
const cfg: LoginConfig = {
|
|
23
24
|
clientID: opts.clientId,
|
|
24
25
|
// 从 git remote -v 动态识别平台域名,兼容不同部署(公开 / 内网 / 自定义域名)
|
|
25
|
-
platformURL: resolvePlatformUrl(),
|
|
26
|
+
platformURL: resolvePlatformUrl(opts.host),
|
|
26
27
|
debug: opts.debug,
|
|
27
28
|
};
|
|
28
29
|
|
|
@@ -79,7 +80,8 @@ export function registerLoginCommand(program: Command): void {
|
|
|
79
80
|
// 持久化 token
|
|
80
81
|
const nowSec = Math.floor(Date.now() / 1000);
|
|
81
82
|
// 从 platformURL 推导 API 域名,例如 https://cnb.cool -> https://api.cnb.cool
|
|
82
|
-
|
|
83
|
+
// 使用 host(而非 hostname)以保留自定义端口,如 https://example.com:8080 -> https://api.example.com:8080
|
|
84
|
+
const platformHost = new URL(cfg.platformURL).host;
|
|
83
85
|
const loginHost = `https://api.${platformHost}`;
|
|
84
86
|
const store: TokenStore = {
|
|
85
87
|
access_token: tok.access_token,
|
|
@@ -52,13 +52,77 @@ function parseUrlHost(url: string): string | null {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
/**
|
|
56
|
+
* 将 --host 传入的裸主机名规范化为平台 base URL。
|
|
57
|
+
* --host 仅接受裸域名(如 cnb.cool、example.com:8080),不兼容 https:// 这类协议头;
|
|
58
|
+
* 含协议头的输入视为非法,返回 null(交由后续优先级处理)。
|
|
59
|
+
* 内部统一补 https://,并去掉常见的 api. 前缀。
|
|
60
|
+
* @param raw 裸主机名,如 cnb.cool、example.com:8080、api.cnb.cool
|
|
61
|
+
* @returns 形如 https://cnb.cool,失败返回 null
|
|
62
|
+
*/
|
|
63
|
+
function normalizeHost(raw: string): string | null {
|
|
64
|
+
const trimmed = raw.trim();
|
|
65
|
+
if (!trimmed) return null;
|
|
66
|
+
// 含协议头(如 https://)视为非法 --host 输入
|
|
67
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed)) return null;
|
|
68
|
+
// 校验为合法主机名(可带端口),拒绝路径、空格等非法字符;
|
|
69
|
+
// 否则后续 new URL(`https://${host}`) 可能抛 Invalid URL,或产生带路径的异常平台地址,
|
|
70
|
+
// 导致 login_host 与 platformURL 脱节。
|
|
71
|
+
if (!/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*(:\d{1,5})?$/i.test(trimmed)) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
// 主机名大小写不敏感,统一转小写;去掉常见的 api. 前缀(api.cnb.cool -> cnb.cool)
|
|
75
|
+
// 使用 host 形式以保留自定义端口,如 example.com:8080
|
|
76
|
+
const host = trimmed.toLowerCase().replace(/^api\./, '');
|
|
77
|
+
return `https://${host}`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* 将 CNB_API_ENDPOINT(完整 API URL,如 https://api.cnb.cool)规范化为平台 base URL。
|
|
82
|
+
* 与 --host 不同,这里是完整 URL,需要按 URL 解析,并去掉常见的 api. 前缀、保留自定义端口。
|
|
83
|
+
* @param raw 完整 URL,如 https://api.cnb.cool、https://api.example.com:8443
|
|
84
|
+
* @returns 形如 https://cnb.cool,失败返回 null
|
|
85
|
+
*/
|
|
86
|
+
function normalizeEndpoint(raw: string): string | null {
|
|
87
|
+
try {
|
|
88
|
+
const u = new URL(raw.trim());
|
|
89
|
+
if (!u.host) return null;
|
|
90
|
+
// 去掉常见的 api. 前缀,统一得到平台域名(api.cnb.cool -> cnb.cool)
|
|
91
|
+
// 使用 host(而非 hostname)以保留自定义端口,如 example.com:8080
|
|
92
|
+
const host = u.host.replace(/^api\./, '');
|
|
93
|
+
return `https://${host}`;
|
|
94
|
+
} catch {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
55
99
|
/**
|
|
56
100
|
* 解析当前平台的 base URL(形如 https://cnb.cool)。
|
|
57
|
-
*
|
|
58
|
-
*
|
|
101
|
+
*
|
|
102
|
+
* 优先级(从高到低):
|
|
103
|
+
* 1. 显式传入的参数(login 的 --host,裸域名)
|
|
104
|
+
* 2. 当前仓库 git remote -v 解析出的 host
|
|
105
|
+
* 3. 环境变量 CNB_API_ENDPOINT(完整 URL)
|
|
106
|
+
* 4. 兜底 https://cnb.cool
|
|
107
|
+
*
|
|
108
|
+
* @param paramUrl 可选的显式 --host 裸主机名
|
|
59
109
|
* @returns 平台 base URL
|
|
60
110
|
*/
|
|
61
|
-
export function resolvePlatformUrl(): string {
|
|
111
|
+
export function resolvePlatformUrl(paramUrl?: string): string {
|
|
112
|
+
// 1. 显式参数(--host 裸主机名)优先
|
|
113
|
+
const fromParam = paramUrl?.trim() ? normalizeHost(paramUrl.trim()) : null;
|
|
114
|
+
if (fromParam) return fromParam;
|
|
115
|
+
|
|
116
|
+
// 2. 无参数时从 git remote 取
|
|
62
117
|
const host = getGitRemoteHosts()[0];
|
|
63
|
-
|
|
118
|
+
if (host) return `https://${host}`;
|
|
119
|
+
|
|
120
|
+
// 3. 都没有则尝试从 CNB_API_ENDPOINT(完整 URL)取
|
|
121
|
+
const fromEnv = process.env.CNB_API_ENDPOINT?.trim()
|
|
122
|
+
? normalizeEndpoint(process.env.CNB_API_ENDPOINT.trim())
|
|
123
|
+
: null;
|
|
124
|
+
if (fromEnv) return fromEnv;
|
|
125
|
+
|
|
126
|
+
// 4. 最后降级到 cnb.cool
|
|
127
|
+
return 'https://cnb.cool';
|
|
64
128
|
}
|