From e491cdb48129752324c4e3764f99bd9203c56dec Mon Sep 17 00:00:00 2001
From: lgq <1015864684@qq.com>
Date: 星期二, 31 三月 2026 09:48:44 +0800
Subject: [PATCH] 1.新增VF205门禁机代码
---
vf205_access/dxmodules/dxQrRule.js | 215 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 215 insertions(+), 0 deletions(-)
diff --git a/vf205_access/dxmodules/dxQrRule.js b/vf205_access/dxmodules/dxQrRule.js
new file mode 100644
index 0000000..36bc9a8
--- /dev/null
+++ b/vf205_access/dxmodules/dxQrRule.js
@@ -0,0 +1,215 @@
+//build: 20240301
+//寰厜浜岀淮鐮佺爜鍒惰鍒欙紝鍖呮嫭101锛�103 绛�
+//渚濊禆缁勪欢: dxDriver,dxCommon,dxLogger
+import common from './dxCommon.js'
+import base64 from './dxBase64.js'
+import logger from './dxLogger.js'
+let sqliteObj
+
+// 姣旇緝涓や釜瀛楃涓茬殑鍓峃涓瓧绗︽槸鍚︾浉绛�
+function comparePrefix(str1, str2, N) {
+ let substring1 = str1.substring(0, N);
+ let substring2 = str2.substring(0, N);
+ return substring1 === substring2;
+}
+
+
+
+// 101鐮佸�艰В鐮�
+function decode101(str) {
+ if (str.length < 5) {
+ logger.info("鏃犳晥浜岀淮鐮�")
+ throw new Error("code invalid,length too short")
+ }
+ let decodeBuf = base64.decode(str.slice(0, -4))
+ decodeBuf=decodeBuf.substring(4)
+
+ return decodeBuf
+}
+function hexStringToArrayBuffer (hexString) {
+ var byteString = hexString.match(/.{1,2}/g);
+ var byteArray = byteString.map(function (byte) {
+ return parseInt(byte, 16);
+ });
+ var buffer = new Uint8Array(byteArray).buffer;
+ return buffer;
+}
+
+/**
+ * 103鐮佸�艰В鐮�
+ * 1銆乥ase64瑙g爜
+ * 2銆佽В鏋愮粍缁囩紪鍙�
+ * 3銆丷SA瑙e瘑
+ * 4銆佽В鏋愯韩浠界被鍨�
+ * 5銆佽В鏋愭潈闄愭爣璇�
+ * 6銆佽В鏋愮敓鐮佹椂闂�
+ * 7銆佽В鏋愮爜杩囨湡鏃堕棿
+ * 8銆佹牎楠岄�氳鐮佹槸鍚﹁繃鏈�
+ * @param {*} str
+ * @returns
+ */
+function decode103(str) {
+ // FIXME 杩欎釜pubKey鍚庢湡闇�瑕佷粠閰嶇疆涓煡璇�
+ let TLV_T_SIZE = 2, TLV_L_SIZE = 2, offset = 0, code, decryptedData, generationCodeTime, expirationTime
+
+ // 1銆乥ase64瑙g爜
+ let decodeBuf = base64.toHexString(str)
+ decodeBuf= hexStringToArrayBuffer(decodeBuf)
+ let view = new Uint8Array(decodeBuf)
+ let organizationNumber;
+ // 2銆佽В鏋愮粍缁囩紪鍙�
+ if (view[offset] == 0x01) {
+ offset += TLV_T_SIZE
+ let orgNumLen = view[offset]
+ offset += TLV_L_SIZE
+ let orgNumBuf = new Uint8Array(decodeBuf, offset, orgNumLen);
+ organizationNumber = String.fromCharCode.apply(null, new Uint8Array(orgNumBuf));
+ logger.info("缁勭粐缂栧彿: " + organizationNumber)
+ offset += orgNumLen
+ } else {
+ throw new Error("code invalid,organization number error")
+ }
+
+ // 3銆丷SA瑙e瘑
+ if (view[offset] == 0x02) {
+ // 缁勭粐缂栧彿鏁版嵁闀垮害
+ offset += TLV_T_SIZE
+ let cipherTextLen = view[offset]
+ offset += TLV_L_SIZE
+ // 瀵瑰瘑鏂囪繘琛孯SA瑙e瘑
+ let encryptedData = decodeBuf.slice(offset, offset + cipherTextLen)
+
+
+ // TODO 绉橀挜鍐欐锛屽悗缁渶瑕佹毚闇插嚭鏉�
+ // RSA 鏌ヨ瀵嗛挜(涔熷彲浠ュ浐瀹氾紝涔熷彲浠ュ啓鍦ㄦ枃鏈腑)锛屾牴鎹瘑閽ュ啀娆¤В瀵�
+ // RSA瑙e瘑鍚庣殑鏁版嵁
+ let arr = sqliteObj.securityFindAllByCodeAndTypeAndTimeAndkey(undefined, undefined, undefined, Math.floor(Date.parse(new Date()) / 1000), organizationNumber)
+ if (arr && arr.length > 0) {
+ for (let data of arr) {
+ decryptedData = common.arrayBufferRsaDecrypt(encryptedData, data.value)
+ if (decryptedData != null) {
+ break
+ }
+ }
+ }
+ if (!arr && arr.length <= 0 || decryptedData == null) {
+ return str
+ }
+ }
+ // 涓�涓澶囦竴涓瘑閽ワ紝鐩稿綋浜庤澶囧唴鐢ㄤ簬瑙e瘑鐨勫叕閽ユ槸鍥哄畾鐨勶紝鍙互鎶婂叕閽ユ斁鍒伴厤缃腑锛岃繖閲屽厛榛樿鍐欐
+ // "MTlBODExMDA2MTkwMzQ4Q0I5QUY3QTc4QzAzOTQzNUU5NzNFODAzMEU4QUU1QzBEMkZFOEYwRjEzRjU4M0M5MTU5QUU5MTdDMDIzRDU0RDgxRUY2NTI0NkUyQ0Y2MUMzMTQzNTNENjA2NDU5N0Y2OTY5RUE4QjA5MUY1RTYyODM=";
+ // let buf = common.arrayBufferRsaDecrypt(deData, deData.length)
+ // 0 3 0 3 0 31 30 33 4 0 a 0 31 30 35 34 33 32 33 33 32 33 5 0 4 0 af 8c fa 5a 6 0 1 0 35 7 0 0 0
+ // 0
+ // 3 0 3 0 31 30 33
+ // 4 0 a 0 31 30 35 34 33 32 33 33 32 33
+ // 5 0 4 0 af 8c fa 5a
+ // 6 0 1 0 35
+ // 7 0 0 0
+
+ offset = 1;
+ view = new Uint8Array(decryptedData)
+ // 4銆佽В鏋愯韩浠界被鍨�(type:103)
+ if (view[offset] == 0x03) {
+ // 韬唤绫诲瀷鏁版嵁闀垮害
+ offset += TLV_T_SIZE
+ let identityTypeLength = view[offset]
+ // 韬唤绫诲瀷鏁版嵁
+ offset += TLV_L_SIZE
+ let identityTypeBuf = new Uint8Array(decryptedData, offset, identityTypeLength);
+ let identityType = String.fromCharCode.apply(null, identityTypeBuf);
+ offset += identityTypeLength
+ logger.info("韬唤绫诲瀷鏁版嵁: " + identityType)
+ }
+
+
+ // 5銆佽В鏋愭潈闄愭爣璇�(code)
+ if (view[offset] == 0x04) {
+ // 鏉冮檺鏍囪瘑鏁版嵁闀垮害
+ offset += TLV_T_SIZE
+ let identityCodeLength = view[offset]
+ // 鏉冮檺鏍囪瘑鏁版嵁
+ offset += TLV_L_SIZE
+ let identityCodeBuf = new Uint8Array(decryptedData, offset, identityCodeLength);
+ offset += identityCodeLength
+ code = String.fromCharCode.apply(null, identityCodeBuf);
+ }
+
+
+ // 6銆佽В鏋愮敓鐮佹椂闂�
+ if (view[offset] == 0x05) {
+ // 鐢熺爜鏃堕棿鏁版嵁闀垮害
+ offset += TLV_T_SIZE
+ let createTimeLength = view[offset]
+ // 鐢熺爜鏃堕棿鏁版嵁
+ offset += TLV_L_SIZE
+ let createTimeBuf = new Uint8Array(decryptedData, offset, createTimeLength);
+ offset += createTimeLength
+ generationCodeTime = parseInt(common.arrayBufferToHexString(createTimeBuf.reverse()), 16)
+ }
+
+
+ // 7銆佽В鏋愮爜杩囨湡鏃堕棿
+ if (view[offset] == 0x06) {
+ // 鐮佽繃鏈熸椂闂存暟鎹暱搴�
+ offset += TLV_T_SIZE
+ let expireTimeLength = view[offset]
+ // 鐮佽繃鏈熸椂闂存暟鎹�
+ offset += TLV_L_SIZE
+ let expireTimeBuf = new Uint8Array(decryptedData, offset, expireTimeLength);
+ offset += expireTimeLength
+ expirationTime = parseInt(String.fromCharCode.apply(null, expireTimeBuf))
+ }
+
+ // 8銆佹牎楠岄�氳鐮佹槸鍚﹁繃鏈�
+ let timestamp = Date.now();
+ expirationTime = generationCodeTime + expirationTime
+ if (expirationTime * 1000 > timestamp) {
+ return code
+ } else {
+ return null
+ }
+
+}
+
+const code = {
+ formatCode: function (msg, sqlObj) {
+ if (!msg) {
+ throw new Error("msg should not be null or empty")
+ }
+ if (!sqlObj) {
+ throw new Error("sqlObj should not be null or empty")
+ }
+ if (!sqliteObj) {
+ sqliteObj = sqlObj
+ }
+
+ let data = {}
+ // 鍒ゆ柇鐮佸��
+ if (comparePrefix(msg, "&llgy", "&llgy".length) || comparePrefix(msg, "&v101", "&v101".length)) {
+ // 101鐮佸��
+ data.type = 101
+ data.code = decode101(msg.substring(5))
+ }
+ else if (comparePrefix(msg, "vg://v103", "vg://v103".length)) {
+ // 103鐮佸��
+ data.type = 103
+ data.code = decode103(msg.substring(9)) ? decode103(msg.substring(9)) : msg.substring(9)
+ } else if (comparePrefix(msg, "___VBAR_CONFIG_V1.1.0___", "___VBAR_CONFIG_V1.1.0___".length) || comparePrefix(msg, "___VBAR_KZB_V1.1.0___", "___VBAR_KZB_V1.1.0___".length)) {
+ //TODO 鍏堣繖鏍峰啓锛岃璁哄ソ鍚庢洿鏀规祦杞�昏緫
+ data.type = 'config'
+ data.code = msg
+ } else {
+ data.type = 100
+ data.code = msg
+ }
+ if (data.code) {
+ return data
+ } else {
+ console.log("decode fail")
+ return
+ }
+ }
+}
+
+export default code;
\ No newline at end of file
--
Gitblit v1.9.3