aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/core/auth/auth.service.ts
diff options
context:
space:
mode:
authorChocobozzz <florian.bigard@gmail.com>2017-09-14 11:57:49 +0200
committerChocobozzz <florian.bigard@gmail.com>2017-09-14 11:57:49 +0200
commitd592e0a9b2931c7c9cbedb27fb8efc9aaacad9bb (patch)
tree549b14b842de296efed846a11b3681efe08cfa9e /client/src/app/core/auth/auth.service.ts
parent91f6f169b1110eeae6ebf5c387f4204b0d07703c (diff)
downloadPeerTube-d592e0a9b2931c7c9cbedb27fb8efc9aaacad9bb.tar.gz
PeerTube-d592e0a9b2931c7c9cbedb27fb8efc9aaacad9bb.tar.zst
PeerTube-d592e0a9b2931c7c9cbedb27fb8efc9aaacad9bb.zip
Move to HttpClient and PrimeNG data table
Diffstat (limited to 'client/src/app/core/auth/auth.service.ts')
-rw-r--r--client/src/app/core/auth/auth.service.ts207
1 files changed, 97 insertions, 110 deletions
diff --git a/client/src/app/core/auth/auth.service.ts b/client/src/app/core/auth/auth.service.ts
index de9e14b2d..522efb23c 100644
--- a/client/src/app/core/auth/auth.service.ts
+++ b/client/src/app/core/auth/auth.service.ts
@@ -1,8 +1,8 @@
1import { Injectable } from '@angular/core' 1import { Injectable } from '@angular/core'
2import { Headers, Http, Response, URLSearchParams } from '@angular/http'
3import { Router } from '@angular/router' 2import { Router } from '@angular/router'
4import { Observable } from 'rxjs/Observable' 3import { Observable } from 'rxjs/Observable'
5import { Subject } from 'rxjs/Subject' 4import { Subject } from 'rxjs/Subject'
5import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'
6import 'rxjs/add/operator/map' 6import 'rxjs/add/operator/map'
7import 'rxjs/add/operator/mergeMap' 7import 'rxjs/add/operator/mergeMap'
8import 'rxjs/add/observable/throw' 8import 'rxjs/add/observable/throw'
@@ -11,15 +11,35 @@ import { NotificationsService } from 'angular2-notifications'
11 11
12import { AuthStatus } from './auth-status.model' 12import { AuthStatus } from './auth-status.model'
13import { AuthUser } from './auth-user.model' 13import { AuthUser } from './auth-user.model'
14import { OAuthClientLocal, UserRole } from '../../../../../shared' 14import { OAuthClientLocal, UserRole, UserRefreshToken } from '../../../../../shared'
15// Do not use the barrel (dependency loop) 15// Do not use the barrel (dependency loop)
16import { RestExtractor } from '../../shared/rest' 16import { RestExtractor } from '../../shared/rest'
17import { UserLogin } from '../../../../../shared/models/users/user-login.model'
18import { User } from '../../shared/users/user.model'
19
20interface UserLoginWithUsername extends UserLogin {
21 access_token: string
22 refresh_token: string
23 token_type: string
24 username: string
25}
26
27interface UserLoginWithUserInformation extends UserLogin {
28 access_token: string
29 refresh_token: string
30 token_type: string
31 username: string
32 id: number
33 role: UserRole
34 displayNSFW: boolean
35 email: string
36}
17 37
18@Injectable() 38@Injectable()
19export class AuthService { 39export class AuthService {
20 private static BASE_CLIENT_URL = API_URL + '/api/v1/oauth-clients/local' 40 private static BASE_CLIENT_URL = API_URL + '/api/v1/oauth-clients/local'
21 private static BASE_TOKEN_URL = API_URL + '/api/v1/users/token' 41 private static BASE_TOKEN_URL = API_URL + '/api/v1/users/token'
22 private static BASE_USER_INFORMATIONS_URL = API_URL + '/api/v1/users/me' 42 private static BASE_USER_INFORMATION_URL = API_URL + '/api/v1/users/me'
23 43
24 loginChangedSource: Observable<AuthStatus> 44 loginChangedSource: Observable<AuthStatus>
25 45
@@ -29,7 +49,7 @@ export class AuthService {
29 private user: AuthUser = null 49 private user: AuthUser = null
30 50
31 constructor ( 51 constructor (
32 private http: Http, 52 private http: HttpClient,
33 private notificationsService: NotificationsService, 53 private notificationsService: NotificationsService,
34 private restExtractor: RestExtractor, 54 private restExtractor: RestExtractor,
35 private router: Router 55 private router: Router
@@ -37,32 +57,33 @@ export class AuthService {
37 this.loginChanged = new Subject<AuthStatus>() 57 this.loginChanged = new Subject<AuthStatus>()
38 this.loginChangedSource = this.loginChanged.asObservable() 58 this.loginChangedSource = this.loginChanged.asObservable()
39 59
40 // Fetch the client_id/client_secret
41 // FIXME: save in local storage?
42 this.http.get(AuthService.BASE_CLIENT_URL)
43 .map(this.restExtractor.extractDataGet)
44 .catch(res => this.restExtractor.handleError(res))
45 .subscribe(
46 (result: OAuthClientLocal) => {
47 this.clientId = result.client_id
48 this.clientSecret = result.client_secret
49 console.log('Client credentials loaded.')
50 },
51
52 error => {
53 let errorMessage = `Cannot retrieve OAuth Client credentials: ${error.text}. \n`
54 errorMessage += 'Ensure you have correctly configured PeerTube (config/ directory), in particular the "webserver" section.'
55
56 // We put a bigger timeout
57 // This is an important message
58 this.notificationsService.error('Error', errorMessage, { timeOut: 7000 })
59 }
60 )
61
62 // Return null if there is nothing to load 60 // Return null if there is nothing to load
63 this.user = AuthUser.load() 61 this.user = AuthUser.load()
64 } 62 }
65 63
64 loadClientCredentials () {
65 // Fetch the client_id/client_secret
66 // FIXME: save in local storage?
67 this.http.get<OAuthClientLocal>(AuthService.BASE_CLIENT_URL)
68 .catch(res => this.restExtractor.handleError(res))
69 .subscribe(
70 res => {
71 this.clientId = res.client_id
72 this.clientSecret = res.client_secret
73 console.log('Client credentials loaded.')
74 },
75
76 error => {
77 let errorMessage = `Cannot retrieve OAuth Client credentials: ${error.text}. \n`
78 errorMessage += 'Ensure you have correctly configured PeerTube (config/ directory), in particular the "webserver" section.'
79
80 // We put a bigger timeout
81 // This is an important message
82 this.notificationsService.error('Error', errorMessage, { timeOut: 7000 })
83 }
84 )
85 }
86
66 getRefreshToken () { 87 getRefreshToken () {
67 if (this.user === null) return null 88 if (this.user === null) return null
68 89
@@ -70,7 +91,11 @@ export class AuthService {
70 } 91 }
71 92
72 getRequestHeaderValue () { 93 getRequestHeaderValue () {
73 return `${this.getTokenType()} ${this.getAccessToken()}` 94 const accessToken = this.getAccessToken()
95
96 if (accessToken === null) return null
97
98 return `${this.getTokenType()} ${accessToken}`
74 } 99 }
75 100
76 getAccessToken () { 101 getAccessToken () {
@@ -96,39 +121,26 @@ export class AuthService {
96 } 121 }
97 122
98 isLoggedIn () { 123 isLoggedIn () {
99 if (this.getAccessToken()) { 124 return !!this.getAccessToken()
100 return true
101 } else {
102 return false
103 }
104 } 125 }
105 126
106 login (username: string, password: string) { 127 login (username: string, password: string) {
107 let body = new URLSearchParams() 128 // Form url encoded
108 body.set('client_id', this.clientId) 129 const body = new HttpParams().set('client_id', this.clientId)
109 body.set('client_secret', this.clientSecret) 130 .set('client_secret', this.clientSecret)
110 body.set('response_type', 'code') 131 .set('response_type', 'code')
111 body.set('grant_type', 'password') 132 .set('grant_type', 'password')
112 body.set('scope', 'upload') 133 .set('scope', 'upload')
113 body.set('username', username) 134 .set('username', username)
114 body.set('password', password) 135 .set('password', password)
115 136
116 let headers = new Headers() 137 const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
117 headers.append('Content-Type', 'application/x-www-form-urlencoded') 138
118 139 return this.http.post<UserLogin>(AuthService.BASE_TOKEN_URL, body, { headers })
119 let options = { 140 .map(res => Object.assign(res, { username }))
120 headers: headers 141 .flatMap(res => this.mergeUserInformation(res))
121 }
122
123 return this.http.post(AuthService.BASE_TOKEN_URL, body.toString(), options)
124 .map(this.restExtractor.extractDataGet)
125 .map(res => {
126 res.username = username
127 return res
128 })
129 .flatMap(res => this.mergeUserInformations(res))
130 .map(res => this.handleLogin(res)) 142 .map(res => this.handleLogin(res))
131 .catch((res) => this.restExtractor.handleError(res)) 143 .catch(res => this.restExtractor.handleError(res))
132 } 144 }
133 145
134 logout () { 146 logout () {
@@ -145,33 +157,26 @@ export class AuthService {
145 157
146 const refreshToken = this.getRefreshToken() 158 const refreshToken = this.getRefreshToken()
147 159
148 let body = new URLSearchParams() 160 // Form url encoded
149 body.set('refresh_token', refreshToken) 161 const body = new HttpParams().set('refresh_token', refreshToken)
150 body.set('client_id', this.clientId) 162 .set('client_id', this.clientId)
151 body.set('client_secret', this.clientSecret) 163 .set('client_secret', this.clientSecret)
152 body.set('response_type', 'code') 164 .set('response_type', 'code')
153 body.set('grant_type', 'refresh_token') 165 .set('grant_type', 'refresh_token')
154
155 let headers = new Headers()
156 headers.append('Content-Type', 'application/x-www-form-urlencoded')
157 166
158 let options = { 167 const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
159 headers: headers
160 }
161 168
162 return this.http.post(AuthService.BASE_TOKEN_URL, body.toString(), options) 169 return this.http.post<UserRefreshToken>(AuthService.BASE_TOKEN_URL, body, { headers })
163 .map(this.restExtractor.extractDataGet)
164 .map(res => this.handleRefreshToken(res)) 170 .map(res => this.handleRefreshToken(res))
165 .catch((res: Response) => { 171 .catch(res => {
166 // The refresh token is invalid? 172 // The refresh token is invalid?
167 if (res.status === 400 && res.json() && res.json().error === 'invalid_grant') { 173 if (res.status === 400 && res.error === 'invalid_grant') {
168 console.error('Cannot refresh token -> logout...') 174 console.error('Cannot refresh token -> logout...')
169 this.logout() 175 this.logout()
170 this.router.navigate(['/login']) 176 this.router.navigate(['/login'])
171 177
172 return Observable.throw({ 178 return Observable.throw({
173 json: () => '', 179 error: 'You need to reconnect.'
174 text: () => 'You need to reconnect.'
175 }) 180 })
176 } 181 }
177 182
@@ -179,7 +184,7 @@ export class AuthService {
179 }) 184 })
180 } 185 }
181 186
182 refreshUserInformations () { 187 refreshUserInformation () {
183 const obj = { 188 const obj = {
184 access_token: this.user.getAccessToken(), 189 access_token: this.user.getAccessToken(),
185 refresh_token: null, 190 refresh_token: null,
@@ -187,7 +192,7 @@ export class AuthService {
187 username: this.user.username 192 username: this.user.username
188 } 193 }
189 194
190 this.mergeUserInformations (obj) 195 this.mergeUserInformation(obj)
191 .subscribe( 196 .subscribe(
192 res => { 197 res => {
193 this.user.displayNSFW = res.displayNSFW 198 this.user.displayNSFW = res.displayNSFW
@@ -198,42 +203,25 @@ export class AuthService {
198 ) 203 )
199 } 204 }
200 205
201 private mergeUserInformations (obj: { 206 private mergeUserInformation (obj: UserLoginWithUsername): Observable<UserLoginWithUserInformation> {
202 access_token: string, 207 // User is not loaded yet, set manually auth header
203 refresh_token: string, 208 const headers = new HttpHeaders().set('Authorization', `${obj.token_type} ${obj.access_token}`)
204 token_type: string, 209
205 username: string 210 return this.http.get<User>(AuthService.BASE_USER_INFORMATION_URL, { headers })
206 }) { 211 .map(res => {
207 // Do not call authHttp here to avoid circular dependencies headaches 212 const newProperties = {
208 213 id: res.id as number,
209 const headers = new Headers() 214 role: res.role as UserRole,
210 headers.set('Authorization', `Bearer ${obj.access_token}`) 215 displayNSFW: res.displayNSFW as boolean,
211 216 email: res.email as string
212 return this.http.get(AuthService.BASE_USER_INFORMATIONS_URL, { headers }) 217 }
213 .map(res => res.json())
214 .map(res => {
215 const newProperties = {
216 id: res.id as number,
217 role: res.role as UserRole,
218 displayNSFW: res.displayNSFW as boolean,
219 email: res.email as string
220 }
221 218
222 return Object.assign(obj, newProperties) 219 return Object.assign(obj, newProperties)
223 } 220 }
224 ) 221 )
225 } 222 }
226 223
227 private handleLogin (obj: { 224 private handleLogin (obj: UserLoginWithUserInformation) {
228 access_token: string,
229 refresh_token: string,
230 token_type: string,
231 id: number,
232 username: string,
233 email: string,
234 role: UserRole,
235 displayNSFW: boolean
236 }) {
237 const id = obj.id 225 const id = obj.id
238 const username = obj.username 226 const username = obj.username
239 const role = obj.role 227 const role = obj.role
@@ -251,7 +239,7 @@ export class AuthService {
251 this.setStatus(AuthStatus.LoggedIn) 239 this.setStatus(AuthStatus.LoggedIn)
252 } 240 }
253 241
254 private handleRefreshToken (obj: { access_token: string, refresh_token: string }) { 242 private handleRefreshToken (obj: UserRefreshToken) {
255 this.user.refreshTokens(obj.access_token, obj.refresh_token) 243 this.user.refreshTokens(obj.access_token, obj.refresh_token)
256 this.user.save() 244 this.user.save()
257 } 245 }
@@ -259,5 +247,4 @@ export class AuthService {
259 private setStatus (status: AuthStatus) { 247 private setStatus (status: AuthStatus) {
260 this.loginChanged.next(status) 248 this.loginChanged.next(status)
261 } 249 }
262
263} 250}