mirror of
https://github.com/linux-odyssey/linux-odyssey.git
synced 2026-11-07 11:10:11 +08:00
feat: complete register validation
* add password policy in frontend
This commit is contained in:
1 parent
1c9d69a8e0
commit
fc6ac11c60
11 files changed
+57
-23
No files matched your search
@@ -5,6 +5,7 @@ COPY package.json yarn.lock ./
|
|||||||
COPY app/package.json ./app/package.json
|
COPY app/package.json ./app/package.json
|
||||||
COPY packages/file-graph/package.json ./packages/file-graph/package.json
|
COPY packages/file-graph/package.json ./packages/file-graph/package.json
|
||||||
COPY packages/utils/package.json ./packages/utils/package.json
|
COPY packages/utils/package.json ./packages/utils/package.json
|
||||||
|
COPY packages/constants/package.json ./packages/constants/package.json
|
||||||
RUN yarn install --frozen-lockfile
|
RUN yarn install --frozen-lockfile
|
||||||
|
|
||||||
# Dev stage
|
# Dev stage
|
||||||
@@ -16,6 +17,7 @@ CMD [ "yarn", "dev:docker", "--host", "0.0.0.0" ]
|
|||||||
FROM base as build
|
FROM base as build
|
||||||
COPY packages/file-graph ./packages/file-graph
|
COPY packages/file-graph ./packages/file-graph
|
||||||
COPY packages/utils ./packages/utils
|
COPY packages/utils ./packages/utils
|
||||||
|
COPY packages/constants ./packages/constants
|
||||||
COPY app ./app
|
COPY app ./app
|
||||||
RUN yarn build
|
RUN yarn build
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -11,15 +11,17 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@linux-odyssey/file-graph": "*",
|
|
||||||
"@linux-odyssey/utils": "*",
|
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
||||||
"@fortawesome/free-brands-svg-icons": "^6.4.0",
|
"@fortawesome/free-brands-svg-icons": "^6.4.0",
|
||||||
"@fortawesome/free-regular-svg-icons": "^6.4.0",
|
"@fortawesome/free-regular-svg-icons": "^6.4.0",
|
||||||
"@fortawesome/free-solid-svg-icons": "^6.4.0",
|
"@fortawesome/free-solid-svg-icons": "^6.4.0",
|
||||||
"@fortawesome/vue-fontawesome": "^3.0.3",
|
"@fortawesome/vue-fontawesome": "^3.0.3",
|
||||||
|
"@linux-odyssey/file-graph": "*",
|
||||||
|
"@linux-odyssey/utils": "*",
|
||||||
|
"@linux-odyssey/constants": "*",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"socket.io-client": "^4.7.1",
|
"socket.io-client": "^4.7.1",
|
||||||
|
"validator": "^13.11.0",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
"vue-router": "^4.2.4",
|
"vue-router": "^4.2.4",
|
||||||
"xterm": "^5.2.1",
|
"xterm": "^5.2.1",
|
||||||
|
|||||||
@@ -128,6 +128,7 @@ const handleChange = () => {
|
|||||||
class="my-4 bg-background-primary text-text-primary bg- rounded-md block w-full px-3 h-10 shadow-sm focus:outline-none placeholder:text-text-line focus:ring-2 focus:ring-text-primary ring-1 ring-background-secondary"
|
class="my-4 bg-background-primary text-text-primary bg- rounded-md block w-full px-3 h-10 shadow-sm focus:outline-none placeholder:text-text-line focus:ring-2 focus:ring-text-primary ring-1 ring-background-secondary"
|
||||||
:placeholder="type === 'login' ? 'Email / Username' : 'Username'"
|
:placeholder="type === 'login' ? 'Email / Username' : 'Username'"
|
||||||
v-model="username"
|
v-model="username"
|
||||||
|
required
|
||||||
@input="handleChange()"
|
@input="handleChange()"
|
||||||
autocomplete="username"
|
autocomplete="username"
|
||||||
/>
|
/>
|
||||||
@@ -147,6 +148,7 @@ const handleChange = () => {
|
|||||||
class="my-4 bg-background-primary text-text-primary bg- rounded-md block w-full px-3 h-10 shadow-sm focus:outline-none placeholder:text-text-line focus:ring-2 focus:ring-text-primary ring-1 ring-background-secondary"
|
class="my-4 bg-background-primary text-text-primary bg- rounded-md block w-full px-3 h-10 shadow-sm focus:outline-none placeholder:text-text-line focus:ring-2 focus:ring-text-primary ring-1 ring-background-secondary"
|
||||||
placeholder="Email"
|
placeholder="Email"
|
||||||
v-model="email"
|
v-model="email"
|
||||||
|
required
|
||||||
@input="handleChange()"
|
@input="handleChange()"
|
||||||
autocomplete="email"
|
autocomplete="email"
|
||||||
/>
|
/>
|
||||||
@@ -158,6 +160,7 @@ const handleChange = () => {
|
|||||||
class="my-4 bg-background-primary text-text-primary bg- rounded-md block w-full px-3 h-10 shadow-sm focus:outline-none placeholder:text-text-line focus:ring-2 focus:ring-text-primary ring-1 ring-background-secondary"
|
class="my-4 bg-background-primary text-text-primary bg- rounded-md block w-full px-3 h-10 shadow-sm focus:outline-none placeholder:text-text-line focus:ring-2 focus:ring-text-primary ring-1 ring-background-secondary"
|
||||||
placeholder="Password"
|
placeholder="Password"
|
||||||
v-model="password"
|
v-model="password"
|
||||||
|
required
|
||||||
@input="handleChange()"
|
@input="handleChange()"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { isValidEmail, isValidUsername } from '@linux-odyssey/utils'
|
import validator from 'validator'
|
||||||
|
import { isValidUsername } from '@linux-odyssey/utils'
|
||||||
|
import { passwordPolicy } from '@linux-odyssey/constants'
|
||||||
import AuthForm from '../components/AuthForm.vue'
|
import AuthForm from '../components/AuthForm.vue'
|
||||||
import Background from '../components/DynamicBackground.vue'
|
import Background from '../components/DynamicBackground.vue'
|
||||||
|
|
||||||
@@ -27,29 +29,35 @@ function handleRegister({ username, email, password, success, error }) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function check({ username, email, error }) {
|
async function check({ username, email, password, error }) {
|
||||||
if (username && !isValidUsername(username)) {
|
if (username && !isValidUsername(username)) {
|
||||||
error('Invalid username.')
|
error('Invalid username.')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (email && !isValidEmail(email)) {
|
if (email && !validator.isEmail(email)) {
|
||||||
error('Invalid email.')
|
error('Invalid email.')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!username && !email) {
|
if (password && !validator.isStrongPassword(password, passwordPolicy)) {
|
||||||
|
error(
|
||||||
|
'Your password must be 8+ characters with at least one number, one upper and one lower case letter.'
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!(username && email && password)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const res = await api.get('/auth/check-username', {
|
const res = await api.get('/auth/check-username', {
|
||||||
params: { username },
|
params: { username },
|
||||||
})
|
})
|
||||||
const { type, available } = res.data
|
const { available } = res.data
|
||||||
if (!available) {
|
if (!available) {
|
||||||
error(`${type} already exists.`)
|
error(`Username already exists.`)
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.response?.status === 400) {
|
if (err.response?.status === 400) {
|
||||||
error('Invalid username or email.')
|
error('Invalid username.')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
console.error(err)
|
console.error(err)
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
export const passwordPolicy = {
|
||||||
|
minLength: 8,
|
||||||
|
minNumbers: 1,
|
||||||
|
minLowercase: 1,
|
||||||
|
minUppercase: 1,
|
||||||
|
minSymbols: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
passwordPolicy,
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"name": "@linux-odyssey/constants",
|
||||||
|
"type": "module",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"main": "index.js",
|
||||||
|
"exports": "./index.js",
|
||||||
|
"license": "GPL"
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ COPY server/package.json ./server/package.json
|
|||||||
COPY packages/file-graph/package.json ./packages/file-graph/package.json
|
COPY packages/file-graph/package.json ./packages/file-graph/package.json
|
||||||
COPY packages/utils/package.json ./packages/utils/package.json
|
COPY packages/utils/package.json ./packages/utils/package.json
|
||||||
COPY packages/models/package.json ./packages/models/package.json
|
COPY packages/models/package.json ./packages/models/package.json
|
||||||
|
COPY packages/constants/package.json ./packages/constants/package.json
|
||||||
RUN yarn install --frozen-lockfile --production
|
RUN yarn install --frozen-lockfile --production
|
||||||
# Install docker cli
|
# Install docker cli
|
||||||
COPY --from=docker:dind /usr/local/bin/docker /usr/local/bin/
|
COPY --from=docker:dind /usr/local/bin/docker /usr/local/bin/
|
||||||
@@ -20,6 +21,7 @@ FROM build as prod
|
|||||||
COPY packages/file-graph ./packages/file-graph
|
COPY packages/file-graph ./packages/file-graph
|
||||||
COPY packages/utils ./packages/utils
|
COPY packages/utils ./packages/utils
|
||||||
COPY packages/models ./packages/models
|
COPY packages/models ./packages/models
|
||||||
|
COPY packages/constants ./packages/constants
|
||||||
COPY ./server ./server
|
COPY ./server ./server
|
||||||
COPY quests ./quests
|
COPY quests ./quests
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
"@linux-odyssey/file-graph": "*",
|
"@linux-odyssey/file-graph": "*",
|
||||||
"@linux-odyssey/models": "*",
|
"@linux-odyssey/models": "*",
|
||||||
"@linux-odyssey/utils": "*",
|
"@linux-odyssey/utils": "*",
|
||||||
|
"@linux-odyssey/constants": "*",
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
"commander": "^11.0.0",
|
"commander": "^11.0.0",
|
||||||
"connect-mongo": "^5.0.0",
|
"connect-mongo": "^5.0.0",
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { query } from 'express-validator'
|
import { check } from 'express-validator'
|
||||||
|
|
||||||
import { isValidUsername } from '@linux-odyssey/utils'
|
import { isValidUsername } from '@linux-odyssey/utils'
|
||||||
import { User } from '@linux-odyssey/models'
|
import { User } from '@linux-odyssey/models'
|
||||||
|
import { passwordPolicy } from '@linux-odyssey/constants'
|
||||||
|
|
||||||
export const checkUsername = () =>
|
export const checkUsername = () =>
|
||||||
query('username')
|
check('username')
|
||||||
.notEmpty()
|
.notEmpty()
|
||||||
.isString()
|
.isString()
|
||||||
.custom((username) => {
|
.custom((username) => {
|
||||||
@@ -23,7 +24,7 @@ export const checkNewUsername = () =>
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
export const checkEmail = () => query('email').notEmpty().isEmail().trim()
|
export const checkEmail = () => check('email').notEmpty().isEmail().trim()
|
||||||
|
|
||||||
export const checkNewEmail = () =>
|
export const checkNewEmail = () =>
|
||||||
checkEmail().custom(async (email) => {
|
checkEmail().custom(async (email) => {
|
||||||
@@ -34,10 +35,4 @@ export const checkNewEmail = () =>
|
|||||||
})
|
})
|
||||||
|
|
||||||
export const checkPassword = () =>
|
export const checkPassword = () =>
|
||||||
query('password').notEmpty().isStrongPassword({
|
check('password').notEmpty().isStrongPassword(passwordPolicy)
|
||||||
minLength: 8,
|
|
||||||
minNumbers: 1,
|
|
||||||
minLowercase: 1,
|
|
||||||
minUppercase: 1,
|
|
||||||
minSymbols: 0,
|
|
||||||
})
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { get, genSecret } from './utils/env.js'
|
import { get } from './utils/env.js'
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
host: get('HOST', 'localhost'),
|
host: get('HOST', 'localhost'),
|
||||||
@@ -23,10 +23,11 @@ const config = {
|
|||||||
config.baseUrl = get('BASE_URL', `http://${config.host}:${config.port}`)
|
config.baseUrl = get('BASE_URL', `http://${config.host}:${config.port}`)
|
||||||
|
|
||||||
if (!config.secret) {
|
if (!config.secret) {
|
||||||
config.secret = genSecret()
|
|
||||||
console.warn(
|
console.warn(
|
||||||
'No SECRET_KEY found in .env! A temporary secret key has been generated. To set up a persistent key, please run the setup script.'
|
'No SECRET_KEY found in .env! To set up a persistent key, please run the setup script:'
|
||||||
)
|
)
|
||||||
|
console.warn('yarn setup')
|
||||||
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default config
|
export default config
|
||||||
@@ -6092,7 +6092,7 @@ v8-to-istanbul@^9.0.1:
|
|||||||
"@types/istanbul-lib-coverage" "^2.0.1"
|
"@types/istanbul-lib-coverage" "^2.0.1"
|
||||||
convert-source-map "^1.6.0"
|
convert-source-map "^1.6.0"
|
||||||
|
|
||||||
validator@^13.9.0:
|
validator@^13.11.0, validator@^13.9.0:
|
||||||
version "13.11.0"
|
version "13.11.0"
|
||||||
resolved "https://registry.yarnpkg.com/validator/-/validator-13.11.0.tgz#23ab3fd59290c61248364eabf4067f04955fbb1b"
|
resolved "https://registry.yarnpkg.com/validator/-/validator-13.11.0.tgz#23ab3fd59290c61248364eabf4067f04955fbb1b"
|
||||||
integrity sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==
|
integrity sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==
|
||||||
|
|||||||
Reference in new issue
Block a user