收口微信认证诊断日志
微信 web-view 认证失败日志改为固定阶段标签 原生壳门禁拒绝认证日志输出原生错误对象 同步宿主壳方案和共享决策记录
This commit is contained in:
@@ -106,6 +106,7 @@
|
||||
- 2026-06-21 微信 WebView env 诊断日志收口:微信 `web-view` 壳读取小程序 envVersion 失败时只记录 `[web-view] read mini program env failed` 固定标签,不输出 `wx.getAccountInfoSync()` 原生异常对象;根级原生壳门禁拒绝恢复 `console.warn(..., error)`。
|
||||
- 2026-06-21 微信九宫切图诊断日志收口:微信 `share-grid` 壳下载封面、读取图片、导出切图、保存相册或最终保存流程失败时,只记录 `[share-grid] <stage>` 固定标签,不输出 `wx.downloadFile`、`wx.getImageInfo`、`wx.canvasToTempFilePath`、`wx.saveImageToPhotosAlbum` 或其它原生错误对象;页面仍只展示 `九宫切图保存失败。` 稳定文案。
|
||||
- 2026-06-21 微信支付与订阅诊断日志收口:微信支付参数解析、虚拟支付失败和订阅消息请求失败只记录 `[wechat-pay] <stage>` / `[subscribe-message] <stage>` 固定标签,不输出微信原生错误对象;H5 回灌继续只使用稳定 `wechat payment unavailable` / `wechat subscribe unavailable` 语义。
|
||||
- 2026-06-21 微信 WebView 认证诊断日志收口:微信 `web-view` 壳解析认证结果、`wx.login`、小程序登录请求、手机号绑定请求、认证流程和手机号授权拒绝失败时,只记录 `[web-view] <stage>` 固定标签,不输出微信原生错误对象、HTTP response 或授权 detail;页面仍只展示稳定登录 / 绑手机号错误文案。
|
||||
- 2026-06-19 微信壳路由一致性门禁:`npm run check:native-shells` 必须反查 `miniprogram/app.json.pages`、`miniprogram/host-bridge/protocol.js`、H5 `src/services/host-bridge/hostBridge.ts` 小程序页面常量、H5 `src/services/wechatMiniProgramSubscribe.ts` 订阅授权页面常量、`miniprogram/host-bridge/webView.js` 分享入口 / 分享消息类型、`miniprogram/config.js` source query / 域名格式、`miniprogram/shell/webView.js` 请求头来源标记、H5 runtime parser 和 H5 路由保留字段。新增或调整小程序页面、登录派生 URL、支付页、九宫切图页、订阅页、WebView 来源标记、H5 入口域名、API base URL 或宿主上下文 query 字段时,必须同步这几处常量并保持生产 / 开发域名都显式配置为纯 HTTPS domain;运行时开发域名回退生产域名只作为异常兜底。
|
||||
- 2026-06-18 登录 / 支付能力禁伪声明:`auth.requestLogin` 和 `payment.request` 保留在共享 HostBridge 契约中供未来真实接入,但 Expo / Tauri 壳在真实 SDK、渠道流程和后端契约落地前不得声明这些 capability,也不得把它们写入入口 URL `hostCapabilities`;两端检查脚本会拒绝伪声明,请求实际到达壳层时必须返回明确 `unsupported_method` 并让 H5 fallback,两端壳测试直接覆盖这两个 method。
|
||||
- 2026-06-20 桌面壳未声明 method 禁伪成功:Tauri 桌面壳只声明真实可用 capability;共享 HostBridge method 白名单中未进入桌面 capability profile 的 method,例如 `auth.requestLogin`、`payment.request`、`file.captureImage`、`scanner.scanQrCode` 和 `haptics.impact`,请求实际到达桌面壳时必须统一返回明确 `unsupported_method`,不得伪造成功或半接入。桌面 Rust 测试必须从 `HOST_BRIDGE_METHODS` 与 `capabilities()` 差集派生 unsupported 覆盖清单,桌面单端配置检查会反查该派生路径,后续共享契约新增 method 时必须同步声明真实桌面能力或补进 unsupported 语义。
|
||||
|
||||
@@ -542,6 +542,8 @@ GameBridge 禁止:
|
||||
|
||||
2026-06-21 追加:微信支付参数解析、虚拟支付失败和订阅消息请求失败诊断只允许记录 `[wechat-pay] <stage>` / `[subscribe-message] <stage>` 固定标签,不把微信原生错误对象写入生产日志;H5 回灌仍只使用稳定支付 / 订阅失败语义。
|
||||
|
||||
2026-06-21 追加:微信 `web-view` 认证链路诊断只允许记录 `[web-view] <stage>` 固定标签,不把 `wx.login` 错误、登录 / 绑手机号 HTTP response、手机号授权 detail 或认证异常对象写入生产日志;页面仍只展示稳定登录 / 绑手机号错误文案。
|
||||
|
||||
2026-06-19 追加:微信小程序壳路由一致性进入原生壳统一验收。`npm run check:native-shells` 会反查 `miniprogram/app.json.pages` 与 `miniprogram/host-bridge/protocol.js` 页面 URL 常量一致,H5 `src/services/host-bridge/hostBridge.ts` 的小程序登录、支付、九宫切图页面常量、H5 `src/services/wechatMiniProgramSubscribe.ts` 的订阅授权页面常量与微信协议常量一致,`miniprogram/host-bridge/webView.js` 的 WebView 分享入口和分享目标消息类型不漂移;同时会校验 `miniprogram/config.js` 的生产 / 开发 H5 入口与 API base URL 都是显式配置的纯 HTTPS 域名,`WEB_VIEW_SOURCE_QUERY` 与共享 `HOST_BRIDGE_WECHAT_MINI_PROGRAM_SOURCE_QUERY` 一致,`miniprogram/shell/webView.js` 请求头从 `WEB_VIEW_SOURCE_QUERY` 读取 `clientType` / `clientRuntime`,H5 runtime parser 读取共享 `HOST_BRIDGE_RUNTIME_CONTEXT_QUERY_KEY`,H5 路由保留字段读取共享 `HOST_BRIDGE_PRESERVED_RUNTIME_CONTEXT_QUERY_KEYS`。运行时对开发域名的生产域名回退只作为异常兜底,不作为配置口径;新增小程序页面、改页面路径、调整来源 query 或切换域名格式时,必须同步协议常量、H5 HostBridge / 订阅服务常量、`app.json`、共享 HostBridge query 契约和这条门禁。
|
||||
|
||||
2026-06-18 追加:原生壳本地生成物不作为生产源码门禁输入。Expo `.expo/`、Expo export smoke 临时目录、Tauri `target/`、Tauri schema `gen/` 和 Tauri 自动生成权限目录都必须保持 gitignored;根级生产壳敏感词扫描只检查可提交的壳源码和配置,避免本机工具输出影响生产门禁。手写 capability / 权限配置仍需保留在扫描范围内。
|
||||
|
||||
@@ -177,6 +177,10 @@ function readMiniProgramEnvVersion() {
|
||||
}
|
||||
}
|
||||
|
||||
function logWebViewAuthFailure(label, _detail) {
|
||||
console.error(`[web-view] ${label}`);
|
||||
}
|
||||
|
||||
function resolveMiniProgramRuntimeConfig() {
|
||||
const miniProgramEnv =
|
||||
normalizeMiniProgramEnv(readMiniProgramEnvVersion()) ||
|
||||
@@ -252,7 +256,7 @@ function consumeAuthResult() {
|
||||
bindingStatus: String(parsed.bindingStatus || 'pending_bind_phone'),
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('[web-view] parse auth result failed', error);
|
||||
logWebViewAuthFailure('parse auth result failed', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -288,11 +292,11 @@ function wxLogin() {
|
||||
resolve(result.code);
|
||||
return;
|
||||
}
|
||||
console.error('[web-view] wx.login returned no code', result);
|
||||
logWebViewAuthFailure('wx.login returned no code', result);
|
||||
reject(new Error(WECHAT_LOGIN_UNAVAILABLE_MESSAGE));
|
||||
},
|
||||
fail(error) {
|
||||
console.error('[web-view] wx.login failed', error);
|
||||
logWebViewAuthFailure('wx.login failed', error);
|
||||
reject(new Error(WECHAT_LOGIN_UNAVAILABLE_MESSAGE));
|
||||
},
|
||||
});
|
||||
@@ -329,11 +333,11 @@ function requestMiniProgramLogin(code, displayName) {
|
||||
resolve(response.data);
|
||||
return;
|
||||
}
|
||||
console.error('[web-view] mini program login failed', response);
|
||||
logWebViewAuthFailure('mini program login failed', response);
|
||||
reject(new Error(WECHAT_LOGIN_UNAVAILABLE_MESSAGE));
|
||||
},
|
||||
fail(error) {
|
||||
console.error('[web-view] mini program login request failed', error);
|
||||
logWebViewAuthFailure('mini program login request failed', error);
|
||||
reject(new Error(WECHAT_LOGIN_UNAVAILABLE_MESSAGE));
|
||||
},
|
||||
});
|
||||
@@ -371,11 +375,11 @@ function requestMiniProgramBindPhone(authToken, wechatPhoneCode, displayName) {
|
||||
resolve(response.data);
|
||||
return;
|
||||
}
|
||||
console.error('[web-view] mini program bind phone failed', response);
|
||||
logWebViewAuthFailure('mini program bind phone failed', response);
|
||||
reject(new Error(WECHAT_BIND_PHONE_UNAVAILABLE_MESSAGE));
|
||||
},
|
||||
fail(error) {
|
||||
console.error('[web-view] mini program bind phone request failed', error);
|
||||
logWebViewAuthFailure('mini program bind phone request failed', error);
|
||||
reject(new Error(WECHAT_BIND_PHONE_UNAVAILABLE_MESSAGE));
|
||||
},
|
||||
});
|
||||
@@ -543,7 +547,7 @@ function createWechatWebViewPage() {
|
||||
webViewUrl: resolveWebViewUrl(authResult, this._lastLaunchQuery || {}),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('[web-view] auth flow failed', error);
|
||||
logWebViewAuthFailure('auth flow failed', error);
|
||||
this.setData({
|
||||
authResult: null,
|
||||
errorMessage: WECHAT_LOGIN_UNAVAILABLE_MESSAGE,
|
||||
@@ -598,7 +602,7 @@ function createWechatWebViewPage() {
|
||||
|
||||
const detail = event.detail || {};
|
||||
if (!detail.code) {
|
||||
console.error('[web-view] bind phone auth declined', detail);
|
||||
logWebViewAuthFailure('bind phone auth declined', detail);
|
||||
this.setData({
|
||||
errorMessage: WECHAT_BIND_PHONE_AUTH_REQUIRED_MESSAGE,
|
||||
});
|
||||
@@ -649,7 +653,7 @@ function createWechatWebViewPage() {
|
||||
),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('[web-view] bind phone failed', error);
|
||||
logWebViewAuthFailure('bind phone failed', error);
|
||||
this.setData({
|
||||
bindingPhone: false,
|
||||
errorMessage: WECHAT_BIND_PHONE_UNAVAILABLE_MESSAGE,
|
||||
|
||||
@@ -2753,10 +2753,18 @@ function assertWechatAuthFailureBoundaries() {
|
||||
"WECHAT_LOGIN_UNAVAILABLE_MESSAGE = '微信登录失败,请稍后重试。'",
|
||||
"WECHAT_BIND_PHONE_UNAVAILABLE_MESSAGE = '绑定手机号失败,请稍后重试。'",
|
||||
"WECHAT_BIND_PHONE_AUTH_REQUIRED_MESSAGE = '需要授权手机号后才能完成绑定。'",
|
||||
"console.error('[web-view] wx.login failed', error)",
|
||||
"console.error('[web-view] mini program login request failed', error)",
|
||||
"console.error('[web-view] mini program bind phone failed', response)",
|
||||
"console.error('[web-view] bind phone auth declined', detail)",
|
||||
'function logWebViewAuthFailure(label, _detail)',
|
||||
'console.error(`[web-view] ${label}`)',
|
||||
"logWebViewAuthFailure('parse auth result failed', error)",
|
||||
"logWebViewAuthFailure('wx.login returned no code', result)",
|
||||
"logWebViewAuthFailure('wx.login failed', error)",
|
||||
"logWebViewAuthFailure('mini program login failed', response)",
|
||||
"logWebViewAuthFailure('mini program login request failed', error)",
|
||||
"logWebViewAuthFailure('mini program bind phone failed', response)",
|
||||
"logWebViewAuthFailure('mini program bind phone request failed', error)",
|
||||
"logWebViewAuthFailure('auth flow failed', error)",
|
||||
"logWebViewAuthFailure('bind phone auth declined', detail)",
|
||||
"logWebViewAuthFailure('bind phone failed', error)",
|
||||
'errorMessage: WECHAT_LOGIN_UNAVAILABLE_MESSAGE',
|
||||
'errorMessage: WECHAT_BIND_PHONE_UNAVAILABLE_MESSAGE',
|
||||
'errorMessage: WECHAT_BIND_PHONE_AUTH_REQUIRED_MESSAGE',
|
||||
@@ -2772,6 +2780,16 @@ function assertWechatAuthFailureBoundaries() {
|
||||
"error && error.message ? error.message : '微信登录失败,请稍后重试。'",
|
||||
"detail.errMsg || '需要授权手机号后才能完成绑定。'",
|
||||
'response.data.error.message',
|
||||
"console.error('[web-view] parse auth result failed', error)",
|
||||
"console.error('[web-view] wx.login returned no code', result)",
|
||||
"console.error('[web-view] wx.login failed', error)",
|
||||
"console.error('[web-view] mini program login failed', response)",
|
||||
"console.error('[web-view] mini program login request failed', error)",
|
||||
"console.error('[web-view] mini program bind phone failed', response)",
|
||||
"console.error('[web-view] mini program bind phone request failed', error)",
|
||||
"console.error('[web-view] auth flow failed', error)",
|
||||
"console.error('[web-view] bind phone auth declined', detail)",
|
||||
"console.error('[web-view] bind phone failed', error)",
|
||||
]) {
|
||||
if (webViewShellSource.includes(forbiddenSnippet)) {
|
||||
throw new Error(`wechat auth shell must not expose native failure detail via ${forbiddenSnippet}`);
|
||||
@@ -2784,6 +2802,14 @@ function assertWechatAuthFailureBoundaries() {
|
||||
"expect(page.data.errorMessage).toBe('微信登录失败,请稍后重试。')",
|
||||
"expect(page.data.errorMessage).toBe('绑定手机号失败,请稍后重试。')",
|
||||
"expect(page.data.errorMessage).toBe('需要授权手机号后才能完成绑定。')",
|
||||
"expect(console.error).toHaveBeenCalledWith('[web-view] wx.login failed')",
|
||||
"expect(console.error).toHaveBeenCalledWith('[web-view] auth flow failed')",
|
||||
'expect(console.error.mock.calls.flat()).not.toContain(loginError)',
|
||||
"expect(console.error).toHaveBeenCalledWith(\n '[web-view] mini program bind phone failed'",
|
||||
"expect(console.error).toHaveBeenCalledWith('[web-view] bind phone failed')",
|
||||
"expect(console.error.mock.calls.flat()).not.toContain('private backend detail')",
|
||||
"expect(console.error).toHaveBeenCalledWith(\n '[web-view] bind phone auth declined'",
|
||||
'expect(console.error.mock.calls.flat()).not.toContain(authDeclined)',
|
||||
]) {
|
||||
if (!authTestSource.includes(snippet)) {
|
||||
throw new Error(`wechat auth boundary test must include ${snippet}`);
|
||||
|
||||
@@ -319,10 +319,9 @@ describe('mini-program web-view auth page', () => {
|
||||
await page.onLoad({ authAction: 'login', returnTo: 'previous' });
|
||||
|
||||
expect(page.data.errorMessage).toBe('微信登录失败,请稍后重试。');
|
||||
expect(console.error).toHaveBeenCalledWith(
|
||||
'[web-view] wx.login failed',
|
||||
loginError,
|
||||
);
|
||||
expect(console.error).toHaveBeenCalledWith('[web-view] wx.login failed');
|
||||
expect(console.error).toHaveBeenCalledWith('[web-view] auth flow failed');
|
||||
expect(console.error.mock.calls.flat()).not.toContain(loginError);
|
||||
expect(page.data.phoneBindingRequired).toBe(false);
|
||||
});
|
||||
|
||||
@@ -353,10 +352,9 @@ describe('mini-program web-view auth page', () => {
|
||||
expect(page.data.errorMessage).toBe('绑定手机号失败,请稍后重试。');
|
||||
expect(console.error).toHaveBeenCalledWith(
|
||||
'[web-view] mini program bind phone failed',
|
||||
expect.objectContaining({
|
||||
statusCode: 500,
|
||||
}),
|
||||
);
|
||||
expect(console.error).toHaveBeenCalledWith('[web-view] bind phone failed');
|
||||
expect(console.error.mock.calls.flat()).not.toContain('private backend detail');
|
||||
});
|
||||
|
||||
test('拒绝手机号授权不向页面透出微信原生错误', async () => {
|
||||
@@ -378,7 +376,7 @@ describe('mini-program web-view auth page', () => {
|
||||
expect(page.data.errorMessage).not.toContain('private native detail');
|
||||
expect(console.error).toHaveBeenCalledWith(
|
||||
'[web-view] bind phone auth declined',
|
||||
authDeclined,
|
||||
);
|
||||
expect(console.error.mock.calls.flat()).not.toContain(authDeclined);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user