From ab398a05e9ffaacb8fc713bb2ba9717ac463b34c Mon Sep 17 00:00:00 2001 From: Rigel Kent Date: Sun, 24 Jan 2021 03:02:04 +0100 Subject: [PATCH] redirect to login on 401, display error variants in 404 component --- .../src/app/+accounts/accounts.component.ts | 2 +- .../page-not-found.component.html | 15 ++++++++++--- .../page-not-found.component.ts | 22 +++++++++++++++++-- .../video-channels.component.ts | 2 +- .../+video-watch/video-watch.component.ts | 13 +++++------ .../app/core/rest/rest-extractor.service.ts | 4 ++-- .../auth/auth-interceptor.service.ts | 19 +++++++++++----- 7 files changed, 55 insertions(+), 22 deletions(-) diff --git a/client/src/app/+accounts/accounts.component.ts b/client/src/app/+accounts/accounts.component.ts index 1458ea59c..e6a5a5d5e 100644 --- a/client/src/app/+accounts/accounts.component.ts +++ b/client/src/app/+accounts/accounts.component.ts @@ -50,7 +50,7 @@ export class AccountsComponent implements OnInit, OnDestroy { switchMap(accountId => this.accountService.getAccount(accountId)), tap(account => this.onAccount(account)), switchMap(account => this.videoChannelService.listAccountVideoChannels(account)), - catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ + catchError(err => this.restExtractor.redirectTo404IfNotFound(err, 'other', [ HttpStatusCode.BAD_REQUEST_400, HttpStatusCode.NOT_FOUND_404 ])) diff --git a/client/src/app/+page-not-found/page-not-found.component.html b/client/src/app/+page-not-found/page-not-found.component.html index aa57b07e8..efd3cc9f9 100644 --- a/client/src/app/+page-not-found/page-not-found.component.html +++ b/client/src/app/+page-not-found/page-not-found.component.html @@ -1,23 +1,32 @@
-
+
{{ status }}. That's an error.
- We couldn't find any ressource tied to the URL {{ pathname }} you were looking for. + We couldn't find any {{ getRessourceName() }} tied to the URL {{ pathname }} you were looking for.
Possible reasons:
    -
  • The page may have been moved or deleted
  • You may have used an outdated or broken link
  • +
  • The {{ getRessourceName() }} may have been moved or deleted
  • You may have typed the address or URL incorrectly
+
+ {{ status }}. + You are not authorized here. + +
+ You might need to check your account is allowed by the {{ getRessourceName() }} or instance owner. +
+
+
{{ status }}. I'm a teapot. diff --git a/client/src/app/+page-not-found/page-not-found.component.ts b/client/src/app/+page-not-found/page-not-found.component.ts index 81830d415..9302201ea 100644 --- a/client/src/app/+page-not-found/page-not-found.component.ts +++ b/client/src/app/+page-not-found/page-not-found.component.ts @@ -1,5 +1,6 @@ import { Component, OnInit } from '@angular/core' import { Title } from '@angular/platform-browser' +import { Router } from '@angular/router' import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' @Component({ @@ -9,10 +10,16 @@ import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' }) export class PageNotFoundComponent implements OnInit { status = HttpStatusCode.NOT_FOUND_404 + type: string public constructor ( - private titleService: Title - ) {} + private titleService: Title, + private router: Router + ) { + const state = this.router.getCurrentNavigation()?.extras.state + this.type = state?.type || this.type + this.status = state?.obj.status || this.status + } ngOnInit () { if (this.pathname.includes('teapot')) { @@ -25,10 +32,21 @@ export class PageNotFoundComponent implements OnInit { return window.location.pathname } + getRessourceName () { + switch (this.type) { + case 'video': + return $localize`video` + default: + return $localize`ressource` + } + } + getMascotName () { switch (this.status) { case HttpStatusCode.I_AM_A_TEAPOT_418: return 'happy' + case HttpStatusCode.FORBIDDEN_403: + return 'arguing' case HttpStatusCode.NOT_FOUND_404: default: return 'defeated' diff --git a/client/src/app/+video-channels/video-channels.component.ts b/client/src/app/+video-channels/video-channels.component.ts index d2fd265c4..bb601e227 100644 --- a/client/src/app/+video-channels/video-channels.component.ts +++ b/client/src/app/+video-channels/video-channels.component.ts @@ -38,7 +38,7 @@ export class VideoChannelsComponent implements OnInit, OnDestroy { map(params => params[ 'videoChannelName' ]), distinctUntilChanged(), switchMap(videoChannelName => this.videoChannelService.getVideoChannel(videoChannelName)), - catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ + catchError(err => this.restExtractor.redirectTo404IfNotFound(err, 'other', [ HttpStatusCode.BAD_REQUEST_400, HttpStatusCode.NOT_FOUND_404 ])) diff --git a/client/src/app/+videos/+video-watch/video-watch.component.ts b/client/src/app/+videos/+video-watch/video-watch.component.ts index c757a5e93..b698d554f 100644 --- a/client/src/app/+videos/+video-watch/video-watch.component.ts +++ b/client/src/app/+videos/+video-watch/video-watch.component.ts @@ -404,7 +404,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { this.videoCaptionService.listCaptions(videoId) ]) .pipe( - // If 401, the video is private or blocked so redirect to 404 + // If 400, 403 or 404, the video is private or blocked so redirect to 404 catchError(err => { if (err.body.errorCode === ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS && err.body.originUrl) { const search = window.location.search @@ -416,9 +416,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy { $localize`Redirection` ).then(res => { if (res === false) { - return this.restExtractor.redirectTo404IfNotFound(err, [ + return this.restExtractor.redirectTo404IfNotFound(err, 'video', [ HttpStatusCode.BAD_REQUEST_400, - HttpStatusCode.UNAUTHORIZED_401, HttpStatusCode.FORBIDDEN_403, HttpStatusCode.NOT_FOUND_404 ]) @@ -428,9 +427,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy { }) } - return this.restExtractor.redirectTo404IfNotFound(err, [ + return this.restExtractor.redirectTo404IfNotFound(err, 'video', [ HttpStatusCode.BAD_REQUEST_400, - HttpStatusCode.UNAUTHORIZED_401, HttpStatusCode.FORBIDDEN_403, HttpStatusCode.NOT_FOUND_404 ]) @@ -464,10 +462,9 @@ export class VideoWatchComponent implements OnInit, OnDestroy { this.playlistService.getVideoPlaylist(playlistId) .pipe( - // If 401, the video is private or blocked so redirect to 404 - catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ + // If 400 or 403, the video is private or blocked so redirect to 404 + catchError(err => this.restExtractor.redirectTo404IfNotFound(err, 'video', [ HttpStatusCode.BAD_REQUEST_400, - HttpStatusCode.UNAUTHORIZED_401, HttpStatusCode.FORBIDDEN_403, HttpStatusCode.NOT_FOUND_404 ])) diff --git a/client/src/app/core/rest/rest-extractor.service.ts b/client/src/app/core/rest/rest-extractor.service.ts index 84d9ed074..b8a95cca6 100644 --- a/client/src/app/core/rest/rest-extractor.service.ts +++ b/client/src/app/core/rest/rest-extractor.service.ts @@ -93,10 +93,10 @@ export class RestExtractor { return observableThrowError(errorObj) } - redirectTo404IfNotFound (obj: { status: number }, status = [ HttpStatusCode.NOT_FOUND_404 ]) { + redirectTo404IfNotFound (obj: { status: number }, type: 'video' | 'other', status = [ HttpStatusCode.NOT_FOUND_404 ]) { if (obj && obj.status && status.indexOf(obj.status) !== -1) { // Do not use redirectService to avoid circular dependencies - this.router.navigate([ '/404' ], { skipLocationChange: true }) + this.router.navigate([ '/404' ], { state: { type, obj }, skipLocationChange: true }) } return observableThrowError(obj) diff --git a/client/src/app/shared/shared-main/auth/auth-interceptor.service.ts b/client/src/app/shared/shared-main/auth/auth-interceptor.service.ts index 68a4acdb5..3ddaffbdf 100644 --- a/client/src/app/shared/shared-main/auth/auth-interceptor.service.ts +++ b/client/src/app/shared/shared-main/auth/auth-interceptor.service.ts @@ -1,15 +1,17 @@ -import { Observable, throwError as observableThrowError } from 'rxjs' +import { Observable, of, throwError as observableThrowError } from 'rxjs' import { catchError, switchMap } from 'rxjs/operators' -import { HTTP_INTERCEPTORS, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http' +import { HTTP_INTERCEPTORS, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpErrorResponse } from '@angular/common/http' import { Injectable, Injector } from '@angular/core' import { AuthService } from '@app/core/auth/auth.service' +import { Router } from '@angular/router' +import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' @Injectable() export class AuthInterceptor implements HttpInterceptor { private authService: AuthService // https://github.com/angular/angular/issues/18224#issuecomment-316957213 - constructor (private injector: Injector) {} + constructor (private injector: Injector, private router: Router) {} intercept (req: HttpRequest, next: HttpHandler): Observable> { if (this.authService === undefined) { @@ -22,9 +24,11 @@ export class AuthInterceptor implements HttpInterceptor { // Catch 401 errors (refresh token expired) return next.handle(authReq) .pipe( - catchError(err => { - if (err.status === 401 && err.error && err.error.code === 'invalid_token') { + catchError((err: HttpErrorResponse) => { + if (err.status === HttpStatusCode.UNAUTHORIZED_401 && err.error && err.error.code === 'invalid_token') { return this.handleTokenExpired(req, next) + } else if (err.status === HttpStatusCode.UNAUTHORIZED_401) { + return this.handleNotAuthenticated(err) } return observableThrowError(err) @@ -51,6 +55,11 @@ export class AuthInterceptor implements HttpInterceptor { // Clone the request to add the new header return req.clone({ headers: req.headers.set('Authorization', authHeaderValue) }) } + + private handleNotAuthenticated (err: HttpErrorResponse, path = '/login'): Observable { + this.router.navigateByUrl(path) + return of(err.message) + } } export const AUTH_INTERCEPTOR_PROVIDER = {