Skip to content

Commit

Permalink
fix #3, #4, comments and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
TheNorthMemory committed Jun 13, 2020
1 parent be01cf5 commit b84c95a
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 4 deletions.
21 changes: 18 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@

`$ npm install wechatpay-axios-plugin`

## Requirements

`Rsa.encrypt` and `Rsa.decrypt` with `oaepHash` was added on Node v12.9.0. So that the Node minimum version should be 12.9.0(I'm not very sure).

## Examples

### Initialization
Expand Down Expand Up @@ -54,6 +58,17 @@ client.post('/v3/combine-transactions/jsapi', {}).then(response => {
})
```

#### POST `/v3/smartguide/guides/{guide_id}/assign` mixed `RESTful` parameter with `JSON` body payload, response as `204` status code.

```js
client.post(`/v3/smartguide/guides/${guide_id}/assign`, {
sub_mchid,
out_trade_no,
}).catch(error => {
console.error(error)
})
```

### Async/Await style

#### GET `/v3/merchant-service/complaints` with `query` parameters
Expand All @@ -71,7 +86,7 @@ client.post('/v3/combine-transactions/jsapi', {}).then(response => {
})
console.info(res.data)
} catch (error) {
console.info(error)
console.error(error)
}
})()
```
Expand All @@ -96,7 +111,7 @@ client.post('/v3/combine-transactions/jsapi', {}).then(response => {
})
console.info(res.data.code_url)
} catch (error) {
console.info(error)
console.error(error)
}
})()
```
Expand Down Expand Up @@ -139,7 +154,7 @@ client.post('/v3/combine-transactions/jsapi', {}).then(response => {
})
console.info(res.data)
} catch (error) {
console.info(error)
console.error(error)
}
})()
```
Expand Down
23 changes: 23 additions & 0 deletions lib/aes.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,21 @@ const base64 = `base64`
const BLOCK_SIZES = 16
const algorithm = `aes-256-gcm`

