fix: require exact ERP account identity
This commit is contained in:
1 parent
6bdaa2a6e6
commit
8f70cbae4d
17 files changed
+201
-31
No files matched your search
@@ -11,9 +11,14 @@ Chrome Manifest V3 扩展,在用户已登录的 LTJT ERP 页面内执行经过
|
||||
|
||||
## 当前版本
|
||||
|
||||
当前源码版本为 `0.5.167`。版本化 ZIP、文件哈希和 Skill/DOCX 基线见 [`../../dist/release-manifest.json`](../../dist/release-manifest.json)。旧版本实现流水已冻结在 [`../../archive/project-history/2026-08-16/chrome-extension-README.pre-governance.md`](../../archive/project-history/2026-08-16/chrome-extension-README.pre-governance.md)。
|
||||
当前源码版本为 `0.5.168`。版本化 ZIP、文件哈希和 Skill/DOCX 基线见 [`../../dist/release-manifest.json`](../../dist/release-manifest.json)。旧版本实现流水已冻结在 [`../../archive/project-history/2026-08-16/chrome-extension-README.pre-governance.md`](../../archive/project-history/2026-08-16/chrome-extension-README.pre-governance.md)。
|
||||
|
||||
0.5.167 当前重点:
|
||||
0.5.168 当前重点:
|
||||
|
||||
- ERP 登录身份只从当前主页面唯一的 `#Lable_UserName` 节点读取,并与平台绑定身份做 Unicode、空白和大小写规范化后的精确全等比较。缺失、重复、空白或仅为子串时都不再执行;不再用整页业务文字猜测账号。
|
||||
- 扩展仍只向平台返回账号是否存在、是否唯一和是否匹配,不回传 ERP 页面显示的账号文本。
|
||||
|
||||
继续保留 0.5.167 的空闲证明和受控重载协议:
|
||||
|
||||
- 插件 PING 会返回当前运行任务、持久化写入边界和待回查结果汇总后的 `extension_update.safe`。只有内存与持久化状态都完全空闲,服务端才允许同一 ECS 实例进入文件部署。
|
||||
- 中央服务完成共享目录替换后,平台通过受控消息请求后台 `chrome.runtime.reload()`,并刷新平台页以重新注入 content script;执行中、已跨写边界或待回查状态会拒绝重载。
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
importScripts('source-region.js', 'operation-plans.js', 'execution-guard.js', 'lifecycle-result.js', 'operation-timing.js');
|
||||
importScripts('source-region.js', 'operation-plans.js', 'execution-guard.js', 'lifecycle-result.js', 'operation-timing.js', 'erp-account-identity.js');
|
||||
|
||||
const runningTasks = new Set();
|
||||
const executionWorkerKeepalives = new Map();
|
||||
@@ -9,6 +9,7 @@ const operationPlans = self.LTJTOperationPlans;
|
||||
const executionGuard = self.LTJTExecutionGuard;
|
||||
const lifecycleResult = self.LTJTLifecycleResult;
|
||||
const operationTiming = self.LTJTOperationTiming;
|
||||
const erpAccountIdentity = self.LTJTErpAccountIdentity;
|
||||
const EXTENSION_VERSION = chrome.runtime.getManifest().version;
|
||||
const operationTimingDetailBuffers = new Map();
|
||||
const erpTabCache = new Map();
|
||||
@@ -1406,7 +1407,7 @@ async function findOrOpenErpTab(taskId = '') {
|
||||
}
|
||||
|
||||
async function readErpSessionStatus(expectedErpAccount = '') {
|
||||
const normalizedExpectedAccount = String(expectedErpAccount || '').trim();
|
||||
const normalizedExpectedAccount = erpAccountIdentity.normalizeErpAccountIdentity(expectedErpAccount);
|
||||
const permission = await erpHostPermissionStatus();
|
||||
const keepalive = await readErpKeepaliveState();
|
||||
const tabs = await chrome.tabs.query({ url: `${ERP_ORIGIN}/*` });
|
||||
@@ -1446,25 +1447,44 @@ async function readErpSessionStatus(expectedErpAccount = '') {
|
||||
try {
|
||||
const [inspection] = await executeErpScript(tab.id, {
|
||||
target: { tabId: tab.id },
|
||||
func: (expectedAccount) => {
|
||||
func: () => {
|
||||
const bodyText = document.body?.innerText || '';
|
||||
const accountNodes = Array.from(document.querySelectorAll('#Lable_UserName'));
|
||||
const accountNode = accountNodes.length === 1 ? accountNodes[0] : null;
|
||||
return {
|
||||
url: location.href,
|
||||
title: document.title,
|
||||
account_configured: Boolean(expectedAccount),
|
||||
account_matched: Boolean(expectedAccount) && bodyText.includes(expectedAccount),
|
||||
observed_account_identity: accountNode?.textContent || '',
|
||||
account_identity_node_count: accountNodes.length,
|
||||
login_or_permission_error: Boolean(document.querySelector('input[type="password"]'))
|
||||
|| /login|无权限|权限不足|permission denied/i.test(`${location.href}\n${document.title}\n${bodyText.slice(0, 400)}`)
|
||||
};
|
||||
},
|
||||
args: [normalizedExpectedAccount]
|
||||
args: []
|
||||
});
|
||||
const inspectionResult = inspection?.result || {
|
||||
const rawInspectionResult = inspection?.result || {
|
||||
url: tab.url || '',
|
||||
title: '',
|
||||
account_matched: false,
|
||||
observed_account_identity: '',
|
||||
account_identity_node_count: 0,
|
||||
login_or_permission_error: true
|
||||
};
|
||||
const {
|
||||
observed_account_identity: observedAccountIdentity,
|
||||
...safeInspectionResult
|
||||
} = rawInspectionResult;
|
||||
const inspectionResult = {
|
||||
...safeInspectionResult,
|
||||
account_configured: Boolean(normalizedExpectedAccount),
|
||||
account_identity_present: Boolean(
|
||||
erpAccountIdentity.normalizeErpAccountIdentity(observedAccountIdentity)
|
||||
),
|
||||
account_matched: Number(safeInspectionResult.account_identity_node_count) === 1
|
||||
&& erpAccountIdentity.exactErpAccountIdentityMatch(
|
||||
normalizedExpectedAccount,
|
||||
observedAccountIdentity
|
||||
)
|
||||
};
|
||||
const recoveryRequest = (shouldRecoverFromSessionStatus(inspectionResult)
|
||||
|| keepalive.last_status === 'session_expired')
|
||||
? requestErpLinkRecovery(
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
(function installLTJTErpAccountIdentity(root, factory) {
|
||||
const api = factory();
|
||||
if (typeof module !== 'undefined' && module.exports) module.exports = api;
|
||||
if (root) root.LTJTErpAccountIdentity = api;
|
||||
}(typeof self !== 'undefined' ? self : globalThis, () => {
|
||||
'use strict';
|
||||
|
||||
function normalizeErpAccountIdentity(value) {
|
||||
return String(value || '')
|
||||
.normalize('NFKC')
|
||||
.replace(/\s+/gu, ' ')
|
||||
.trim()
|
||||
.toLocaleLowerCase();
|
||||
}
|
||||
|
||||
function exactErpAccountIdentityMatch(expectedAccount, observedAccount) {
|
||||
const expected = normalizeErpAccountIdentity(expectedAccount);
|
||||
const observed = normalizeErpAccountIdentity(observedAccount);
|
||||
return Boolean(expected && observed && expected === observed);
|
||||
}
|
||||
|
||||
return {
|
||||
normalizeErpAccountIdentity,
|
||||
exactErpAccountIdentityMatch
|
||||
};
|
||||
}));
|
||||
@@ -6118,7 +6118,7 @@
|
||||
}
|
||||
|
||||
window.LTJTOrderAssistant = {
|
||||
version: '0.5.167',
|
||||
version: '0.5.168',
|
||||
resolveNativeListSearchValues,
|
||||
lookupKeywordMatchesText,
|
||||
inspectLifecycleSearchCriteria: lifecycleSearchCriteria,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "联泰下单助手",
|
||||
"version": "0.5.167",
|
||||
"version": "0.5.168",
|
||||
"description": "在已登录 LTJT ERP 页面内规划并受控执行联泰 ERP 业务操作。",
|
||||
"permissions": [
|
||||
"activeTab",
|
||||
|
||||
@@ -944,7 +944,7 @@
|
||||
|
||||
window.LTJTOrderAssistant = {
|
||||
...(window.LTJTOrderAssistant || {}),
|
||||
version: '0.5.167',
|
||||
version: '0.5.168',
|
||||
openTeamBatchForm,
|
||||
pingTeamBatchFrame,
|
||||
preflightTeamBatchNative,
|
||||
|
||||
Reference in new issue
Block a user