opencode-go-usage-tui 1.1.0 → 1.2.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 +15 -1
- package/README_EN.md +15 -1
- package/build.tui.mjs +1 -1
- package/dist/tui.js +119 -22
- package/package.json +1 -1
- package/src/index.tsx +90 -20
package/README.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# opencode-go-usage-tui
|
|
2
2
|
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
🌏 **语言 / Language:** [简体中文](/README.md) | [English](/README_EN.md)
|
|
6
|
+
|
|
7
|
+
</div>
|
|
8
|
+
|
|
3
9
|
在 OpenCode 侧边栏实时显示 OpenCode Go 额度用量(5小时/每周/每月)。
|
|
4
10
|
|
|
5
11
|
支持中英双语界面(`/go-lang` 切换,首次启动自动引导选择语言)。
|
|
@@ -47,7 +53,15 @@ npm install -g opencode-go-usage-tui
|
|
|
47
53
|
1. **workspace_id**:`wrk_` 开头,在 opencode.ai 控制台 URL 中获取
|
|
48
54
|
2. **auth cookie**:浏览器 F12 → Application → Cookies → opencode.ai → 复制 `auth` 的值(`Fe26.2*` 开头)
|
|
49
55
|
|
|
50
|
-
配置保存在 `~/.config/opencode
|
|
56
|
+
配置保存在 `~/.config/opencode/`:
|
|
57
|
+
|
|
58
|
+
- `go-usage-config.json` — workspace_id(明文,非敏感)
|
|
59
|
+
- `go-auth-cookie.enc` — auth cookie(**AES-256-GCM 加密**)
|
|
60
|
+
- `.encryption-key` — 加密密钥(32 字节随机生成)
|
|
61
|
+
|
|
62
|
+
> 🔒 **安全说明**:cookie 以 AES-256-GCM 加密存储,密钥随机生成且独立保存,文件被备份/同步/日志收集不会泄露 cookie。旧版明文文件(`go-auth-cookie.txt` / config.json 内嵌 cookie)首次读取时**自动迁移**为加密存储并清理明文。
|
|
63
|
+
>
|
|
64
|
+
> ⚠️ 局限:密钥与密文同目录,能防御"被动泄露"(备份/同步),无法防御能读取该目录的本地恶意程序。如需更强保护可改用系统级凭据存储。
|
|
51
65
|
|
|
52
66
|
### 方式二:环境变量
|
|
53
67
|
|
package/README_EN.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# opencode-go-usage-tui
|
|
2
2
|
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
🌏 **Language / 语言:** [English](/README_EN.md) | [简体中文](/README.md)
|
|
6
|
+
|
|
7
|
+
</div>
|
|
8
|
+
|
|
3
9
|
Display your OpenCode Go quota usage (5h / weekly / monthly) in the OpenCode sidebar in real time.
|
|
4
10
|
|
|
5
11
|
Bilingual UI (Chinese / English) — switch with `/go-lang`, or pick a language during the first-run onboarding.
|
|
@@ -47,7 +53,15 @@ Enter two values (unique per user — get them by logging into opencode.ai):
|
|
|
47
53
|
1. **workspace_id**: starts with `wrk_`, found in the opencode.ai console URL
|
|
48
54
|
2. **auth cookie**: in your browser, F12 → Application → Cookies → opencode.ai → copy the `auth` value (starts with `Fe26.2*`)
|
|
49
55
|
|
|
50
|
-
Config is saved to `~/.config/opencode
|
|
56
|
+
Config is saved to `~/.config/opencode/`:
|
|
57
|
+
|
|
58
|
+
- `go-usage-config.json` — workspace_id (plain text, not sensitive)
|
|
59
|
+
- `go-auth-cookie.enc` — auth cookie (**AES-256-GCM encrypted**)
|
|
60
|
+
- `.encryption-key` — encryption key (random 32 bytes)
|
|
61
|
+
|
|
62
|
+
> 🔒 **Security**: The cookie is stored encrypted with AES-256-GCM, with a randomly generated key stored separately — backups, syncs, and logs cannot leak the cookie. Legacy plaintext files (`go-auth-cookie.txt` / cookie embedded in config.json) are **auto-migrated** to encrypted storage on first read, and the plaintext is cleaned up.
|
|
63
|
+
>
|
|
64
|
+
> ⚠️ Limitation: The key lives in the same directory as the ciphertext. This defends against passive leaks (backups/sync) but not against local malware that can read your user directory. Use system credential storage (Windows DPAPI / macOS Keychain) for stronger protection.
|
|
51
65
|
|
|
52
66
|
### Option 2: Environment variables
|
|
53
67
|
|
package/build.tui.mjs
CHANGED
|
@@ -10,7 +10,7 @@ await esbuild.build({
|
|
|
10
10
|
format: "esm",
|
|
11
11
|
platform: "node",
|
|
12
12
|
bundle: true,
|
|
13
|
-
external: ["@opencode-ai/*", "@opentui/*", "solid-js", "node:fs", "node:path"],
|
|
13
|
+
external: ["@opencode-ai/*", "@opentui/*", "solid-js", "node:fs", "node:path", "node:crypto"],
|
|
14
14
|
plugins: [solidPlugin({ solid: { moduleName: "@opentui/solid", generate: "universal" } })],
|
|
15
15
|
define: { __PLUGIN_VERSION__: JSON.stringify(pkg.version) },
|
|
16
16
|
logLevel: "info",
|
package/dist/tui.js
CHANGED
|
@@ -9,8 +9,9 @@ import { insertNode as _$insertNode } from "@opentui/solid";
|
|
|
9
9
|
import { insert as _$insert } from "@opentui/solid";
|
|
10
10
|
import { createElement as _$createElement } from "@opentui/solid";
|
|
11
11
|
import { createSignal, createEffect, onMount, onCleanup, Show } from "solid-js";
|
|
12
|
-
import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
12
|
+
import { readFileSync, writeFileSync, mkdirSync, renameSync, existsSync } from "node:fs";
|
|
13
13
|
import { join, dirname } from "node:path";
|
|
14
|
+
import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
|
|
14
15
|
|
|
15
16
|
// src/i18n.ts
|
|
16
17
|
var ZH_T = {
|
|
@@ -113,44 +114,140 @@ function detectLang() {
|
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
// src/index.tsx
|
|
116
|
-
var VERSION = "1.
|
|
117
|
+
var VERSION = "1.2.0";
|
|
117
118
|
var CHECK_INTERVAL = Number(process?.env?.OPENCODE_GO_CHECK_INTERVAL ?? 6e4);
|
|
118
119
|
var WARN_THRESHOLD = Number(process?.env?.OPENCODE_GO_WARN_THRESHOLD ?? 0.8);
|
|
119
120
|
var CONFIG_DIR = process?.env?.OPENCODE_CONFIG_DIR || (process?.env?.USERPROFILE ? `${process.env.USERPROFILE}\\.config\\opencode` : "") || process?.env?.HOME + "/.config/opencode";
|
|
120
121
|
var CONFIG_FILE = join(CONFIG_DIR, "go-usage-config.json");
|
|
122
|
+
var COOKIE_ENC_FILE = join(CONFIG_DIR, "go-auth-cookie.enc");
|
|
123
|
+
var KEY_FILE = join(CONFIG_DIR, ".encryption-key");
|
|
124
|
+
var COOKIE_PLAIN_FILE = `${CONFIG_DIR}\\go-auth-cookie.txt`;
|
|
121
125
|
var KV_PREFIX = "go-usage";
|
|
122
|
-
function
|
|
123
|
-
|
|
124
|
-
|
|
126
|
+
function loadEncryptionKey() {
|
|
127
|
+
try {
|
|
128
|
+
const hex2 = readFileSync(KEY_FILE, "utf8").trim();
|
|
129
|
+
if (hex2) return Buffer.from(hex2, "hex");
|
|
130
|
+
} catch {
|
|
131
|
+
}
|
|
132
|
+
const key = randomBytes(32);
|
|
133
|
+
mkdirSync(dirname(KEY_FILE), {
|
|
134
|
+
recursive: true
|
|
135
|
+
});
|
|
136
|
+
writeFileSync(KEY_FILE, key.toString("hex"), {
|
|
137
|
+
encoding: "utf8",
|
|
138
|
+
mode: 384
|
|
139
|
+
});
|
|
140
|
+
return key;
|
|
141
|
+
}
|
|
142
|
+
function encryptText(text) {
|
|
143
|
+
const key = loadEncryptionKey();
|
|
144
|
+
const iv = randomBytes(16);
|
|
145
|
+
const cipher = createCipheriv("aes-256-gcm", key, iv);
|
|
146
|
+
const data = cipher.update(text, "utf8", "hex") + cipher.final("hex");
|
|
147
|
+
return JSON.stringify({
|
|
148
|
+
v: 1,
|
|
149
|
+
iv: iv.toString("hex"),
|
|
150
|
+
data,
|
|
151
|
+
tag: cipher.getAuthTag().toString("hex")
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
function decryptText(encJson) {
|
|
155
|
+
const {
|
|
156
|
+
iv,
|
|
157
|
+
data,
|
|
158
|
+
tag
|
|
159
|
+
} = JSON.parse(encJson);
|
|
160
|
+
const key = loadEncryptionKey();
|
|
161
|
+
const decipher = createDecipheriv("aes-256-gcm", key, Buffer.from(iv, "hex"));
|
|
162
|
+
decipher.setAuthTag(Buffer.from(tag, "hex"));
|
|
163
|
+
return decipher.update(data, "hex", "utf8") + decipher.final("utf8");
|
|
164
|
+
}
|
|
165
|
+
function readJsonFile(file) {
|
|
125
166
|
try {
|
|
126
|
-
|
|
167
|
+
return JSON.parse(readFileSync(file, "utf8"));
|
|
127
168
|
} catch {
|
|
128
|
-
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function loadConfig() {
|
|
173
|
+
const env = process?.env ?? {};
|
|
174
|
+
const fileCfg = readJsonFile(CONFIG_FILE) ?? {};
|
|
175
|
+
if (env.OPENCODE_GO_AUTH_COOKIE) {
|
|
176
|
+
return {
|
|
177
|
+
workspaceId: env.OPENCODE_GO_WORKSPACE_ID || fileCfg.workspace_id || "",
|
|
178
|
+
authCookie: env.OPENCODE_GO_AUTH_COOKIE
|
|
179
|
+
};
|
|
129
180
|
}
|
|
130
|
-
const cookieFile = env.OPENCODE_GO_COOKIE_FILE || fileCfg.cookie_file || `${CONFIG_DIR}\\go-auth-cookie.txt`;
|
|
131
|
-
let fileCookie = "";
|
|
132
181
|
try {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
182
|
+
if (existsSync(COOKIE_ENC_FILE)) {
|
|
183
|
+
const cookie = decryptText(readFileSync(COOKIE_ENC_FILE, "utf8"));
|
|
184
|
+
if (cookie) {
|
|
185
|
+
return {
|
|
186
|
+
workspaceId: env.OPENCODE_GO_WORKSPACE_ID || fileCfg.workspace_id || "",
|
|
187
|
+
authCookie: cookie
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
}
|
|
137
191
|
} catch {
|
|
138
|
-
|
|
192
|
+
}
|
|
193
|
+
const legacyCookie = fileCfg.auth_cookie || fileCfg.cookie || (() => {
|
|
194
|
+
try {
|
|
195
|
+
return readFileSync(COOKIE_PLAIN_FILE, "utf8").trim();
|
|
196
|
+
} catch {
|
|
197
|
+
return "";
|
|
198
|
+
}
|
|
199
|
+
})();
|
|
200
|
+
if (legacyCookie) {
|
|
201
|
+
const enc = encryptText(legacyCookie);
|
|
202
|
+
mkdirSync(CONFIG_DIR, {
|
|
203
|
+
recursive: true
|
|
204
|
+
});
|
|
205
|
+
writeFileSync(COOKIE_ENC_FILE, enc, "utf8");
|
|
206
|
+
const cleanCfg = {
|
|
207
|
+
...fileCfg
|
|
208
|
+
};
|
|
209
|
+
delete cleanCfg.cookie;
|
|
210
|
+
delete cleanCfg.auth_cookie;
|
|
211
|
+
try {
|
|
212
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(cleanCfg, null, 2), "utf8");
|
|
213
|
+
} catch {
|
|
214
|
+
}
|
|
215
|
+
try {
|
|
216
|
+
if (existsSync(COOKIE_PLAIN_FILE)) renameSync(COOKIE_PLAIN_FILE, COOKIE_PLAIN_FILE + ".bak");
|
|
217
|
+
} catch {
|
|
218
|
+
}
|
|
219
|
+
return {
|
|
220
|
+
workspaceId: env.OPENCODE_GO_WORKSPACE_ID || fileCfg.workspace_id || "",
|
|
221
|
+
authCookie: legacyCookie
|
|
222
|
+
};
|
|
139
223
|
}
|
|
140
224
|
return {
|
|
141
225
|
workspaceId: env.OPENCODE_GO_WORKSPACE_ID || fileCfg.workspace_id || "",
|
|
142
|
-
authCookie:
|
|
226
|
+
authCookie: ""
|
|
143
227
|
};
|
|
144
228
|
}
|
|
145
229
|
function saveConfig(patch) {
|
|
146
|
-
|
|
147
|
-
try {
|
|
148
|
-
fileCfg = JSON.parse(readFileSync(CONFIG_FILE, "utf8"));
|
|
149
|
-
} catch {
|
|
150
|
-
fileCfg = {};
|
|
151
|
-
}
|
|
230
|
+
const fileCfg = readJsonFile(CONFIG_FILE) ?? {};
|
|
152
231
|
if (patch.workspace_id !== void 0) fileCfg.workspace_id = patch.workspace_id;
|
|
153
|
-
if (patch.cookie !== void 0)
|
|
232
|
+
if (patch.cookie !== void 0) {
|
|
233
|
+
if (patch.cookie) {
|
|
234
|
+
mkdirSync(CONFIG_DIR, {
|
|
235
|
+
recursive: true
|
|
236
|
+
});
|
|
237
|
+
writeFileSync(COOKIE_ENC_FILE, encryptText(patch.cookie), "utf8");
|
|
238
|
+
delete fileCfg.cookie;
|
|
239
|
+
delete fileCfg.auth_cookie;
|
|
240
|
+
try {
|
|
241
|
+
if (existsSync(COOKIE_PLAIN_FILE)) renameSync(COOKIE_PLAIN_FILE, COOKIE_PLAIN_FILE + ".bak");
|
|
242
|
+
} catch {
|
|
243
|
+
}
|
|
244
|
+
} else {
|
|
245
|
+
try {
|
|
246
|
+
if (existsSync(COOKIE_ENC_FILE)) renameSync(COOKIE_ENC_FILE, COOKIE_ENC_FILE + ".bak");
|
|
247
|
+
} catch {
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
154
251
|
try {
|
|
155
252
|
mkdirSync(dirname(CONFIG_FILE), {
|
|
156
253
|
recursive: true
|
package/package.json
CHANGED
package/src/index.tsx
CHANGED
|
@@ -10,8 +10,9 @@ import type {
|
|
|
10
10
|
} from "@opencode-ai/plugin/tui"
|
|
11
11
|
import { createSignal, createEffect, onMount, onCleanup, Show } from "solid-js"
|
|
12
12
|
import type { JSX } from "@opentui/solid"
|
|
13
|
-
import { readFileSync, writeFileSync, mkdirSync } from "node:fs"
|
|
13
|
+
import { readFileSync, writeFileSync, mkdirSync, renameSync, existsSync } from "node:fs"
|
|
14
14
|
import { join, dirname } from "node:path"
|
|
15
|
+
import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto"
|
|
15
16
|
import { createT, detectLang, LANG_META } from "./i18n"
|
|
16
17
|
import type { LangCode } from "./i18n"
|
|
17
18
|
|
|
@@ -24,35 +25,104 @@ const CONFIG_DIR = process?.env?.OPENCODE_CONFIG_DIR
|
|
|
24
25
|
|| (process?.env?.USERPROFILE ? `${process.env.USERPROFILE}\\.config\\opencode` : "")
|
|
25
26
|
|| process?.env?.HOME + "/.config/opencode"
|
|
26
27
|
const CONFIG_FILE = join(CONFIG_DIR, "go-usage-config.json")
|
|
28
|
+
const COOKIE_ENC_FILE = join(CONFIG_DIR, "go-auth-cookie.enc")
|
|
29
|
+
const KEY_FILE = join(CONFIG_DIR, ".encryption-key")
|
|
30
|
+
const COOKIE_PLAIN_FILE = `${CONFIG_DIR}\\go-auth-cookie.txt`
|
|
27
31
|
const KV_PREFIX = "go-usage"
|
|
28
32
|
|
|
33
|
+
// ── AES-256-GCM 加密存储 ────────────────────────────────
|
|
34
|
+
// cookie 以密文存 go-auth-cookie.enc,密钥存 .encryption-key。
|
|
35
|
+
// 注意:Windows 无 Unix 权限位,mode 0o600 仅对 macOS/Linux 生效;
|
|
36
|
+
// Windows 上密钥与密文同目录,防护重点是"被动泄露"(备份/云同步/日志),
|
|
37
|
+
// 无法抵御能读取该目录的本地恶意程序。
|
|
38
|
+
function loadEncryptionKey(): Buffer {
|
|
39
|
+
try {
|
|
40
|
+
const hex = readFileSync(KEY_FILE, "utf8").trim()
|
|
41
|
+
if (hex) return Buffer.from(hex, "hex")
|
|
42
|
+
} catch { /* 无密钥则新建 */ }
|
|
43
|
+
const key = randomBytes(32)
|
|
44
|
+
mkdirSync(dirname(KEY_FILE), { recursive: true })
|
|
45
|
+
writeFileSync(KEY_FILE, key.toString("hex"), { encoding: "utf8", mode: 0o600 })
|
|
46
|
+
return key
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function encryptText(text: string): string {
|
|
50
|
+
const key = loadEncryptionKey()
|
|
51
|
+
const iv = randomBytes(16)
|
|
52
|
+
const cipher = createCipheriv("aes-256-gcm", key, iv)
|
|
53
|
+
const data = cipher.update(text, "utf8", "hex") + cipher.final("hex")
|
|
54
|
+
return JSON.stringify({ v: 1, iv: iv.toString("hex"), data, tag: cipher.getAuthTag().toString("hex") })
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function decryptText(encJson: string): string {
|
|
58
|
+
const { iv, data, tag } = JSON.parse(encJson)
|
|
59
|
+
const key = loadEncryptionKey()
|
|
60
|
+
const decipher = createDecipheriv("aes-256-gcm", key, Buffer.from(iv, "hex"))
|
|
61
|
+
decipher.setAuthTag(Buffer.from(tag, "hex"))
|
|
62
|
+
return decipher.update(data, "hex", "utf8") + decipher.final("utf8")
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function readJsonFile<T>(file: string): T | null {
|
|
66
|
+
try { return JSON.parse(readFileSync(file, "utf8")) as T } catch { return null }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
interface ConfigFile { workspace_id?: string; cookie?: string; auth_cookie?: string; cookie_file?: string }
|
|
70
|
+
|
|
29
71
|
function loadConfig(): { workspaceId: string; authCookie: string } {
|
|
30
72
|
const env = process?.env ?? {}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
73
|
+
const fileCfg = readJsonFile<ConfigFile>(CONFIG_FILE) ?? {}
|
|
74
|
+
|
|
75
|
+
// 1. 环境变量优先
|
|
76
|
+
if (env.OPENCODE_GO_AUTH_COOKIE) {
|
|
77
|
+
return { workspaceId: env.OPENCODE_GO_WORKSPACE_ID || fileCfg.workspace_id || "", authCookie: env.OPENCODE_GO_AUTH_COOKIE }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// 2. 加密存储
|
|
37
81
|
try {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
82
|
+
if (existsSync(COOKIE_ENC_FILE)) {
|
|
83
|
+
const cookie = decryptText(readFileSync(COOKIE_ENC_FILE, "utf8"))
|
|
84
|
+
if (cookie) {
|
|
85
|
+
return { workspaceId: env.OPENCODE_GO_WORKSPACE_ID || fileCfg.workspace_id || "", authCookie: cookie }
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
} catch { /* 密文损坏时回退到明文迁移 */ }
|
|
89
|
+
|
|
90
|
+
// 3. 兼容旧明文(config.json 内嵌 cookie / auth_cookie / 独立 txt 文件)——自动迁移
|
|
91
|
+
const legacyCookie = fileCfg.auth_cookie || fileCfg.cookie || (() => {
|
|
92
|
+
try { return readFileSync(COOKIE_PLAIN_FILE, "utf8").trim() } catch { return "" }
|
|
93
|
+
})()
|
|
94
|
+
if (legacyCookie) {
|
|
95
|
+
const enc = encryptText(legacyCookie)
|
|
96
|
+
mkdirSync(CONFIG_DIR, { recursive: true })
|
|
97
|
+
writeFileSync(COOKIE_ENC_FILE, enc, "utf8")
|
|
98
|
+
// 清理旧明文
|
|
99
|
+
const cleanCfg: ConfigFile = { ...fileCfg }
|
|
100
|
+
delete cleanCfg.cookie
|
|
101
|
+
delete cleanCfg.auth_cookie
|
|
102
|
+
try { writeFileSync(CONFIG_FILE, JSON.stringify(cleanCfg, null, 2), "utf8") } catch { /* 忽略 */ }
|
|
103
|
+
try { if (existsSync(COOKIE_PLAIN_FILE)) renameSync(COOKIE_PLAIN_FILE, COOKIE_PLAIN_FILE + ".bak") } catch { /* 忽略 */ }
|
|
104
|
+
return { workspaceId: env.OPENCODE_GO_WORKSPACE_ID || fileCfg.workspace_id || "", authCookie: legacyCookie }
|
|
46
105
|
}
|
|
106
|
+
|
|
107
|
+
return { workspaceId: env.OPENCODE_GO_WORKSPACE_ID || fileCfg.workspace_id || "", authCookie: "" }
|
|
47
108
|
}
|
|
48
109
|
|
|
49
110
|
function saveConfig(patch: { workspace_id?: string; cookie?: string }): void {
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
fileCfg = JSON.parse(readFileSync(CONFIG_FILE, "utf8"))
|
|
53
|
-
} catch { fileCfg = {} }
|
|
111
|
+
const fileCfg = readJsonFile<ConfigFile>(CONFIG_FILE) ?? {}
|
|
54
112
|
if (patch.workspace_id !== undefined) fileCfg.workspace_id = patch.workspace_id
|
|
55
|
-
if (patch.cookie !== undefined)
|
|
113
|
+
if (patch.cookie !== undefined) {
|
|
114
|
+
// cookie 改为加密存储,不再写明文到 config.json
|
|
115
|
+
if (patch.cookie) {
|
|
116
|
+
mkdirSync(CONFIG_DIR, { recursive: true })
|
|
117
|
+
writeFileSync(COOKIE_ENC_FILE, encryptText(patch.cookie), "utf8")
|
|
118
|
+
delete fileCfg.cookie
|
|
119
|
+
delete fileCfg.auth_cookie
|
|
120
|
+
// 清理可能存在的旧明文 txt
|
|
121
|
+
try { if (existsSync(COOKIE_PLAIN_FILE)) renameSync(COOKIE_PLAIN_FILE, COOKIE_PLAIN_FILE + ".bak") } catch { /* 忽略 */ }
|
|
122
|
+
} else {
|
|
123
|
+
try { if (existsSync(COOKIE_ENC_FILE)) renameSync(COOKIE_ENC_FILE, COOKIE_ENC_FILE + ".bak") } catch { /* 忽略 */ }
|
|
124
|
+
}
|
|
125
|
+
}
|
|
56
126
|
try {
|
|
57
127
|
mkdirSync(dirname(CONFIG_FILE), { recursive: true })
|
|
58
128
|
writeFileSync(CONFIG_FILE, JSON.stringify(fileCfg, null, 2), "utf8")
|