u1s1-cli 0.5.3 → 0.6.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/dist/index.js +0 -0
- package/dist/login.js +86 -10
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
File without changes
|
package/dist/login.js
CHANGED
|
@@ -8,24 +8,100 @@ const VERSION = require("../package.json").version;
|
|
|
8
8
|
function tryOpenBrowser(url) {
|
|
9
9
|
import("node:child_process")
|
|
10
10
|
.then(({ spawn }) => {
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
// Windows 的 start 是 cmd 内置命令,不能直接 spawn;空引号占住"窗口标题"参数位
|
|
12
|
+
const [cmd, args] = process.platform === "darwin" ? ["open", [url]]
|
|
13
|
+
: process.platform === "win32" ? ["cmd", ["/c", "start", "", url]]
|
|
14
|
+
: ["xdg-open", [url]];
|
|
15
|
+
spawn(cmd, args, { detached: true, stdio: "ignore" }).on("error", () => { }).unref();
|
|
13
16
|
})
|
|
14
17
|
.catch(() => { });
|
|
15
18
|
}
|
|
19
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
20
|
+
/** baseUrl 形如 https://api.u1s1.io/v1;auth 路由挂在同一域名的根路径。 */
|
|
21
|
+
function apiOrigin(cfg) {
|
|
22
|
+
return cfg.baseUrl.replace(/\/v1\/?$/, "");
|
|
23
|
+
}
|
|
24
|
+
/** 发起浏览器登录;网关太老或连不上时返回 null,退回手动粘贴。 */
|
|
25
|
+
async function startDeviceLogin(origin) {
|
|
26
|
+
try {
|
|
27
|
+
const resp = await fetch(`${origin}/auth/device/start`, { method: "POST" });
|
|
28
|
+
if (!resp.ok)
|
|
29
|
+
return null;
|
|
30
|
+
const data = (await resp.json());
|
|
31
|
+
if (typeof data.verify_url !== "string" || typeof data.poll_secret !== "string")
|
|
32
|
+
return null;
|
|
33
|
+
return {
|
|
34
|
+
verify_url: data.verify_url,
|
|
35
|
+
poll_secret: data.poll_secret,
|
|
36
|
+
interval: data.interval || 2,
|
|
37
|
+
expires_in: data.expires_in || 900,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** 轮询等浏览器那边批准;拿到 key 返回,过期返回 null。 */
|
|
45
|
+
async function pollDeviceLogin(origin, start) {
|
|
46
|
+
const deadline = Date.now() + start.expires_in * 1000;
|
|
47
|
+
while (Date.now() < deadline) {
|
|
48
|
+
await sleep(start.interval * 1000);
|
|
49
|
+
try {
|
|
50
|
+
const resp = await fetch(`${origin}/auth/device/poll`, {
|
|
51
|
+
method: "POST",
|
|
52
|
+
headers: { "content-type": "application/json" },
|
|
53
|
+
body: JSON.stringify({ poll_secret: start.poll_secret }),
|
|
54
|
+
});
|
|
55
|
+
if (!resp.ok)
|
|
56
|
+
continue;
|
|
57
|
+
const data = (await resp.json());
|
|
58
|
+
if (data.status === "ok" && data.api_key)
|
|
59
|
+
return data.api_key;
|
|
60
|
+
if (data.status === "expired")
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// 网络抖一下,下一轮继续
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
async function promptForKey() {
|
|
70
|
+
console.log(" 需要一把 API Key(免费):");
|
|
71
|
+
console.log(` 1. 打开 ${DASHBOARD_URL} 注册/登录(30 秒,送 $10 额度)`);
|
|
72
|
+
console.log(" 2. 复制你的 API Key,粘贴到下面");
|
|
73
|
+
console.log("");
|
|
74
|
+
tryOpenBrowser(DASHBOARD_URL);
|
|
75
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
76
|
+
const key = (await rl.question(" 粘贴 API Key: ")).trim();
|
|
77
|
+
rl.close();
|
|
78
|
+
return key;
|
|
79
|
+
}
|
|
16
80
|
export async function login(keyArg) {
|
|
17
81
|
const cfg = loadConfig();
|
|
18
82
|
let key = keyArg?.trim();
|
|
19
83
|
if (!key) {
|
|
20
84
|
printConsoleBanner(VERSION);
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
85
|
+
const origin = apiOrigin(cfg);
|
|
86
|
+
const start = await startDeviceLogin(origin);
|
|
87
|
+
if (start) {
|
|
88
|
+
console.log(" 用浏览器登录(免费,注册送 $10 额度):");
|
|
89
|
+
console.log("");
|
|
90
|
+
console.log(` ${start.verify_url}`);
|
|
91
|
+
console.log("");
|
|
92
|
+
console.log(" 已经帮你打开浏览器了;如果没打开,把上面这行网址复制到浏览器打开。");
|
|
93
|
+
console.log(" 在浏览器里登录成功后,这里会自动继续,等着就行……");
|
|
94
|
+
tryOpenBrowser(start.verify_url);
|
|
95
|
+
key = (await pollDeviceLogin(origin, start)) ?? undefined;
|
|
96
|
+
if (!key) {
|
|
97
|
+
console.error(" 等了太久没等到浏览器登录。重新运行一次 u1s1,会给你一个新链接。");
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
console.log("");
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
key = await promptForKey();
|
|
104
|
+
}
|
|
29
105
|
}
|
|
30
106
|
if (!key.startsWith("u1s1-")) {
|
|
31
107
|
console.error(" 这不像一把 u1s1 的 Key(应该以 u1s1- 开头),再看看?");
|