Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(Password.vue): validate and encrypt password #597

Merged
merged 1 commit into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading