Просмотр исходного кода

凭据本地缓存: ~/.fmode/credentials/gogs.json 600权限持久化, 缓存优先免重复开户, 已有.fmode直接复用

liuyuyang 1 неделя назад
Родитель
Сommit
730d64dae7
1 измененных файлов с 33 добавлено и 2 удалено
  1. 33 2
      skills/study-report/scripts/precheck.mjs

+ 33 - 2
skills/study-report/scripts/precheck.mjs

@@ -20,6 +20,27 @@ import fs from 'node:fs';
 import path from 'node:path';
 import os from 'node:os';
 import { execFileSync } from 'node:child_process';
+const HOME = os.homedir();
+
+// 凭据本地缓存(~/.fmode/credentials/gogs.json, 600 权限):
+// 首次开户成功后持久化 {username, token, savedAt};后续运行直接复用,
+// 仅当缓存 token 校验失败(401/403)时才重调开户接口刷新缓存。
+// 已有 ~/.fmode 完整配置的用户天然命中缓存路径,零重复获取。
+const GOGS_CACHE = path.join(HOME, '.fmode', 'credentials', 'gogs.json');
+function readGogsCache() {
+  try {
+    if (!fs.existsSync(GOGS_CACHE)) return null;
+    const j = JSON.parse(fs.readFileSync(GOGS_CACHE, 'utf8'));
+    return (j.username && j.token) ? j : null;
+  } catch { return null; }
+}
+function writeGogsCache(username, token) {
+  try {
+    fs.mkdirSync(path.dirname(GOGS_CACHE), { recursive: true });
+    fs.writeFileSync(GOGS_CACHE, JSON.stringify({ username, token, savedAt: new Date().toISOString() }, null, 2));
+    fs.chmodSync(GOGS_CACHE, 0o600);
+  } catch { /* 缓存写失败不阻塞主流程 */ }
+}
 
 const FMODE_API_BASE = (process.env.FMODE_FUNCTIONS_BASE_URL || 'https://server.fmode.cn').replace(/\/$/, '');
 const GOGS_BASE = 'https://git.fmode.cn';
@@ -83,12 +104,22 @@ async function probePlatformReachable() {
 /* ── 环节 2:Git 账户(07-git.md 已验证链路)──────────────────── */
 async function ensureGitAccount(platformToken) {
   const row = { item: 'Git 账户', ok: false, detail: '', hint: '' };
+  // ① 本地缓存优先:有凭据直接复用(验证有效性,失败才刷新)
+  const cached = readGogsCache();
+  if (cached) {
+    const v = await fetch(`${GOGS_BASE}/api/v1/user`, { headers: { Authorization: `token ${cached.token}` }, signal: AbortSignal.timeout(15000) });
+    if (v.ok) {
+      return { row: { item: 'Git 账户', ok: true, detail: `本地缓存复用(${cached.username},savedAt ${cached.savedAt.slice(0,10)})`, hint: '' }, gogsToken: cached.token, gogsUser: cached.username };
+    }
+    row.hint = '缓存 token 已失效,重调开户接口刷新…';
+  }
   if (!platformToken) {
     row.detail = '跳过(无平台 token)';
     row.hint = '先恢复平台身份';
     return { row, gogsToken: null, gogsUser: null };
   }
-  const mobile = process.env.FMODE_MOBILE || 'user'; // 稳定用户标识,来自环境或默认
+  // ② 开户/刷新(幂等)
+  const mobile = process.env.FMODE_MOBILE || (cached && cached.username.replace(/^fmode-/, '')) || 'user'; // 稳定用户标识
   const username = `fmode-${mobile}`;
   try {
     const res = await fetch(`${FMODE_API_BASE}/api/functions`, {
@@ -135,7 +166,7 @@ async function ensureGitAccount(platformToken) {
       if (again.status === 200 && againBody.token && againBody.token.sha1) {
         row.ok = true;
         row.detail = `新建 Gogs 账户 ${againBody.username},access token 已签发(sha1 ***${againBody.token.sha1.slice(-4)})`;
-        return { row, gogsToken: againBody.token.sha1, gogsUser: againBody.username };
+        writeGogsCache(againBody.username, againBody.token.sha1); return { row, gogsToken: againBody.token.sha1, gogsUser: againBody.username };
       }
       row.detail = `账户已创建(201)但 token 续发未返回(${again.status})`;
       row.hint = '重跑本自检(幂等)';