Skip to content
代码片段 群组 项目
validation.js 6.1 KB
更新 更旧
  • 了解如何忽略特定修订
  • /**
     *
     *    Copyright (c) 2020 Silicon Labs
     *
     *    Licensed under the Apache License, Version 2.0 (the "License");
     *    you may not use this file except in compliance with the License.
     *    You may obtain a copy of the License at
     *
     *        http://www.apache.org/licenses/LICENSE-2.0
     *
     *    Unless required by applicable law or agreed to in writing, software
     *    distributed under the License is distributed on an "AS IS" BASIS,
     *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     *    See the License for the specific language governing permissions and
     *    limitations under the License.
     */
    
    Timotej Ecimovic's avatar
    Timotej Ecimovic 已提交
    
    
    /**
     * This module provides the APIs for validating inputs to the database, and returning flags indicating if
     * things were successful or not.
     *
    
    Timotej Ecimovic's avatar
    Timotej Ecimovic 已提交
     */
    
    
    const queryZcl = require('../db/query-zcl.js')
    
    const queryConfig = require('../db/query-config.js')
    
    Timotej Ecimovic's avatar
    Timotej Ecimovic 已提交
    const queryEndpoint = require('../db/query-endpoint.js')
    
    const types = require('../util/types.js')
    
    async function validateAttribute(db, endpointTypeId, attributeRef, clusterRef) {
      let endpointAttribute = await queryZcl.selectEndpointTypeAttribute(
        db,
        endpointTypeId,
        attributeRef,
        clusterRef
      )
      let attribute = await queryZcl.selectAttributeById(db, attributeRef)
    
      return validateSpecificAttribute(endpointAttribute, attribute)
    
    Timotej Ecimovic's avatar
    Timotej Ecimovic 已提交
    }
    
    
    Timotej Ecimovic's avatar
    Timotej Ecimovic 已提交
    async function validateEndpoint(db, endpointId) {
    
    Timotej Ecimovic's avatar
    Timotej Ecimovic 已提交
      let endpoint = await queryEndpoint.selectEndpoint(db, endpointId)
    
    Timotej Ecimovic's avatar
    Timotej Ecimovic 已提交
      let currentIssues = validateSpecificEndpoint(endpoint)
      let noDuplicates = await validateNoDuplicateEndpoints(
        db,
        endpoint.endpointId,
        endpoint.sessionRef
      )
      if (!noDuplicates) {
        currentIssues.endpointId.push('Duplicate EndpointIds Exist')
      }
      return currentIssues
    
    Timotej Ecimovic's avatar
    Timotej Ecimovic 已提交
    async function validateNoDuplicateEndpoints(
      db,
      endpointIdentifier,
      sessionRef
    ) {
    
      let count =
        await queryConfig.selectCountOfEndpointsWithGivenEndpointIdentifier(
          db,
          endpointIdentifier,
          sessionRef
        )
    
    Timotej Ecimovic's avatar
    Timotej Ecimovic 已提交
      return count.length <= 1
    
    function validateSpecificAttribute(endpointAttribute, attribute) {
    
      if (!types.isString(attribute.type)) {
        if (types.isFloat(attribute.type)) {
    
          if (!isValidFloat(endpointAttribute.defaultValue))
            defaultAttributeIssues.push('Invalid Float')
          //Interpreting float values
          if (!checkAttributeBoundsFloat(attribute, endpointAttribute))
            defaultAttributeIssues.push('Out of range')
    
        } else if (types.isSignedInteger(attribute.type)) {
          if (!isValidSignedNumberString(endpointAttribute.defaultValue))
            defaultAttributeIssues.push('Invalid Integer')
          if (!checkAttributeBoundsInteger(attribute, endpointAttribute))
            defaultAttributeIssues.push('Out of range')
    
        } else {
          if (!isValidNumberString(endpointAttribute.defaultValue))
            defaultAttributeIssues.push('Invalid Integer')
          if (!checkAttributeBoundsInteger(attribute, endpointAttribute))
            defaultAttributeIssues.push('Out of range')
        }
      }
      return { defaultValue: defaultAttributeIssues }
    }
    
    
    function validateSpecificEndpoint(endpoint) {
    
      let zclEndpointIdIssues = []
      let zclNetworkIdIssues = []
    
      if (!isValidNumberString(endpoint.endpointId))
        zclEndpointIdIssues.push('EndpointId is invalid number string')
      if (
        extractIntegerValue(endpoint.endpointId) > 0xffff ||
        extractIntegerValue(endpoint.endpointId) < 0
      )
        zclEndpointIdIssues.push('EndpointId is out of valid range')
      if (!isValidNumberString(endpoint.networkId))
        zclNetworkIdIssues.push('NetworkId is invalid number string')
      if (extractIntegerValue(endpoint.endpointId) == 0)
        zclEndpointIdIssues.push('0 is not a valid endpointId')
      return {
        endpointId: zclEndpointIdIssues,
        networkId: zclNetworkIdIssues,
      }
    }
    
    
    //This applies to both actual numbers as well as octet strings.
    
    function isValidNumberString(value) {
    
      //We test to see if the number is valid in hex. Decimals numbers also pass this test
    
      return /^(0x)?[\dA-F]+$/i.test(value) || Number.isInteger(Number(value));
    
    Timotej Ecimovic's avatar
    Timotej Ecimovic 已提交
    }
    
    
    function isValidFloat(value) {
    
      return !/^0x/i.test(value) && !isNaN(Number(value));
    
    Timotej Ecimovic's avatar
    Timotej Ecimovic 已提交
    }
    
    function extractFloatValue(value) {
    
      return parseFloat(value)
    
    Timotej Ecimovic's avatar
    Timotej Ecimovic 已提交
    }
    
    
    function extractIntegerValue(value) {
    
      if (/^-?\d+$/.test(value)) {
    
        return parseInt(value)
    
      } else if (/^[0-9A-F]+$/i.test(value)) {
    
        return parseInt(value, 16)
      } else {
        return parseInt(value, 16)
      }
    
    Timotej Ecimovic's avatar
    Timotej Ecimovic 已提交
    }
    
    
    function getBoundsInteger(attribute) {
    
      return {
        min: extractIntegerValue(attribute.min),
        max: extractIntegerValue(attribute.max),
      }
    
    Timotej Ecimovic's avatar
    Timotej Ecimovic 已提交
    }
    
    
    function checkAttributeBoundsInteger(attribute, endpointAttribute) {
    
      let { min, max } = getBoundsInteger(attribute)
      let defaultValue = extractIntegerValue(endpointAttribute.defaultValue)
    
      return checkBoundsInteger(defaultValue, min, max)
    }
    
    Timotej Ecimovic's avatar
    Timotej Ecimovic 已提交
    
    
    function checkBoundsInteger(defaultValue, min, max) {
    
      if (Number.isNaN(min)) min = Number.MIN_SAFE_INTEGER
      if (Number.isNaN(max)) max = Number.MAX_SAFE_INTEGER
      return defaultValue >= min && defaultValue <= max
    
    Timotej Ecimovic's avatar
    Timotej Ecimovic 已提交
    }
    
    
    function checkAttributeBoundsFloat(attribute, endpointAttribute) {
    
      let { min, max } = getBoundsFloat(attribute)
      let defaultValue = extractFloatValue(endpointAttribute.defaultValue)
    
      return checkBoundsFloat(defaultValue, min, max)
    }
    
    
    function getBoundsFloat(attribute) {
    
      return {
        min: extractFloatValue(attribute.min),
        max: extractFloatValue(attribute.max),
      }
    }
    
    
    function checkBoundsFloat(defaultValue, min, max) {
    
      if (Number.isNaN(min)) min = Number.MIN_VALUE
      if (Number.isNaN(max)) max = Number.MAX_VALUE
      return defaultValue >= min && defaultValue <= max
    }
    
    
    // exports
    exports.validateAttribute = validateAttribute
    exports.validateEndpoint = validateEndpoint
    
    exports.validateNoDuplicateEndpoints = validateNoDuplicateEndpoints
    
    exports.validateSpecificAttribute = validateSpecificAttribute
    exports.validateSpecificEndpoint = validateSpecificEndpoint
    exports.isValidNumberString = isValidNumberString
    exports.isValidFloat = isValidFloat
    exports.extractFloatValue = extractFloatValue
    exports.extractIntegerValue = extractIntegerValue
    exports.getBoundsInteger = getBoundsInteger
    exports.checkBoundsInteger = checkBoundsInteger
    exports.getBoundsFloat = getBoundsFloat
    exports.checkBoundsFloat = checkBoundsFloat