From e9ad27b46af7549e9c193454eb699297ca4f5594 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Tue, 4 Jun 2024 23:25:25 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E8=AF=81?= =?UTF-8?q?=E4=B9=A6=E7=AD=BE=E5=90=8D=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes https://github.com/alipay/alipay-sdk-nodejs-all/issues/131 --- README.md | 12 +- src/alipay.ts | 16 ++- src/types.ts | 6 +- test/alipay.test.ts | 124 ++++++++++++++++++ ...lipayCertPublicKey_RSA2_aesEncryptText.crt | 1 + .../test_alipayRootCert_aesEncryptText.crt | 1 + .../test_appCertPublicKey_aesEncryptText.crt | 1 + 7 files changed, 149 insertions(+), 12 deletions(-) create mode 100644 test/fixtures/test_alipayCertPublicKey_RSA2_aesEncryptText.crt create mode 100644 test/fixtures/test_alipayRootCert_aesEncryptText.crt create mode 100644 test/fixtures/test_appCertPublicKey_aesEncryptText.crt diff --git a/README.md b/README.md index c783316..3b0224d 100644 --- a/README.md +++ b/README.md @@ -56,9 +56,9 @@ const alipaySdk = new AlipaySdk({ // 设置应用 ID appId: 'your-APPID', // 设置应用私钥 - privateKey: fs.readFileSync('private-key.pem', 'ascii'), + privateKey: fs.readFileSync('/path/to/private-key.pem', 'ascii'), // 设置支付宝公钥 - alipayPublicKey: fs.readFileSync('alipay-public-key.pem', 'ascii'), + alipayPublicKey: fs.readFileSync('/path/to/alipay-public-key.pem', 'ascii'), // 密钥类型,请与生成的密钥格式保持一致,参考平台配置一节 // keyType: 'PKCS1', // 设置网关地址,默认是 https://openapi.alipay.com @@ -73,11 +73,11 @@ import { AlipaySdk } from 'alipay-sdk'; const alipaySdk = new AlipaySdk({ appId: '2016123456789012', - privateKey: fs.readFileSync('private-key.pem', 'ascii'), + privateKey: fs.readFileSync('/path/to/private-key.pem', 'ascii'), // 传入支付宝根证书、支付宝公钥证书和应用公钥证书。 - alipayRootCertPath: path.join(__dirname, 'alipayRootCert.crt'), - alipayPublicCertPath: path.join(__dirname, 'alipayCertPublicKey_RSA2.crt'), - appCertPath: path.join(__dirname, 'appCertPublicKey.crt'), + alipayRootCertPath: '/path/to/alipayRootCert.crt', + alipayPublicCertPath: '/path/to/alipayCertPublicKey_RSA2.crt', + appCertPath: '/path/to/appCertPublicKey.crt', }); ``` diff --git a/src/alipay.ts b/src/alipay.ts index 625f699..706ae5f 100644 --- a/src/alipay.ts +++ b/src/alipay.ts @@ -403,7 +403,20 @@ export class AlipaySdk { requestOptions.content = httpRequestBody; } } + if (this.config.alipayRootCertSn) { + requestOptions.headers['alipay-root-cert-sn'] = this.config.alipayRootCertSn; + } // 签名规则 https://opendocs.alipay.com/open-v3/054q58?pathHash=474929ac#%E6%99%AE%E9%80%9A%E8%AF%B7%E6%B1%82 + // authString 拼接格式: + // + // ```txt + // app_id=${app_id},app_cert_sn=${app_cert_sn},nonce=${nonce},timestamp=${timestamp} + // ``` + let authString = `app_id=${this.config.appId}`; + if (this.config.appCertSn) { + authString += `,app_cert_sn=${this.config.appCertSn}`; + } + authString += `,nonce=${randomUUID()},timestamp=${Date.now()}`; // 签名字符串拼接格式: // // ```txt @@ -413,9 +426,6 @@ export class AlipaySdk { // ${httpRequestBody}\n // ${appAuthToken}\n // ``` - // - // TODO: 需要支持 app_cert_sn - const authString = `app_id=${this.config.appId},nonce=${randomUUID()},timestamp=${Date.now()}`; let signString = `${authString}\n${httpMethod}\n${httpRequestUrl}\n${httpRequestBody}\n`; if (options?.appAuthToken) { requestOptions.headers['alipay-app-auth-token'] = options.appAuthToken; diff --git a/src/types.ts b/src/types.ts index a72c29b..d93020c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -36,19 +36,19 @@ export interface AlipaySdkConfig { appCertPath?: string; /** 应用公钥证书文件内容 */ appCertContent?: string | Buffer; - /** 应用公钥证书sn */ + /** 应用公钥证书sn,不需要手动设置,会根据 appCertPath 自动计算出来 */ appCertSn?: string; /** 支付宝根证书文件路径 */ alipayRootCertPath?: string; /** 支付宝根证书文件内容 */ alipayRootCertContent?: string | Buffer; - /** 支付宝根证书sn */ + /** 支付宝根证书sn,不需要手动设置,会根据 alipayRootCertPath 自动计算出来 */ alipayRootCertSn?: string; /** 支付宝公钥证书文件路径 */ alipayPublicCertPath?: string; /** 支付宝公钥证书文件内容 */ alipayPublicCertContent?: string | Buffer; - /** 支付宝公钥证书sn */ + /** 支付宝公钥证书sn,不需要手动设置,会根据 alipayPublicCertPath 自动计算出来 */ alipayCertSn?: string; /** AES 密钥,调用 AES 加解密相关接口时需要 */ encryptKey?: string; diff --git a/test/alipay.test.ts b/test/alipay.test.ts index 69ea885..0ed0167 100755 --- a/test/alipay.test.ts +++ b/test/alipay.test.ts @@ -11,6 +11,7 @@ import { import { AlipayFormData, AlipayFormStream, AlipayRequestError, AlipaySdk, AlipaySdkConfig, } from '../src/index.js'; +import { aesDecryptText } from '../src/util.js'; const privateKey = readFixturesFile('app-private-key.pem', 'ascii'); const alipayPublicKey = readFixturesFile('alipay-public-key.pem', 'ascii'); @@ -406,6 +407,129 @@ describe('test/alipay.test.ts', () => { return true; }); }); + + it('转账接口强制要求证书签名调用', async () => { + // https://opendocs.alipay.com/open-v3/08e7ef12_alipay.fund.trans.uni.transfer?scene=ca56bca529e64125a2786703c6192d41&pathHash=52e2898b + await assert.rejects(async () => { + await sdkStable.curl('POST', '/v3/alipay/fund/trans/uni/transfer', { + body: { + order_title: '201905代发', + biz_scene: 'DIRECT_TRANSFER', + sign_data: { + ori_sign: 'EqHFP0z4a9iaQ1ep==', + partner_id: '签名被授权方支付宝账号ID', + ori_app_id: '2021000185629012', + ori_out_biz_no: '商户订单号', + ori_sign_type: 'RSA2', + ori_char_set: 'UTF-8', + }, + business_params: '{"payer_show_name_use_alias":"true"}', + remark: '201905代发', + out_biz_no: '201806300001', + trans_amount: '23.00', + product_code: 'TRANS_ACCOUNT_NO_PWD', + payee_info: { + identity: '2088123412341234', + name: '黄龙国际有限公司', + identity_type: 'ALIPAY_USER_ID', + }, + original_order_id: '20190620110075000006640000063056', + }, + }); + }, (err: any) => { + assert.equal(err.code, 'INVALID_PARAMETER'); + assert.match(err.message, /参数有误未开启验签,不允许传入sign_data签名参数/); + return true; + }); + }); + }); + + describe('curl() + 证书签名模式', () => { + if (!process.env.TEST_ALIPAY_APP_ENCRYPT_KEY_ENCRYPTION) { + return; + } + // 测试密钥维护找@苏千,https://u.alipay.cn/_25tzRNHiQZU + const encryptKey = process.env.TEST_ALIPAY_APP_ENCRYPT_KEY_ENCRYPTION; + const sdk = new AlipaySdk({ + appId: process.env.TEST_ALIPAY_APP_ID_ENCRYPTION!, + privateKey: process.env.TEST_ALIPAY_APP_PRIVATE_KEY_ENCRYPTION!, + timeout: 10000, + encryptKey, + appCertContent: + aesDecryptText(readFixturesFile('test_appCertPublicKey_aesEncryptText.crt'), encryptKey), + alipayRootCertContent: + aesDecryptText(readFixturesFile('test_alipayRootCert_aesEncryptText.crt'), encryptKey), + alipayPublicCertContent: + aesDecryptText(readFixturesFile('test_alipayCertPublicKey_RSA2_aesEncryptText.crt'), encryptKey), + }); + + it.skip('POST 文件上传,使用 AlipayFormStream with body', async () => { + // https://opendocs.alipay.com/open-v3/5aa91070_alipay.open.file.upload?scene=common&pathHash=c8e11ccc + const filePath = getFixturesFile('demo.jpg'); + const form = new AlipayFormStream(); + form.file('file_content', filePath, 'demo.jpg'); + + const uploadResult = await sdk.curl<{ + file_id: string; + }>('POST', '/v3/alipay/open/file/upload', { + form, + body: { + biz_code: 'openpt_appstore', + }, + }); + // console.log(uploadResult); + assert(uploadResult.data.file_id); + assert.equal(uploadResult.responseHttpStatus, 200); + assert(uploadResult.traceId); + }); + + it('POST /v3/alipay/user/deloauth/detail/query', async () => { + // https://opendocs.alipay.com/open-v3/668cd27c_alipay.user.deloauth.detail.query?pathHash=3ab93168 + const result = await sdk.curl('POST', '/v3/alipay/user/deloauth/detail/query', { + body: { + date: '20230102', + offset: 20, + limit: 1, + }, + }); + console.log(result); + assert.equal(result.responseHttpStatus, 200); + }); + + it('转账接口强制要求证书签名调用', async () => { + // https://opendocs.alipay.com/open-v3/08e7ef12_alipay.fund.trans.uni.transfer?scene=ca56bca529e64125a2786703c6192d41&pathHash=52e2898b + await assert.rejects(async () => { + await sdk.curl('POST', '/v3/alipay/fund/trans/uni/transfer', { + body: { + order_title: '201905代发', + biz_scene: 'DIRECT_TRANSFER', + sign_data: { + ori_sign: 'EqHFP0z4a9iaQ1ep==', + partner_id: '签名被授权方支付宝账号ID', + ori_app_id: '2021000185629012', + ori_out_biz_no: '商户订单号', + ori_sign_type: 'RSA2', + ori_char_set: 'UTF-8', + }, + business_params: '{"payer_show_name_use_alias":"true"}', + remark: '201905代发', + out_biz_no: '201806300001', + trans_amount: '23.00', + product_code: 'TRANS_ACCOUNT_NO_PWD', + payee_info: { + identity: '2088123412341234', + name: '黄龙国际有限公司', + identity_type: 'ALIPAY_USER_ID', + }, + original_order_id: '20190620110075000006640000063056', + }, + }); + }, (err: any) => { + assert.equal(err.code, 'insufficient-isv-permissions'); + assert.match(err.message, /ISV权限不足,建议在开发者中心检查对应功能是否已经添加/); + return true; + }); + }); }); describe('sse(), curlStream(), curl() with needEncrypt = true', () => { diff --git a/test/fixtures/test_alipayCertPublicKey_RSA2_aesEncryptText.crt b/test/fixtures/test_alipayCertPublicKey_RSA2_aesEncryptText.crt new file mode 100644 index 0000000..3ff413a --- /dev/null +++ b/test/fixtures/test_alipayCertPublicKey_RSA2_aesEncryptText.crt @@ -0,0 +1 @@ +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 diff --git a/test/fixtures/test_alipayRootCert_aesEncryptText.crt b/test/fixtures/test_alipayRootCert_aesEncryptText.crt new file mode 100644 index 0000000..04d4840 --- /dev/null +++ b/test/fixtures/test_alipayRootCert_aesEncryptText.crt @@ -0,0 +1 @@ +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 diff --git a/test/fixtures/test_appCertPublicKey_aesEncryptText.crt b/test/fixtures/test_appCertPublicKey_aesEncryptText.crt new file mode 100644 index 0000000..4fba3d8 --- /dev/null +++ b/test/fixtures/test_appCertPublicKey_aesEncryptText.crt @@ -0,0 +1 @@ +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 From 3c3b644cd726b0e65592e10e6545fb6e0972d97d Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Tue, 4 Jun 2024 23:43:14 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20requestTimeout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + src/alipay.ts | 4 +++- test/alipay.test.ts | 5 ++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3b0224d..f2d3dc1 100644 --- a/README.md +++ b/README.md @@ -388,6 +388,7 @@ curl 方式调用支付宝 [API v3 协议](https://opendocs.alipay.com/open-v3/0 | options.requestId | `string` | 调用方的 requestId,不填会默认生成 uuid v4 | 否 | | options.needEncrypt | `boolean` | 自动 AES 加解密,默认值是 `false` | 否 | | options.appAuthToken | `string` | [应用授权令牌](https://opendocs.alipay.com/isv/10467/xldcyq?pathHash=abce531a),代商家调用支付宝开放接口必填 | 否 | +| options.requestTimeout | `number` | 请求超时时间,默认使用 `config.timeout` | 否 | #### `AlipayCommonResult` diff --git a/src/alipay.ts b/src/alipay.ts index 706ae5f..3298b6c 100644 --- a/src/alipay.ts +++ b/src/alipay.ts @@ -154,6 +154,8 @@ export interface AlipayCURLOptions { * 应用授权令牌,代商家调用支付宝开放接口必填 */ appAuthToken?: string; + /** 请求超时时间,默认使用 config.timeout */ + requestTimeout?: number; } /** @@ -324,7 +326,7 @@ export class AlipaySdk { const requestOptions: RequestOptions = { method: httpMethod, dataType: dataType === 'stream' ? 'stream' : 'text', - timeout: this.config.timeout, + timeout: options?.requestTimeout ?? this.config.timeout, }; if (dataType === 'stream') { // 使用 HTTP/2 请求才支持流式响应 diff --git a/test/alipay.test.ts b/test/alipay.test.ts index 0ed0167..220f00c 100755 --- a/test/alipay.test.ts +++ b/test/alipay.test.ts @@ -136,7 +136,10 @@ describe('test/alipay.test.ts', () => { const uploadResult = await sdkStable.curl<{ file_id: string; - }>('POST', '/v3/alipay/open/file/upload', { form }); + }>('POST', '/v3/alipay/open/file/upload', { + form, + requestTimeout: 10000, + }); // console.log(uploadResult); assert(uploadResult.data.file_id); assert.equal(uploadResult.responseHttpStatus, 200);