aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--client/src/app/+accounts/accounts.component.ts2
-rw-r--r--client/src/app/+page-not-found/page-not-found.component.html15
-rw-r--r--client/src/app/+page-not-found/page-not-found.component.ts22
-rw-r--r--client/src/app/+video-channels/video-channels.component.ts2
-rw-r--r--client/src/app/+videos/+video-watch/video-watch.component.ts13
-rw-r--r--client/src/app/core/rest/rest-extractor.service.ts4
-rw-r--r--client/src/app/shared/shared-main/auth/auth-interceptor.service.ts19
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 {
50 switchMap(accountId => this.accountService.getAccount(accountId)), 50 switchMap(accountId => this.accountService.getAccount(accountId)),
51 tap(account => this.onAccount(account)), 51 tap(account => this.onAccount(account)),
52 switchMap(account => this.videoChannelService.listAccountVideoChannels(account)), 52 switchMap(account => this.videoChannelService.listAccountVideoChannels(account)),
53 catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 53 catchError(err => this.restExtractor.redirectTo404IfNotFound(err, 'other', [
54 HttpStatusCode.BAD_REQUEST_400, 54 HttpStatusCode.BAD_REQUEST_400,
55 HttpStatusCode.NOT_FOUND_404 55 HttpStatusCode.NOT_FOUND_404
56 ])) 56 ]))
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 @@
1<div class="root"> 1<div class="root">
2 <div *ngIf="status === 404" class="box"> 2 <div *ngIf="status !== 403 && status !== 418" class="box">
3 <strong>{{ status }}.</strong> 3 <strong>{{ status }}.</strong>
4 <span class="ml-1 text-muted" i18n>That's an error.</span> 4 <span class="ml-1 text-muted" i18n>That's an error.</span>
5 5
6 <div class="text mt-4" i18n> 6 <div class="text mt-4" i18n>
7 We couldn't find any ressource tied to the URL {{ pathname }} you were looking for. 7 We couldn't find any {{ getRessourceName() }} tied to the URL {{ pathname }} you were looking for.
8 </div> 8 </div>
9 9
10 <div class="text-muted mt-4"> 10 <div class="text-muted mt-4">
11 <span i18n="Possible reasons preceding a list of reasons a `Not Found` error page may occur">Possible reasons:</span> 11 <span i18n="Possible reasons preceding a list of reasons a `Not Found` error page may occur">Possible reasons:</span>
12 12
13 <ul> 13 <ul>
14 <li i18n>The page may have been moved or deleted</li>
15 <li i18n>You may have used an outdated or broken link</li> 14 <li i18n>You may have used an outdated or broken link</li>
15 <li i18n>The {{ getRessourceName() }} may have been moved or deleted</li>
16 <li i18n>You may have typed the address or URL incorrectly</li> 16 <li i18n>You may have typed the address or URL incorrectly</li>
17 </ul> 17 </ul>
18 </div> 18 </div>
19 </div> 19 </div>
20 20
21 <div *ngIf="status === 403" class="box">
22 <strong>{{ status }}.</strong>
23 <span class="ml-1 text-muted" i18n>You are not authorized here.</span>
24
25 <div class="text mt-4" i18n>
26 You might need to check your account is allowed by the {{ getRessourceName() }} or instance owner.
27 </div>
28 </div>
29
21 <div *ngIf="status === 418" class="box"> 30 <div *ngIf="status === 418" class="box">
22 <strong>{{ status }}.</strong> 31 <strong>{{ status }}.</strong>
23 <span class="ml-1 text-muted">I'm a teapot.</span> 32 <span class="ml-1 text-muted">I'm a teapot.</span>
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 @@
1import { Component, OnInit } from '@angular/core' 1import { Component, OnInit } from '@angular/core'
2import { Title } from '@angular/platform-browser' 2import { Title } from '@angular/platform-browser'
3import { Router } from '@angular/router'
3import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' 4import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
4 5
5@Component({ 6@Component({
@@ -9,10 +10,16 @@ import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
9}) 10})
10export class PageNotFoundComponent implements OnInit { 11export class PageNotFoundComponent implements OnInit {
11 status = HttpStatusCode.NOT_FOUND_404 12 status = HttpStatusCode.NOT_FOUND_404
13 type: string
12 14
13 public constructor ( 15 public constructor (
14 private titleService: Title 16 private titleService: Title,
15 ) {} 17 private router: Router
18 ) {
19 const state = this.router.getCurrentNavigation()?.extras.state
20 this.type = state?.type || this.type
21 this.status = state?.obj.status || this.status
22 }
16 23
17 ngOnInit () { 24 ngOnInit () {
18 if (this.pathname.includes('teapot')) { 25 if (this.pathname.includes('teapot')) {
@@ -25,10 +32,21 @@ export class PageNotFoundComponent implements OnInit {
25 return window.location.pathname 32 return window.location.pathname
26 } 33 }
27 34
35 getRessourceName () {
36 switch (this.type) {
37 case 'video':
38 return $localize`video`
39 default:
40 return $localize`ressource`
41 }
42 }
43
28 getMascotName () { 44 getMascotName () {
29 switch (this.status) { 45 switch (this.status) {
30 case HttpStatusCode.I_AM_A_TEAPOT_418: 46 case HttpStatusCode.I_AM_A_TEAPOT_418:
31 return 'happy' 47 return 'happy'
48 case HttpStatusCode.FORBIDDEN_403:
49 return 'arguing'
32 case HttpStatusCode.NOT_FOUND_404: 50 case HttpStatusCode.NOT_FOUND_404:
33 default: 51 default:
34 return 'defeated' 52 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 {
38 map(params => params[ 'videoChannelName' ]), 38 map(params => params[ 'videoChannelName' ]),
39 distinctUntilChanged(), 39 distinctUntilChanged(),
40 switchMap(videoChannelName => this.videoChannelService.getVideoChannel(videoChannelName)), 40 switchMap(videoChannelName => this.videoChannelService.getVideoChannel(videoChannelName)),
41 catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 41 catchError(err => this.restExtractor.redirectTo404IfNotFound(err, 'other', [
42 HttpStatusCode.BAD_REQUEST_400, 42 HttpStatusCode.BAD_REQUEST_400,
43 HttpStatusCode.NOT_FOUND_404 43 HttpStatusCode.NOT_FOUND_404
44 ])) 44 ]))
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 {
404 this.videoCaptionService.listCaptions(videoId) 404 this.videoCaptionService.listCaptions(videoId)
405 ]) 405 ])
406 .pipe( 406 .pipe(
407 // If 401, the video is private or blocked so redirect to 404 407 // If 400, 403 or 404, the video is private or blocked so redirect to 404
408 catchError(err => { 408 catchError(err => {
409 if (err.body.errorCode === ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS && err.body.originUrl) { 409 if (err.body.errorCode === ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS && err.body.originUrl) {
410 const search = window.location.search 410 const search = window.location.search
@@ -416,9 +416,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
416 $localize`Redirection` 416 $localize`Redirection`
417 ).then(res => { 417 ).then(res => {
418 if (res === false) { 418 if (res === false) {
419 return this.restExtractor.redirectTo404IfNotFound(err, [ 419 return this.restExtractor.redirectTo404IfNotFound(err, 'video', [
420 HttpStatusCode.BAD_REQUEST_400, 420 HttpStatusCode.BAD_REQUEST_400,
421 HttpStatusCode.UNAUTHORIZED_401,
422 HttpStatusCode.FORBIDDEN_403, 421 HttpStatusCode.FORBIDDEN_403,
423 HttpStatusCode.NOT_FOUND_404 422 HttpStatusCode.NOT_FOUND_404
424 ]) 423 ])
@@ -428,9 +427,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
428 }) 427 })
429 } 428 }
430 429
431 return this.restExtractor.redirectTo404IfNotFound(err, [ 430 return this.restExtractor.redirectTo404IfNotFound(err, 'video', [
432 HttpStatusCode.BAD_REQUEST_400, 431 HttpStatusCode.BAD_REQUEST_400,
433 HttpStatusCode.UNAUTHORIZED_401,
434 HttpStatusCode.FORBIDDEN_403, 432 HttpStatusCode.FORBIDDEN_403,
435 HttpStatusCode.NOT_FOUND_404 433 HttpStatusCode.NOT_FOUND_404
436 ]) 434 ])
@@ -464,10 +462,9 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
464 462
465 this.playlistService.getVideoPlaylist(playlistId) 463 this.playlistService.getVideoPlaylist(playlistId)
466 .pipe( 464 .pipe(
467 // If 401, the video is private or blocked so redirect to 404 465 // If 400 or 403, the video is private or blocked so redirect to 404
468 catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 466 catchError(err => this.restExtractor.redirectTo404IfNotFound(err, 'video', [
469 HttpStatusCode.BAD_REQUEST_400, 467 HttpStatusCode.BAD_REQUEST_400,
470 HttpStatusCode.UNAUTHORIZED_401,
471 HttpStatusCode.FORBIDDEN_403, 468 HttpStatusCode.FORBIDDEN_403,
472 HttpStatusCode.NOT_FOUND_404 469 HttpStatusCode.NOT_FOUND_404
473 ])) 470 ]))
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 {
93 return observableThrowError(errorObj) 93 return observableThrowError(errorObj)
94 } 94 }
95 95
96 redirectTo404IfNotFound (obj: { status: number }, status = [ HttpStatusCode.NOT_FOUND_404 ]) { 96 redirectTo404IfNotFound (obj: { status: number }, type: 'video' | 'other', status = [ HttpStatusCode.NOT_FOUND_404 ]) {
97 if (obj && obj.status && status.indexOf(obj.status) !== -1) { 97 if (obj && obj.status && status.indexOf(obj.status) !== -1) {
98 // Do not use redirectService to avoid circular dependencies 98 // Do not use redirectService to avoid circular dependencies
99 this.router.navigate([ '/404' ], { skipLocationChange: true }) 99 this.router.navigate([ '/404' ], { state: { type, obj }, skipLocationChange: true })
100 } 100 }
101 101
102 return observableThrowError(obj) 102 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 @@
1import { Observable, throwError as observableThrowError } from 'rxjs' 1import { Observable, of, throwError as observableThrowError } from 'rxjs'
2import { catchError, switchMap } from 'rxjs/operators' 2import { catchError, switchMap } from 'rxjs/operators'
3import { HTTP_INTERCEPTORS, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http' 3import { HTTP_INTERCEPTORS, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpErrorResponse } from '@angular/common/http'
4import { Injectable, Injector } from '@angular/core' 4import { Injectable, Injector } from '@angular/core'
5import { AuthService } from '@app/core/auth/auth.service' 5import { AuthService } from '@app/core/auth/auth.service'
6import { Router } from '@angular/router'
7import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
6 8
7@Injectable() 9@Injectable()
8export class AuthInterceptor implements HttpInterceptor { 10export class AuthInterceptor implements HttpInterceptor {
9 private authService: AuthService 11 private authService: AuthService
10 12
11 // https://github.com/angular/angular/issues/18224#issuecomment-316957213 13 // https://github.com/angular/angular/issues/18224#issuecomment-316957213
12 constructor (private injector: Injector) {} 14 constructor (private injector: Injector, private router: Router) {}
13 15
14 intercept (req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { 16 intercept (req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
15 if (this.authService === undefined) { 17 if (this.authService === undefined) {
@@ -22,9 +24,11 @@ export class AuthInterceptor implements HttpInterceptor {
22 // Catch 401 errors (refresh token expired) 24 // Catch 401 errors (refresh token expired)
23 return next.handle(authReq) 25 return next.handle(authReq)
24 .pipe( 26 .pipe(
25 catchError(err => { 27 catchError((err: HttpErrorResponse) => {
26 if (err.status === 401 && err.error && err.error.code === 'invalid_token') { 28 if (err.status === HttpStatusCode.UNAUTHORIZED_401 && err.error && err.error.code === 'invalid_token') {
27 return this.handleTokenExpired(req, next) 29 return this.handleTokenExpired(req, next)
30 } else if (err.status === HttpStatusCode.UNAUTHORIZED_401) {
31 return this.handleNotAuthenticated(err)
28 } 32 }
29 33
30 return observableThrowError(err) 34 return observableThrowError(err)
@@ -51,6 +55,11 @@ export class AuthInterceptor implements HttpInterceptor {
51 // Clone the request to add the new header 55 // Clone the request to add the new header
52 return req.clone({ headers: req.headers.set('Authorization', authHeaderValue) }) 56 return req.clone({ headers: req.headers.set('Authorization', authHeaderValue) })
53 } 57 }
58
59 private handleNotAuthenticated (err: HttpErrorResponse, path = '/login'): Observable<any> {
60 this.router.navigateByUrl(path)
61 return of(err.message)
62 }
54} 63}
55 64
56export const AUTH_INTERCEPTOR_PROVIDER = { 65export const AUTH_INTERCEPTOR_PROVIDER = {