import { Hotkey, HotkeysService } from 'angular2-hotkeys'
import { Observable, ReplaySubject, Subject, throwError as observableThrowError } from 'rxjs'
import { catchError, map, mergeMap, share, tap } from 'rxjs/operators'
-import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'
+import { HttpClient, HttpErrorResponse, HttpHeaders, HttpParams } from '@angular/common/http'
import { Injectable } from '@angular/core'
import { Router } from '@angular/router'
import { Notifier } from '@app/core/notification/notifier.service'
-import { logger, objectToUrlEncoded, peertubeLocalStorage, UserTokens } from '@root-helpers/index'
+import { logger, OAuthUserTokens, objectToUrlEncoded, peertubeLocalStorage } from '@root-helpers/index'
import { HttpStatusCode, MyUser as UserServerModel, OAuthClientLocal, User, UserLogin, UserRefreshToken } from '@shared/models'
import { environment } from '../../../environments/environment'
import { RestExtractor } from '../rest/rest-extractor.service'
+import { RedirectService } from '../routing'
import { AuthStatus } from './auth-status.model'
import { AuthUser } from './auth-user.model'
private refreshingTokenObservable: Observable<any>
constructor (
+ private redirectService: RedirectService,
private http: HttpClient,
private notifier: Notifier,
private hotkeysService: HotkeysService,
]
}
- buildAuthUser (userInfo: Partial<User>, tokens: UserTokens) {
+ buildAuthUser (userInfo: Partial<User>, tokens: OAuthUserTokens) {
this.user = new AuthUser(userInfo, tokens)
}
return !!this.getAccessToken()
}
- login (username: string, password: string, token?: string) {
+ login (options: {
+ username: string
+ password: string
+ otpToken?: string
+ token?: string
+ }) {
+ const { username, password, token, otpToken } = options
+
// Form url encoded
const body = {
client_id: this.clientId,
if (token) Object.assign(body, { externalAuthToken: token })
- const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
+ let headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
+ if (otpToken) headers = headers.set('x-peertube-otp', otpToken)
+
return this.http.post<UserLogin>(AuthService.BASE_TOKEN_URL, objectToUrlEncoded(body), { headers })
.pipe(
map(res => Object.assign(res, { username })),
const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
this.refreshingTokenObservable = this.http.post<UserRefreshToken>(AuthService.BASE_TOKEN_URL, body, { headers })
- .pipe(
- map(res => this.handleRefreshToken(res)),
- tap(() => {
- this.refreshingTokenObservable = null
- }),
- catchError(err => {
- this.refreshingTokenObservable = null
-
- logger.error(err)
- logger.info('Cannot refresh token -> logout...')
- this.logout()
- this.router.navigate([ '/login' ])
-
- return observableThrowError(() => ({
- error: $localize`You need to reconnect.`
- }))
- }),
- share()
- )
+ .pipe(
+ map(res => this.handleRefreshToken(res)),
+ tap(() => {
+ this.refreshingTokenObservable = null
+ }),
+ catchError(err => {
+ this.refreshingTokenObservable = null
+
+ logger.error(err)
+ logger.info('Cannot refresh token -> logout...')
+ this.logout()
+
+ this.redirectService.redirectToLogin()
+
+ return observableThrowError(() => ({
+ error: $localize`You need to reconnect.`
+ }))
+ }),
+ share()
+ )
return this.refreshingTokenObservable
}
})
}
+ isOTPMissingError (err: HttpErrorResponse) {
+ if (err.status !== HttpStatusCode.UNAUTHORIZED_401) return false
+
+ if (err.headers.get('x-peertube-otp') !== 'required; app') return false
+
+ return true
+ }
+
private mergeUserInformation (obj: UserLoginWithUsername): Observable<UserLoginWithUserInformation> {
// User is not loaded yet, set manually auth header
const headers = new HttpHeaders().set('Authorization', `${obj.token_type} ${obj.access_token}`)