Correctly handle invalid current password
This commit is contained in:
parent
d0304f6712
commit
a9d08d2646
|
@ -4,7 +4,7 @@ import { HTTP_INTERCEPTORS, HttpErrorResponse, HttpEvent, HttpHandler, HttpInter
|
||||||
import { Injectable, Injector } from '@angular/core'
|
import { Injectable, Injector } from '@angular/core'
|
||||||
import { Router } from '@angular/router'
|
import { Router } from '@angular/router'
|
||||||
import { AuthService } from '@app/core/auth/auth.service'
|
import { AuthService } from '@app/core/auth/auth.service'
|
||||||
import { HttpStatusCode, OAuth2ErrorCode, PeerTubeProblemDocument } from '@peertube/peertube-models'
|
import { HttpStatusCode, OAuth2ErrorCode, PeerTubeProblemDocument, ServerErrorCode } from '@peertube/peertube-models'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthInterceptor implements HttpInterceptor {
|
export class AuthInterceptor implements HttpInterceptor {
|
||||||
|
@ -23,24 +23,28 @@ export class AuthInterceptor implements HttpInterceptor {
|
||||||
// Pass on the cloned request instead of the original request
|
// Pass on the cloned request instead of the original request
|
||||||
// Catch 401 errors (refresh token expired)
|
// Catch 401 errors (refresh token expired)
|
||||||
return next.handle(authReq)
|
return next.handle(authReq)
|
||||||
.pipe(
|
.pipe(
|
||||||
catchError((err: HttpErrorResponse) => {
|
catchError((err: HttpErrorResponse) => {
|
||||||
const error = err.error as PeerTubeProblemDocument
|
const error = err.error as PeerTubeProblemDocument
|
||||||
const isOTPMissingError = this.authService.isOTPMissingError(err)
|
const isOTPMissingError = this.authService.isOTPMissingError(err)
|
||||||
|
|
||||||
if (!isOTPMissingError) {
|
if (error && error.code === ServerErrorCode.CURRENT_PASSWORD_IS_INVALID) {
|
||||||
if (err.status === HttpStatusCode.UNAUTHORIZED_401 && error && error.code === OAuth2ErrorCode.INVALID_TOKEN) {
|
return observableThrowError(() => err)
|
||||||
return this.handleTokenExpired(req, next)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (err.status === HttpStatusCode.UNAUTHORIZED_401) {
|
if (!isOTPMissingError) {
|
||||||
return this.handleNotAuthenticated(err)
|
if (err.status === HttpStatusCode.UNAUTHORIZED_401 && error && error.code === OAuth2ErrorCode.INVALID_TOKEN) {
|
||||||
}
|
return this.handleTokenExpired(req, next)
|
||||||
}
|
}
|
||||||
|
|
||||||
return observableThrowError(() => err)
|
if (err.status === HttpStatusCode.UNAUTHORIZED_401) {
|
||||||
})
|
return this.handleNotAuthenticated(err)
|
||||||
)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return observableThrowError(() => err)
|
||||||
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleTokenExpired (req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
private handleTokenExpired (req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||||
|
|
|
@ -58,7 +58,9 @@ export const ServerErrorCode = {
|
||||||
VIDEO_ALREADY_BEING_TRANSCRIBED: 'video_already_being_transcribed',
|
VIDEO_ALREADY_BEING_TRANSCRIBED: 'video_already_being_transcribed',
|
||||||
VIDEO_ALREADY_HAS_CAPTIONS: 'video_already_has_captions',
|
VIDEO_ALREADY_HAS_CAPTIONS: 'video_already_has_captions',
|
||||||
|
|
||||||
MAX_USER_VIDEO_QUOTA_EXCEEDED_FOR_USER_EXPORT: 'max_user_video_quota_exceeded_for_user_export'
|
MAX_USER_VIDEO_QUOTA_EXCEEDED_FOR_USER_EXPORT: 'max_user_video_quota_exceeded_for_user_export',
|
||||||
|
|
||||||
|
CURRENT_PASSWORD_IS_INVALID: 'current_password_is_invalid'
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { forceNumber } from '@peertube/peertube-core-utils'
|
import { forceNumber } from '@peertube/peertube-core-utils'
|
||||||
import { HttpStatusCode, UserRight, UserRole } from '@peertube/peertube-models'
|
import { HttpStatusCode, ServerErrorCode, UserRight, UserRole } from '@peertube/peertube-models'
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { body, param, query } from 'express-validator'
|
import { body, param, query } from 'express-validator'
|
||||||
import { exists, isBooleanValid, isIdValid, toBooleanOrNull, toIntOrNull } from '../../../helpers/custom-validators/misc.js'
|
import { exists, isBooleanValid, isIdValid, toBooleanOrNull, toIntOrNull } from '../../../helpers/custom-validators/misc.js'
|
||||||
|
@ -40,7 +40,7 @@ import {
|
||||||
isValidVideoIdParam
|
isValidVideoIdParam
|
||||||
} from '../shared/index.js'
|
} from '../shared/index.js'
|
||||||
|
|
||||||
const usersListValidator = [
|
export const usersListValidator = [
|
||||||
query('blocked')
|
query('blocked')
|
||||||
.optional()
|
.optional()
|
||||||
.customSanitizer(toBooleanOrNull)
|
.customSanitizer(toBooleanOrNull)
|
||||||
|
@ -53,7 +53,7 @@ const usersListValidator = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const usersAddValidator = [
|
export const usersAddValidator = [
|
||||||
body('username')
|
body('username')
|
||||||
.custom(isUserUsernameValid)
|
.custom(isUserUsernameValid)
|
||||||
.withMessage('Should have a valid username (lowercase alphanumeric characters)'),
|
.withMessage('Should have a valid username (lowercase alphanumeric characters)'),
|
||||||
|
@ -112,7 +112,7 @@ const usersAddValidator = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const usersRemoveValidator = [
|
export const usersRemoveValidator = [
|
||||||
param('id')
|
param('id')
|
||||||
.custom(isIdValid),
|
.custom(isIdValid),
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ const usersRemoveValidator = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const usersBlockingValidator = [
|
export const usersBlockingValidator = [
|
||||||
param('id')
|
param('id')
|
||||||
.custom(isIdValid),
|
.custom(isIdValid),
|
||||||
body('reason')
|
body('reason')
|
||||||
|
@ -149,7 +149,7 @@ const usersBlockingValidator = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const deleteMeValidator = [
|
export const deleteMeValidator = [
|
||||||
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
const user = res.locals.oauth.token.User
|
const user = res.locals.oauth.token.User
|
||||||
if (user.username === 'root') {
|
if (user.username === 'root') {
|
||||||
|
@ -160,7 +160,7 @@ const deleteMeValidator = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const usersUpdateValidator = [
|
export const usersUpdateValidator = [
|
||||||
param('id').custom(isIdValid),
|
param('id').custom(isIdValid),
|
||||||
|
|
||||||
body('password')
|
body('password')
|
||||||
|
@ -202,7 +202,7 @@ const usersUpdateValidator = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const usersUpdateMeValidator = [
|
export const usersUpdateMeValidator = [
|
||||||
body('displayName')
|
body('displayName')
|
||||||
.optional()
|
.optional()
|
||||||
.custom(isUserDisplayNameValid),
|
.custom(isUserDisplayNameValid),
|
||||||
|
@ -263,13 +263,14 @@ const usersUpdateMeValidator = [
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!req.body.currentPassword) {
|
if (!req.body.currentPassword) {
|
||||||
return res.fail({ message: 'currentPassword parameter is missing.' })
|
return res.fail({ message: 'currentPassword parameter is missing' })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await user.isPasswordMatch(req.body.currentPassword) !== true) {
|
if (await user.isPasswordMatch(req.body.currentPassword) !== true) {
|
||||||
return res.fail({
|
return res.fail({
|
||||||
status: HttpStatusCode.UNAUTHORIZED_401,
|
status: HttpStatusCode.UNAUTHORIZED_401,
|
||||||
message: 'currentPassword is invalid.'
|
message: 'currentPassword is invalid.',
|
||||||
|
type: ServerErrorCode.CURRENT_PASSWORD_IS_INVALID
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -280,7 +281,7 @@ const usersUpdateMeValidator = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const usersGetValidator = [
|
export const usersGetValidator = [
|
||||||
param('id')
|
param('id')
|
||||||
.custom(isIdValid),
|
.custom(isIdValid),
|
||||||
query('withStats')
|
query('withStats')
|
||||||
|
@ -295,7 +296,7 @@ const usersGetValidator = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const usersVideoRatingValidator = [
|
export const usersVideoRatingValidator = [
|
||||||
isValidVideoIdParam('videoId'),
|
isValidVideoIdParam('videoId'),
|
||||||
|
|
||||||
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
|
@ -306,7 +307,7 @@ const usersVideoRatingValidator = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const usersVideosValidator = [
|
export const usersVideosValidator = [
|
||||||
query('isLive')
|
query('isLive')
|
||||||
.optional()
|
.optional()
|
||||||
.customSanitizer(toBooleanOrNull)
|
.customSanitizer(toBooleanOrNull)
|
||||||
|
@ -326,7 +327,7 @@ const usersVideosValidator = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const usersAskResetPasswordValidator = [
|
export const usersAskResetPasswordValidator = [
|
||||||
body('email')
|
body('email')
|
||||||
.isEmail(),
|
.isEmail(),
|
||||||
|
|
||||||
|
@ -351,7 +352,7 @@ const usersAskResetPasswordValidator = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const usersResetPasswordValidator = [
|
export const usersResetPasswordValidator = [
|
||||||
param('id')
|
param('id')
|
||||||
.custom(isIdValid),
|
.custom(isIdValid),
|
||||||
body('verificationString')
|
body('verificationString')
|
||||||
|
@ -377,7 +378,7 @@ const usersResetPasswordValidator = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const usersCheckCurrentPasswordFactory = (targetUserIdGetter: (req: express.Request) => number | string) => {
|
export const usersCheckCurrentPasswordFactory = (targetUserIdGetter: (req: express.Request) => number | string) => {
|
||||||
return [
|
return [
|
||||||
body('currentPassword').optional().custom(exists),
|
body('currentPassword').optional().custom(exists),
|
||||||
|
|
||||||
|
@ -402,8 +403,9 @@ const usersCheckCurrentPasswordFactory = (targetUserIdGetter: (req: express.Requ
|
||||||
|
|
||||||
if (await user.isPasswordMatch(req.body.currentPassword) !== true) {
|
if (await user.isPasswordMatch(req.body.currentPassword) !== true) {
|
||||||
return res.fail({
|
return res.fail({
|
||||||
status: HttpStatusCode.FORBIDDEN_403,
|
status: HttpStatusCode.UNAUTHORIZED_401,
|
||||||
message: 'currentPassword is invalid.'
|
message: 'currentPassword is invalid.',
|
||||||
|
type: ServerErrorCode.CURRENT_PASSWORD_IS_INVALID
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,13 +414,13 @@ const usersCheckCurrentPasswordFactory = (targetUserIdGetter: (req: express.Requ
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
const userAutocompleteValidator = [
|
export const userAutocompleteValidator = [
|
||||||
param('search')
|
param('search')
|
||||||
.isString()
|
.isString()
|
||||||
.not().isEmpty()
|
.not().isEmpty()
|
||||||
]
|
]
|
||||||
|
|
||||||
const ensureAuthUserOwnsAccountValidator = [
|
export const ensureAuthUserOwnsAccountValidator = [
|
||||||
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
const user = res.locals.oauth.token.User
|
const user = res.locals.oauth.token.User
|
||||||
|
|
||||||
|
@ -428,7 +430,7 @@ const ensureAuthUserOwnsAccountValidator = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const ensureCanManageChannelOrAccount = [
|
export const ensureCanManageChannelOrAccount = [
|
||||||
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
const user = res.locals.oauth.token.user
|
const user = res.locals.oauth.token.user
|
||||||
const account = res.locals.videoChannel?.Account ?? res.locals.account
|
const account = res.locals.videoChannel?.Account ?? res.locals.account
|
||||||
|
@ -439,7 +441,7 @@ const ensureCanManageChannelOrAccount = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const ensureCanModerateUser = [
|
export const ensureCanModerateUser = [
|
||||||
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
const authUser = res.locals.oauth.token.User
|
const authUser = res.locals.oauth.token.User
|
||||||
const onUser = res.locals.user
|
const onUser = res.locals.user
|
||||||
|
@ -453,11 +455,3 @@ const ensureCanModerateUser = [
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
export {
|
|
||||||
deleteMeValidator, ensureAuthUserOwnsAccountValidator, ensureCanManageChannelOrAccount, ensureCanModerateUser, userAutocompleteValidator, usersAddValidator, usersAskResetPasswordValidator, usersBlockingValidator, usersCheckCurrentPasswordFactory,
|
|
||||||
usersGetValidator, usersListValidator, usersRemoveValidator, usersResetPasswordValidator, usersUpdateMeValidator, usersUpdateValidator, usersVideoRatingValidator, usersVideosValidator
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue