bonus-ui/src/utils/validate.js

279 lines
8.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { CONFIG } from '@/utils/configure'
import passwordConfig from '@/utils/passwordConfig'
/**
* @param {string} path
* @returns {Boolean}
*/
export function isExternal(path) {
return /^(https?:|mailto:|tel:)/.test(path)
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function validUsername(str) {
const valid_map = ['admin', 'editor']
return valid_map.indexOf(str.trim()) >= 0
}
/**
* @param {string} url
* @returns {Boolean}
*/
export function validURL(url) {
const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
return reg.test(url)
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function validLowerCase(str) {
const reg = /^[a-z]+$/
return reg.test(str)
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function validUpperCase(str) {
const reg = /^[A-Z]+$/
return reg.test(str)
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function validAlphabets(str) {
const reg = /^[A-Za-z]+$/
return reg.test(str)
}
/**
* @param {string} email
* @returns {Boolean}
*/
export function validEmail(email) {
const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
return reg.test(email)
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function isString(str) {
return typeof str === 'string' || str instanceof String
}
/**
* @param {Array} arg
* @returns {Boolean}
*/
export function isArray(arg) {
if (typeof Array.isArray === 'undefined') {
return Object.prototype.toString.call(arg) === '[object Array]'
}
return Array.isArray(arg)
}
/**
* 密码的正则表达式 最少8个字符最多20个字符至少一个字母一个数字和一个特殊字符
* @param {string} password
* @returns {Boolean}
*/
export function validPwd(value) {
const reg = /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,20}$/
return reg.test(value)
}
/**
* 弱长度至少为8个字符。
* 一般长度至少为8个字符并包含至少一种字符类型。
* 强长度至少为8个字符并包含至少两种字符类型。
* 非常强长度至少为8个字符并包含所有四种字符类型。
* @param rule
* @param value
* @param callback
* @returns {*}
*/
export function validatePassword(rule, value, callback) {
if (!value) {
return callback(new Error('请输入密码'))
}
const lengthRegex = /^.{8,20}$/
const uppercaseRegex = /[A-Z]/
const lowercaseRegex = /[a-z]/
const digitRegex = /\d/
const specialCharRegex = /[!@#$%^&*(),.?":{}|<>]/
if (!lengthRegex.test(value)) {
return callback(new Error('密码长度必须为8到20位'))
}
const checks = [
{ regex: uppercaseRegex, message: '必须包含至少一个大写字母' },
{ regex: lowercaseRegex, message: '必须包含至少一个小写字母' },
{ regex: digitRegex, message: '必须包含至少一个数字' },
{ regex: specialCharRegex, message: '必须包含至少一个特殊字符' }
]
let passedChecks = checks.filter(check => check.regex.test(value)).length
let requiredChecks
switch (CONFIG.STRENGTH) {
case 'weak':
requiredChecks = 1
break
case 'medium':
requiredChecks = 2
break
case 'strong':
requiredChecks = 3
break
case 'very-strong':
requiredChecks = 4
break
default:
return callback(new Error('请选择有效的密码强度'))
}
if (passedChecks < requiredChecks) {
return callback(new Error(`密码至少包含 ${requiredChecks} 类字符(大写字母,小写字母,数字,特殊字符)`))
}
callback()
}
export function validateNewPassword(rule, value, callback) {
// 使用配置文件中的策略进行验证
// 1. 检查密码长度
if (value.length < passwordConfig.minLength || value.length > passwordConfig.maxLength) {
callback(new Error('密码长度应为' + passwordConfig.minLength + '至' + passwordConfig.maxLength + '位!'))
return
}
// 2. 检查密码复杂度
const hasUpperCase = /[A-Z]/.test(value)
const hasLowerCase = /[a-z]/.test(value)
const hasDigit = /\d/.test(value)
const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(value)
if (passwordConfig.requireUpperCase && !hasUpperCase) {
callback(new Error('密码必须包含大写字母!'))
return
}
if (passwordConfig.requireLowerCase && !hasLowerCase) {
callback(new Error('密码必须包含小写字母!'))
return
}
if (passwordConfig.requireDigit && !hasDigit) {
callback(new Error('密码必须包含数字!'))
return
}
if (passwordConfig.requireSpecialChar && !hasSpecialChar) {
callback(new Error('密码必须包含特殊字符!'))
return
}
// 3. 检查是否包含弱密码
for (const weakPwd of passwordConfig.weakPasswords) {
// 将密码和弱密码都转换为小写进行比较
if (value.toLowerCase().includes(weakPwd.toLowerCase())) {
callback(new Error(`密码包含常见的弱密码片段: ${weakPwd}`))
return
}
}
// 4. 检查是否包含超过规定数量的连续字符
if (passwordConfig.restrictConsecutiveChars && containsConsecutiveCharacters(value, passwordConfig.maxConsecutiveChars)) {
callback(new Error(`密码不能包含超过${passwordConfig.maxConsecutiveChars}位连续字符!`))
return
}
callback() // 验证成功
}
/**
* 检查密码中是否包含超过 n 个连续相同字符、连续递增/递减的数字或字母(不区分大小写)
*/
function containsConsecutiveCharacters(password, n) {
// 检查连续相同字符
n = n + 1; // 允许最多 n 个连续字符
for (let i = 0; i <= password.length - n; i++) {
let consecutiveSameChar = true;
for (let j = 1; j < n; j++) {
if (password[i + j] !== password[i]) {
consecutiveSameChar = false;
break;
}
}
if (consecutiveSameChar) {
return true; // 包含超过 n 个连续相同字符
}
}
// 检查连续递增或递减的数字
for (let i = 0; i <= password.length - n; i++) {
let consecutiveIncreasing = true;
let consecutiveDecreasing = true;
for (let j = 1; j < n; j++) {
const currentChar = password[i];
const nextChar = password[i + j];
// 检查数字递增或递减
if (/\d/.test(currentChar) && /\d/.test(nextChar)) {
if (nextChar.charCodeAt(0) !== currentChar.charCodeAt(0) + j) {
consecutiveIncreasing = false;
}
if (nextChar.charCodeAt(0) !== currentChar.charCodeAt(0) - j) {
consecutiveDecreasing = false;
}
} else {
consecutiveIncreasing = false;
consecutiveDecreasing = false;
break;
}
}
if (consecutiveIncreasing || consecutiveDecreasing) {
return true; // 包含超过 n 个递增或递减的连续数字
}
}
// 检查连续递增或递减的字母(不区分大小写)
for (let i = 0; i <= password.length - n; i++) {
let consecutiveIncreasing = true;
let consecutiveDecreasing = true;
for (let j = 1; j < n; j++) {
const currentChar = password[i].toLowerCase(); // 转为小写
const nextChar = password[i + j].toLowerCase(); // 转为小写
// 检查字母递增或递减
if (/[a-zA-Z]/.test(currentChar) && /[a-zA-Z]/.test(nextChar)) {
if (nextChar.charCodeAt(0) !== currentChar.charCodeAt(0) + j) {
consecutiveIncreasing = false;
}
if (nextChar.charCodeAt(0) !== currentChar.charCodeAt(0) - j) {
consecutiveDecreasing = false;
}
} else {
consecutiveIncreasing = false;
consecutiveDecreasing = false;
break;
}
}
if (consecutiveIncreasing || consecutiveDecreasing) {
return true; // 包含超过 n 个递增或递减的连续字母
}
}
// 不包含连续相同字符、数字或字母序列
return false;
}