123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432 |
- const {
- isValidString,
- getType
- } = require('./utils.js')
- const {
- ERROR
- } = require('./error')
- const baseValidator = Object.create(null)
- baseValidator.username = function (username) {
- const errCode = ERROR.INVALID_USERNAME
- if (!isValidString(username)) {
- return {
- errCode
- }
- }
- if (/^\d+$/.test(username)) {
- // 用户名不能为纯数字
- return {
- errCode
- }
- };
- if (!/^[a-zA-Z0-9_-]+$/.test(username)) {
- // 用户名仅能使用数字、字母、“_”及“-”
- return {
- errCode
- }
- }
- }
- baseValidator.password = function (password) {
- const errCode = ERROR.INVALID_PASSWORD
- if (!isValidString(password)) {
- return {
- errCode
- }
- }
- if (password.length < 6) {
- // 密码长度不能小于6
- return {
- errCode
- }
- }
- }
- baseValidator.mobile = function (mobile) {
- const errCode = ERROR.INVALID_MOBILE
- if (!isValidString(mobile)) {
- return {
- errCode
- }
- }
- if (!/^1\d{10}$/.test(mobile)) {
- return {
- errCode
- }
- }
- }
- baseValidator.email = function (email) {
- const errCode = ERROR.INVALID_EMAIL
- if (!isValidString(email)) {
- return {
- errCode
- }
- }
- if (!/@/.test(email)) {
- return {
- errCode
- }
- }
- }
- baseValidator.nickname = function (nickname) {
- const errCode = ERROR.INVALID_NICKNAME
- if (nickname.indexOf('@') !== -1) {
- // 昵称不允许含@
- return {
- errCode
- }
- };
- if (/^\d+$/.test(nickname)) {
- // 昵称不能为纯数字
- return {
- errCode
- }
- };
- if (nickname.length > 100) {
- // 昵称不可超过100字符
- return {
- errCode
- }
- }
- }
- const baseType = ['string', 'boolean', 'number', 'null'] // undefined不会由客户端提交上来
- baseType.forEach((type) => {
- baseValidator[type] = function (val) {
- if (getType(val) === type) {
- return
- }
- return {
- errCode: ERROR.INVALID_PARAM
- }
- }
- })
- function tokenize(name) {
- let i = 0
- const result = []
- let token = ''
- while (i < name.length) {
- const char = name[i]
- switch (char) {
- case '|':
- case '<':
- case '>':
- token && result.push(token)
- result.push(char)
- token = ''
- break
- default:
- token += char
- break
- }
- i++
- if (i === name.length && token) {
- result.push(token)
- }
- }
- return result
- }
- /**
- * 处理validator名
- * @param {string} name
- */
- function parseValidatorName(name) {
- const tokenList = tokenize(name)
- let i = 0
- let currentToken = tokenList[i]
- const result = {
- type: 'root',
- children: [],
- parent: null
- }
- let lastRealm = result
- while (currentToken) {
- switch (currentToken) {
- case 'array': {
- const currentRealm = {
- type: 'array',
- children: [],
- parent: lastRealm
- }
- lastRealm.children.push(currentRealm)
- lastRealm = currentRealm
- break
- }
- case '<':
- if (lastRealm.type !== 'array') {
- throw new Error('Invalid validator token "<"')
- }
- break
- case '>':
- if (lastRealm.type !== 'array') {
- throw new Error('Invalid validator token ">"')
- }
- lastRealm = lastRealm.parent
- break
- case '|':
- if (lastRealm.type !== 'array' && lastRealm.type !== 'root') {
- throw new Error('Invalid validator token "|"')
- }
- break
- default:
- lastRealm.children.push({
- type: currentToken
- })
- break
- }
- i++
- currentToken = tokenList[i]
- }
- return result
- }
- function getRuleCategory(rule) {
- switch (rule.type) {
- case 'array':
- return 'array'
- case 'root':
- return 'root'
- default:
- return 'base'
- }
- }
- function isMatchUnionType(val, rule) {
- if (!rule.children || rule.children.length === 0) {
- return true
- }
- const children = rule.children
- for (let i = 0; i < children.length; i++) {
- const child = children[i]
- const category = getRuleCategory(child)
- let pass = false
- switch (category) {
- case 'base':
- pass = isMatchBaseType(val, child)
- break
- case 'array':
- pass = isMatchArrayType(val, child)
- break
- default:
- break
- }
- if (pass) {
- return true
- }
- }
- return false
- }
- function isMatchBaseType(val, rule) {
- if (typeof baseValidator[rule.type] !== 'function') {
- throw new Error(`invalid schema type: ${rule.type}`)
- }
- const validateRes = baseValidator[rule.type](val)
- if (validateRes && validateRes.errCode) {
- return false
- }
- return true
- }
- function isMatchArrayType(arr, rule) {
- if (getType(arr) !== 'array') {
- return false
- }
- if (rule.children && rule.children.length && arr.some(item => !isMatchUnionType(item, rule))) {
- return false
- }
- return true
- }
- // 特殊符号 https://www.ibm.com/support/pages/password-strength-rules ~!@#$%^&*_-+=`|\(){}[]:;"'<>,.?/
- // const specialChar = '~!@#$%^&*_-+=`|\(){}[]:;"\'<>,.?/'
- // const specialCharRegExp = /^[~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]$/
- // for (let i = 0, arr = specialChar.split(''); i < arr.length; i++) {
- // const char = arr[i]
- // if (!specialCharRegExp.test(char)) {
- // throw new Error('check special character error: ' + char)
- // }
- // }
- // 密码强度表达式
- const passwordRules = {
- // 密码必须包含大小写字母、数字和特殊符号
- super: /^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/])[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{8,16}$/,
- // 密码必须包含字母、数字和特殊符号
- strong: /^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/])[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{8,16}$/,
- // 密码必须为字母、数字和特殊符号任意两种的组合
- medium: /^(?![0-9]+$)(?![a-zA-Z]+$)(?![~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]+$)[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{8,16}$/,
- // 密码必须包含字母和数字
- weak: /^(?=.*[0-9])(?=.*[a-zA-Z])[0-9a-zA-Z~!@#$%^&*_\-+=`|\\(){}[\]:;"'<>,.?/]{6,16}$/,
- }
- function createPasswordVerifier({
- passwordStrength = ''
- } = {}) {
- return function (password) {
- const passwordRegExp = passwordRules[passwordStrength]
- if (!passwordRegExp) {
- throw new Error('Invalid password strength config: ' + passwordStrength)
- }
- const errCode = ERROR.INVALID_PASSWORD
- if (!isValidString(password)) {
- return {
- errCode
- }
- }
- if (!passwordRegExp.test(password)) {
- return {
- errCode: errCode + '-' + passwordStrength
- }
- }
- }
- }
- class Validator {
- constructor({
- passwordStrength = ''
- } = {}) {
- this.baseValidator = baseValidator
- this.customValidator = Object.create(null)
- if (passwordStrength) {
- this.mixin(
- 'password',
- createPasswordVerifier({
- passwordStrength
- })
- )
- }
- }
- mixin(type, handler) {
- this.customValidator[type] = handler
- }
- getRealBaseValidator(type) {
- return this.customValidator[type] || this.baseValidator[type]
- }
- get validator() {
- return new Proxy({}, {
- get: (_, prop) => {
- if (typeof prop !== 'string') {
- return
- }
- const realBaseValidator = this.getRealBaseValidator(prop)
- if (realBaseValidator) {
- return realBaseValidator
- }
- const rule = parseValidatorName(prop)
- return function (val) {
- if (!isMatchUnionType(val, rule)) {
- return {
- errCode: ERROR.INVALID_PARAM
- }
- }
- }
- }
- })
- }
- validate(value = {}, schema = {}) {
- for (const schemaKey in schema) {
- let schemaValue = schema[schemaKey]
- if (getType(schemaValue) === 'string') {
- schemaValue = {
- required: true,
- type: schemaValue
- }
- }
- const {
- required,
- type
- } = schemaValue
- // value内未传入了schemaKey或对应值为undefined
- if (value[schemaKey] === undefined) {
- if (required) {
- return {
- errCode: ERROR.PARAM_REQUIRED,
- errMsgValue: {
- param: schemaKey
- },
- schemaKey
- }
- } else {
- continue
- }
- }
- const validateMethod = this.validator[type]
- if (!validateMethod) {
- throw new Error(`invalid schema type: ${type}`)
- }
- const validateRes = validateMethod(value[schemaKey])
- if (validateRes) {
- validateRes.schemaKey = schemaKey
- return validateRes
- }
- }
- }
- }
- function checkClientInfo(clientInfo) {
- const stringNotRequired = {
- required: false,
- type: 'string'
- }
- const numberNotRequired = {
- required: false,
- type: 'number'
- }
- const numberOrStringNotRequired = {
- required: false,
- type: 'number|string'
- }
- const schema = {
- uniPlatform: 'string',
- appId: 'string',
- deviceId: stringNotRequired,
- osName: stringNotRequired,
- locale: stringNotRequired,
- clientIP: stringNotRequired,
- appName: stringNotRequired,
- appVersion: stringNotRequired,
- appVersionCode: numberOrStringNotRequired,
- channel: numberOrStringNotRequired,
- userAgent: stringNotRequired,
- uniIdToken: stringNotRequired,
- deviceBrand: stringNotRequired,
- deviceModel: stringNotRequired,
- osVersion: stringNotRequired,
- osLanguage: stringNotRequired,
- osTheme: stringNotRequired,
- romName: stringNotRequired,
- romVersion: stringNotRequired,
- devicePixelRatio: numberNotRequired,
- windowWidth: numberNotRequired,
- windowHeight: numberNotRequired,
- screenWidth: numberNotRequired,
- screenHeight: numberNotRequired
- }
- const validateRes = new Validator().validate(clientInfo, schema)
- if (validateRes) {
- if (validateRes.errCode === ERROR.PARAM_REQUIRED) {
- console.warn('- 如果使用HBuilderX运行本地云函数/云对象功能时出现此提示,请改为使用客户端调用本地云函数方式调试,或更新HBuilderX到3.4.12及以上版本。\n- 如果是缺少clientInfo.appId,请检查项目manifest.json内是否配置了DCloud AppId')
- throw new Error(`"clientInfo.${validateRes.schemaKey}" is required.`)
- } else {
- throw new Error(`Invalid client info: clienInfo.${validateRes.schemaKey}`)
- }
- }
- }
- module.exports = {
- Validator,
- checkClientInfo
- }
|