e10-data 0.1.6 → 0.1.7

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 CHANGED
@@ -9,7 +9,7 @@ npm i -g e10-data # 全局安装
9
9
  e10-data --version # 验证
10
10
  ```
11
11
 
12
- > 依赖:认证复用 `weaver-e10-login` 的登录态(用户级缓存 `~/.workbuddy/e10-login-cache.md`)。请先安装并登录 weaver-e10-login(`e10-login oidc`),登录态失效时 CLI 会提示重新登录。
12
+ > 依赖:认证复用 `weaver-e10-login` 的登录态。**认证单一权威源 = `~/.e10-cli/profiles/<active>/auth`**(e10-login 统一认证,与所有专家/工具共享);CLI 进程内读取并解密(AES-256-GCM,seed 与 e10-login 一致),随后自动回写同步明文镜像 `~/.workbuddy/e10-login-cache.md`(仅供查看/兜底)。请先安装并登录 weaver-e10-login(`e10-login oidc`),登录态失效时 CLI 会提示重新登录。
13
13
 
14
14
  ## 命令总览
15
15
 
@@ -29,7 +29,7 @@ e10-data attend statis 考勤假期余额统计 getAttendInfoStatis(hr-atte
29
29
  - `--json`:原样输出接口 JSON(供脚本/Agent 消费);默认人读输出。
30
30
  - 复杂 JSON/中文参数:推荐 `@文件` 承载(如 `--dsl @q.json`、`--where @cond.json`)。
31
31
  - ⚠️ 大整数精度(自动处理):E10 的 ID 多为 19 位,超过 JS 安全整数(2^53-1≈9e15)。CLI 解析 JSON 时**自动把超范围裸整数转成字符串**再发请求/输出(实测后端接受字符串做 =/IN/BETWEEN 数值比较),无需手动加引号,也不误伤字符串正文。
32
- - 认证:进程内读取 `~/.workbuddy/e10-login-cache.md`;失效提示重新执行 `e10-login oidc`。
32
+ - 认证:优先读权威源 `~/.e10-cli/profiles/<active>/auth`(进程内 AES-256-GCM 解密)并自动同步明文镜像 `~/.workbuddy/e10-login-cache.md`;两者皆无提示先执行 `e10-login oidc`。
33
33
  - 版本更新:`npm i -g e10-data@latest`;查看源上最新 `npm view e10-data version`。
34
34
 
35
35
  ## 用法示例
@@ -69,7 +69,7 @@ e10-data attend statis --user 6264843388578732287 --begin 2026-09-01 --end 2026-
69
69
 
70
70
  ## attend statis 考勤假期余额(v0.1.5 新增)
71
71
 
72
- 封装 E10 考勤 REST 接口 `POST /api/attend/web/attendInfoV2/getAttendInfoStatis`(hr-attendance 场景六:病假/事假/年假余额统计,替代原手工 curl)。认证/绕代理由 CLI 进程内自动完成(读 `~/.workbuddy/e10-login-cache.md`)。
72
+ 封装 E10 考勤 REST 接口 `POST /api/attend/web/attendInfoV2/getAttendInfoStatis`(hr-attendance 场景六:病假/事假/年假余额统计,替代原手工 curl)。认证/绕代理由 CLI 进程内自动完成(权威源 `~/.e10-cli/profiles/<active>/auth`)。
73
73
 
74
74
  ```bash
75
75
  e10-data attend statis [--user <人员ID>] [--begin 2026-09-01] [--end 2026-09-30]
package/bin/e10-data.mjs CHANGED
@@ -14,7 +14,7 @@
14
14
  * e10-data attend statis 考勤假期余额统计 getAttendInfoStatis(hr-attendance 病假/事假,2026-09-07)
15
15
  *
16
16
  * 通用:--json 原样输出;复杂 JSON 参数支持 @文件 或 内联(中文走 @文件 更稳)
17
- * 认证:进程内读取用户级登录缓存 ~/.workbuddy/e10-login-cache.md;不存在/失效提示先 e10-login
17
+ * 认证:进程内读取权威源 ~/.e10-cli/profiles/<active>/auth(e10-login 统一认证,AES-256-GCM seed 硬编码纯 JS 解密,v0.1.7 起),并自动回写同步明文镜像 ~/.workbuddy/e10-login-cache.md;两者皆无时提示先 e10-login
18
18
  *
19
19
  * 用法示例:
20
20
  * node e10-data.mjs query --conn 1144919996804022272 --model dw --schema dw --dsl @q.json
@@ -40,19 +40,93 @@ const UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,
40
40
  const EB_BIZ_ID = "10000000000000000";
41
41
 
