Skip to content

Commit

Permalink
refactor(Password.vue): validate and encrypt password
Browse files Browse the repository at this point in the history
  • Loading branch information
oucb authored and ysfscream committed May 30, 2024
1 parent 5dcd017 commit 5d55596
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 22 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"base64-js": "^1.5.1",
"blueimp-md5": "^2.19.0",
"core-js": "^3.6.5",
"crypto-js": "^4.2.0",
"dateformat": "^5.0.2",
"dayjs": "^1.10.4",
"echarts": "^5.2.2",
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export default {
en: 'Please enter a new password again',
},
passwordStrengthTip: {
zh: '密码必须由数字、英文字母、特殊字符组成,且长度在 8 到 20 之间',
zh: '密码必须由数字、英文字母、特殊字符组成,且长度在 8 到 20 之间。不能连续输入 3 位及以上一样的字符;不能输入键盘连接 3 位及以上的字符;不能包含 admin、mysql、oracle、system、windows、linux、java、python、unix、test',
en: 'Passwords should be between 8 and 20 in length and combination of letters, numbers, or symbols',
},
newPassNotMatch: {
Expand Down
1 change: 1 addition & 0 deletions src/types/shims-vue.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
type $TSFixed = any
declare module '@emqx/emqx-ui'
declare module 'dateformat'
declare module 'crypto-js'
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
Expand Down
12 changes: 12 additions & 0 deletions src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ERROR_CODE_ARR, SELF_HANDLE_ERROR_CODES } from './constants'
import { utils as XLSXUtils, writeFile } from 'xlsx'
import { EmqxMessage } from '@emqx/emqx-ui'
import { omit, cloneDeep, orderBy } from 'lodash'
import CryptoJS from 'crypto-js'

/**
* when the value is int, can use this func to create option list
Expand Down Expand Up @@ -255,3 +256,14 @@ export const randomString = (stringLen: number): string => {

return str
}

export const encryptStr = (str: string): string => {
const utf8Str = CryptoJS.enc.Utf8.parse(str)
const kStr = '0000neuronex0000'
const encrypted = CryptoJS.AES.encrypt(utf8Str, kStr, {
iv: kStr,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
})
return encrypted.ciphertext.toString()
}
4 changes: 2 additions & 2 deletions src/views/Login.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

<script lang="ts" setup>
import { login as requestLogin } from '@/api/common'
import { createCommonErrorMessage } from '@/utils/utils'
import { createCommonErrorMessage, encryptStr } from '@/utils/utils'
import { computed, reactive, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
Expand Down Expand Up @@ -64,7 +64,7 @@ const login = async () => {
await formCom.value.validate()
isLoading.value = true
const { userName, password } = form
const { data } = await requestLogin({ name: userName, pass: password })
const { data } = await requestLogin({ name: userName, pass: encryptStr(password) })
store.commit('SET_TOKEN', data.token)
setLang()
Expand Down
60 changes: 41 additions & 19 deletions src/views/admin/Password.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import { reactive, ref, toRefs, computed, watch, nextTick } from 'vue'
import { useI18n } from 'vue-i18n'
import { changePassword } from '@/api/common'
import { EmqxMessage } from '@emqx/emqx-ui'
import { createCommonErrorMessage } from '@/utils/utils'
import { createCommonErrorMessage, encryptStr } from '@/utils/utils'
import { useStore } from 'vuex'
const { t } = useI18n()
Expand All @@ -66,32 +66,51 @@ const isNewPassMatch = computed(() => {
})
const checkNewPassMatch = (rule: any, value: string, callback: any) => {
const { newPassConfirm } = formState.formData
const strongRegex = new RegExp(
'^(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[~`!@#$%^&*()_+\\-=:;<>?,./|\\\\])[a-zA-Z\\d~`!@#$%^&*()_+\\-=:;<>?,./|\\\\]{8,20}$',
'^(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[~`!@#$%^&*()_+\\-=\\[\\]:;\'"<>?,./|\\\\])[a-zA-Z\\d~`!@#$%^&*()_+\\-=\\[\\]:;\'"<>?,./|\\\\]{8,20}$',
)
const repeatRegex = new RegExp('(.)\\1{2,}')
const filterMeta = [
// eslint-disable-next-line prettier/prettier
"qwertyuiop[]\\", "asdfghjkl;'", "zxcvbnm,./", "01234567890-=", "901", "abcdefghijklmnopqrstuvwxyz"
]
const filterList = [
// eslint-disable-next-line prettier/prettier
"qaz", "wsx", "edc", "rfv", "tgb", "yhn", "ujm", "ik,", "ol.", "p;/", "esz", "rdx",
// eslint-disable-next-line prettier/prettier
"tfc", "ygv", "uhb", "ijn", "okm", "pl,", "[;.", "]'/", "1qa", "2ws", "3ed", "4rf",
// eslint-disable-next-line prettier/prettier
"5tg", "6yh", "7uj", "8ik", "9ol", "0p;", "-['", "=[;", "-pl", "0ok", "9ij", "8uh",
// eslint-disable-next-line prettier/prettier
"7yg", "6tf", "5rd", "4es", "3wa", "root", "admin", "mysql", "oracle", "system",
// eslint-disable-next-line prettier/prettier
"windows", "linux", "java", "python", "unix", "test"
]
filterMeta.forEach((item) => {
let i
for (i = 0; i < item.length - 2; i += 1) {
filterList.push(item.substring(i, i + 3))
}
})
const metaRegex = new RegExp(
filterList.join('|').replace(/\\/g, '\\\\\\\\').replace(/\[/g, '\\[').replace(/\]/g, '\\]'),
'g',
)
if (value && !strongRegex.test(value)) {
callback(new Error(`${t('common.passwordStrengthTip')}`))
}
if (!newPassConfirm || (newPassConfirm && isNewPassMatch.value)) {
if (newPassConfirm) {
const { form } = formRef.value
form.validateField(['newPassConfirm'])
}
callback()
} else {
callback(new Error(`${t('common.newPassNotMatch')}`))
if (value && (repeatRegex.test(value) || value.match(metaRegex))) {
callback(new Error(`${t('common.passwordStrengthTip')}`))
}
const { form } = formRef.value
const { newPassConfirm } = formState.formData
if (newPassConfirm) {
form.validateField(['newPassConfirm'])
}
}
const checkNewPassConfirmMatch = (rule: any, value: string, callback: any) => {
const { form } = formRef.value
if (isNewPassMatch.value) {
form.validateField(['newPass'])
callback()
} else {
if (!isNewPassMatch.value) {
callback(new Error(`${t('common.newPassNotMatch')}`))
}
}
Expand Down Expand Up @@ -148,7 +167,7 @@ const changeUserPassword = async () => {
try {
isSubmitting.value = true
const { name, oldPass: old_pass, newPass: new_pass } = formState.formData
await changePassword({ name, old_pass, new_pass })
await changePassword({ name, old_pass: encryptStr(old_pass), new_pass: encryptStr(new_pass) })
EmqxMessage.success(t('common.changePwSuccessful'))
formRef.value.resetField()
} catch (error) {
Expand All @@ -171,5 +190,8 @@ const submit = () => {
.pw-form {
width: 50%;
min-width: 500px;
:deep(.el-form-item) {
margin-bottom: 30px;
}
}
</style>
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3378,6 +3378,11 @@ crypto-browserify@^3.11.0:
randombytes "^2.0.0"
randomfill "^1.0.3"

crypto-js@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631"
integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==

[email protected], css-color-names@^0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
Expand Down

0 comments on commit 5d55596

Please sign in to comment.