@alipay/alipay-aipay 1.7.0 → 1.7.2
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 +30 -0
- package/dist/commands/install-current.js +15 -7
- package/dist/commands/install.js +20 -16
- package/dist/commands/uninstall.js +8 -3
- package/dist/commands/update.js +34 -16
- package/dist/index.js +10 -4
- package/dist/utils/channels.js +67 -0
- package/dist/utils/config.js +15 -11
- package/dist/utils/file.js +23 -10
- package/dist/utils/npm.js +19 -33
- package/package.json +8 -3
- package/skill/SKILL.md +2 -0
- package/skill/references/normal/json/release-channel.json +1 -0
- package/skill/references/normal/scripts/self_update.mjs +62 -17
- package/skill/references/normal/self-update.md +3 -1
- package/skill-pre/SKILL.md +65 -0
- package/skill-pre/VERSION +1 -0
- package/skill-pre/references/integration/flow.md +602 -0
- package/skill-pre/references/integration/modules/alipay-sdk-reminder.md +281 -0
- package/skill-pre/references/integration/modules/checklist.md +154 -0
- package/skill-pre/references/integration/modules/code-examples/csharp/1-/351/200/232/347/224/250/346/216/245/345/217/243//345/274/202/346/255/245/351/200/232/347/237/245/345/244/204/347/220/206/344/273/243/347/240/201/347/244/272/344/276/213.md +199 -0
- package/skill-pre/references/integration/modules/code-examples/csharp/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/345/205/263/351/227/255/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +68 -0
- package/skill-pre/references/integration/modules/code-examples/csharp/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/346/237/245/350/257/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +83 -0
- package/skill-pre/references/integration/modules/code-examples/csharp/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/351/200/200/346/254/276/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +80 -0
- package/skill-pre/references/integration/modules/code-examples/csharp/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/351/200/200/346/254/276/346/237/245/350/257/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +73 -0
- package/skill-pre/references/integration/modules/code-examples/csharp/2-/347/275/221/347/253/231/346/224/257/344/273/230//347/273/237/344/270/200/346/224/266/345/215/225/344/270/213/345/215/225/345/271/266/346/224/257/344/273/230/351/241/265/351/235/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +62 -0
- package/skill-pre/references/integration/modules/code-examples/csharp/3-APP/346/224/257/344/273/230/APP/346/224/257/344/273/230/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +132 -0
- package/skill-pre/references/integration/modules/code-examples/csharp/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemo.md +640 -0
- package/skill-pre/references/integration/modules/code-examples/java/1-/351/200/232/347/224/250/346/216/245/345/217/243//345/274/202/346/255/245/351/200/232/347/237/245/345/244/204/347/220/206/344/273/243/347/240/201/347/244/272/344/276/213.md +184 -0
- package/skill-pre/references/integration/modules/code-examples/java/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/345/205/263/351/227/255/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +72 -0
- package/skill-pre/references/integration/modules/code-examples/java/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/346/237/245/350/257/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +96 -0
- package/skill-pre/references/integration/modules/code-examples/java/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/351/200/200/346/254/276/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +81 -0
- package/skill-pre/references/integration/modules/code-examples/java/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/351/200/200/346/254/276/346/237/245/350/257/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +77 -0
- package/skill-pre/references/integration/modules/code-examples/java/2-/347/275/221/347/253/231/346/224/257/344/273/230//347/273/237/344/270/200/346/224/266/345/215/225/344/270/213/345/215/225/345/271/266/346/224/257/344/273/230/351/241/265/351/235/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +69 -0
- package/skill-pre/references/integration/modules/code-examples/java/3-APP/346/224/257/344/273/230/APP/346/224/257/344/273/230/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +138 -0
- package/skill-pre/references/integration/modules/code-examples/java/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemoController.md +623 -0
- package/skill-pre/references/integration/modules/code-examples/nodejs/1-/351/200/232/347/224/250/346/216/245/345/217/243//345/274/202/346/255/245/351/200/232/347/237/245/345/244/204/347/220/206/344/273/243/347/240/201/347/244/272/344/276/213.md +135 -0
- package/skill-pre/references/integration/modules/code-examples/nodejs/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/345/205/263/351/227/255/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +51 -0
- package/skill-pre/references/integration/modules/code-examples/nodejs/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/346/237/245/350/257/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +63 -0
- package/skill-pre/references/integration/modules/code-examples/nodejs/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/351/200/200/346/254/276/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +59 -0
- package/skill-pre/references/integration/modules/code-examples/nodejs/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/351/200/200/346/254/276/346/237/245/350/257/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +54 -0
- package/skill-pre/references/integration/modules/code-examples/nodejs/2-/347/275/221/347/253/231/346/224/257/344/273/230//347/273/237/344/270/200/346/224/266/345/215/225/344/270/213/345/215/225/345/271/266/346/224/257/344/273/230/351/241/265/351/235/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +84 -0
- package/skill-pre/references/integration/modules/code-examples/nodejs/3-APP/346/224/257/344/273/230/APP/346/224/257/344/273/230/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +71 -0
- package/skill-pre/references/integration/modules/code-examples/nodejs/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemo.md +498 -0
- package/skill-pre/references/integration/modules/code-examples/php/1-/351/200/232/347/224/250/346/216/245/345/217/243//345/274/202/346/255/245/351/200/232/347/237/245/345/244/204/347/220/206/344/273/243/347/240/201/347/244/272/344/276/213.md +157 -0
- package/skill-pre/references/integration/modules/code-examples/php/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/345/205/263/351/227/255/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +59 -0
- package/skill-pre/references/integration/modules/code-examples/php/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/346/237/245/350/257/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +73 -0
- package/skill-pre/references/integration/modules/code-examples/php/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/351/200/200/346/254/276/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +69 -0
- package/skill-pre/references/integration/modules/code-examples/php/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/351/200/200/346/254/276/346/237/245/350/257/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +65 -0
- package/skill-pre/references/integration/modules/code-examples/php/2-/347/275/221/347/253/231/346/224/257/344/273/230//347/273/237/344/270/200/346/224/266/345/215/225/344/270/213/345/215/225/345/271/266/346/224/257/344/273/230/351/241/265/351/235/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +59 -0
- package/skill-pre/references/integration/modules/code-examples/php/3-APP/346/224/257/344/273/230/APP/346/224/257/344/273/230/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +110 -0
- package/skill-pre/references/integration/modules/code-examples/php/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemo.md +806 -0
- package/skill-pre/references/integration/modules/code-examples/python/1-/351/200/232/347/224/250/346/216/245/345/217/243//345/274/202/346/255/245/351/200/232/347/237/245/345/244/204/347/220/206/344/273/243/347/240/201/347/244/272/344/276/213.md +128 -0
- package/skill-pre/references/integration/modules/code-examples/python/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/345/205/263/351/227/255/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +57 -0
- package/skill-pre/references/integration/modules/code-examples/python/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/346/237/245/350/257/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +70 -0
- package/skill-pre/references/integration/modules/code-examples/python/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/351/200/200/346/254/276/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +65 -0
- package/skill-pre/references/integration/modules/code-examples/python/1-/351/200/232/347/224/250/346/216/245/345/217/243//347/273/237/344/270/200/346/224/266/345/215/225/344/272/244/346/230/223/351/200/200/346/254/276/346/237/245/350/257/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +62 -0
- package/skill-pre/references/integration/modules/code-examples/python/2-/347/275/221/347/253/231/346/224/257/344/273/230//347/273/237/344/270/200/346/224/266/345/215/225/344/270/213/345/215/225/345/271/266/346/224/257/344/273/230/351/241/265/351/235/242/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +51 -0
- package/skill-pre/references/integration/modules/code-examples/python/3-APP/346/224/257/344/273/230/APP/346/224/257/344/273/230/346/216/245/345/217/243/344/273/243/347/240/201/347/244/272/344/276/213.md +47 -0
- package/skill-pre/references/integration/modules/code-examples/python/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemo.md +541 -0
- package/skill-pre/references/integration/modules/interface-contract/aipay-interface-contract.md +52 -0
- package/skill-pre/references/integration/modules/interface-contract/apppay-interface-contract.md +45 -0
- package/skill-pre/references/integration/modules/interface-contract/common-trade-contract.md +42 -0
- package/skill-pre/references/integration/modules/interface-contract/notify-url-contract.md +68 -0
- package/skill-pre/references/integration/modules/interface-contract/webpay-interface-contract.md +44 -0
- package/skill-pre/references/integration/modules/interface-guide.md +61 -0
- package/skill-pre/references/integration/modules/product-decision.md +73 -0
- package/skill-pre/references/integration/modules/sandbox/a2m-sandbox-test.md +235 -0
- package/skill-pre/references/integration/modules/sandbox/alipay-sandbox-tool.md +142 -0
- package/skill-pre/references/integration/modules/sandbox/sandbox-setup-guide.md +239 -0
- package/skill-pre/references/integration/modules/scripts/local_402_sandbox_pay.py +900 -0
- package/skill-pre/references/integration/modules/scripts/sandbox_config.sh +347 -0
- package/skill-pre/references/integration/modules/troubleshooting-flow.md +28 -0
- package/skill-pre/references/normal/alipay-cli-env.md +169 -0
- package/skill-pre/references/normal/conversation-telemetry.md +101 -0
- package/skill-pre/references/normal/full-process-routing.md +92 -0
- package/skill-pre/references/normal/integration-worker.md +90 -0
- package/skill-pre/references/normal/json/customer-messages.json +1 -0
- package/skill-pre/references/normal/json/managed-jq-assets.json +1 -0
- package/skill-pre/references/normal/json/policy-rules.json +1 -0
- package/skill-pre/references/normal/json/release-channel.json +1 -0
- package/skill-pre/references/normal/rejection-guide.md +41 -0
- package/skill-pre/references/normal/scripts/agent_platform.mjs +43 -0
- package/skill-pre/references/normal/scripts/alipay_cli_env.mjs +34 -0
- package/skill-pre/references/normal/scripts/alipay_cli_env.sh +55 -0
- package/skill-pre/references/normal/scripts/alipay_cli_refresh.mjs +129 -0
- package/skill-pre/references/normal/scripts/auth_runtime_runner.mjs +60 -0
- package/skill-pre/references/normal/scripts/checklist_sections.mjs +43 -0
- package/skill-pre/references/normal/scripts/common.sh +365 -0
- package/skill-pre/references/normal/scripts/conversation_telemetry.mjs +105 -0
- package/skill-pre/references/normal/scripts/detect_dev_tool.sh +79 -0
- package/skill-pre/references/normal/scripts/flow_loader.mjs +237 -0
- package/skill-pre/references/normal/scripts/integration_context_runner.mjs +151 -0
- package/skill-pre/references/normal/scripts/integration_message_runner.mjs +1456 -0
- package/skill-pre/references/normal/scripts/interaction_reply.mjs +140 -0
- package/skill-pre/references/normal/scripts/managed_jq.mjs +215 -0
- package/skill-pre/references/normal/scripts/onboarding_discovery_runner.mjs +387 -0
- package/skill-pre/references/normal/scripts/onboarding_message_runner.mjs +1425 -0
- package/skill-pre/references/normal/scripts/onboarding_recovery_runner.mjs +100 -0
- package/skill-pre/references/normal/scripts/open_official_url.sh +205 -0
- package/skill-pre/references/normal/scripts/platform_compat.mjs +42 -0
- package/skill-pre/references/normal/scripts/preview_runtime.mjs +151 -0
- package/skill-pre/references/normal/scripts/project_route_inspector.sh +132 -0
- package/skill-pre/references/normal/scripts/python_script_runner.mjs +58 -0
- package/skill-pre/references/normal/scripts/render_customer_message.mjs +1792 -0
- package/skill-pre/references/normal/scripts/runtime.mjs +271 -0
- package/skill-pre/references/normal/scripts/self_update.mjs +376 -0
- package/skill-pre/references/normal/scripts/telemetry.mjs +2102 -0
- package/skill-pre/references/normal/self-update.md +7 -0
- package/skill-pre/references/normal/telemetry.md +70 -0
- package/skill-pre/references/onboarding/assets/keygen.html +927 -0
- package/skill-pre/references/onboarding/flow.md +607 -0
- package/skill-pre/references/onboarding/modules/app-release.md +90 -0
- package/skill-pre/references/onboarding/modules/authorization.md +43 -0
- package/skill-pre/references/onboarding/modules/error-handling.md +62 -0
- package/skill-pre/references/onboarding/modules/product-sign.md +49 -0
- package/skill-pre/references/onboarding/modules/scripts/app.sh +1485 -0
- package/skill-pre/references/onboarding/modules/scripts/ar_sign_apply.sh +331 -0
- package/skill-pre/references/onboarding/modules/scripts/auth.sh +1040 -0
- package/skill-pre/references/onboarding/modules/scripts/download_key_tool.sh +4 -0
- package/skill-pre/references/onboarding/modules/scripts/error_handler.sh +841 -0
- package/skill-pre/references/onboarding/modules/scripts/mcc.sh +1085 -0
- package/skill-pre/references/onboarding/modules/scripts/network_retry.sh +135 -0
- package/skill-pre/references/onboarding/modules/scripts/query_sign_status.sh +105 -0
- package/skill-pre/references/onboarding/modules/scripts/service.sh +528 -0
- package/skill-pre/references/onboarding/modules/scripts/sign_status_parser.sh +58 -0
- package/skill-pre/references/onboarding/modules/scripts/upload_screenshots.sh +208 -0
- package/skill-pre/references/onboarding/modules/scripts/upload_special_license.sh +195 -0
- package/skill-pre/references/onboarding/modules/service-registration.md +40 -0
- package/skill-pre/references/runtime-entry.md +99 -0
- package/dist/commands/install-current.d.ts +0 -4
- package/dist/commands/install-current.d.ts.map +0 -1
- package/dist/commands/install-current.js.map +0 -1
- package/dist/commands/install.d.ts +0 -10
- package/dist/commands/install.d.ts.map +0 -1
- package/dist/commands/install.js.map +0 -1
- package/dist/commands/prepare-tools.d.ts +0 -5
- package/dist/commands/prepare-tools.d.ts.map +0 -1
- package/dist/commands/prepare-tools.js.map +0 -1
- package/dist/commands/uninstall.d.ts +0 -10
- package/dist/commands/uninstall.d.ts.map +0 -1
- package/dist/commands/uninstall.js.map +0 -1
- package/dist/commands/update.d.ts +0 -10
- package/dist/commands/update.d.ts.map +0 -1
- package/dist/commands/update.js.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/types.d.ts +0 -42
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/utils/alipay-cli.d.ts +0 -20
- package/dist/utils/alipay-cli.d.ts.map +0 -1
- package/dist/utils/alipay-cli.js.map +0 -1
- package/dist/utils/config.d.ts +0 -52
- package/dist/utils/config.d.ts.map +0 -1
- package/dist/utils/config.js.map +0 -1
- package/dist/utils/file.d.ts +0 -77
- package/dist/utils/file.d.ts.map +0 -1
- package/dist/utils/file.js.map +0 -1
- package/dist/utils/jq.d.ts +0 -17
- package/dist/utils/jq.d.ts.map +0 -1
- package/dist/utils/jq.js.map +0 -1
- package/dist/utils/npm.d.ts +0 -17
- package/dist/utils/npm.d.ts.map +0 -1
- package/dist/utils/npm.js.map +0 -1
- package/dist/utils/shell.d.ts +0 -24
- package/dist/utils/shell.d.ts.map +0 -1
- package/dist/utils/shell.js.map +0 -1
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import process from 'node:process';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { isAffirmativeReply } from './interaction_reply.mjs';
|
|
8
|
+
|
|
9
|
+
const internalPrefix = 'ALIPAY_AIPAY_INTERNAL:';
|
|
10
|
+
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const onboardingScriptsDir = path.resolve(scriptDir, '../../onboarding/modules/scripts');
|
|
12
|
+
|
|
13
|
+
function parseArgs(argv) {
|
|
14
|
+
const command = argv[2];
|
|
15
|
+
const args = {};
|
|
16
|
+
for (let index = 3; index < argv.length; index += 1) {
|
|
17
|
+
const token = argv[index];
|
|
18
|
+
if (!token.startsWith('--')) throw new Error(`未知参数 ${token}`);
|
|
19
|
+
const value = argv[index + 1];
|
|
20
|
+
if (value === undefined || value.startsWith('--')) throw new Error(`参数 ${token} 缺少取值`);
|
|
21
|
+
const name = token.slice(2);
|
|
22
|
+
if (Object.prototype.hasOwnProperty.call(args, name)) throw new Error(`参数 ${token} 重复`);
|
|
23
|
+
args[name] = value;
|
|
24
|
+
index += 1;
|
|
25
|
+
}
|
|
26
|
+
return { command, args };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function required(args, name) {
|
|
30
|
+
const value = args[name];
|
|
31
|
+
if (typeof value !== 'string' || !value) throw new Error(`缺少参数 --${name}`);
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function assertRegisteredReply(args, kind) {
|
|
36
|
+
required(args, 'input-id');
|
|
37
|
+
if (!isAffirmativeReply(required(args, 'reply'))) {
|
|
38
|
+
process.stderr.write(`${internalPrefix}RECOVERY_INPUT_REJECTED=${kind}\n`);
|
|
39
|
+
process.exitCode = 2;
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function runScript(scriptName, argv, env = process.env) {
|
|
46
|
+
const result = spawnSync('bash', [path.join(onboardingScriptsDir, scriptName), ...argv], {
|
|
47
|
+
cwd: onboardingScriptsDir,
|
|
48
|
+
env,
|
|
49
|
+
encoding: 'utf8',
|
|
50
|
+
maxBuffer: 4 * 1024 * 1024
|
|
51
|
+
});
|
|
52
|
+
if (result.stdout) process.stdout.write(result.stdout);
|
|
53
|
+
if (result.stderr) process.stderr.write(result.stderr);
|
|
54
|
+
if (result.error) throw result.error;
|
|
55
|
+
process.exitCode = result.status === null ? 1 : result.status;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function runAuthConfirm(args) {
|
|
59
|
+
if (!assertRegisteredReply(args, 'AUTH_PENDING')) return;
|
|
60
|
+
const context = [
|
|
61
|
+
['scope', required(args, 'scope')],
|
|
62
|
+
['sales-code', required(args, 'sales-code')],
|
|
63
|
+
['mcc-code', required(args, 'mcc-code')],
|
|
64
|
+
['product-name', required(args, 'product-name')],
|
|
65
|
+
['mcc-name', required(args, 'mcc-name')],
|
|
66
|
+
['mcc-context-receipt', required(args, 'mcc-context-receipt')]
|
|
67
|
+
].flatMap(([name, value]) => [`--${name}`, value]);
|
|
68
|
+
runScript('auth.sh', ['confirm', ...context]);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function runApplicationKeyRecovery(args) {
|
|
72
|
+
if (!assertRegisteredReply(args, 'APPLICATION_KEY_PENDING')) return;
|
|
73
|
+
const mode = required(args, 'mode');
|
|
74
|
+
const productType = required(args, 'product-type');
|
|
75
|
+
if (!['aipay', 'webpay', 'apppay'].includes(productType)) {
|
|
76
|
+
throw new Error('product-type 仅支持 aipay、webpay 或 apppay');
|
|
77
|
+
}
|
|
78
|
+
if (!['verify-key', 'verify-key-and-audit'].includes(mode)) {
|
|
79
|
+
throw new Error('mode 仅支持 verify-key 或 verify-key-and-audit');
|
|
80
|
+
}
|
|
81
|
+
const argv = [mode, '--product-type', productType, required(args, 'app-id')];
|
|
82
|
+
if (args['public-key'] !== undefined) argv.push(args['public-key']);
|
|
83
|
+
runScript('app.sh', argv, { ...process.env, ALIPAY_AIPAY_RECOVERY_QUERY_ONCE: '1' });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function runOnboardingRecoveryCli(argv = process.argv) {
|
|
87
|
+
const { command, args } = parseArgs(argv);
|
|
88
|
+
if (command === 'auth-confirm') return runAuthConfirm(args);
|
|
89
|
+
if (command === 'application-key') return runApplicationKeyRecovery(args);
|
|
90
|
+
throw new Error('用法: onboarding_recovery_runner.mjs <auth-confirm|application-key> --reply <明确完成表达> --input-id <本地用户输入幂等键> ...');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
94
|
+
try {
|
|
95
|
+
runOnboardingRecoveryCli();
|
|
96
|
+
} catch (error) {
|
|
97
|
+
process.stderr.write(`${internalPrefix}RECOVERY_RUNNER_ERROR=${String(error?.message || error).replace(/[\r\n]/gu, ' ')}\n`);
|
|
98
|
+
process.exitCode = 1;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -u
|
|
4
|
+
|
|
5
|
+
KIND="${1:-}"
|
|
6
|
+
IFS= read -r URL || URL=""
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
8
|
+
POLICY_FILE="${SCRIPT_DIR}/../json/policy-rules.json"
|
|
9
|
+
|
|
10
|
+
case "$KIND" in authorization|public-key-confirmation) ;; *) echo "OPEN_FAILED"; exit 1 ;; esac
|
|
11
|
+
command -v node >/dev/null 2>&1 || { echo "OPEN_FAILED"; exit 1; }
|
|
12
|
+
[ -f "$POLICY_FILE" ] || { echo "OPEN_FAILED"; exit 1; }
|
|
13
|
+
|
|
14
|
+
if ! node -e '
|
|
15
|
+
const fs = require("node:fs");
|
|
16
|
+
const [kind, raw, policyFile] = process.argv.slice(1);
|
|
17
|
+
const policy = JSON.parse(fs.readFileSync(policyFile, "utf8"));
|
|
18
|
+
if (/[\u0000-\u0020\u007f`()\[\]<>|]/.test(raw)) process.exit(1);
|
|
19
|
+
let url;
|
|
20
|
+
try { url = new URL(raw); } catch { process.exit(1); }
|
|
21
|
+
const allowed = policy.temporaryUrlAllowlist[kind === "authorization" ? "authorization" : "publicKeyConfirmation"];
|
|
22
|
+
if (!allowed || url.protocol !== "https:" || url.hostname !== allowed.host || url.pathname !== allowed.path || url.username || url.password || url.port || url.hash) process.exit(1);
|
|
23
|
+
if (kind === "authorization") {
|
|
24
|
+
const required = allowed.requiredQueryParams;
|
|
25
|
+
const optional = allowed.optionalQueryParams;
|
|
26
|
+
const allowedKeys = new Set([...required, ...optional]);
|
|
27
|
+
if ([...url.searchParams.keys()].some((key) => !allowedKeys.has(key))) process.exit(1);
|
|
28
|
+
for (const key of required) {
|
|
29
|
+
if (url.searchParams.getAll(key).length !== 1 || !url.searchParams.get(key)) process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
for (const key of optional) {
|
|
32
|
+
if (url.searchParams.getAll(key).length > 1) process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
if (!policy.authorizationProducts.some((product) => product.salesCode === url.searchParams.get("productCode"))) process.exit(1);
|
|
35
|
+
if (!/^A\d{4}_B\d{4}$/.test(url.searchParams.get("mccCode"))) process.exit(1);
|
|
36
|
+
if (/[\r\n]/.test(url.searchParams.get("deviceCode"))) process.exit(1);
|
|
37
|
+
if (url.searchParams.has("platform") && (!url.searchParams.get("platform") || /[\r\n]/.test(url.searchParams.get("platform")))) process.exit(1);
|
|
38
|
+
} else {
|
|
39
|
+
const required = allowed.requiredQueryParams || ["keyConfirmToken"];
|
|
40
|
+
const optional = allowed.optionalQueryParams || [];
|
|
41
|
+
const allowedKeys = new Set([...required, ...optional]);
|
|
42
|
+
if ([...url.searchParams.keys()].some((key) => !allowedKeys.has(key))) process.exit(1);
|
|
43
|
+
for (const key of required) {
|
|
44
|
+
if (url.searchParams.getAll(key).length !== 1 || !url.searchParams.get(key)) process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
for (const key of optional) {
|
|
47
|
+
if (url.searchParams.getAll(key).length > 1) process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
if (/[\r\n]/.test(url.searchParams.get("keyConfirmToken"))) process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
' "$KIND" "$URL" "$POLICY_FILE"; then
|
|
52
|
+
echo "OPEN_FAILED"
|
|
53
|
+
exit 1
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
OS_NAME="$(uname -s 2>/dev/null || true)"
|
|
57
|
+
OPEN_ERROR_KIND_REPORTED=false
|
|
58
|
+
OPEN_TIMEOUT_MS=3000
|
|
59
|
+
if [ "${ALIPAY_AIPAY_TEST_MODE:-}" = 1 ] && [[ "${ALIPAY_AIPAY_OPEN_TIMEOUT_MS:-}" =~ ^[1-9][0-9]*$ ]]; then
|
|
60
|
+
OPEN_TIMEOUT_MS="$ALIPAY_AIPAY_OPEN_TIMEOUT_MS"
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
emit_internal() { printf 'ALIPAY_AIPAY_INTERNAL:%s\n' "$*" >&2; }
|
|
64
|
+
emit_open_error_kind() {
|
|
65
|
+
if [ "$OPEN_ERROR_KIND_REPORTED" != true ]; then
|
|
66
|
+
emit_internal "OPEN_ERROR_KIND=$1"
|
|
67
|
+
OPEN_ERROR_KIND_REPORTED=true
|
|
68
|
+
fi
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
diagnose_failed_open() {
|
|
72
|
+
[ "$1" = macos-open ] && [ -f "$2" ] || return 0
|
|
73
|
+
grep -qiE 'NSOSStatusErrorDomain|kLSExecutableIncorrectFormat|-10661' "$2" || return 0
|
|
74
|
+
emit_open_error_kind "MACOS_LAUNCHSERVICES"
|
|
75
|
+
grep -q -- '-10661' "$2" && emit_internal "OPEN_ERROR_CODE=-10661"
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
run_open_command() {
|
|
79
|
+
local KIND="$1" ERROR_FILE OPEN_RC OPEN_TIMEOUT_SENTINEL
|
|
80
|
+
shift
|
|
81
|
+
ERROR_FILE=$(mktemp "${TMPDIR:-/tmp}/alipay-aipay-open.XXXXXX" 2>/dev/null || true)
|
|
82
|
+
OPEN_TIMEOUT_SENTINEL="ALIPAY_AIPAY_OPEN_TIMEOUT_${$}_${RANDOM:-0}"
|
|
83
|
+
node -e '
|
|
84
|
+
const { spawn } = require("node:child_process");
|
|
85
|
+
const [timeoutSentinel, timeout, command, ...args] = process.argv.slice(1);
|
|
86
|
+
const child = spawn(command, args, {
|
|
87
|
+
detached: true,
|
|
88
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
let stderr = "";
|
|
92
|
+
let finished = false;
|
|
93
|
+
let timedOut = false;
|
|
94
|
+
const outputLimit = 64 * 1024;
|
|
95
|
+
const appendStderr = (chunk) => {
|
|
96
|
+
stderr += chunk.toString("utf8");
|
|
97
|
+
if (stderr.length > outputLimit) stderr = stderr.slice(-outputLimit);
|
|
98
|
+
};
|
|
99
|
+
const finish = (code, includeTimeoutSentinel = false) => {
|
|
100
|
+
if (finished) return;
|
|
101
|
+
finished = true;
|
|
102
|
+
clearTimeout(timeoutTimer);
|
|
103
|
+
const output = `${stderr}${includeTimeoutSentinel ? `${timeoutSentinel}\n` : ""}`;
|
|
104
|
+
if (output) process.stderr.write(output, () => process.exit(code));
|
|
105
|
+
else process.exit(code);
|
|
106
|
+
};
|
|
107
|
+
const killGroup = (signal) => {
|
|
108
|
+
if (!child.pid) return;
|
|
109
|
+
try { process.kill(-child.pid, signal); } catch {}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
child.stderr.on("data", appendStderr);
|
|
113
|
+
child.once("error", () => finish(125));
|
|
114
|
+
child.once("close", (status) => {
|
|
115
|
+
if (!timedOut) finish(Number.isInteger(status) ? status : 125);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const timeoutTimer = setTimeout(() => {
|
|
119
|
+
timedOut = true;
|
|
120
|
+
killGroup("SIGTERM");
|
|
121
|
+
setTimeout(() => {
|
|
122
|
+
killGroup("SIGKILL");
|
|
123
|
+
finish(124, true);
|
|
124
|
+
}, 100);
|
|
125
|
+
}, Number(timeout));
|
|
126
|
+
|
|
127
|
+
if (!Number.isFinite(Number(timeout)) || Number(timeout) <= 0) {
|
|
128
|
+
finish(125);
|
|
129
|
+
}
|
|
130
|
+
' "$OPEN_TIMEOUT_SENTINEL" "$OPEN_TIMEOUT_MS" "$@" >/dev/null 2>"${ERROR_FILE:-/dev/null}"
|
|
131
|
+
OPEN_RC=$?
|
|
132
|
+
if [ "$OPEN_RC" -eq 124 ] && [ -n "$ERROR_FILE" ] && grep -Fqx -- "$OPEN_TIMEOUT_SENTINEL" "$ERROR_FILE"; then
|
|
133
|
+
emit_open_error_kind "OPENER_TIMEOUT"
|
|
134
|
+
elif [ "$OPEN_RC" -ne 0 ] && [ -n "$ERROR_FILE" ]; then
|
|
135
|
+
diagnose_failed_open "$KIND" "$ERROR_FILE"
|
|
136
|
+
fi
|
|
137
|
+
[ -z "$ERROR_FILE" ] || rm -f "$ERROR_FILE" 2>/dev/null || true
|
|
138
|
+
return "$OPEN_RC"
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
open_with_unix_fallbacks() {
|
|
142
|
+
local TRIED=false
|
|
143
|
+
command -v xdg-open >/dev/null 2>&1 && { TRIED=true; run_open_command xdg-open xdg-open "$URL" && return 0; }
|
|
144
|
+
command -v gio >/dev/null 2>&1 && { TRIED=true; run_open_command gio gio open "$URL" && return 0; }
|
|
145
|
+
command -v sensible-browser >/dev/null 2>&1 && { TRIED=true; run_open_command sensible-browser sensible-browser "$URL" && return 0; }
|
|
146
|
+
if [ "$TRIED" != true ]; then
|
|
147
|
+
emit_open_error_kind "GUI_UNAVAILABLE"
|
|
148
|
+
return 2
|
|
149
|
+
fi
|
|
150
|
+
if [ -z "${DISPLAY:-}" ] && [ -z "${WAYLAND_DISPLAY:-}" ] && [ -z "${MIR_SOCKET:-}" ]; then
|
|
151
|
+
emit_open_error_kind "GUI_UNAVAILABLE"
|
|
152
|
+
else emit_open_error_kind "OPENER_FAILED"; fi
|
|
153
|
+
return 1
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
open_url() {
|
|
157
|
+
local OPEN_BIN TRIED
|
|
158
|
+
case "$OS_NAME" in
|
|
159
|
+
Darwin)
|
|
160
|
+
TRIED=false
|
|
161
|
+
OPEN_BIN="$(command -v open 2>/dev/null || true)"
|
|
162
|
+
if [ -n "$OPEN_BIN" ]; then
|
|
163
|
+
TRIED=true
|
|
164
|
+
run_open_command "macos-open" "$OPEN_BIN" "$URL" && return 0
|
|
165
|
+
fi
|
|
166
|
+
if command -v osascript >/dev/null 2>&1; then
|
|
167
|
+
TRIED=true
|
|
168
|
+
run_open_command osascript osascript \
|
|
169
|
+
-e 'on run argv' -e 'open location (item 1 of argv)' -e 'end run' \
|
|
170
|
+
"$URL" && return 0
|
|
171
|
+
fi
|
|
172
|
+
if [ "$TRIED" = true ]; then
|
|
173
|
+
emit_open_error_kind "OPENER_FAILED"
|
|
174
|
+
return 1
|
|
175
|
+
fi
|
|
176
|
+
emit_open_error_kind "GUI_UNAVAILABLE"
|
|
177
|
+
return 2
|
|
178
|
+
;;
|
|
179
|
+
Linux|FreeBSD|NetBSD|OpenBSD|DragonFly|SunOS|AIX)
|
|
180
|
+
open_with_unix_fallbacks; return $?
|
|
181
|
+
;;
|
|
182
|
+
MINGW*|MSYS*|CYGWIN*)
|
|
183
|
+
if command -v powershell.exe >/dev/null 2>&1; then
|
|
184
|
+
env "ALIPAY_AIPAY_OPEN_URL=$URL" powershell.exe -NoProfile -NonInteractive -Command \
|
|
185
|
+
'Start-Process -FilePath $env:ALIPAY_AIPAY_OPEN_URL' >/dev/null 2>&1 && return 0
|
|
186
|
+
emit_open_error_kind "OPENER_FAILED"
|
|
187
|
+
return 1
|
|
188
|
+
fi
|
|
189
|
+
emit_open_error_kind "GUI_UNAVAILABLE"
|
|
190
|
+
return 2
|
|
191
|
+
;;
|
|
192
|
+
*)
|
|
193
|
+
emit_open_error_kind "GUI_UNAVAILABLE"
|
|
194
|
+
return 2
|
|
195
|
+
;;
|
|
196
|
+
esac
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
open_url
|
|
200
|
+
OPEN_RC=$?
|
|
201
|
+
case "$OPEN_RC" in
|
|
202
|
+
0) echo "OPENED" ;;
|
|
203
|
+
2) echo "GUI_UNAVAILABLE" ;;
|
|
204
|
+
*) echo "OPEN_FAILED" ;;
|
|
205
|
+
esac
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import process from 'node:process';
|
|
4
|
+
|
|
5
|
+
export function runtimePlatform(env = process.env) {
|
|
6
|
+
const testPlatform = env.ALIPAY_AIPAY_TEST_MODE === '1' ? env.ALIPAY_AIPAY_TEST_PLATFORM : '';
|
|
7
|
+
return ['darwin', 'linux', 'win32'].includes(testPlatform) ? testPlatform : process.platform;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function isWindowsPlatform(env = process.env) {
|
|
11
|
+
return runtimePlatform(env) === 'win32';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function commandRuns(command, args = [], options = {}) {
|
|
15
|
+
const result = spawnSync(command, args, {
|
|
16
|
+
encoding: 'utf8',
|
|
17
|
+
stdio: 'ignore',
|
|
18
|
+
shell: false,
|
|
19
|
+
env: options.env || process.env
|
|
20
|
+
});
|
|
21
|
+
return result.status === 0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function currentNodeAvailable(env = process.env) {
|
|
25
|
+
return Boolean(process.execPath && fs.existsSync(process.execPath));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function checkCliEnvironment(options = {}) {
|
|
29
|
+
const env = options.env || process.env;
|
|
30
|
+
const requireJq = options.requireJq ?? !isWindowsPlatform(env);
|
|
31
|
+
const requireAlipayCli = options.requireAlipayCli ?? true;
|
|
32
|
+
const missing = [];
|
|
33
|
+
|
|
34
|
+
if (!currentNodeAvailable(env)) missing.push('node');
|
|
35
|
+
if (requireJq && (
|
|
36
|
+
!commandRuns('jq', ['--version'], { env }) ||
|
|
37
|
+
!commandRuns('jq', ['-n', '-e', '--arg', 'value', 'ok', '$value == "ok"'], { env })
|
|
38
|
+
)) missing.push('jq');
|
|
39
|
+
if (requireAlipayCli && !commandRuns('alipay-cli', ['version'], { env })) missing.push('alipay-cli');
|
|
40
|
+
|
|
41
|
+
return missing;
|
|
42
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
4
|
+
import { spawnSync } from 'node:child_process';
|
|
5
|
+
import { renderMessage } from './render_customer_message.mjs';
|
|
6
|
+
import { runtimePlatform } from './platform_compat.mjs';
|
|
7
|
+
import { setConversationConsent } from './telemetry.mjs';
|
|
8
|
+
|
|
9
|
+
const pagePath = fileURLToPath(new URL('../../onboarding/assets/keygen.html', import.meta.url));
|
|
10
|
+
const internalPrefix = 'ALIPAY_AIPAY_INTERNAL:';
|
|
11
|
+
const inheritedEnvironmentKeys = Object.freeze([
|
|
12
|
+
'HOME',
|
|
13
|
+
'USERPROFILE',
|
|
14
|
+
'TMPDIR',
|
|
15
|
+
'TEMP',
|
|
16
|
+
'TMP',
|
|
17
|
+
'LANG',
|
|
18
|
+
'LC_ALL',
|
|
19
|
+
'LC_CTYPE',
|
|
20
|
+
'DISPLAY',
|
|
21
|
+
'WAYLAND_DISPLAY',
|
|
22
|
+
'DBUS_SESSION_BUS_ADDRESS',
|
|
23
|
+
'XDG_CURRENT_DESKTOP',
|
|
24
|
+
'XDG_SESSION_TYPE',
|
|
25
|
+
'XDG_RUNTIME_DIR'
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
function deliver(messageId, variant = 'DEFAULT') {
|
|
29
|
+
const body = renderMessage(messageId, variant, {});
|
|
30
|
+
if (!body.trim()) throw new Error('预发版消息正文为空');
|
|
31
|
+
process.stdout.write(`${body}\n`);
|
|
32
|
+
process.stderr.write(`${internalPrefix}CUSTOMER_MESSAGE_DELIVERY_REQUIRED=${messageId}\n`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function safeEnvironmentValue(value) {
|
|
36
|
+
return typeof value === 'string' && !value.includes('\0') ? value : undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function openerEnvironment(platform, source) {
|
|
40
|
+
const env = {};
|
|
41
|
+
for (const key of inheritedEnvironmentKeys) {
|
|
42
|
+
const value = safeEnvironmentValue(source[key]);
|
|
43
|
+
if (value !== undefined) env[key] = value;
|
|
44
|
+
}
|
|
45
|
+
if (platform === 'darwin') env.PATH = '/usr/bin:/bin:/usr/sbin:/sbin';
|
|
46
|
+
if (platform === 'linux') env.PATH = '/usr/bin:/bin';
|
|
47
|
+
return env;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function windowsPowerShell(source) {
|
|
51
|
+
const candidate = safeEnvironmentValue(source.SystemRoot) || safeEnvironmentValue(source.WINDIR) || 'C:\\Windows';
|
|
52
|
+
const root = path.win32.normalize(candidate).replace(/[\\/]+$/u, '');
|
|
53
|
+
if (!/^[A-Za-z]:\\Windows$/iu.test(root)) return null;
|
|
54
|
+
return {
|
|
55
|
+
command: path.win32.join(root, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe'),
|
|
56
|
+
root
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// This helper opens only the bundled, static page. It never generates or reads keys.
|
|
61
|
+
export function openLocalKeygen({ platform = runtimePlatform(), env = process.env, spawn = spawnSync } = {}) {
|
|
62
|
+
try {
|
|
63
|
+
if (!fs.lstatSync(pagePath).isFile() || fs.realpathSync(pagePath) !== path.resolve(pagePath)) return 'OPEN_FAILED';
|
|
64
|
+
if (platform === 'linux' && !env.DISPLAY && !env.WAYLAND_DISPLAY) return 'GUI_UNAVAILABLE';
|
|
65
|
+
const url = pathToFileURL(pagePath).href;
|
|
66
|
+
let command;
|
|
67
|
+
let args;
|
|
68
|
+
if (platform === 'darwin') {
|
|
69
|
+
command = '/usr/bin/open';
|
|
70
|
+
args = [url];
|
|
71
|
+
} else if (platform === 'linux') {
|
|
72
|
+
command = '/usr/bin/xdg-open';
|
|
73
|
+
args = [url];
|
|
74
|
+
} else if (platform === 'win32') {
|
|
75
|
+
const powershell = windowsPowerShell(env);
|
|
76
|
+
if (!powershell) return 'OPEN_FAILED';
|
|
77
|
+
command = powershell.command;
|
|
78
|
+
// Pass the URL as data through the child's environment, never as shell code.
|
|
79
|
+
args = ['-NoProfile', '-NonInteractive', '-Command', "$ErrorActionPreference='Stop'; Start-Process -FilePath $env:ALIPAY_AIPAY_PRE_KEYGEN_URL"];
|
|
80
|
+
const childEnv = openerEnvironment(platform, env);
|
|
81
|
+
childEnv.SystemRoot = powershell.root;
|
|
82
|
+
childEnv.WINDIR = powershell.root;
|
|
83
|
+
childEnv.PATH = `${powershell.root}\\System32;${powershell.root}\\System32\\WindowsPowerShell\\v1.0`;
|
|
84
|
+
childEnv.ALIPAY_AIPAY_PRE_KEYGEN_URL = url;
|
|
85
|
+
const result = spawn(command, args, {
|
|
86
|
+
env: childEnv,
|
|
87
|
+
shell: false,
|
|
88
|
+
stdio: 'ignore',
|
|
89
|
+
timeout: 10000,
|
|
90
|
+
windowsHide: true
|
|
91
|
+
});
|
|
92
|
+
return result.status === 0 && !result.error ? 'OPEN_REQUESTED' : 'OPEN_FAILED';
|
|
93
|
+
} else {
|
|
94
|
+
return 'GUI_UNAVAILABLE';
|
|
95
|
+
}
|
|
96
|
+
const childEnv = openerEnvironment(platform, env);
|
|
97
|
+
childEnv.ALIPAY_AIPAY_PRE_KEYGEN_URL = url;
|
|
98
|
+
const result = spawn(command, args, {
|
|
99
|
+
env: childEnv,
|
|
100
|
+
shell: false,
|
|
101
|
+
stdio: 'ignore',
|
|
102
|
+
timeout: 10000,
|
|
103
|
+
windowsHide: true
|
|
104
|
+
});
|
|
105
|
+
return result.status === 0 && !result.error ? 'OPEN_REQUESTED' : 'OPEN_FAILED';
|
|
106
|
+
} catch {
|
|
107
|
+
return 'OPEN_FAILED';
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function runPreviewCli(argv = process.argv) {
|
|
112
|
+
const action = argv[2];
|
|
113
|
+
if (action === 'consent') {
|
|
114
|
+
const args = new Map();
|
|
115
|
+
for (let i = 3; i < argv.length; i += 2) {
|
|
116
|
+
if (!['--reply', '--input-id'].includes(argv[i]) || args.has(argv[i]) || typeof argv[i + 1] !== 'string') {
|
|
117
|
+
throw new Error('preview consent 只接受 --reply 与 --input-id');
|
|
118
|
+
}
|
|
119
|
+
args.set(argv[i], argv[i + 1]);
|
|
120
|
+
}
|
|
121
|
+
if (!args.get('--input-id')) throw new Error('preview consent 缺少 --input-id');
|
|
122
|
+
// A generic business confirmation (1/OK/继续) is not consent to collection.
|
|
123
|
+
const reply = (args.get('--reply') || '').trim().replace(/[。!!]+$/u, '');
|
|
124
|
+
const decision = reply === '确认' ? 'GRANTED' : reply === '仅使用服务' ? 'DENIED' : null;
|
|
125
|
+
if (!decision) {
|
|
126
|
+
process.stderr.write(`${internalPrefix}PREVIEW_DECISION=UNCONFIRMED\n`);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const saved = setConversationConsent({ decision, inputId: args.get('--input-id') });
|
|
130
|
+
// Respect the current persisted choice on retries of an earlier reply.
|
|
131
|
+
const effective = saved?.decision || 'UNAVAILABLE';
|
|
132
|
+
const serviceOnly = effective === 'DENIED' || (effective !== 'GRANTED' && decision === 'DENIED');
|
|
133
|
+
process.stderr.write(`${internalPrefix}PREVIEW_DECISION=${serviceOnly ? 'SERVICE_ONLY' : 'CONFIRMED'}\n`);
|
|
134
|
+
process.stderr.write(`${internalPrefix}CONVERSATION_CONSENT=${effective}\n`);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (argv.length !== 3 || !['notice', 'key-options', 'open-keygen', 'key-tool-fallback'].includes(action)) {
|
|
138
|
+
throw new Error('用法: runtime.mjs preview <notice|key-options|open-keygen|key-tool-fallback>');
|
|
139
|
+
}
|
|
140
|
+
if (action === 'notice') return deliver('preview.notice');
|
|
141
|
+
if (action === 'key-options') return deliver('application.key.methods');
|
|
142
|
+
if (action === 'key-tool-fallback') return deliver('application.key.local.fallback');
|
|
143
|
+
const outcome = openLocalKeygen();
|
|
144
|
+
process.stderr.write(`${internalPrefix}LOCAL_KEYGEN_OPEN=${outcome}\n`);
|
|
145
|
+
deliver(outcome === 'OPEN_REQUESTED' ? 'application.key.local.opened' : 'application.key.local.fallback');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function runManualKeyToolCli(argv = process.argv) {
|
|
149
|
+
if (argv.length !== 2) throw new Error('预发版 key-tool 仅提供手动下载安装引导,不接受下载目录');
|
|
150
|
+
deliver('application.key.tool.manual');
|
|
151
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -u
|
|
4
|
+
|
|
5
|
+
MODE="${1:-}"
|
|
6
|
+
PRODUCT_TYPE=""
|
|
7
|
+
PROJECT_PATH=""
|
|
8
|
+
PROJECT_SELECTION=""
|
|
9
|
+
|
|
10
|
+
prepare_new_project() {
|
|
11
|
+
local project_path="$1"
|
|
12
|
+
case "$project_path" in /*) ;; *) echo "ROUTE_INSPECT_ERROR:projectPath 必须是绝对路径" >&2; exit 2 ;; esac
|
|
13
|
+
if [ -L "$project_path" ] || { [ -e "$project_path" ] && { [ ! -d "$project_path" ] || [ -n "$(find "$project_path" -mindepth 1 -maxdepth 1 -print -quit 2>/dev/null)" ]; }; }; then
|
|
14
|
+
echo "ROUTE_INSPECT_ERROR:NEW_PROJECT 路径必须尚不存在或为空且不能是符号链接" >&2
|
|
15
|
+
exit 2
|
|
16
|
+
fi
|
|
17
|
+
jq -n '{projectSelection:"NEW_PROJECT",projectOrigin:"NEW_PROJECT",projectOriginLabel:"本轮新建项目",preparationStatus:"READY"}'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
case "$MODE" in
|
|
21
|
+
prepare-new)
|
|
22
|
+
[ "$#" -eq 2 ] || { echo "ROUTE_INSPECT_ERROR:用法 project_route_inspector.sh prepare-new <projectPath>" >&2; exit 2; }
|
|
23
|
+
prepare_new_project "$2"
|
|
24
|
+
exit 0
|
|
25
|
+
;;
|
|
26
|
+
scan)
|
|
27
|
+
[ "$#" -eq 4 ] || { echo "ROUTE_INSPECT_ERROR:用法 project_route_inspector.sh scan <productType> <projectPath> <projectSelection>" >&2; exit 2; }
|
|
28
|
+
PRODUCT_TYPE="$2"
|
|
29
|
+
PROJECT_PATH="$3"
|
|
30
|
+
PROJECT_SELECTION="$4"
|
|
31
|
+
;;
|
|
32
|
+
*)
|
|
33
|
+
echo "ROUTE_INSPECT_ERROR:用法 project_route_inspector.sh prepare-new <projectPath> 或 scan <productType> <projectPath> <projectSelection>" >&2
|
|
34
|
+
exit 2
|
|
35
|
+
;;
|
|
36
|
+
esac
|
|
37
|
+
|
|
38
|
+
case "$PRODUCT_TYPE" in aipay|webpay|apppay) ;; *) echo "ROUTE_INSPECT_ERROR:productType 非法" >&2; exit 2 ;; esac
|
|
39
|
+
case "$PROJECT_SELECTION" in CURRENT_PROJECT|OTHER_PROJECT|PREPARED_NEW_PROJECT) ;; *) echo "ROUTE_INSPECT_ERROR:projectSelection 非法" >&2; exit 2 ;; esac
|
|
40
|
+
case "$PROJECT_PATH" in /*) ;; *) echo "ROUTE_INSPECT_ERROR:projectPath 必须是绝对路径" >&2; exit 2 ;; esac
|
|
41
|
+
|
|
42
|
+
[ -d "$PROJECT_PATH" ] && [ -r "$PROJECT_PATH" ] || { echo "ROUTE_INSPECT_ERROR:项目路径不可访问" >&2; exit 2; }
|
|
43
|
+
|
|
44
|
+
if [ "$PROJECT_SELECTION" = "PREPARED_NEW_PROJECT" ]; then
|
|
45
|
+
PROJECT_ORIGIN="NEW_PROJECT"
|
|
46
|
+
PROJECT_ORIGIN_LABEL="本轮新建项目"
|
|
47
|
+
else
|
|
48
|
+
PROJECT_ORIGIN="EXISTING_PROJECT"
|
|
49
|
+
PROJECT_ORIGIN_LABEL="现有项目"
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
scan() {
|
|
53
|
+
local pattern="$1"
|
|
54
|
+
local file
|
|
55
|
+
while IFS= read -r -d '' file; do
|
|
56
|
+
if grep -En "$pattern" "$file" 2>/dev/null | grep -Ev '^[0-9]+:[[:space:]]*(//|#|\*|<!--)' | head -n 1 | grep -q .; then
|
|
57
|
+
printf '%s\n' "$file"
|
|
58
|
+
return 0
|
|
59
|
+
fi
|
|
60
|
+
done < <(find "$PROJECT_PATH" -type d \( \
|
|
61
|
+
-name .git -o -name .hg -o -name .svn -o -name .cache -o -name .gradle -o -name .idea -o \
|
|
62
|
+
-name .next -o -name .nuxt -o -name .pytest_cache -o -name .tox -o -name .Trash -o -name .venv -o \
|
|
63
|
+
-name Library -o -name __pycache__ -o -name build -o -name coverage -o -name dist -o -name node_modules -o -name target -o -name vendor \
|
|
64
|
+
\) -prune -o -type f \( -name '*.java' -o -name '*.kt' -o -name '*.js' -o -name '*.mjs' -o -name '*.cjs' -o -name '*.ts' -o -name '*.tsx' -o -name '*.py' -o -name '*.php' -o -name '*.cs' \) -print0)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
webpay_marker='alipay\.trade\.page\.pay|AlipayTradePagePay(Request|Model|Response)'
|
|
68
|
+
apppay_marker='alipay\.trade\.app\.pay|AlipayTradeAppPay(Request|Model|Response)'
|
|
69
|
+
trade_query_marker='alipay\.trade\.query|AlipayTradeQuery(Request|Model|Response)|alipay_trade_query_response'
|
|
70
|
+
trade_refund_marker='alipay\.trade\.refund|AlipayTradeRefund(Request|Model|Response)|alipay_trade_refund_response'
|
|
71
|
+
trade_refund_query_marker='alipay\.trade\.fastpay\.refund\.query|AlipayTradeFastpayRefundQuery(Request|Model|Response)|alipay_trade_fastpay_refund_query_response'
|
|
72
|
+
trade_close_marker='alipay\.trade\.close|AlipayTradeClose(Request|Model|Response)|alipay_trade_close_response'
|
|
73
|
+
trade_notify_marker='notify_url|notifyUrl|NotifyUrl|setNotifyUrl|异步通知'
|
|
74
|
+
aipay_payment_needed_marker='Payment-Needed'
|
|
75
|
+
aipay_payment_proof_marker='Payment-Proof'
|
|
76
|
+
aipay_payment_validation_marker='Payment-Validation'
|
|
77
|
+
aipay_payment_verify_marker='alipay\.aipay\.agent\.payment\.verify|AlipayAipayAgentPaymentVerify(Request|Model|Response)|alipay_aipay_agent_payment_verify_response'
|
|
78
|
+
aipay_fulfillment_confirm_marker='alipay\.aipay\.agent\.fulfillment\.confirm|AlipayAipayAgentFulfillmentConfirm(Request|Model|Response)|alipay_aipay_agent_fulfillment_confirm_response'
|
|
79
|
+
aipay_marker="$aipay_payment_needed_marker|$aipay_payment_proof_marker|$aipay_payment_verify_marker|$aipay_fulfillment_confirm_marker"
|
|
80
|
+
|
|
81
|
+
target_marker=""
|
|
82
|
+
other_products=""
|
|
83
|
+
case "$PRODUCT_TYPE" in
|
|
84
|
+
aipay) target_marker="$aipay_marker" ;;
|
|
85
|
+
webpay) target_marker="$webpay_marker" ;;
|
|
86
|
+
apppay) target_marker="$apppay_marker" ;;
|
|
87
|
+
esac
|
|
88
|
+
|
|
89
|
+
[ -z "$(scan "$webpay_marker")" ] || [ "$PRODUCT_TYPE" = "webpay" ] || other_products="${other_products}AI 网页应用收款,"
|
|
90
|
+
[ -z "$(scan "$apppay_marker")" ] || [ "$PRODUCT_TYPE" = "apppay" ] || other_products="${other_products}AI 移动应用收款,"
|
|
91
|
+
[ -z "$(scan "$aipay_marker")" ] || [ "$PRODUCT_TYPE" = "aipay" ] || other_products="${other_products}AI 按量付费,"
|
|
92
|
+
other_products="${other_products%,}"
|
|
93
|
+
[ -n "$other_products" ] || other_products="无"
|
|
94
|
+
|
|
95
|
+
if [ -z "$(scan "$target_marker")" ]; then
|
|
96
|
+
if [ "$other_products" = "无" ]; then
|
|
97
|
+
status="NO_PAYMENT"
|
|
98
|
+
if [ "$PROJECT_SELECTION" = "PREPARED_NEW_PROJECT" ]; then
|
|
99
|
+
evidence="固定检查器扫描本轮已初始化的新项目,未发现目标产品或其他受支持支付代码"
|
|
100
|
+
else
|
|
101
|
+
evidence="固定检查器未发现目标产品或其他受支持支付代码"
|
|
102
|
+
fi
|
|
103
|
+
else status="OTHER_PRODUCT_ONLY"; evidence="固定检查器只发现其他受支持支付产品代码"; fi
|
|
104
|
+
else
|
|
105
|
+
if [ "$PRODUCT_TYPE" = "aipay" ]; then
|
|
106
|
+
required_patterns=("$aipay_payment_needed_marker" "$aipay_payment_proof_marker" "$aipay_payment_verify_marker" "$aipay_fulfillment_confirm_marker" "$aipay_payment_validation_marker")
|
|
107
|
+
elif [ "$PRODUCT_TYPE" = "webpay" ]; then
|
|
108
|
+
required_patterns=("$webpay_marker" "$trade_query_marker" "$trade_refund_marker" "$trade_refund_query_marker" "$trade_close_marker" "$trade_notify_marker")
|
|
109
|
+
else
|
|
110
|
+
required_patterns=("$apppay_marker" "$trade_query_marker" "$trade_refund_marker" "$trade_refund_query_marker" "$trade_close_marker" "$trade_notify_marker")
|
|
111
|
+
fi
|
|
112
|
+
missing=()
|
|
113
|
+
for pattern in "${required_patterns[@]}"; do
|
|
114
|
+
[ -n "$(scan "$pattern")" ] || missing+=("$pattern")
|
|
115
|
+
done
|
|
116
|
+
if [ "${#missing[@]}" -eq 0 ]; then
|
|
117
|
+
status="TARGET_PARTIAL"
|
|
118
|
+
evidence="固定检查器逐项发现目标产品入口及全部核心接口标记,但静态扫描不能证明配置、安全、测试和 checklist 完成;必须进入 Integration 验证分支"
|
|
119
|
+
else
|
|
120
|
+
status="TARGET_PARTIAL"
|
|
121
|
+
evidence="固定检查器发现目标产品代码,但至少一个核心接口标记缺失;不得按完整集成路由"
|
|
122
|
+
fi
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
jq -n \
|
|
126
|
+
--arg selection "$PROJECT_SELECTION" \
|
|
127
|
+
--arg origin "$PROJECT_ORIGIN" \
|
|
128
|
+
--arg originLabel "$PROJECT_ORIGIN_LABEL" \
|
|
129
|
+
--arg status "$status" \
|
|
130
|
+
--arg evidence "$evidence" \
|
|
131
|
+
--arg others "$other_products" \
|
|
132
|
+
'{projectSelection:$selection,projectOrigin:$origin,projectOriginLabel:$originLabel,integrationStatus:$status,evidence:$evidence,otherProducts:$others}'
|