使用 TypeScript 開發 Node.js 的微信開放平臺/企業微信/釘釘開放平臺消息 AES 加密解密庫而且發佈

首先附上連接:https://github.com/ecfexorg/w...node

因爲工做緣由,前後進行過微信開放平臺,企業微信,阿里釘釘的第三方開發。在這個過程當中都會有解密服務器推送來的消息的需求,並且通過這幾回開發後,發現微信開放平臺/企業微信/阿里釘釘的加密解密算法都是使用的 AES256,同時加密的消息體結構也是同樣的。git

同時因爲找到的第三方包的代碼要麼提供的功能太多,要麼用了過期的 api,對於強迫症的我來講很難忍受,因此本身造了一個輪子來解決這三方的消息加密解密的需求。github

使用的是 TypeScript 編寫的,編譯生成聲明文件,用 vscode 開發能有良好的代碼提示(不過這麼簡單的庫貌似也沒啥需求...)算法

下面說下用 TypeScript 開發一個 npm 項目而且發佈到 npm 的構建和開發流程:typescript

1、首先在 github 上建立一個項目,項目名稱最好和想要發佈的 npm 包名一致,建立時能夠選擇是否生成 README 和證書,這裏我就選擇了 MIT 證書和默認的 README。npm

2、而後在本地使用git clone命令將項目克隆下來,而後cd wx-ding-aes,再執行npm init,由於目錄中包含了.git文件夾,因此 npm 初始化時能夠自動填入 github 地址,文檔地址等 package 屬性。json

咱們給生成的 package.json 文件的scripts增長一條"build": "tsc",因而呆會兒執行npm run build就能編譯咱們的代碼了。api

同時爲了讓別人使用咱們的庫時也能有良好的代碼提示,因此咱們編譯時生成聲明文件在types文件夾下,發佈時要連聲明文件一塊兒提交,同時還要在 package.json 中增長一個屬性"types": "types/index.d.ts",意思是告訴別人這個庫是自帶聲明文件的,而且聲明文件的入口是在types目錄下的index.d.ts裏,固然若是你的"main"的值不是index.js,那麼"types"也要改變,讓它能和"main"對上號。服務器

3、初始化完成後,執行npm i typescript @types/node -D安裝 TypeScript 和 Node.js 標準庫的聲明文件。而後在touch tsconfig.json建立 TypeScript 的配置文件,在 vscode 中編寫 TypeScript 的配置文件會有屬性名和屬性值提示。微信

{
  "compilerOptions": {
    "target": "es2017",
    "outDir": "dist",
    "module": "commonjs",
    "declaration": true,
    "declarationDir": "types"
  },
  "include": [
    "src"
  ]
}

這裏個人配置很簡單,"target": "es2017"表示編譯目標的 JS 版本是 es2017;"outDir": "dist"表示編譯後的 JS 文件放在dist文件夾中;"module": "commonjs"表示編譯後的 JS 仍是使用 commonjs 的模塊系統;"declaration": true"declarationDir": "types"表示編譯時會自動生成聲明文件,而且聲明文件放在types目錄下。"include": [ "src" ] 表示 src 目錄裏面的文件會被編譯。

注:Node.js 從 8.5 版本開始已經開始支持 es 模塊系統,不過寫這篇文章時還處於實驗階段,須要加上--experimental-modules參數才能使用

4、準備工做作完,而後能夠開始寫代碼了,我把全部的代碼都放在src目錄下,寫完後npm run build就能看到自動生成的dist文件夾裏裝着編譯後的 JS 文件,而types文件夾則裝着自動生成的聲明文件。

關於微信的加密解密邏輯,其使用的是標準的 aes-256 加密算法的 cbc 模式,算法是能夠實現的,不過 node.js 的標準庫提供的crypto模塊已經有了,因此咱們就不須要重複造輪子(有人看到這個名詞確定會立刻跑去 npmjs.org 搜 aes256,可是我以爲一個項目的依賴應該越少越好,畢竟別人寫的東西質量可維護性都不可控)。aes-256 加密時,被加密的內容長度應該是 32 字節的倍數,若是不是 32 的倍數則須要進行補全。補全有不少種方式,最簡單的是用 0x00 補全,可是微信要求用 pkcs7 進行補全,因此這裏咱們也用這種方式(有人看到確定又會跑去 npmjs.org 搜 pkcs7 了...)。

簡單幾句話就能歸納這種補全方式:

假設被加密的內容長度爲 x

  1. 若是 x 不是 32 的倍數,能夠獲得比 x 大的最小的 32 的整數是 y,加密時在被加密內容後面加上 y - x 個 y - x
  2. 若是 x 是 32 的倍數,那麼在被加密內容後面加上 32 個 32

兩個例子:

  1. 被加密的 buffer 長度爲 53 ,比 53 大的、最小的 32 的倍數的證書應該是 64 ,64 - 53 = 9,那麼這個 buffer 後面就加上 9 個 9 使他的長度變成 64 ;
  2. 被加密的 buffer 長度爲 64 ,那麼直接加上 32 個 32 ,使他的長度變成 96 。

這樣作的目的是方便解密後截取原來的數據,解密後,只要看看最後一個數是多少(假設是 x ),那麼就把最後的 x 個 byte 截掉就能獲得前面被補全以前的數據了。上面的兩個例子中,第一個只要看到最後一個數是 9 ,那就把最後 9 個 byte 去掉,前面的就是正確的內容,第二個例子之因此補 32 個 32 ,也是由於看到最後一個數是 32 ,那就把後面的 32 個 byte 截掉便可。假如由於已是 32 的倍數就不補全,那麼就不知道是補全了的仍是沒補全過的了。

代碼就不一一解釋,由於原理就在上面了。

5、寫完後npm run build就能編譯了,若是想發佈到 npmjs.org ,首先並非整個項目裏的全部文件都要被髮布的,發佈到 npm 的話應該在package.json"files"屬性裏選擇哪些是想上傳的,好比這個項目我之上傳生成的 JS 和聲明文件以及證書,由於源碼是不必上傳的。

若是沒有 npm 賬號的話,那麼就要先註冊一個 npm 的賬號,而後在終端裏執行npm login登錄你的賬號。而後運行npm publish便可發佈,若是你擔憂有時忘了編譯就執行了publish,能夠在"scripts"裏面增長"prepublish": "npm run build",表示每次發佈以前都會先自動執行編譯腳本。更多的鉤子命令能夠在 npmjs.org 的官方文檔查看。

6、
目前 npm 發佈的包是沒法使用npm unpublish <package name>來進行下架了,只能經過npm deprecate來標記過期,因此建議你們除非肯定本身有能力和精力去維護一個包,不然不要輕易發佈一些亂七八糟的包,更不要去佔一些本身沒有能力維護的好的包名。若是實在想unpublish,能夠郵件聯繫 support@npmjs.com 說明緣由,他們會根據描述來進行處理。根據個人經驗,因爲時差,通常白天發郵件他們會深夜回覆,而後你次日會收到回覆。

但願對你們有幫助 :P

相關文章
相關標籤/搜索