import { sm4 } from 'sm-crypto' import { cmdIds, Result, subCmdIds } from '../constant' import { searchAndConnectDevice, writeBLECharacteristicValue } from '../uni/basic' import { createPackageEnd, md5Encrypt, timestampToArray } from '../format' import { checkPasswordRequest, getOfflinePasswordRequest } from '../api' /** * 离线密码 * 该功能无需蓝牙交互直接请求服务端,详细参数说明请看星云接口文档 * @typedef {Object} OfflinePassword * @property {String} keyboardPwdName - 密码名称 * @property {Number} keyboardPwdType - 密码类型 * @property {Number} lockId - 锁 Id * @property {Number} isCoerced - 胁迫 1:胁迫 2:非胁迫 * @property {Number} startDate - 开始时间 * @property {Number} endDate - 结束时间 * @property {Number} hoursStart - 开始小时 * @property {Number} hoursEnd - 结束小时 */ /** * 自定义密码 * @typedef {Object} CustomPassword * @property {String} keyboardPwdName - 密码名称 * @property {Number} keyboardPwdType - 密码类型 * @property {Number} isCoerced - 胁迫 1:胁迫 2:非胁迫 * @property {Number} startDate - 开始时间 * @property {Number} endDate - 结束时间 * @property {Number} keyboardPwd - 密码 * @property {Number} addType - 添加方式,当前仅支持1 1:蓝牙 2:网关 * @property {Number} operate - 操作类型,0:注册 1:修改 * @property {Number} pwdRight - 是否是管理员密码,0:否 1:是 * @property {Number} keyboardPwdId - 密码ID */ /** * 获取离线密码 * @param params * @param {Number} [params.uid] 用户ID * @param {OfflinePassword} params.password 密码信息 * @returns {Promise} */ export async function getOfflinePassword(params) { const { password } = params // 设置执行账号 const result = await this.login(params.uid) if (result.code !== Result.Success.code) { return result } return await getOfflinePasswordRequest(password) } /** * 自定义密码 * @param params * @param {Number} [params.uid] 用户ID * @param {CustomPassword} params.password 密码信息 * @param {Boolean} [params.disconnect] 操作后是否断开连接,默认断开 * @returns {Promise} */ export async function customPassword(params) { const { password } = params // 设置执行账号 const result = await this.login(params.uid) if (result.code !== Result.Success.code) { return result } this.requestParams = password let { pwdNo, operate, keyboardPwd, startDate, endDate, pwdRight } = password if (operate === 0 || operate === 1) { const checkPasswordParams = { lockId: this.lockInfo.lockId, keyboardPwd } if (password.keyboardPwdId) { checkPasswordParams.keyboardPwdId = password.keyboardPwdId } const checkPasswordResult = await this.checkPassword({ uid:params.uid, info:checkPasswordParams }) if (checkPasswordResult.code === -3) { return Result.ReadyHasPassword } if (checkPasswordResult.code !== Result.Success.code) { return result } } // 确认设备连接正常 if (!params.connected) { const searchResult = await searchAndConnectDevice(this.lockInfo.bluetooth.bluetoothDeviceName) if (searchResult.code !== Result.Success.code) { return searchResult } this.updateLockInfo(searchResult.data) } // 检查是否已添加为用户 const checkResult = await this.checkLockUser() if (checkResult.code !== Result.Success.code) { return checkResult } const uid = this.accountInfo.uid.toString() const keyId = this.lockInfo.keyId.toString() const isAdmin = pwdRight const userCountLimit = 0xffff startDate = Math.floor(startDate / 1000) endDate = Math.floor(endDate / 1000) keyboardPwd = keyboardPwd.toString() if (!pwdNo) { pwdNo = 0 } const length = 2 + 1 + 1 + 40 + 20 + 2 + 1 + 1 + 20 + 2 + 4 + 4 + 4 + 1 + 16 const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.expandCmd / 256 contentArray[1] = cmdIds.expandCmd % 256 // 子命令 contentArray[2] = subCmdIds.setLockPassword contentArray[3] = length - 3 for (let i = 0; i < keyId.length; i++) { contentArray[i + 4] = keyId.charCodeAt(i) } for (let i = 0; i < uid.length; i++) { contentArray[i + 44] = uid.charCodeAt(i) } contentArray[64] = pwdNo / 256 contentArray[65] = pwdNo % 256 contentArray[66] = operate contentArray[67] = isAdmin for (let i = 0; i < keyboardPwd.length; i++) { contentArray[i + 68] = keyboardPwd.charCodeAt(i) } contentArray[88] = userCountLimit / 256 contentArray[89] = userCountLimit % 256 contentArray.set(this.lockInfo.token || new Uint8Array([0, 0, 0, 0]), 90) contentArray.set(timestampToArray(startDate), 94) contentArray.set(timestampToArray(endDate), 98) contentArray[102] = 16 const md5Array = md5Encrypt( keyId + uid, this.lockInfo.token || new Uint8Array([0, 0, 0, 0]), this.lockInfo.bluetooth.signKey ) contentArray.set(md5Array, 103) const cebArray = sm4.encrypt(contentArray, this.lockInfo.bluetooth.privateKey, { mode: 'ecb', output: 'array' }) const packageArray = createPackageEnd(headArray, cebArray) const writeResult = await writeBLECharacteristicValue( this.lockInfo.deviceId, this.lockInfo.serviceId, this.lockInfo.writeCharacteristicId, packageArray ) if (writeResult.code !== Result.Success.code) { return writeResult } return this.getWriteResult(this.customPassword, params) } /** * 修改管理员密码 * @param params * @param {Number} [params.uid] 用户ID * @param {String} params.adminPwd 管理员密码 * @param {Boolean} [params.disconnect] 操作后是否断开连接,默认断开 * @returns {Promise} */ export async function updateAdminPassword(params) { const { adminPwd } = params // 设置执行账号 const result = await this.login(params.uid) if (result.code !== Result.Success.code) { return result } // 确认设备连接正常 if (!params.connected) { const searchResult = await searchAndConnectDevice(this.lockInfo.bluetooth.bluetoothDeviceName) if (searchResult.code !== Result.Success.code) { return searchResult } this.updateLockInfo(searchResult.data) } // 检查是否已添加为用户 const checkResult = await this.checkLockUser() if (checkResult.code !== Result.Success.code) { return checkResult } this.requestParams = params const uid = this.lockInfo.uid.toString() const keyId = this.lockInfo.keyId.toString() const pwdNo = 1 const userCountLimit = 0xff const startDate = Math.floor(this.lockInfo.startDate / 1000) const endDate = Math.floor(this.lockInfo.endDate / 1000) const length = 2 + 1 + 1 + 40 + 20 + 2 + 20 + 2 + 4 + 4 + 4 + 1 + 16 const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.expandCmd / 256 contentArray[1] = cmdIds.expandCmd % 256 // 子命令 contentArray[2] = subCmdIds.updateAdminPassword contentArray[3] = length - 3 for (let i = 0; i < keyId.length; i++) { contentArray[i + 4] = keyId.charCodeAt(i) } for (let i = 0; i < uid.length; i++) { contentArray[i + 44] = uid.charCodeAt(i) } contentArray[64] = pwdNo / 256 contentArray[65] = pwdNo % 256 for (let i = 0; i < adminPwd.length; i++) { contentArray[i + 66] = adminPwd.charCodeAt(i) } contentArray[86] = userCountLimit / 256 contentArray[87] = userCountLimit % 256 contentArray.set(this.lockInfo.token || new Uint8Array([0, 0, 0, 0]), 88) contentArray.set(timestampToArray(startDate), 92) contentArray.set(timestampToArray(endDate), 96) contentArray[100] = 16 const md5Array = md5Encrypt( keyId + uid, this.lockInfo.token || new Uint8Array([0, 0, 0, 0]), this.lockInfo.bluetooth.signKey ) contentArray.set(md5Array, 101) const cebArray = sm4.encrypt(contentArray, this.lockInfo.bluetooth.privateKey, { mode: 'ecb', output: 'array' }) const packageArray = createPackageEnd(headArray, cebArray) const writeResult = await writeBLECharacteristicValue( this.lockInfo.deviceId, this.lockInfo.serviceId, this.lockInfo.writeCharacteristicId, packageArray ) if (writeResult.code !== Result.Success.code) { return writeResult } return this.getWriteResult(this.updateAdminPassword, params) } // 检查密码名称与密码是否已存在 export async function checkPassword(params) { const { info } = params // 设置执行账号 const result = await this.login(params.uid) if (result.code !== Result.Success.code) { return result } return await checkPasswordRequest(info) }