mirror of
https://github.com/linux-odyssey/linux-odyssey.git
synced 2026-11-06 03:20:13 +08:00
feat: add rate limit for authentication
* improve error handling in frontend
This commit is contained in:
1 parent
203114cd5e
commit
f65b72c5b4
10 files changed
+146
-42
No files matched your search
+47
-7
@@ -1,5 +1,11 @@
|
||||
import api from './api'
|
||||
|
||||
import {
|
||||
TooManyRequestsError,
|
||||
UnauthorizedError,
|
||||
ValidationError,
|
||||
} from './errors'
|
||||
|
||||
export async function isLoggedIn() {
|
||||
const res = await api.get('/auth/check-session')
|
||||
const { loggedIn } = res.data
|
||||
@@ -12,18 +18,52 @@ export const login = async (username, password) => {
|
||||
return true
|
||||
} catch (err) {
|
||||
if (err.response?.status === 401) {
|
||||
return false
|
||||
throw new UnauthorizedError(err.response.data.message)
|
||||
}
|
||||
if (err.response?.status === 429) {
|
||||
throw new TooManyRequestsError(err.response.data.message)
|
||||
}
|
||||
if (err.response?.status === 400) {
|
||||
throw new ValidationError(err.response.data.message)
|
||||
}
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
export const register = (username, email, password) => {
|
||||
return api.post('/auth/register', {
|
||||
username,
|
||||
password,
|
||||
email,
|
||||
})
|
||||
export const register = async (username, email, password) => {
|
||||
try {
|
||||
await api.post('/auth/register', {
|
||||
username,
|
||||
password,
|
||||
email,
|
||||
})
|
||||
return true
|
||||
} catch (err) {
|
||||
const status = err.response?.status
|
||||
if (status === 429) {
|
||||
throw new TooManyRequestsError(err.response.data.message)
|
||||
}
|
||||
if (status === 401) {
|
||||
throw new UnauthorizedError(err.response.data.message)
|
||||
}
|
||||
if (status === 400) {
|
||||
const { errors } = err.response.data
|
||||
if (errors?.length > 0) {
|
||||
const { path, msg } = errors[0]
|
||||
switch (path) {
|
||||
case 'username':
|
||||
throw new ValidationError('Username is already taken')
|
||||
case 'email':
|
||||
throw new ValidationError('Email is already taken')
|
||||
case 'password':
|
||||
throw new ValidationError('Password is too weak')
|
||||
default:
|
||||
throw new ValidationError(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
export const logout = () => {
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/* eslint-disable max-classes-per-file */
|
||||
export class TooManyRequestsError extends Error {
|
||||
constructor(message) {
|
||||
super(message)
|
||||
this.name = 'TooManyRequestsError'
|
||||
}
|
||||
}
|
||||
|
||||
export class ValidationError extends Error {
|
||||
constructor(message) {
|
||||
super(message)
|
||||
this.name = 'ValidationError'
|
||||
}
|
||||
}
|
||||
|
||||
export class UnauthorizedError extends Error {
|
||||
constructor(message) {
|
||||
super(message)
|
||||
this.name = 'UnauthorizedError'
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
TooManyRequestsError,
|
||||
ValidationError,
|
||||
UnauthorizedError,
|
||||
}
|
||||
@@ -2,14 +2,30 @@
|
||||
import AuthForm from '../components/AuthForm.vue'
|
||||
import Background from '../components/DynamicBackground.vue'
|
||||
|
||||
import {
|
||||
TooManyRequestsError,
|
||||
UnauthorizedError,
|
||||
ValidationError,
|
||||
} from '../utils/errors'
|
||||
import { login } from '../utils/auth'
|
||||
|
||||
const handleLogin = async ({ username, password, success, error }) => {
|
||||
try {
|
||||
const isSuccess = await login(username, password)
|
||||
if (isSuccess) success()
|
||||
else error('Wrong username or password.')
|
||||
} catch (err) {
|
||||
if (err instanceof TooManyRequestsError) {
|
||||
error('Too many requests. Try again in 2 minutes.')
|
||||
return
|
||||
}
|
||||
if (err instanceof UnauthorizedError) {
|
||||
error('Wrong username or password.')
|
||||
return
|
||||
}
|
||||
if (err instanceof ValidationError) {
|
||||
error('Invalid username or password.')
|
||||
return
|
||||
}
|
||||
console.error(err)
|
||||
error('Something went wrong.')
|
||||
}
|
||||
|
||||
@@ -7,25 +7,29 @@ import Background from '../components/DynamicBackground.vue'
|
||||
|
||||
import api from '../utils/api'
|
||||
import { register } from '../utils/auth'
|
||||
import {
|
||||
UnauthorizedError,
|
||||
TooManyRequestsError,
|
||||
ValidationError,
|
||||
} from '../utils/errors'
|
||||
|
||||
function handleRegister({ username, email, password, success, error }) {
|
||||
register(username, email, password)
|
||||
.then(success)
|
||||
.catch((err) => {
|
||||
if (err.response?.status === 409) {
|
||||
// Handle username or email already exists error here
|
||||
if (err.response.data.type === 'username') {
|
||||
error('Username already exists.')
|
||||
} else if (err.response.data.type === 'email') {
|
||||
error('Email already exists.')
|
||||
} else {
|
||||
error('Something went wrong.')
|
||||
}
|
||||
} else if (err.response?.status === 400) {
|
||||
error('Invalid username or email.')
|
||||
} else {
|
||||
console.error(err)
|
||||
if (err instanceof TooManyRequestsError) {
|
||||
error('Too many requests. Try again in 2 minutes.')
|
||||
return
|
||||
}
|
||||
if (err instanceof UnauthorizedError) {
|
||||
error('Invalid username or password.')
|
||||
return
|
||||
}
|
||||
if (err instanceof ValidationError) {
|
||||
error(err.message)
|
||||
return
|
||||
}
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user