2025-04-10 15:01:55 +08:00
|
|
|
|
import {sm4} from 'sm-crypto'
|
|
|
|
|
|
import {cmdIds, Result, subCmdIds} from '../constant'
|
|
|
|
|
|
import {searchAndConnectDevice, writeBLECharacteristicValue} from '../uni/basic'
|
2025-04-15 15:21:17 +08:00
|
|
|
|
import {createPackageEnd, md5Encrypt, timestampToArray,checkRequiredFields} from '../format'
|
2025-04-10 15:01:55 +08:00
|
|
|
|
import {checkPasswordRequest, getOfflinePasswordRequest} from '../api'
|
2025-04-07 11:19:18 +08:00
|
|
|
|
import {getConfig} from "../common.js";
|
|
|
|
|
|
import StarCloud from "../star-cloud.js";
|
2025-04-15 15:21:17 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 离线密码
|
|
|
|
|
|
* 该功能无需蓝牙交互直接请求服务端,详细参数说明请看星云接口文档
|
|
|
|
|
|
* @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
|
2024-12-20 17:36:14 +08:00
|
|
|
|
* @param {Number} [params.uid] 用户ID
|
2024-12-19 16:01:45 +08:00
|
|
|
|
* @param {OfflinePassword} params.password 密码信息
|
|
|
|
|
|
* @returns {Promise<Result>}
|
|
|
|
|
|
*/
|
|
|
|
|
|
export async function getOfflinePassword(params) {
|
2025-04-10 15:01:55 +08:00
|
|
|
|
const {password} = params
|
|
|
|
|
|
// 设置执行账号
|
|
|
|
|
|
const result = await this.login(params.uid)
|
|
|
|
|
|
if (result.code !== Result.Success.code) {
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
return await getOfflinePasswordRequest(password)
|
2024-12-19 16:01:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 自定义密码
|
|
|
|
|
|
* @param params
|
2024-12-20 17:36:14 +08:00
|
|
|
|
* @param {Number} [params.uid] 用户ID
|
2024-12-19 16:01:45 +08:00
|
|
|
|
* @param {CustomPassword} params.password 密码信息
|
2024-12-20 17:36:14 +08:00
|
|
|
|
* @param {Boolean} [params.disconnect] 操作后是否断开连接,默认断开
|
2024-12-19 16:01:45 +08:00
|
|
|
|
* @returns {Promise<Result>}
|
|
|
|
|
|
*/
|
|
|
|
|
|
export async function customPassword(params) {
|
2025-04-10 15:01:55 +08:00
|
|
|
|
const baseRequiredFields = [
|
|
|
|
|
|
'keyboardPwdName',
|
|
|
|
|
|
'keyboardPwdType',
|
|
|
|
|
|
'keyboardPwd',
|
|
|
|
|
|
'addType',
|
|
|
|
|
|
'isCoerced',
|
|
|
|
|
|
'startDate',
|
|
|
|
|
|
'endDate',
|
|
|
|
|
|
'operate',
|
|
|
|
|
|
'pwdRight',
|
|
|
|
|
|
'lockId'
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
// 根据operate值动态添加必填字段
|
|
|
|
|
|
let cardRequiredFields = [...baseRequiredFields];
|
|
|
|
|
|
if (params.password && (params.password.operate === 1 || params.password.operate === 2)) {
|
|
|
|
|
|
cardRequiredFields.push('pwdNo', 'keyboardPwdId');
|
2024-12-19 16:01:45 +08:00
|
|
|
|
}
|
2025-04-10 15:01:55 +08:00
|
|
|
|
|
|
|
|
|
|
const missingField = checkRequiredFields(params.password, cardRequiredFields);
|
|
|
|
|
|
if (missingField) {
|
2025-04-15 15:21:17 +08:00
|
|
|
|
return new Result(Result.codes.NotMoreData, null, `参数信息不完整: ${missingField}`);
|
2024-12-19 16:01:45 +08:00
|
|
|
|
}
|
2025-04-10 15:01:55 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const {password} = params
|
|
|
|
|
|
// 设置执行账号
|
|
|
|
|
|
const result = await this.login(params.uid)
|
|
|
|
|
|
if (result.code !== Result.Success.code) {
|
|
|
|
|
|
return result
|
2024-12-19 16:01:45 +08:00
|
|
|
|
}
|
2025-04-10 15:01:55 +08:00
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
}
|
2024-12-19 16:01:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
// 确认设备连接正常
|
|
|
|
|
|
if (!params.connected) {
|
|
|
|
|
|
const searchResult = await searchAndConnectDevice(this.lockInfo.bluetooth.bluetoothDeviceName)
|
|
|
|
|
|
if (searchResult.code !== Result.Success.code) {
|
|
|
|
|
|
return searchResult
|
|
|
|
|
|
}
|
|
|
|
|
|
this.updateLockInfo(searchResult.data)
|
2024-12-19 16:01:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
// 检查是否已添加为用户
|
|
|
|
|
|
const checkResult = await this.checkLockUser()
|
|
|
|
|
|
if (checkResult.code !== Result.Success.code) {
|
|
|
|
|
|
return checkResult
|
|
|
|
|
|
}
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
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()
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
if (!pwdNo) {
|
|
|
|
|
|
pwdNo = 0
|
|
|
|
|
|
}
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
const length = 2 + 1 + 1 + 40 + 20 + 2 + 1 + 1 + 20 + 2 + 4 + 4 + 4 + 1 + 16
|
|
|
|
|
|
const headArray = this.createPackageHeader(3, length)
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
const contentArray = new Uint8Array(length)
|
|
|
|
|
|
contentArray[0] = cmdIds.expandCmd / 256
|
|
|
|
|
|
contentArray[1] = cmdIds.expandCmd % 256
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
// 子命令
|
|
|
|
|
|
contentArray[2] = subCmdIds.setLockPassword
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
contentArray[3] = length - 3
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
for (let i = 0; i < keyId.length; i++) {
|
|
|
|
|
|
contentArray[i + 4] = keyId.charCodeAt(i)
|
|
|
|
|
|
}
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
for (let i = 0; i < uid.length; i++) {
|
|
|
|
|
|
contentArray[i + 44] = uid.charCodeAt(i)
|
|
|
|
|
|
}
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
contentArray[64] = pwdNo / 256
|
|
|
|
|
|
contentArray[65] = pwdNo % 256
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
contentArray[66] = operate
|
|
|
|
|
|
contentArray[67] = isAdmin
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
for (let i = 0; i < keyboardPwd.length; i++) {
|
|
|
|
|
|
contentArray[i + 68] = keyboardPwd.charCodeAt(i)
|
|
|
|
|
|
}
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
contentArray[88] = userCountLimit / 256
|
|
|
|
|
|
contentArray[89] = userCountLimit % 256
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
contentArray.set(this.lockInfo.token || new Uint8Array([0, 0, 0, 0]), 90)
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
contentArray.set(timestampToArray(startDate), 94)
|
|
|
|
|
|
contentArray.set(timestampToArray(endDate), 98)
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
contentArray[102] = 16
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
const md5Array = md5Encrypt(
|
|
|
|
|
|
keyId + uid,
|
|
|
|
|
|
this.lockInfo.token || new Uint8Array([0, 0, 0, 0]),
|
|
|
|
|
|
this.lockInfo.bluetooth.signKey
|
|
|
|
|
|
)
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
contentArray.set(md5Array, 103)
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
const cebArray = sm4.encrypt(contentArray, this.lockInfo.bluetooth.privateKey, {
|
|
|
|
|
|
mode: 'ecb',
|
|
|
|
|
|
output: 'array'
|
|
|
|
|
|
})
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
const packageArray = createPackageEnd(headArray, cebArray)
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
const writeResult = await writeBLECharacteristicValue(
|
|
|
|
|
|
this.lockInfo.deviceId,
|
|
|
|
|
|
this.lockInfo.serviceId,
|
|
|
|
|
|
this.lockInfo.writeCharacteristicId,
|
|
|
|
|
|
packageArray
|
|
|
|
|
|
)
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
if (writeResult.code !== Result.Success.code) {
|
|
|
|
|
|
return writeResult
|
|
|
|
|
|
}
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
return this.getWriteResult(this.customPassword, params)
|
2024-12-19 16:01:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 修改管理员密码
|
|
|
|
|
|
* @param params
|
2024-12-20 17:36:14 +08:00
|
|
|
|
* @param {Number} [params.uid] 用户ID
|
2024-12-19 16:01:45 +08:00
|
|
|
|
* @param {String} params.adminPwd 管理员密码
|
2024-12-20 17:36:14 +08:00
|
|
|
|
* @param {Boolean} [params.disconnect] 操作后是否断开连接,默认断开
|
2024-12-19 16:01:45 +08:00
|
|
|
|
* @returns {Promise<Result>}
|
|
|
|
|
|
*/
|
|
|
|
|
|
export async function updateAdminPassword(params) {
|
2025-04-10 15:01:55 +08:00
|
|
|
|
// 需要校验的参数
|
|
|
|
|
|
const baseRequiredFields = [
|
|
|
|
|
|
'adminPwd',
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
// 根据operate值动态添加必填字段
|
|
|
|
|
|
let cardRequiredFields = [...baseRequiredFields];
|
|
|
|
|
|
|
|
|
|
|
|
const missingField = checkRequiredFields(params, cardRequiredFields);
|
|
|
|
|
|
if (missingField) {
|
|
|
|
|
|
return new Result(Result.NotMoreData, null, `参数信息不完整: ${missingField}`);
|
2024-12-19 16:01:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
const {adminPwd} = params
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
// 设置执行账号
|
|
|
|
|
|
const result = await this.login(params.uid)
|
|
|
|
|
|
if (result.code !== Result.Success.code) {
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
// 确认设备连接正常
|
|
|
|
|
|
if (!params.connected) {
|
|
|
|
|
|
const searchResult = await searchAndConnectDevice(this.lockInfo.bluetooth.bluetoothDeviceName)
|
|
|
|
|
|
if (searchResult.code !== Result.Success.code) {
|
|
|
|
|
|
return searchResult
|
|
|
|
|
|
}
|
|
|
|
|
|
this.updateLockInfo(searchResult.data)
|
|
|
|
|
|
}
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
// 检查是否已添加为用户
|
|
|
|
|
|
const checkResult = await this.checkLockUser()
|
|
|
|
|
|
if (checkResult.code !== Result.Success.code) {
|
|
|
|
|
|
return checkResult
|
|
|
|
|
|
}
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
this.requestParams = params
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
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)
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
const length = 2 + 1 + 1 + 40 + 20 + 2 + 20 + 2 + 4 + 4 + 4 + 1 + 16
|
|
|
|
|
|
const headArray = this.createPackageHeader(3, length)
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
const contentArray = new Uint8Array(length)
|
|
|
|
|
|
contentArray[0] = cmdIds.expandCmd / 256
|
|
|
|
|
|
contentArray[1] = cmdIds.expandCmd % 256
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
// 子命令
|
|
|
|
|
|
contentArray[2] = subCmdIds.updateAdminPassword
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
contentArray[3] = length - 3
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
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)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (StarCloud.env !== null &&
|
|
|
|
|
|
StarCloud.env !== undefined &&
|
|
|
|
|
|
StarCloud.env !== '' &&
|
|
|
|
|
|
StarCloud.env === 'SKY') {
|
|
|
|
|
|
contentArray[64] = Math.floor(pwdNo / 256) & 0xFF // 确保高字节为 0x00
|
|
|
|
|
|
contentArray[65] = pwdNo & 0xFF
|
|
|
|
|
|
} else {
|
|
|
|
|
|
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)
|
2024-12-19 16:01:45 +08:00
|
|
|
|
|
2025-04-10 15:01:55 +08:00
|
|
|
|
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)
|
2024-12-19 16:01:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查密码名称与密码是否已存在
|
|
|
|
|
|
export async function checkPassword(params) {
|
2025-04-10 15:01:55 +08:00
|
|
|
|
const {info} = params
|
|
|
|
|
|
// 设置执行账号
|
|
|
|
|
|
const result = await this.login(params.uid)
|
|
|
|
|
|
if (result.code !== Result.Success.code) {
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
return await checkPasswordRequest(info)
|
2024-12-19 16:01:45 +08:00
|
|
|
|
}
|