42
42
  // ---------------- 认证 ----------------
43
- function loadAuth() {
43
+ // 认证单一权威源:~/.e10-cli/profiles/<active>/auth(e10-login / e10-cli 统一认证,与所有专家共享,无需各自存登录信息)。
44
+ // AES-256-GCM 加密,seed 与 e10-login 一致(ccw_eteams_auth_v1_8a3f2c1b9e4d → sha256),纯 JS 进程内可解、零外部依赖。
45
+ // 明文镜像:~/.workbuddy/e10-login-cache.md(历史遗留,仅供查看/兜底;读到权威源后自动回写同步,不再需要手工维护)。
46
+ const E10_AUTH_SEED = "ccw_eteams_auth_v1_8a3f2c1b9e4d";
47
+ function decryptAuthWrapper(wrapper) {
48
+ try {
49
+ const combined = Buffer.from(wrapper.data, "base64");
50
+ const IV = 12, TAG = 16;
51
+ if (combined.length < IV + TAG + 1) return null;
52
+ const key = crypto.createHash("sha256").update(E10_AUTH_SEED).digest();
53
+ const decipher = crypto.createDecipheriv("aes-256-gcm", key, combined.subarray(0, IV), { authTagLength: TAG });
54
+ decipher.setAuthTag(combined.subarray(combined.length - TAG));
55
+ return JSON.parse(Buffer.concat([decipher.update(combined.subarray(IV, combined.length - TAG)), decipher.final()]).toString("utf-8"));
56
+ } catch { return null; }
57
+ }
58
+ function parseAuthPayload(raw) {
59
+ try { // 兼容两种形态:加密 wrapper({enc:true,data:base64})与明文 JSON({cookies,userId,...})
60
+ const obj = JSON.parse(raw);
61
+ if (obj && obj.enc === true && typeof obj.data === "string") return decryptAuthWrapper(obj);
62
+ if (obj && obj.cookies && (obj.userId || obj.cookies.ETEAMSID)) return obj;
63
+ } catch {}
64
+ return null;
65
+ }
66
+ function cookieFromAuthData(data) { // 组装完整 cookie 串:cookies.raw 优先,逐项补齐 langType/agentType/isAgent
67
+ const eteamsid = (data && data.cookies && data.cookies.ETEAMSID) || "";
68
+ const agent = (data && (data.agentType || data.agent_type)) || "workbuddy";
69
+ let c = (data && data.cookies && data.cookies.raw) || "";
70
+ if (c && !/langType=/.test(c)) c = "langType=zh_CN; " + c;
71
+ if (c && agent && !/agentType=/.test(c)) c += "; agentType=" + agent;
72
+ if (c && !/isAgent=/.test(c)) c += "; isAgent=true";
73
+ if (!c && eteamsid) c = "langType=zh_CN; ETEAMSID=" + eteamsid + "; agentType=" + agent + "; isAgent=true";
74
+ return { eteamsid, cookie: c };
75
+ }
76
+ function authFromE10Cli() { // ① 权威源:~/.e10-cli/profiles/<active>/auth
77
+ try {
78
+ const home = os.homedir();
79
+ let profile = "default";
80
+ try {
81
+ const activeFile = path.join(home, ".e10-cli", "profile");
82
+ if (fs.existsSync(activeFile)) { const n = fs.readFileSync(activeFile, "utf-8").trim(); if (n) profile = n; }
83
+ } catch {}
84
+ const p = path.join(home, ".e10-cli", "profiles", profile, "auth");
85
+ if (!fs.existsSync(p)) return null;
86
+ const data = parseAuthPayload(fs.readFileSync(p, "utf-8"));
87
+ if (!data || !data.cookies || !data.cookies.ETEAMSID || !data.baseUrl) return null;
88
+ const { eteamsid, cookie } = cookieFromAuthData(data);
89
+ return { baseUrl: data.baseUrl, eteamsid, cookie, userId: data.userId || "", tenantKey: data.tenantKey || "", profile };
90
+ } catch { return null; }
91
+ }
92
+ function authFromCacheMd() { // ② 兜底:历史明文缓存 ~/.workbuddy/e10-login-cache.md
44
93
  const p = path.join(os.homedir(), ".workbuddy", "e10-login-cache.md");
45
- if (!fs.existsSync(p)) throw new Error("未找到登录缓存 " + p + ",请先执行 e10-login oidc / set 登录");
94
+ if (!fs.existsSync(p)) return null;
46
95
  const txt = fs.readFileSync(p, "utf-8");
47
96
  const get = (key) => {
48
97
  const m = txt.match(new RegExp("\\*\\*" + key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "\\*\\*\\s*[::]\\s*`?([^`\\n]+)`?"));
49
98
  return m ? m[1].trim() : "";
50
99
  };
51
100
  const auth = { baseUrl: get("baseUrl"), eteamsid: get("ETEAMSID"), cookie: get("完整 Cookie 串"), userId: get("userId") || get("employeeId"), tenantKey: get("tenantKey") };
52
- if (!auth.baseUrl || !auth.eteamsid) throw new Error("登录缓存缺少 baseUrl/ETEAMSID,请重新登录(e10-login oidc)");
101
+ if (!auth.baseUrl || !auth.eteamsid) return null;
53
102
  if (!auth.cookie) auth.cookie = "langType=zh_CN; ETEAMSID=" + auth.eteamsid + "; agentType=workbuddy; isAgent=true";
54
103
  return auth;
55
104
  }
105
+ function syncCacheMd(auth) { // 读到权威源后自动回写明文镜像(内容无变化不写盘),根治"重登后手工同步"问题
106
+ try {
107
+ const p = path.join(os.homedir(), ".workbuddy", "e10-login-cache.md");
108
+ if (!fs.existsSync(p) || !/🔐 登录信息缓存/.test(fs.readFileSync(p, "utf-8"))) return; // 非标准缓存文件不动它
109
+ const d = new Date();
110
+ const ts = d.getFullYear() + "-" + String(d.getMonth() + 1).padStart(2, "0") + "-" + String(d.getDate()).padStart(2, "0") + " " + String(d.getHours()).padStart(2, "0") + ":" + String(d.getMinutes()).padStart(2, "0");
111
+ let txt = fs.readFileSync(p, "utf-8");
112
+ let changed = false;
113
+ const rep = (key, val) => {
114
+ const re = new RegExp("(\\*\\*" + key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "\\*\\*\\s*[::]\\s*`?)([^`\\n]*)(`?)");
115
+ const n = txt.replace(re, (m, a, b, c) => { if (b === val && c === "`") return m; changed = true; return a + val + (c || "`"); });
116
+ txt = n;
117
+ };
118
+ rep("baseUrl", auth.baseUrl); rep("ETEAMSID", auth.eteamsid); rep("完整 Cookie 串", auth.cookie); rep("userId", auth.userId || ""); rep("tenantKey", auth.tenantKey || "");
119
+ rep("缓存记录时间", ts + "(e10-data 自动同步自 ~/.e10-cli/profiles/" + (auth.profile || "") + "/auth)");
120
+ if (changed) fs.writeFileSync(p, txt, "utf-8");
121
+ } catch {}
122
+ }
123
+ function loadAuth() {
124
+ const cli = authFromE10Cli(); // ① 权威源优先(e10-login 统一认证,多专家共享)
125
+ if (cli) { syncCacheMd(cli); return cli; }
126
+ const cached = authFromCacheMd(); // ② 权威源缺失时回退旧明文缓存
127
+ if (cached) return cached;
128
+ throw new Error("未找到登录认证(~/.e10-cli/profiles 与 ~/.workbuddy/e10-login-cache.md 均无),请先执行 e10-login oidc / set 登录");
129
+ }
56
130
  const auth = loadAuth();
57
131
  const BASE = auth.baseUrl.replace(/\/+$/, "");
58
132
  const USER = { id: auth.userId || "", tenantKey: auth.tenantKey || "" };
@@ -1090,7 +1164,7 @@ exp 专家包版本管理(expert-repository/v1,响应以 data.actionMsg.
1090
1164
  exp rollback --expert <code> --version vX.Y.Z
1091
1165
  attend 考勤 REST 接口(2026-09-07 新增,hr-attendance 病假/事假等假期余额)
1092
1166
  attend statis [--user <人员ID>] [--begin 2026-09-01] [--end 2026-09-30] # getAttendInfoStatis 假期余额统计;--user 默认当前登录用户,--begin/--end 默认当月
1093
- 认证: 读 ~/.workbuddy/e10-login-cache.md;失效请先 e10-login oidc`);
1167
+ 认证: 优先读权威源 ~/.e10-cli/profiles/<active>/auth(自动同步镜像 ~/.workbuddy/e10-login-cache.md);皆无请先 e10-login oidc`);
1094
1168
  }
1095
1169
 
1096
1170
  async function main() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "e10-data",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "泛微 E10 数据接口统一 CLI(data-assistant 专家配套):DSL 查询/数据源/文档/词库/关联字段翻译/环境参数配置中心(conf)/专家包版本管理,认证复用 weaver-e10-login 登录态",
5
5
  "author": "e10-dw",
6
6
  "license": "MIT",