/**
* Aes encrypt/decrypt using `aes-256-gcm` algorithm with `AAD`.
*/
class Aes {

/**
* Encrypts plaintext.
*
* @param {string} iv - The initialization vector, 16 bytes string.
* @param {string} key - The secret key, 32 bytes string.
* @param {string} plaintext - Text to encode.
* @param {string} aad - The additional authenticated data, maybe empty string.
*
* @returns {object}
*/
static encrypt(iv, key, plaintext, aad = '') {
const cipher = crypto.createCipheriv(
algorithm, key, iv
Expand All @@ -21,6 +34,16 @@ class Aes {
]).toString(base64)
}

/**
* Decrypts ciphertext.
*
* @param {string} iv - The initialization vector, 16 bytes string.
* @param {string} key - The secret key, 32 bytes string.
* @param {string} ciphertext - Base64-encoded ciphertext.
* @param {string} aad - The additional authenticated data, maybe empty string.
*
* @returns {string}
*/
static decrypt(iv, key, ciphertext, aad = '') {
const buf = Buffer.from(ciphertext, base64)
const tag = buf.slice(-BLOCK_SIZES)
Expand Down
47 changes: 46 additions & 1 deletion lib/formatter.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,69 @@

/**
* Provides easy used methods using in this project.
*/
class Formatter {

/**
* Generate a random string aka `nonce`, similar as `crypto.randomBytes`.
*
* @param {number} size - Nonce string length, default is 32 bytes.
*
* @returns {string}
*/
static nonce(size = 32) {
const chars = `0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`

return `0`.repeat(size).replace(/0/g, _ => chars[Math.random()*62|0])
}

/**
* Retrieve the current `Unix` timestamp.
*
* @returns {number}
*/
static timestamp() {
return +(new Date)/1000|0
}

/**
* Formatting for the heading `Authorization` value.
*
* @param {string} mchid - The merchant ID.
* @param {string} nonce_str - The Nonce string.
* @param {string} signature - The base64-encoded `Rsa.sign` ciphertext.
* @param {string} timestamp - The `Unix` timestamp.
* @param {string} serial_no - The serial number of the merchant public certification.
*
* @returns {string}
*/
static authorization(mchid, nonce_str, signature, timestamp, serial_no) {
return `WECHATPAY2-SHA256-RSA2048 mchid="${mchid}",nonce_str="${nonce_str}",signature="${signature}",timestamp="${timestamp}",serial_no="${serial_no}"`
}

/**
* Formatting this `HTTP.request` for `Rsa.sign` input.
*
* @param {string} method - The merchant ID.
* @param {string} uri - Combined string with `URL.pathname` and `URL.search`.
* @param {string} timestamp - The `Unix` timestamp, should be the one used in `authorization`.
* @param {string} nonce - The `Nonce` string, should be the one used in `authorization`.
* @param {string} body - The playload string, HTTP `GET` should be an empty string.
*
* @returns {string}
*/
static request(method, uri, timestamp, nonce, body = '') {
return `${method}\n${uri}\n${timestamp}\n${nonce}\n${body}\n`
}

/**
* Formatting this `HTTP.response` for `Rsa.verify` input.
*
* @param {string} timestamp - The `Unix` timestamp, should be the one from `response.headers[wechatpay-timestamp]`.
* @param {string} nonce - The `Nonce` string, should be the one from `response.headers[wechatpay-nonce]`.
* @param {string} body - The response payload string, HTTP status(`204`) should be an empty string.
*
* @returns {string}
*/
static response(timestamp, nonce, body = '') {
return `${timestamp}\n${nonce}\n${body}\n`
}
Expand Down
38 changes: 38 additions & 0 deletions lib/rsa.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,20 @@ const base64 = `base64`
const sha256WithRSAEncryption = `sha256WithRSAEncryption`
const RSA_PKCS1_OAEP_PADDING = crypto.constants.RSA_PKCS1_OAEP_PADDING

/**
* Provides some methods for the RSA `sha256WithRSAEncryption` with `RSA_PKCS1_OAEP_PADDING`.
*/
class Rsa {

/**
* Encrypts text with sha256WithRSAEncryption/RSA_PKCS1_OAEP_PADDING.
* Node Limits >= 12.9.0 (`oaepHash` was added)
*
* @param {string} plaintext - Cleartext to encode.
* @param {string|Buffer} publicCertificate - A PEM encoded public certification.
*
* @returns {string}
*/
static encrypt(plaintext, publicCertificate) {
return crypto.publicEncrypt({
oaepHash : sha1,
Expand All @@ -17,6 +29,15 @@ class Rsa {
}, Buffer.from(plaintext, utf8)).toString(base64)
}

/**
* Decrypts base64 encoded string with `privateKeyCertificate`.
* Node Limits >= 12.9.0 (`oaepHash` was added)
*
* @param {string} ciphertext - Was previously encrypted string using the corresponding public certication.
* @param {string|Buffer} privateKeyCertificate - A PEM encoded private key certification.
*
* @returns {string}
*/
static decrypt(ciphertext, privateKeyCertificate) {
return crypto.privateDecrypt({
oaepHash : sha1,
Expand All @@ -25,6 +46,14 @@ class Rsa {
}, Buffer.from(ciphertext, base64)).toString(utf8)
}

/**
* Creates and returns a `Sign` string that uses `sha256WithRSAEncryption`.
*
* @param {string} message - Content will be `crypto.Sign`.
* @param {string|Buffer} privateKeyCertificate - A PEM encoded private key certification.
*
* @returns {string}
*/
static sign(message, privateKeyCertificate) {
return crypto.createSign(
sha256WithRSAEncryption
Expand All @@ -34,6 +63,15 @@ class Rsa {
)
}

/**
* Verifying the `message` with given `signature` string that uses `sha256WithRSAEncryption`.
*
* @param {string} message - Content will be `crypto.Verify`.
* @param {string} signature - The base64-encoded ciphertext.
* @param {string|Buffer} publicCertificate - A PEM encoded public certification.
*
* @returns {string}
*/
static verify(message, signature, publicCertificate) {
return crypto.createVerify(
sha256WithRSAEncryption
Expand Down

0 comments on commit b84c95a

Please sign in to comment.