Correctly handle invalid current password

This commit is contained in:
Chocobozzz 2024-07-31 08:35:24 +02:00
parent d0304f6712
commit a9d08d2646
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
3 changed files with 47 additions and 47 deletions

View File

@ -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>> {

View File

@ -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
/** /**

View File

@ -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
}