@alipay/alipay-aipay 1.2.2 → 1.4.9
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 +5 -0
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +13 -12
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/uninstall.d.ts.map +1 -1
- package/dist/commands/uninstall.js +17 -9
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +5 -5
- package/dist/commands/update.js.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/utils/config.d.ts +5 -3
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +34 -12
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/file.d.ts +8 -0
- package/dist/utils/file.d.ts.map +1 -1
- package/dist/utils/file.js +161 -9
- package/dist/utils/file.js.map +1 -1
- package/dist/utils/jq.d.ts.map +1 -1
- package/dist/utils/jq.js +8 -0
- package/dist/utils/jq.js.map +1 -1
- package/package.json +6 -5
- package/skill/SKILL.md +15 -169
- package/skill/VERSION +1 -1
- package/skill/references/integration/flow.md +321 -292
- package/skill/references/integration/modules/alipay-sdk-reminder.md +5 -3
- package/skill/references/integration/modules/checklist.md +41 -27
- package/skill/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/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 +8 -4
- package/skill/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 +6 -2
- package/skill/references/integration/modules/code-examples/csharp/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemo.cs +3 -1
- package/skill/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/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 +4 -1
- package/skill/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 +5 -2
- package/skill/references/integration/modules/code-examples/java/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemoController.java +3 -1
- package/skill/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/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 +16 -10
- package/skill/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 +10 -4
- package/skill/references/integration/modules/code-examples/nodejs/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemo.js +2 -1
- package/skill/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/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 +4 -1
- package/skill/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 +5 -2
- package/skill/references/integration/modules/code-examples/php/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemo.php +2 -1
- package/skill/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/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 +4 -1
- package/skill/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 +5 -1
- package/skill/references/integration/modules/code-examples/python/4-/346/214/211/351/207/217/344/273/230/350/264/271/A2MPaymentDemo.py +4 -2
- package/skill/references/integration/modules/interface-contract/aipay-interface-contract.md +53 -0
- package/skill/references/integration/modules/interface-contract/apppay-interface-contract.md +45 -0
- package/skill/references/integration/modules/interface-contract/common-trade-contract.md +42 -0
- package/skill/references/integration/modules/interface-contract/notify-url-contract.md +68 -0
- package/skill/references/integration/modules/interface-contract/webpay-interface-contract.md +44 -0
- package/skill/references/integration/modules/interface-guide.md +37 -72
- package/skill/references/integration/modules/product-decision.md +10 -27
- package/skill/references/integration/modules/sandbox/a2m-sandbox-test.md +62 -94
- package/skill/references/integration/modules/sandbox/alipay-sandbox-tool.md +43 -40
- package/skill/references/integration/modules/sandbox/sandbox-setup-guide.md +93 -114
- package/skill/references/integration/modules/scripts/local_402_sandbox_pay.py +357 -147
- package/skill/references/integration/modules/scripts/sandbox_config.sh +299 -0
- package/skill/references/integration/modules/troubleshooting-flow.md +28 -0
- package/skill/references/normal/alipay-cli-env.md +15 -5
- package/skill/references/normal/full-process-routing.md +80 -0
- package/skill/references/normal/json/customer-messages.json +937 -0
- package/skill/references/normal/json/policy-rules.json +179 -0
- package/skill/references/normal/rejection-guide.md +11 -6
- package/skill/references/normal/scripts/alipay_cli_env.mjs +29 -0
- package/skill/references/normal/scripts/alipay_cli_env.sh +21 -0
- package/skill/references/normal/scripts/common.sh +87 -0
- package/skill/references/normal/scripts/detect_dev_tool.sh +5 -1
- package/skill/references/normal/scripts/integration_message_runner.mjs +801 -0
- package/skill/references/normal/scripts/onboarding_message_runner.mjs +436 -0
- package/skill/references/normal/scripts/open_official_url.sh +82 -0
- package/skill/references/normal/scripts/platform_compat.mjs +39 -0
- package/skill/references/normal/scripts/project_route_inspector.sh +132 -0
- package/skill/references/normal/scripts/python_script_runner.mjs +56 -0
- package/skill/references/normal/scripts/render_customer_message.mjs +1263 -0
- package/skill/references/normal/scripts/self_update.mjs +160 -0
- package/skill/references/normal/scripts/telemetry.mjs +1278 -0
- package/skill/references/normal/self-update.md +18 -51
- package/skill/references/onboarding/flow.md +381 -283
- package/skill/references/onboarding/modules/app-release.md +132 -179
- package/skill/references/onboarding/modules/authorization.md +53 -64
- package/skill/references/onboarding/modules/error-handling.md +31 -34
- package/skill/references/onboarding/modules/product-sign.md +62 -66
- package/skill/references/onboarding/modules/scripts/app.sh +397 -158
- package/skill/references/onboarding/modules/scripts/ar_sign_apply.sh +38 -22
- package/skill/references/onboarding/modules/scripts/auth.sh +479 -167
- package/skill/references/onboarding/modules/scripts/download_key_tool.sh +157 -0
- package/skill/references/onboarding/modules/scripts/error_handler.sh +100 -130
- package/skill/references/onboarding/modules/scripts/network_retry.sh +96 -0
- package/skill/references/onboarding/modules/scripts/query_sign_status.sh +17 -70
- package/skill/references/onboarding/modules/scripts/service.sh +153 -89
- package/skill/references/onboarding/modules/scripts/sign_status_parser.sh +58 -0
- package/skill/references/onboarding/modules/scripts/upload_screenshots.sh +16 -14
- package/skill/references/onboarding/modules/service-registration.md +67 -72
- package/skill/references/runtime-entry.md +62 -0
|
@@ -3,24 +3,28 @@
|
|
|
3
3
|
# 脚本名称: app.sh
|
|
4
4
|
# 功能描述: 应用发布全流程 - 查询/复用 + 创建 + 公钥设置 + 提交审核
|
|
5
5
|
# 调用位置: list 用于 Step 3.1 前置资源查询;其他命令用于 Step 5.3 应用发布
|
|
6
|
-
# 调用前置: 脚本通过 error_handler.sh 间接初始化 DEV_TOOL_NAME
|
|
6
|
+
# 调用前置: 脚本通过 error_handler.sh 间接初始化 DEV_TOOL_NAME/PLATFORM_ID
|
|
7
7
|
# list/create 可传 --application-type,未传时按 --product-type/--sales-code 或兼容环境变量推断
|
|
8
8
|
# 用法:
|
|
9
9
|
# app list [--product-type <type> --sales-code <code> --application-type <type>] - 查询已有应用并判断复用/新建
|
|
10
10
|
# app create [--product-type <type> --sales-code <code> --application-type <type>] [--mobile-platform IOS|ANDROID|ALL ...] - 创建新应用
|
|
11
|
-
# app key <appId> <publicKey>
|
|
11
|
+
# app key --defer-open <appId> <publicKey> - 设置应用公钥
|
|
12
|
+
# app open-key-page <appId> - 打开上一次生成的公钥确认页
|
|
12
13
|
# app verify-key <appId> [publicKey] - 确认应用公钥已设置
|
|
14
|
+
# app verify-key-and-audit <appId> [publicKey] - 复用最终密钥查询结果并提交审核
|
|
13
15
|
# app audit <appId> - 提交应用审核
|
|
14
16
|
# app reuse <appId> - 复用已有应用(查询安全密钥)
|
|
15
17
|
# 返回值:
|
|
16
|
-
# list:
|
|
17
|
-
# create:
|
|
18
|
+
# list: stdout 成功时为空;stderr 输出带统一内部前缀的候选 JSON、FLOW 和候选 ID
|
|
19
|
+
# create: 成功在 stderr 输出 APP_ID=xxx;失败 exit 1,返回结构异常时同时输出 FLOW:ERROR
|
|
18
20
|
# key: 输出 confirmPageUrl
|
|
19
21
|
# audit: 输出审核结果
|
|
20
|
-
# reuse: FLOW:REUSE_SUCCESS | FLOW:REUSE_NO_KEY | FLOW:ERROR
|
|
22
|
+
# reuse: stderr 输出 FLOW:REUSE_SUCCESS | FLOW:REUSE_NO_KEY | FLOW:ERROR
|
|
21
23
|
#=============================================================================
|
|
22
24
|
|
|
23
25
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
26
|
+
RENDERER="${SCRIPT_DIR}/../../../normal/scripts/render_customer_message.mjs"
|
|
27
|
+
CANDIDATE_RUNNER="${SCRIPT_DIR}/../../../normal/scripts/onboarding_message_runner.mjs"
|
|
24
28
|
|
|
25
29
|
# 一次性 source error_handler(含 unwrap_mcp)
|
|
26
30
|
if [ -f "${SCRIPT_DIR}/error_handler.sh" ]; then
|
|
@@ -29,8 +33,80 @@ else
|
|
|
29
33
|
echo "❌ 缺少错误处理脚本: ${SCRIPT_DIR}/error_handler.sh"
|
|
30
34
|
exit 1
|
|
31
35
|
fi
|
|
36
|
+
source "${SCRIPT_DIR}/network_retry.sh"
|
|
32
37
|
|
|
33
38
|
require_command jq || exit 1
|
|
39
|
+
require_command node || exit 1
|
|
40
|
+
|
|
41
|
+
APP_KEY_STATE_OWNER="$(id -u 2>/dev/null || printf '%s' "${USER:-unknown}" | tr -c 'A-Za-z0-9_-' '_')"
|
|
42
|
+
APP_KEY_STATE_BASE="${TMPDIR:-/tmp}"
|
|
43
|
+
APP_KEY_STATE_BASE="${APP_KEY_STATE_BASE%/}"
|
|
44
|
+
if [ -n "${ALIPAY_APP_KEY_STATE_FILE:-}" ]; then
|
|
45
|
+
APP_KEY_STATE_FILE="$ALIPAY_APP_KEY_STATE_FILE"
|
|
46
|
+
APP_KEY_STATE_DIR="$(dirname "$APP_KEY_STATE_FILE")"
|
|
47
|
+
APP_KEY_STATE_DIR_MANAGED=false
|
|
48
|
+
else
|
|
49
|
+
APP_KEY_STATE_DIR="${APP_KEY_STATE_BASE}/alipay-aipay-app-key-${APP_KEY_STATE_OWNER}"
|
|
50
|
+
APP_KEY_STATE_FILE="${APP_KEY_STATE_DIR}/key-page-state.json"
|
|
51
|
+
APP_KEY_STATE_DIR_MANAGED=true
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
app_key_secure_mode() {
|
|
55
|
+
local target="$1" expected="$2" mode
|
|
56
|
+
if mode=$(stat -f '%Lp' "$target" 2>/dev/null); then
|
|
57
|
+
:
|
|
58
|
+
elif mode=$(stat -c '%a' "$target" 2>/dev/null); then
|
|
59
|
+
:
|
|
60
|
+
else
|
|
61
|
+
return 1
|
|
62
|
+
fi
|
|
63
|
+
[ "$mode" = "$expected" ]
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
prepare_app_key_state_dir() {
|
|
67
|
+
if [ "$APP_KEY_STATE_DIR_MANAGED" = true ]; then
|
|
68
|
+
if [ -L "$APP_KEY_STATE_DIR" ] || { [ -e "$APP_KEY_STATE_DIR" ] && [ ! -d "$APP_KEY_STATE_DIR" ]; }; then
|
|
69
|
+
echo "❌ 公钥确认页临时目录不安全,已停止" >&2
|
|
70
|
+
return 1
|
|
71
|
+
fi
|
|
72
|
+
mkdir -p "$APP_KEY_STATE_DIR" || return 1
|
|
73
|
+
chmod 700 "$APP_KEY_STATE_DIR" 2>/dev/null || return 1
|
|
74
|
+
app_key_secure_mode "$APP_KEY_STATE_DIR" 700 || return 1
|
|
75
|
+
else
|
|
76
|
+
[ -d "$APP_KEY_STATE_DIR" ] && [ ! -L "$APP_KEY_STATE_DIR" ] || {
|
|
77
|
+
echo "❌ 指定的公钥确认页状态目录不可用或不安全,已停止" >&2
|
|
78
|
+
return 1
|
|
79
|
+
}
|
|
80
|
+
fi
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
validate_app_key_state_file() {
|
|
84
|
+
[ -f "$APP_KEY_STATE_FILE" ] && [ ! -L "$APP_KEY_STATE_FILE" ] || return 1
|
|
85
|
+
chmod 600 "$APP_KEY_STATE_FILE" 2>/dev/null || return 1
|
|
86
|
+
app_key_secure_mode "$APP_KEY_STATE_FILE" 600
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
save_app_key_page_state() {
|
|
90
|
+
local temp_state
|
|
91
|
+
require_command mktemp || return 1
|
|
92
|
+
prepare_app_key_state_dir || return 1
|
|
93
|
+
if [ -L "$APP_KEY_STATE_FILE" ] || { [ -e "$APP_KEY_STATE_FILE" ] && [ ! -f "$APP_KEY_STATE_FILE" ]; }; then
|
|
94
|
+
echo "❌ 公钥确认页状态路径不是安全的普通文件,已停止" >&2
|
|
95
|
+
return 1
|
|
96
|
+
fi
|
|
97
|
+
temp_state=$(mktemp "${APP_KEY_STATE_DIR}/.key-page-state.XXXXXX") || return 1
|
|
98
|
+
chmod 600 "$temp_state" 2>/dev/null || { rm -f "$temp_state"; return 1; }
|
|
99
|
+
jq -n \
|
|
100
|
+
--arg appId "$APP_ID" \
|
|
101
|
+
--arg confirmPageUrl "$CONFIRM_PAGE_URL" \
|
|
102
|
+
'{appId:$appId,confirmPageUrl:$confirmPageUrl}' > "$temp_state" || { rm -f "$temp_state"; return 1; }
|
|
103
|
+
mv "$temp_state" "$APP_KEY_STATE_FILE" || { rm -f "$temp_state"; return 1; }
|
|
104
|
+
validate_app_key_state_file || {
|
|
105
|
+
rm -f "$APP_KEY_STATE_FILE"
|
|
106
|
+
echo "❌ 无法确认公钥确认页状态文件权限为 0600,已停止" >&2
|
|
107
|
+
return 1
|
|
108
|
+
}
|
|
109
|
+
}
|
|
34
110
|
|
|
35
111
|
parse_app_context_args() {
|
|
36
112
|
while [[ $# -gt 0 ]]; do
|
|
@@ -73,7 +149,7 @@ validate_mobile_platform_args() {
|
|
|
73
149
|
fi
|
|
74
150
|
if [ "$APP_APPLICATION_TYPE" = "MOBILEAPP" ]; then
|
|
75
151
|
echo "❌ 创建 MOBILEAPP 必须传 --mobile-platform IOS|ANDROID|ALL" >&2
|
|
76
|
-
echo "📋 IOS 需同时传 --bundle-id;ANDROID 需同时传 --app-package 和 --app-sign;ALL
|
|
152
|
+
echo "📋 IOS 需同时传 --bundle-id;ANDROID 需同时传 --app-package 和 --app-sign;ALL 需三项都传;HarmonyOS 移动应用不支持通过 Skill 创建" >&2
|
|
77
153
|
return 1
|
|
78
154
|
fi
|
|
79
155
|
return 0
|
|
@@ -112,7 +188,7 @@ validate_mobile_platform_args() {
|
|
|
112
188
|
fi
|
|
113
189
|
;;
|
|
114
190
|
*)
|
|
115
|
-
echo "❌ --mobile-platform 参数值无效: ${MOBILE_PLATFORM}(仅支持 IOS|ANDROID|ALL
|
|
191
|
+
echo "❌ --mobile-platform 参数值无效: ${MOBILE_PLATFORM}(仅支持 IOS|ANDROID|ALL;HarmonyOS 移动应用需前往支付宝开放平台控制台创建)" >&2
|
|
116
192
|
return 1
|
|
117
193
|
;;
|
|
118
194
|
esac
|
|
@@ -213,9 +289,15 @@ query_security_key() {
|
|
|
213
289
|
REQUEST_JSON=$(jq -n --arg appId "$APP_ID" '{request:{appId:$appId}}')
|
|
214
290
|
fi
|
|
215
291
|
|
|
216
|
-
|
|
292
|
+
export PLATFORM="${DEV_TOOL_NAME}" PLATFORM_ID="${PLATFORM_ID:-}"
|
|
293
|
+
run_network_retry RESULT read application_security_key -- alipay-cli mcp call apprelease.queryApplicationSecurityKey \
|
|
217
294
|
-d "$REQUEST_JSON" \
|
|
218
|
-
--json
|
|
295
|
+
--json
|
|
296
|
+
RETRY_RC=$?
|
|
297
|
+
if [ "$RETRY_RC" -ne 0 ]; then
|
|
298
|
+
echo "❌ 应用安全密钥查询因网络或服务异常在自动重试两次后仍未恢复"
|
|
299
|
+
return 1
|
|
300
|
+
fi
|
|
219
301
|
|
|
220
302
|
if ! handle_error "$RESULT"; then
|
|
221
303
|
return 1
|
|
@@ -226,6 +308,7 @@ query_security_key() {
|
|
|
226
308
|
|
|
227
309
|
if [ "$SUCCESS" != "true" ]; then
|
|
228
310
|
ERROR_MSG=$(echo "$SECURITY_BUSINESS" | jq -r '.error.message // .errorMessage // "未知错误"')
|
|
311
|
+
ERROR_MSG=$(sanitize_customer_error_text "$ERROR_MSG")
|
|
229
312
|
echo "❌ 查询安全密钥失败: $ERROR_MSG"
|
|
230
313
|
return 1
|
|
231
314
|
fi
|
|
@@ -235,9 +318,15 @@ query_application_info() {
|
|
|
235
318
|
local APP_ID="$1"
|
|
236
319
|
|
|
237
320
|
REQUEST_JSON=$(jq -n --arg appId "$APP_ID" '{request:{appId:$appId}}')
|
|
238
|
-
|
|
321
|
+
export PLATFORM="${DEV_TOOL_NAME}" PLATFORM_ID="${PLATFORM_ID:-}"
|
|
322
|
+
run_network_retry RESULT read application_info -- alipay-cli mcp call apprelease.queryApplicationInfo \
|
|
239
323
|
-d "$REQUEST_JSON" \
|
|
240
|
-
--json
|
|
324
|
+
--json
|
|
325
|
+
RETRY_RC=$?
|
|
326
|
+
if [ "$RETRY_RC" -ne 0 ]; then
|
|
327
|
+
echo "❌ 应用信息查询因网络或服务异常在自动重试两次后仍未恢复"
|
|
328
|
+
return 1
|
|
329
|
+
fi
|
|
241
330
|
|
|
242
331
|
if ! handle_error "$RESULT"; then
|
|
243
332
|
return 1
|
|
@@ -248,6 +337,7 @@ query_application_info() {
|
|
|
248
337
|
|
|
249
338
|
if [ "$SUCCESS" != "true" ]; then
|
|
250
339
|
ERROR_MSG=$(echo "$APPLICATION_INFO_BUSINESS" | jq -r '.error.message // .errorMessage // "未知错误"')
|
|
340
|
+
ERROR_MSG=$(sanitize_customer_error_text "$ERROR_MSG")
|
|
251
341
|
echo "❌ 查询应用信息失败: $ERROR_MSG"
|
|
252
342
|
return 1
|
|
253
343
|
fi
|
|
@@ -324,20 +414,20 @@ write_alipay_public_key() {
|
|
|
324
414
|
fi
|
|
325
415
|
|
|
326
416
|
while [ "$ATTEMPT" -le "$MAX_ATTEMPTS" ]; do
|
|
327
|
-
if { mkdir -p "${HOME}/.config" && printf '%s\n' "$ALIPAY_PUBLIC_KEY" > "$KEY_FILE"; } 2>/dev/null; then
|
|
417
|
+
if { mkdir -p "${HOME}/.config" && chmod 700 "${HOME}/.config" && (umask 077; printf '%s\n' "$ALIPAY_PUBLIC_KEY" > "$KEY_FILE") && chmod 600 "$KEY_FILE"; } 2>/dev/null; then
|
|
328
418
|
return 0
|
|
329
419
|
fi
|
|
330
420
|
|
|
331
421
|
if [ "$ATTEMPT" -lt "$MAX_ATTEMPTS" ]; then
|
|
332
|
-
|
|
422
|
+
emit_control "⚠️ 支付宝公钥文件写入失败,正在重试(${ATTEMPT}/${MAX_ATTEMPTS})..."
|
|
333
423
|
sleep 1
|
|
334
424
|
fi
|
|
335
425
|
ATTEMPT=$((ATTEMPT + 1))
|
|
336
426
|
done
|
|
337
427
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
428
|
+
emit_control "⚠️ 已获取到 RSA2 支付宝公钥,但本地文件写入失败: $KEY_FILE"
|
|
429
|
+
emit_control "📋 这不是公钥查询失败;当前流程会继续,但后续集成时需要手动配置支付宝公钥。"
|
|
430
|
+
emit_control "📋 可检查本地目录权限或设置 HOME 后重新执行导出。"
|
|
341
431
|
return 1
|
|
342
432
|
}
|
|
343
433
|
|
|
@@ -345,42 +435,50 @@ ensure_rsa2_application_key_ready() {
|
|
|
345
435
|
local APP_ID="$1"
|
|
346
436
|
local PUBLIC_KEY="${2:-}"
|
|
347
437
|
local ATTEMPT=1
|
|
348
|
-
local MAX_ATTEMPTS=
|
|
349
|
-
local INTERVAL_SECONDS=
|
|
438
|
+
local MAX_ATTEMPTS=20
|
|
439
|
+
local INTERVAL_SECONDS=2
|
|
440
|
+
KEY_VERIFY_RESULT=""
|
|
350
441
|
|
|
351
|
-
if
|
|
352
|
-
MAX_ATTEMPTS=
|
|
442
|
+
if [ "${ALIPAY_AIPAY_RECOVERY_QUERY_ONCE:-0}" = "1" ]; then
|
|
443
|
+
MAX_ATTEMPTS=1
|
|
353
444
|
fi
|
|
354
445
|
|
|
355
|
-
if
|
|
356
|
-
INTERVAL_SECONDS=
|
|
446
|
+
if [ "${ALIPAY_AIPAY_TEST_MODE:-0}" = "1" ] && [[ "${APP_KEY_VERIFY_INTERVAL_SECONDS:-}" =~ ^[0-9]+$ ]]; then
|
|
447
|
+
INTERVAL_SECONDS="$APP_KEY_VERIFY_INTERVAL_SECONDS"
|
|
357
448
|
fi
|
|
358
449
|
|
|
359
450
|
while [ "$ATTEMPT" -le "$MAX_ATTEMPTS" ]; do
|
|
360
|
-
query_security_key "$APP_ID" "$PUBLIC_KEY"
|
|
451
|
+
if ! query_security_key "$APP_ID" "$PUBLIC_KEY"; then
|
|
452
|
+
KEY_VERIFY_RESULT="QUERY_FAILED"
|
|
453
|
+
return 1
|
|
454
|
+
fi
|
|
361
455
|
|
|
362
456
|
RSA2_KEY_INFO=$(extract_rsa2_application_key_info)
|
|
363
457
|
|
|
364
458
|
if is_rsa2_application_key_ready "$RSA2_KEY_INFO"; then
|
|
459
|
+
KEY_VERIFY_RESULT="CONFIRMED"
|
|
365
460
|
return 0
|
|
366
461
|
fi
|
|
367
462
|
|
|
368
463
|
if [ "$ATTEMPT" -lt "$MAX_ATTEMPTS" ]; then
|
|
369
|
-
|
|
464
|
+
emit_control "KEY_POLL_PENDING=${ATTEMPT}/${MAX_ATTEMPTS}"
|
|
370
465
|
sleep "$INTERVAL_SECONDS"
|
|
371
466
|
fi
|
|
372
467
|
|
|
373
468
|
ATTEMPT=$((ATTEMPT + 1))
|
|
374
469
|
done
|
|
375
470
|
|
|
376
|
-
|
|
471
|
+
KEY_VERIFY_RESULT="PENDING"
|
|
377
472
|
return 1
|
|
378
473
|
}
|
|
379
474
|
|
|
380
|
-
|
|
381
|
-
|
|
475
|
+
render_key_pending() {
|
|
476
|
+
printf '%s' '{}' \
|
|
477
|
+
| ALIPAY_AIPAY_RENDERER_MANAGED_CALLER=app.sh node "$RENDERER" application.key.pending --variant DEFAULT
|
|
478
|
+
}
|
|
382
479
|
|
|
383
|
-
|
|
480
|
+
export_alipay_public_key_from_security_business() {
|
|
481
|
+
local APP_ID="$1"
|
|
384
482
|
|
|
385
483
|
RSA2_KEY_INFO=$(extract_rsa2_application_key_info)
|
|
386
484
|
RSA2_ALIPAY_KEY_INFO=$(extract_rsa2_alipay_key_info)
|
|
@@ -397,17 +495,24 @@ verify_key_and_export_alipay_public_key() {
|
|
|
397
495
|
fi
|
|
398
496
|
|
|
399
497
|
if write_alipay_public_key "$APP_ID" "$ALIPAY_PUBLIC_KEY"; then
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
498
|
+
emit_control "✅ 已确认应用公钥并导出支付宝公钥"
|
|
499
|
+
emit_control "支付宝公钥保存路径: ~/.config/${APP_ID}-alipayPublicKey.keytext"
|
|
500
|
+
emit_control "ALIPAY_PUBLIC_KEY_EXPORT_STATUS=EXPORTED"
|
|
501
|
+
emit_control "ALIPAY_PUBLIC_KEY_FILE=~/.config/${APP_ID}-alipayPublicKey.keytext"
|
|
404
502
|
else
|
|
405
|
-
|
|
503
|
+
emit_control "ALIPAY_PUBLIC_KEY_EXPORT_STATUS=MANUAL_CONFIGURATION_REQUIRED"
|
|
406
504
|
fi
|
|
407
505
|
|
|
408
506
|
return 0
|
|
409
507
|
}
|
|
410
508
|
|
|
509
|
+
verify_key_and_export_alipay_public_key() {
|
|
510
|
+
local APP_ID="$1"
|
|
511
|
+
|
|
512
|
+
query_security_key "$APP_ID" || return 1
|
|
513
|
+
export_alipay_public_key_from_security_business "$APP_ID"
|
|
514
|
+
}
|
|
515
|
+
|
|
411
516
|
# ─── app list: 查询已有应用 ──────────────────────────────────────────────────
|
|
412
517
|
app_list() {
|
|
413
518
|
parse_app_context_args "$@" || {
|
|
@@ -417,9 +522,16 @@ app_list() {
|
|
|
417
522
|
APP_APPLICATION_TYPE=$(resolve_application_type) || exit 1
|
|
418
523
|
REQUEST_JSON=$(jq -n --arg applicationType "$APP_APPLICATION_TYPE" '{request:{appTypes:[$applicationType]}}')
|
|
419
524
|
|
|
420
|
-
|
|
525
|
+
export PLATFORM="${DEV_TOOL_NAME}" PLATFORM_ID="${PLATFORM_ID:-}"
|
|
526
|
+
run_network_retry RESULT read application_list -- alipay-cli mcp call apprelease.queryApplicationList \
|
|
421
527
|
-d "$REQUEST_JSON" \
|
|
422
|
-
--json
|
|
528
|
+
--json
|
|
529
|
+
RETRY_RC=$?
|
|
530
|
+
if [ "$RETRY_RC" -ne 0 ]; then
|
|
531
|
+
echo "❌ 应用列表查询因网络或服务异常在自动重试两次后仍未恢复"
|
|
532
|
+
emit_control "FLOW:ERROR"
|
|
533
|
+
exit 1
|
|
534
|
+
fi
|
|
423
535
|
|
|
424
536
|
# 错误检测
|
|
425
537
|
if ! handle_error "$RESULT"; then
|
|
@@ -432,8 +544,9 @@ app_list() {
|
|
|
432
544
|
|
|
433
545
|
if [ "$SUCCESS" != "true" ]; then
|
|
434
546
|
ERROR_MSG=$(echo "$BUSINESS" | jq -r '.error.message // .errorMessage // "未知错误"')
|
|
547
|
+
ERROR_MSG=$(sanitize_customer_error_text "$ERROR_MSG")
|
|
435
548
|
echo "❌ 查询应用列表失败: $ERROR_MSG"
|
|
436
|
-
|
|
549
|
+
emit_control "FLOW:ERROR"
|
|
437
550
|
exit 1
|
|
438
551
|
fi
|
|
439
552
|
|
|
@@ -448,78 +561,56 @@ app_list() {
|
|
|
448
561
|
' 2>/dev/null)
|
|
449
562
|
if [ -z "$APP_LIST" ] || ! echo "$APP_LIST" | jq -e 'type == "array"' >/dev/null 2>&1; then
|
|
450
563
|
echo "❌ 应用列表返回结构异常,无法解析应用列表"
|
|
451
|
-
|
|
564
|
+
emit_control "FLOW:ERROR"
|
|
452
565
|
exit 1
|
|
453
566
|
fi
|
|
454
567
|
APP_COUNT=$(echo "$APP_LIST" | jq 'length')
|
|
568
|
+
APP_CANDIDATES=$(echo "$APP_LIST" | jq -c '[.[] | {
|
|
569
|
+
appId: ((.appId // "未知") | tostring),
|
|
570
|
+
appName: ((.appName // "未知") | tostring),
|
|
571
|
+
status: ((.status // "未知") | tostring)
|
|
572
|
+
}]')
|
|
573
|
+
ONLINE_APPS=$(echo "$APP_LIST" | jq -r '[.[] | select(.status == "ON_LINE")]')
|
|
574
|
+
NON_ONLINE_APPS=$(echo "$APP_LIST" | jq -r '[.[] | select(.status != "ON_LINE")]')
|
|
575
|
+
ONLINE_COUNT=$(echo "$ONLINE_APPS" | jq 'length')
|
|
576
|
+
NON_ONLINE_COUNT=$(echo "$NON_ONLINE_APPS" | jq 'length')
|
|
577
|
+
ONLINE_COUNT=${ONLINE_COUNT:-0}
|
|
578
|
+
NON_ONLINE_COUNT=${NON_ONLINE_COUNT:-0}
|
|
579
|
+
|
|
580
|
+
if [ "$ONLINE_COUNT" -gt 0 ] && ! echo "$ONLINE_APPS" | jq -e '
|
|
581
|
+
all(.[];
|
|
582
|
+
((.appId | type) == "string") and
|
|
583
|
+
(.appId | length > 0) and
|
|
584
|
+
((.appId | test("[\u0000-\u001f\u007f]") | not))
|
|
585
|
+
)
|
|
586
|
+
' >/dev/null 2>&1; then
|
|
587
|
+
echo "❌ 应用列表返回结构异常:可复用候选 appId 缺失或包含控制字符"
|
|
588
|
+
emit_control "FLOW:ERROR"
|
|
589
|
+
exit 1
|
|
590
|
+
fi
|
|
591
|
+
|
|
592
|
+
if ! printf '%s' "$APP_CANDIDATES" \
|
|
593
|
+
| node "$CANDIDATE_RUNNER" application-candidates --application-type "$APP_APPLICATION_TYPE" >/dev/null 2>&1; then
|
|
594
|
+
echo "❌ 应用候选事实安全校验失败"
|
|
595
|
+
emit_control "FLOW:ERROR"
|
|
596
|
+
exit 1
|
|
597
|
+
fi
|
|
598
|
+
emit_control_field "APP_CANDIDATES_JSON" "$APP_CANDIDATES" || {
|
|
599
|
+
echo "❌ 应用候选事实包含非法控制字符"
|
|
600
|
+
emit_control "FLOW:ERROR"
|
|
601
|
+
exit 1
|
|
602
|
+
}
|
|
603
|
+
emit_control_field "APPLICATION_TYPE" "$APP_APPLICATION_TYPE" || exit 1
|
|
455
604
|
|
|
456
605
|
if [ "$APP_COUNT" -eq 0 ]; then
|
|
457
|
-
|
|
458
|
-
echo "FLOW:CREATE_NEW"
|
|
606
|
+
emit_control "FLOW:CREATE_NEW"
|
|
459
607
|
else
|
|
460
|
-
# 实际返回的状态字段值是 "ON_LINE"(带下划线)
|
|
461
|
-
ONLINE_APPS=$(echo "$APP_LIST" | jq -r '[.[] | select(.status == "ON_LINE")]')
|
|
462
|
-
NON_ONLINE_APPS=$(echo "$APP_LIST" | jq -r '[.[] | select(.status != "ON_LINE")]')
|
|
463
|
-
ONLINE_COUNT=$(echo "$ONLINE_APPS" | jq 'length')
|
|
464
|
-
NON_ONLINE_COUNT=$(echo "$NON_ONLINE_APPS" | jq 'length')
|
|
465
|
-
ONLINE_COUNT=${ONLINE_COUNT:-0}
|
|
466
|
-
NON_ONLINE_COUNT=${NON_ONLINE_COUNT:-0}
|
|
467
|
-
|
|
468
608
|
if [ "$ONLINE_COUNT" -eq 0 ]; then
|
|
469
|
-
|
|
470
|
-
echo ""
|
|
471
|
-
echo "| 应用ID | 应用名称 | 实际状态 |"
|
|
472
|
-
echo "|--------|----------|----------|"
|
|
473
|
-
for i in $(seq 0 $((NON_ONLINE_COUNT-1))); do
|
|
474
|
-
APP=$(echo "$NON_ONLINE_APPS" | jq ".[$i]")
|
|
475
|
-
APP_ID=$(echo "$APP" | jq -r '.appId // "未知"')
|
|
476
|
-
APP_NAME=$(echo "$APP" | jq -r '.appName // "未知"')
|
|
477
|
-
APP_STATUS=$(echo "$APP" | jq -r '.status // "未知"')
|
|
478
|
-
echo "| $APP_ID | $APP_NAME | $APP_STATUS |"
|
|
479
|
-
done
|
|
480
|
-
echo ""
|
|
481
|
-
echo "以上应用当前不可复用。请等待应用上线,或在了解现有应用状态后明确选择新建。"
|
|
482
|
-
echo "FLOW:PENDING_APPLICATIONS"
|
|
609
|
+
emit_control "FLOW:PENDING_APPLICATIONS"
|
|
483
610
|
else
|
|
484
|
-
echo "
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
echo "|------|--------|----------|------|"
|
|
488
|
-
|
|
489
|
-
for i in $(seq 0 $((ONLINE_COUNT-1))); do
|
|
490
|
-
APP=$(echo "$ONLINE_APPS" | jq ".[$i]")
|
|
491
|
-
APP_ID=$(echo "$APP" | jq -r '.appId // "未知"')
|
|
492
|
-
APP_NAME=$(echo "$APP" | jq -r '.appName // "未知"')
|
|
493
|
-
echo "| $((i+1)) | $APP_ID | $APP_NAME | 已上线 |"
|
|
494
|
-
done
|
|
495
|
-
|
|
496
|
-
if [ "$NON_ONLINE_COUNT" -gt 0 ]; then
|
|
497
|
-
echo ""
|
|
498
|
-
echo "另有以下尚未上线的同类型应用,当前不可复用:"
|
|
499
|
-
echo ""
|
|
500
|
-
echo "| 应用ID | 应用名称 | 实际状态 |"
|
|
501
|
-
echo "|--------|----------|----------|"
|
|
502
|
-
for i in $(seq 0 $((NON_ONLINE_COUNT-1))); do
|
|
503
|
-
APP=$(echo "$NON_ONLINE_APPS" | jq ".[$i]")
|
|
504
|
-
APP_ID=$(echo "$APP" | jq -r '.appId // "未知"')
|
|
505
|
-
APP_NAME=$(echo "$APP" | jq -r '.appName // "未知"')
|
|
506
|
-
APP_STATUS=$(echo "$APP" | jq -r '.status // "未知"')
|
|
507
|
-
echo "| $APP_ID | $APP_NAME | $APP_STATUS |"
|
|
508
|
-
done
|
|
509
|
-
echo ""
|
|
510
|
-
echo "新建前请结合以上状态避免重复创建。"
|
|
511
|
-
fi
|
|
512
|
-
|
|
513
|
-
echo ""
|
|
514
|
-
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
515
|
-
echo " 请选择操作:"
|
|
516
|
-
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
517
|
-
echo ""
|
|
518
|
-
echo " 【复用】输入序号 (1-$ONLINE_COUNT) → 复用对应应用"
|
|
519
|
-
echo " 【新建】输入 \"新建\" → 创建新应用"
|
|
520
|
-
echo ""
|
|
521
|
-
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
522
|
-
echo "FLOW:SELECT"
|
|
611
|
+
echo "$ONLINE_APPS" | jq -r '.[] | select((.appId // "") != "") | "APP_CANDIDATE_ID=" + .appId' \
|
|
612
|
+
| while IFS= read -r marker; do emit_control "$marker"; done
|
|
613
|
+
emit_control "FLOW:SELECT"
|
|
523
614
|
fi
|
|
524
615
|
fi
|
|
525
616
|
}
|
|
@@ -537,9 +628,20 @@ app_create() {
|
|
|
537
628
|
exit 1
|
|
538
629
|
}
|
|
539
630
|
|
|
540
|
-
|
|
631
|
+
export PLATFORM="${DEV_TOOL_NAME}" PLATFORM_ID="${PLATFORM_ID:-}"
|
|
632
|
+
run_network_retry RESULT write application_create -- alipay-cli mcp call apprelease.createApplication \
|
|
541
633
|
-d "$REQUEST_JSON" \
|
|
542
|
-
--json
|
|
634
|
+
--json
|
|
635
|
+
RETRY_RC=$?
|
|
636
|
+
if [ "$RETRY_RC" -eq 75 ]; then
|
|
637
|
+
echo "❌ 应用创建响应不明;现有应用列表无法把同类型新应用唯一归属于本次创建,结果标记为 UNKNOWN,禁止自动重复创建"
|
|
638
|
+
emit_control "FLOW:ERROR"
|
|
639
|
+
exit 1
|
|
640
|
+
elif [ "$RETRY_RC" -ne 0 ]; then
|
|
641
|
+
echo "❌ 应用创建因明确未发送的网络异常在自动重试两次后仍未恢复"
|
|
642
|
+
emit_control "FLOW:ERROR"
|
|
643
|
+
exit 1
|
|
644
|
+
fi
|
|
543
645
|
|
|
544
646
|
# 错误检测
|
|
545
647
|
if ! handle_error "$RESULT"; then
|
|
@@ -552,16 +654,17 @@ app_create() {
|
|
|
552
654
|
|
|
553
655
|
if [ "$SUCCESS" = "true" ]; then
|
|
554
656
|
APP_ID=$(echo "$BUSINESS" | jq -r '.resultObj.appId // .data.appId // empty')
|
|
555
|
-
if
|
|
657
|
+
if ! validate_control_value "$APP_ID"; then
|
|
556
658
|
echo "❌ 应用创建返回成功,但未解析到 appId,禁止进入公钥设置流程"
|
|
557
|
-
|
|
659
|
+
emit_control "FLOW:ERROR"
|
|
558
660
|
exit 1
|
|
559
661
|
fi
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
662
|
+
emit_control "✅ 应用创建成功"
|
|
663
|
+
emit_control_field "APPLICATION_TYPE" "$APP_APPLICATION_TYPE" || exit 1
|
|
664
|
+
emit_control_field "APP_ID" "$APP_ID" || exit 1
|
|
563
665
|
else
|
|
564
666
|
ERROR_MSG=$(echo "$BUSINESS" | jq -r '.error.message // .errorMessage // "未知错误"')
|
|
667
|
+
ERROR_MSG=$(sanitize_customer_error_text "$ERROR_MSG")
|
|
565
668
|
echo "❌ 应用创建失败: $ERROR_MSG"
|
|
566
669
|
exit 1
|
|
567
670
|
fi
|
|
@@ -569,9 +672,17 @@ app_create() {
|
|
|
569
672
|
|
|
570
673
|
# ─── app key: 设置应用公钥 ───────────────────────────────────────────────────
|
|
571
674
|
app_key() {
|
|
675
|
+
if [ "${1:-}" = "--defer-open" ]; then
|
|
676
|
+
shift
|
|
677
|
+
else
|
|
678
|
+
echo "❌ 参数格式错误:app key 必须使用 --defer-open,确保先展示公钥确认说明和链接,再自动打开页面"
|
|
679
|
+
echo "用法: bash app.sh key --defer-open <appId> <publicKey>"
|
|
680
|
+
exit 1
|
|
681
|
+
fi
|
|
682
|
+
|
|
572
683
|
if [ "$#" -ne 2 ] || [[ "${1:-}" == --* ]]; then
|
|
573
|
-
echo "❌ 参数格式错误:key 使用位置参数 <appId> <publicKey
|
|
574
|
-
echo "用法: bash app.sh key <appId> <publicKey>"
|
|
684
|
+
echo "❌ 参数格式错误:key 使用位置参数 <appId> <publicKey>"
|
|
685
|
+
echo "用法: bash app.sh key --defer-open <appId> <publicKey>"
|
|
575
686
|
exit 1
|
|
576
687
|
fi
|
|
577
688
|
|
|
@@ -580,7 +691,11 @@ app_key() {
|
|
|
580
691
|
|
|
581
692
|
if [ -z "$APP_ID" ] || [ -z "$PUBLIC_KEY" ]; then
|
|
582
693
|
echo "❌ 请提供 appId 和 publicKey"
|
|
583
|
-
echo "用法: bash app.sh key <appId> <publicKey>"
|
|
694
|
+
echo "用法: bash app.sh key --defer-open <appId> <publicKey>"
|
|
695
|
+
exit 1
|
|
696
|
+
fi
|
|
697
|
+
if ! validate_control_value "$APP_ID"; then
|
|
698
|
+
echo "❌ appId 包含非法控制字符"
|
|
584
699
|
exit 1
|
|
585
700
|
fi
|
|
586
701
|
|
|
@@ -589,9 +704,18 @@ app_key() {
|
|
|
589
704
|
--arg publicKey "$PUBLIC_KEY" \
|
|
590
705
|
'{request:{appId:$appId,signType:"RSA2",publicKey:$publicKey}}')
|
|
591
706
|
|
|
592
|
-
|
|
707
|
+
export PLATFORM="${DEV_TOOL_NAME}" PLATFORM_ID="${PLATFORM_ID:-}"
|
|
708
|
+
run_network_retry RESULT write application_key_confirm_page -- alipay-cli mcp call apprelease.createKeyConfirmPage \
|
|
593
709
|
-d "$REQUEST_JSON" \
|
|
594
|
-
--json
|
|
710
|
+
--json
|
|
711
|
+
RETRY_RC=$?
|
|
712
|
+
if [ "$RETRY_RC" -eq 75 ]; then
|
|
713
|
+
echo "❌ 公钥确认页生成响应不明,结果标记为 UNKNOWN;不得自动生成第二个页面"
|
|
714
|
+
exit 1
|
|
715
|
+
elif [ "$RETRY_RC" -ne 0 ]; then
|
|
716
|
+
echo "❌ 公钥确认页因明确未发送的网络异常在自动重试两次后仍未恢复"
|
|
717
|
+
exit 1
|
|
718
|
+
fi
|
|
595
719
|
|
|
596
720
|
# 错误检测
|
|
597
721
|
if ! handle_error "$RESULT"; then
|
|
@@ -606,50 +730,101 @@ app_key() {
|
|
|
606
730
|
CONFIRM_PAGE_URL=$(echo "$BUSINESS" | jq -r '.resultObj.confirmPageUrl // empty')
|
|
607
731
|
|
|
608
732
|
if [ -n "$CONFIRM_PAGE_URL" ]; then
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
733
|
+
RENDERER="${SCRIPT_DIR}/../../../normal/scripts/render_customer_message.mjs"
|
|
734
|
+
save_app_key_page_state || exit 1
|
|
735
|
+
MESSAGE_INPUT=$(printf '%s\n' "$APP_ID" "$CONFIRM_PAGE_URL" | jq -Rs '
|
|
736
|
+
split("\n") as $v | {appId:$v[0],officialUrl:$v[1]}
|
|
737
|
+
')
|
|
738
|
+
if ! printf '%s' "$MESSAGE_INPUT" | ALIPAY_AIPAY_RENDERER_MANAGED_CALLER=app.sh node "$RENDERER" application.key.page --variant READY; then
|
|
739
|
+
echo "❌ 公钥确认页已生成,但标准消息无法安全输出;结果保持待核验,禁止自动生成第二个页面"
|
|
740
|
+
exit 1
|
|
741
|
+
fi
|
|
742
|
+
emit_control "KEY_PAGE:READY_TO_OPEN"
|
|
619
743
|
else
|
|
620
|
-
echo "❌
|
|
744
|
+
echo "❌ 公钥确认页响应缺少 confirmPageUrl,结果标记为 UNKNOWN;不得自动生成第二个页面"
|
|
621
745
|
exit 1
|
|
622
746
|
fi
|
|
623
747
|
else
|
|
624
748
|
ERROR_MSG=$(echo "$BUSINESS" | jq -r '.error.message // .errorMessage // "未知错误"')
|
|
749
|
+
ERROR_MSG=$(sanitize_customer_error_text "$ERROR_MSG")
|
|
625
750
|
echo "❌ 公钥设置失败: $ERROR_MSG"
|
|
626
751
|
exit 1
|
|
627
752
|
fi
|
|
628
753
|
}
|
|
629
754
|
|
|
630
|
-
|
|
631
|
-
|
|
755
|
+
app_open_key_page() {
|
|
756
|
+
local APP_ID="$1" SAVED_APP_ID CONFIRM_PAGE_URL MESSAGE_INPUT OPEN_HELPER OPEN_STATUS
|
|
757
|
+
|
|
632
758
|
if [ "$#" -ne 1 ] || [[ "${1:-}" == --* ]]; then
|
|
633
|
-
echo "❌ 参数格式错误:
|
|
634
|
-
echo "用法: bash app.sh
|
|
759
|
+
echo "❌ 参数格式错误:open-key-page 使用位置参数 <appId>,不支持 --app-id 等未定义选项"
|
|
760
|
+
echo "用法: bash app.sh open-key-page <appId>"
|
|
761
|
+
exit 1
|
|
762
|
+
fi
|
|
763
|
+
if ! validate_control_value "$APP_ID"; then
|
|
764
|
+
echo "❌ appId 包含非法控制字符"
|
|
635
765
|
exit 1
|
|
636
766
|
fi
|
|
767
|
+
if ! validate_app_key_state_file; then
|
|
768
|
+
echo "❌ 缺少待打开的公钥确认页上下文,请重新执行 app.sh key --defer-open <appId> <publicKey>"
|
|
769
|
+
emit_control "FLOW:ERROR"
|
|
770
|
+
return 1
|
|
771
|
+
fi
|
|
772
|
+
if ! jq -e . "$APP_KEY_STATE_FILE" >/dev/null 2>&1; then
|
|
773
|
+
echo "❌ 公钥确认页状态文件不是合法 JSON,已停止"
|
|
774
|
+
emit_control "FLOW:ERROR"
|
|
775
|
+
return 1
|
|
776
|
+
fi
|
|
637
777
|
|
|
638
|
-
|
|
778
|
+
SAVED_APP_ID=$(jq -r '.appId // ""' "$APP_KEY_STATE_FILE")
|
|
779
|
+
CONFIRM_PAGE_URL=$(jq -r '.confirmPageUrl // ""' "$APP_KEY_STATE_FILE")
|
|
780
|
+
if [ "$SAVED_APP_ID" != "$APP_ID" ] || [ -z "$CONFIRM_PAGE_URL" ]; then
|
|
781
|
+
echo "❌ 当前 appId 与已生成的公钥确认页上下文不一致,已停止打开"
|
|
782
|
+
emit_control "FLOW:ERROR"
|
|
783
|
+
return 1
|
|
784
|
+
fi
|
|
639
785
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
786
|
+
MESSAGE_INPUT=$(printf '%s\n' "$APP_ID" "$CONFIRM_PAGE_URL" | jq -Rs '
|
|
787
|
+
split("\n") as $v | {appId:$v[0],officialUrl:$v[1]}
|
|
788
|
+
')
|
|
789
|
+
if ! printf '%s' "$MESSAGE_INPUT" | ALIPAY_AIPAY_RENDERER_MANAGED_CALLER=app.sh node "$RENDERER" application.key.page --variant READY >/dev/null; then
|
|
790
|
+
echo "❌ 公钥确认页 URL 校验失败,已停止打开"
|
|
791
|
+
emit_control "FLOW:ERROR"
|
|
792
|
+
return 1
|
|
644
793
|
fi
|
|
645
794
|
|
|
646
|
-
|
|
795
|
+
OPEN_HELPER="${SCRIPT_DIR}/../../../normal/scripts/open_official_url.sh"
|
|
796
|
+
OPEN_STATUS=$(printf '%s\n' "$CONFIRM_PAGE_URL" | bash "$OPEN_HELPER" public-key-confirmation)
|
|
797
|
+
case "$OPEN_STATUS" in OPENED|OPEN_FAILED|GUI_UNAVAILABLE|LINK_ONLY) ;; *) OPEN_STATUS="OPEN_FAILED" ;; esac
|
|
798
|
+
emit_control "KEY_OPEN:${OPEN_STATUS}"
|
|
799
|
+
}
|
|
647
800
|
|
|
801
|
+
submit_application_audit() {
|
|
802
|
+
local APP_ID="$1"
|
|
648
803
|
REQUEST_JSON=$(jq -n --arg appId "$APP_ID" '{request:{appId:$appId}}')
|
|
649
804
|
|
|
650
|
-
|
|
805
|
+
export PLATFORM="${DEV_TOOL_NAME}" PLATFORM_ID="${PLATFORM_ID:-}"
|
|
806
|
+
run_network_retry RESULT write application_audit -- alipay-cli mcp call apprelease.submitApplicationAudit \
|
|
651
807
|
-d "$REQUEST_JSON" \
|
|
652
|
-
--json
|
|
808
|
+
--json
|
|
809
|
+
RETRY_RC=$?
|
|
810
|
+
if [ "$RETRY_RC" -eq 75 ]; then
|
|
811
|
+
if query_application_info "$APP_ID"; then
|
|
812
|
+
ACTUAL_STATUS=$(extract_application_status)
|
|
813
|
+
case "$ACTUAL_STATUS" in
|
|
814
|
+
AUDITING|ON_LINE)
|
|
815
|
+
emit_control "✅ 应用审核提交已由应用信息查询核验成功"
|
|
816
|
+
emit_control_field "APP_ID" "$APP_ID" || return 1
|
|
817
|
+
emit_control "FLOW:AUDIT_SUBMITTED"
|
|
818
|
+
return 0
|
|
819
|
+
;;
|
|
820
|
+
esac
|
|
821
|
+
fi
|
|
822
|
+
echo "❌ 应用提审响应不明且现有状态无法排除传播延迟,结果标记为 UNKNOWN,禁止自动重复提审"
|
|
823
|
+
exit 1
|
|
824
|
+
elif [ "$RETRY_RC" -ne 0 ]; then
|
|
825
|
+
echo "❌ 应用提审因明确未发送的网络异常在自动重试两次后仍未恢复"
|
|
826
|
+
exit 1
|
|
827
|
+
fi
|
|
653
828
|
|
|
654
829
|
# 错误检测
|
|
655
830
|
if ! handle_error "$RESULT"; then
|
|
@@ -661,16 +836,32 @@ app_audit() {
|
|
|
661
836
|
SUCCESS=$(echo "$BUSINESS" | jq -r '.success // false')
|
|
662
837
|
|
|
663
838
|
if [ "$SUCCESS" = "true" ]; then
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
839
|
+
emit_control "✅ 应用审核提交成功"
|
|
840
|
+
emit_control_field "APP_ID" "$APP_ID" || return 1
|
|
841
|
+
emit_control "FLOW:AUDIT_SUBMITTED"
|
|
667
842
|
else
|
|
668
843
|
ERROR_MSG=$(echo "$BUSINESS" | jq -r '.error.message // .errorMessage // "未知错误"')
|
|
844
|
+
ERROR_MSG=$(sanitize_customer_error_text "$ERROR_MSG")
|
|
669
845
|
echo "❌ 提交审核失败: $ERROR_MSG"
|
|
670
846
|
exit 1
|
|
671
847
|
fi
|
|
672
848
|
}
|
|
673
849
|
|
|
850
|
+
# ─── app audit: 提交应用审核 ─────────────────────────────────────────────────
|
|
851
|
+
app_audit() {
|
|
852
|
+
if [ "$#" -ne 1 ] || [[ "${1:-}" == --* ]]; then
|
|
853
|
+
echo "❌ 参数格式错误:audit 使用位置参数 <appId>,不支持 --app-id 等未定义选项"
|
|
854
|
+
echo "用法: bash app.sh audit <appId>"
|
|
855
|
+
exit 1
|
|
856
|
+
fi
|
|
857
|
+
|
|
858
|
+
APP_ID="$1"
|
|
859
|
+
[ -n "$APP_ID" ] || { echo "❌ 请提供 appId"; echo "用法: bash app.sh audit <appId>"; exit 1; }
|
|
860
|
+
validate_control_value "$APP_ID" || { echo "❌ appId 包含非法控制字符"; exit 1; }
|
|
861
|
+
verify_key_and_export_alipay_public_key "$APP_ID" || exit 1
|
|
862
|
+
submit_application_audit "$APP_ID"
|
|
863
|
+
}
|
|
864
|
+
|
|
674
865
|
# ─── app verify-key: 确认应用公钥已设置 ─────────────────────────────────────
|
|
675
866
|
app_verify_key() {
|
|
676
867
|
if [ "$#" -lt 1 ] || [ "$#" -gt 2 ] || [[ "${1:-}" == --* ]]; then
|
|
@@ -687,17 +878,54 @@ app_verify_key() {
|
|
|
687
878
|
echo "用法: bash app.sh verify-key <appId> [publicKey]"
|
|
688
879
|
exit 1
|
|
689
880
|
fi
|
|
881
|
+
validate_control_value "$APP_ID" || { echo "❌ appId 包含非法控制字符"; exit 1; }
|
|
690
882
|
|
|
691
883
|
if ensure_rsa2_application_key_ready "$APP_ID" "$PUBLIC_KEY"; then
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
884
|
+
emit_control "✅ 应用公钥已确认"
|
|
885
|
+
emit_control_field "APP_ID" "$APP_ID" || exit 1
|
|
886
|
+
emit_control "FLOW:KEY_CONFIRMED"
|
|
695
887
|
else
|
|
696
|
-
|
|
888
|
+
if [ "$KEY_VERIFY_RESULT" = "PENDING" ]; then
|
|
889
|
+
if ! render_key_pending; then
|
|
890
|
+
emit_control "FLOW:ERROR"
|
|
891
|
+
exit 1
|
|
892
|
+
fi
|
|
893
|
+
emit_control "FLOW:KEY_NOT_CONFIRMED"
|
|
894
|
+
else
|
|
895
|
+
emit_control "FLOW:ERROR"
|
|
896
|
+
fi
|
|
697
897
|
exit 1
|
|
698
898
|
fi
|
|
699
899
|
}
|
|
700
900
|
|
|
901
|
+
app_verify_key_and_audit() {
|
|
902
|
+
if [ "$#" -lt 1 ] || [ "$#" -gt 2 ] || [[ "${1:-}" == --* ]]; then
|
|
903
|
+
echo "❌ 参数格式错误:verify-key-and-audit 使用位置参数 <appId> [publicKey],不支持 --app-id 等未定义选项"
|
|
904
|
+
echo "用法: bash app.sh verify-key-and-audit <appId> [publicKey]"
|
|
905
|
+
exit 1
|
|
906
|
+
fi
|
|
907
|
+
|
|
908
|
+
APP_ID="$1"
|
|
909
|
+
PUBLIC_KEY="${2:-}"
|
|
910
|
+
[ -n "$APP_ID" ] || { echo "❌ 请提供 appId"; exit 1; }
|
|
911
|
+
validate_control_value "$APP_ID" || { echo "❌ appId 包含非法控制字符"; exit 1; }
|
|
912
|
+
|
|
913
|
+
if ! ensure_rsa2_application_key_ready "$APP_ID" "$PUBLIC_KEY"; then
|
|
914
|
+
if [ "$KEY_VERIFY_RESULT" = "PENDING" ]; then
|
|
915
|
+
if ! render_key_pending; then
|
|
916
|
+
emit_control "FLOW:ERROR"
|
|
917
|
+
exit 1
|
|
918
|
+
fi
|
|
919
|
+
emit_control "FLOW:KEY_NOT_CONFIRMED"
|
|
920
|
+
else
|
|
921
|
+
emit_control "FLOW:ERROR"
|
|
922
|
+
fi
|
|
923
|
+
exit 1
|
|
924
|
+
fi
|
|
925
|
+
export_alipay_public_key_from_security_business "$APP_ID" || exit 1
|
|
926
|
+
submit_application_audit "$APP_ID"
|
|
927
|
+
}
|
|
928
|
+
|
|
701
929
|
# ─── app reuse: 复用已有应用(查询安全密钥) ──────────────────────────────────
|
|
702
930
|
app_reuse() {
|
|
703
931
|
if [ "$#" -ne 1 ] || [[ "${1:-}" == --* ]]; then
|
|
@@ -713,16 +941,17 @@ app_reuse() {
|
|
|
713
941
|
echo "用法: bash app.sh reuse <appId>"
|
|
714
942
|
exit 1
|
|
715
943
|
fi
|
|
944
|
+
validate_control_value "$APP_ID" || { echo "❌ appId 包含非法控制字符"; exit 1; }
|
|
716
945
|
|
|
717
946
|
if query_application_info "$APP_ID"; then
|
|
718
947
|
APP_STATUS=$(extract_application_status)
|
|
719
948
|
if [ "$APP_STATUS" != "ON_LINE" ]; then
|
|
720
949
|
echo "❌ 仅允许复用 ON_LINE(已上线)应用,当前应用状态: ${APP_STATUS:-未知}"
|
|
721
|
-
|
|
950
|
+
emit_control "FLOW:ERROR"
|
|
722
951
|
exit 1
|
|
723
952
|
fi
|
|
724
953
|
else
|
|
725
|
-
|
|
954
|
+
emit_control "FLOW:ERROR"
|
|
726
955
|
exit 1
|
|
727
956
|
fi
|
|
728
957
|
|
|
@@ -732,27 +961,27 @@ app_reuse() {
|
|
|
732
961
|
ALIPAY_PUBLIC_KEY=$(extract_alipay_public_key "$RSA2_ALIPAY_KEY_INFO")
|
|
733
962
|
|
|
734
963
|
if ! is_rsa2_application_key_ready "$RSA2_KEY_INFO"; then
|
|
735
|
-
|
|
736
|
-
|
|
964
|
+
emit_control "⚠️ 未确认到已生效的 RSA2 应用公钥"
|
|
965
|
+
emit_control "FLOW:REUSE_NO_KEY"
|
|
737
966
|
exit 1
|
|
738
967
|
elif [ -n "$ALIPAY_PUBLIC_KEY" ]; then
|
|
739
968
|
if write_alipay_public_key "$APP_ID" "$ALIPAY_PUBLIC_KEY"; then
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
969
|
+
emit_control "✅ 已获取支付宝公钥"
|
|
970
|
+
emit_control "支付宝公钥保存路径: ~/.config/${APP_ID}-alipayPublicKey.keytext"
|
|
971
|
+
emit_control "ALIPAY_PUBLIC_KEY_EXPORT_STATUS=EXPORTED"
|
|
972
|
+
emit_control "ALIPAY_PUBLIC_KEY_FILE=~/.config/${APP_ID}-alipayPublicKey.keytext"
|
|
744
973
|
else
|
|
745
|
-
|
|
974
|
+
emit_control "ALIPAY_PUBLIC_KEY_EXPORT_STATUS=MANUAL_CONFIGURATION_REQUIRED"
|
|
746
975
|
fi
|
|
747
|
-
|
|
748
|
-
|
|
976
|
+
emit_control_field "APP_ID" "$APP_ID" || exit 1
|
|
977
|
+
emit_control "FLOW:REUSE_SUCCESS"
|
|
749
978
|
else
|
|
750
979
|
echo "❌ 已确认应用公钥生效,但未获取到 RSA2 支付宝公钥"
|
|
751
|
-
|
|
980
|
+
emit_control "FLOW:ERROR"
|
|
752
981
|
exit 1
|
|
753
982
|
fi
|
|
754
983
|
else
|
|
755
|
-
|
|
984
|
+
emit_control "FLOW:ERROR"
|
|
756
985
|
exit 1
|
|
757
986
|
fi
|
|
758
987
|
}
|
|
@@ -760,7 +989,7 @@ app_reuse() {
|
|
|
760
989
|
# ─── 入口分发 ────────────────────────────────────────────────────────────────
|
|
761
990
|
APP_COMMAND="${1:-}"
|
|
762
991
|
case "$APP_COMMAND" in
|
|
763
|
-
list|create|key|verify-key|audit|reuse)
|
|
992
|
+
list|create|key|verify-key|verify-key-and-audit|audit|reuse)
|
|
764
993
|
require_command alipay-cli || exit 1
|
|
765
994
|
;;
|
|
766
995
|
esac
|
|
@@ -778,10 +1007,18 @@ case "$APP_COMMAND" in
|
|
|
778
1007
|
shift
|
|
779
1008
|
app_key "$@"
|
|
780
1009
|
;;
|
|
1010
|
+
open-key-page)
|
|
1011
|
+
shift
|
|
1012
|
+
app_open_key_page "$@"
|
|
1013
|
+
;;
|
|
781
1014
|
verify-key)
|
|
782
1015
|
shift
|
|
783
1016
|
app_verify_key "$@"
|
|
784
1017
|
;;
|
|
1018
|
+
verify-key-and-audit)
|
|
1019
|
+
shift
|
|
1020
|
+
app_verify_key_and_audit "$@"
|
|
1021
|
+
;;
|
|
785
1022
|
audit)
|
|
786
1023
|
shift
|
|
787
1024
|
app_audit "$@"
|
|
@@ -791,12 +1028,14 @@ case "$APP_COMMAND" in
|
|
|
791
1028
|
app_reuse "$@"
|
|
792
1029
|
;;
|
|
793
1030
|
*)
|
|
794
|
-
echo "用法: bash app.sh <list|create|key|verify-key|audit|reuse> [参数...]"
|
|
1031
|
+
echo "用法: bash app.sh <list|create|key|open-key-page|verify-key|verify-key-and-audit|audit|reuse> [参数...]"
|
|
795
1032
|
echo ""
|
|
796
1033
|
echo " app list [--product-type <type> --sales-code <code> --application-type <type>] - 查询已有应用"
|
|
797
1034
|
echo " app create [--product-type <type> --sales-code <code> --application-type <type>] [--mobile-platform IOS|ANDROID|ALL ...] - 创建新应用"
|
|
798
|
-
echo " app key <appId> <pubKey> - 设置公钥"
|
|
1035
|
+
echo " app key --defer-open <appId> <pubKey> - 设置公钥"
|
|
1036
|
+
echo " app open-key-page <appId> - 打开已生成的公钥确认页"
|
|
799
1037
|
echo " app verify-key <appId> [pubKey] - 确认公钥设置结果"
|
|
1038
|
+
echo " app verify-key-and-audit <appId> [pubKey] - 确认公钥并提交审核"
|
|
800
1039
|
echo " app audit <appId> - 提交审核"
|
|
801
1040
|
echo " app reuse <appId> - 复用应用"
|
|
802
1041
|
exit 1
|