]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - client/src/app/core/auth/auth.service.ts
Remove ng2-completer
[github/Chocobozzz/PeerTube.git] / client / src / app / core / auth / auth.service.ts
CommitLineData
df98563e
C
1import { Injectable } from '@angular/core'
2import { Headers, Http, Response, URLSearchParams } from '@angular/http'
3import { Router } from '@angular/router'
4import { Observable } from 'rxjs/Observable'
5import { Subject } from 'rxjs/Subject'
6import 'rxjs/add/operator/map'
7import 'rxjs/add/operator/mergeMap'
8import 'rxjs/add/observable/throw'
9
10import { NotificationsService } from 'angular2-notifications'
11
12import { AuthStatus } from './auth-status.model'
13import { AuthUser } from './auth-user.model'
154898b0 14import { ClientLocal } from '../../../../../shared'
693b1aba 15// Do not use the barrel (dependency loop)
df98563e 16import { RestExtractor } from '../../shared/rest'
b1794c53
C
17
18@Injectable()
19export class AuthService {
df98563e
C
20 private static BASE_CLIENT_URL = API_URL + '/api/v1/clients/local'
21 private static BASE_TOKEN_URL = API_URL + '/api/v1/users/token'
22 private static BASE_USER_INFORMATIONS_URL = API_URL + '/api/v1/users/me'
b1794c53 23
df98563e 24 loginChangedSource: Observable<AuthStatus>
b1794c53 25
df98563e
C
26 private clientId: string
27 private clientSecret: string
28 private loginChanged: Subject<AuthStatus>
29 private user: AuthUser = null
ccf6ed16 30
df98563e 31 constructor (
14ad0c27 32 private http: Http,
7ddd02c9 33 private notificationsService: NotificationsService,
14ad0c27
C
34 private restExtractor: RestExtractor,
35 private router: Router
36 ) {
df98563e
C
37 this.loginChanged = new Subject<AuthStatus>()
38 this.loginChangedSource = this.loginChanged.asObservable()
23a5a916
C
39
40 // Fetch the client_id/client_secret
41 // FIXME: save in local storage?
ccf6ed16 42 this.http.get(AuthService.BASE_CLIENT_URL)
de59c48f 43 .map(this.restExtractor.extractDataGet)
154898b0 44 .catch(res => this.restExtractor.handleError(res))
23a5a916 45 .subscribe(
154898b0 46 (result: ClientLocal) => {
df98563e
C
47 this.clientId = result.client_id
48 this.clientSecret = result.client_secret
49 console.log('Client credentials loaded.')
23a5a916 50 },
7ddd02c9 51
23a5a916 52 error => {
df98563e
C
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.'
7ddd02c9
C
55
56 // We put a bigger timeout
57 // This is an important message
df98563e 58 this.notificationsService.error('Error', errorMessage, { timeOut: 7000 })
23a5a916 59 }
df98563e 60 )
bd5c83a8
C
61
62 // Return null if there is nothing to load
df98563e 63 this.user = AuthUser.load()
1553e15d 64 }
b1794c53 65
df98563e
C
66 getRefreshToken () {
67 if (this.user === null) return null
bd5c83a8 68
df98563e 69 return this.user.getRefreshToken()
bd5c83a8
C
70 }
71
df98563e
C
72 getRequestHeaderValue () {
73 return `${this.getTokenType()} ${this.getAccessToken()}`
1553e15d
C
74 }
75
df98563e
C
76 getAccessToken () {
77 if (this.user === null) return null
bd5c83a8 78
df98563e 79 return this.user.getAccessToken()
1553e15d
C
80 }
81
df98563e
C
82 getTokenType () {
83 if (this.user === null) return null
bd5c83a8 84
df98563e 85 return this.user.getTokenType()
1553e15d
C
86 }
87
df98563e
C
88 getUser () {
89 return this.user
1553e15d
C
90 }
91
df98563e
C
92 isAdmin () {
93 if (this.user === null) return false
7da18e44 94
df98563e 95 return this.user.isAdmin()
7da18e44
C
96 }
97
df98563e 98 isLoggedIn () {
0f3a78e7 99 if (this.getAccessToken()) {
df98563e 100 return true
1553e15d 101 } else {
df98563e 102 return false
1553e15d
C
103 }
104 }
105
df98563e
C
106 login (username: string, password: string) {
107 let body = new URLSearchParams()
108 body.set('client_id', this.clientId)
109 body.set('client_secret', this.clientSecret)
110 body.set('response_type', 'code')
111 body.set('grant_type', 'password')
112 body.set('scope', 'upload')
113 body.set('username', username)
114 body.set('password', password)
4fd8aa32 115
df98563e
C
116 let headers = new Headers()
117 headers.append('Content-Type', 'application/x-www-form-urlencoded')
4fd8aa32
C
118
119 let options = {
120 headers: headers
df98563e 121 }
4fd8aa32 122
bd5c83a8 123 return this.http.post(AuthService.BASE_TOKEN_URL, body.toString(), options)
de59c48f 124 .map(this.restExtractor.extractDataGet)
bd5c83a8 125 .map(res => {
df98563e
C
126 res.username = username
127 return res
bd5c83a8 128 })
af5e743b 129 .flatMap(res => this.mergeUserInformations(res))
bd5c83a8 130 .map(res => this.handleLogin(res))
df98563e 131 .catch((res) => this.restExtractor.handleError(res))
4fd8aa32
C
132 }
133
df98563e 134 logout () {
bd5c83a8 135 // TODO: make an HTTP request to revoke the tokens
df98563e 136 this.user = null
724fed29 137
df98563e 138 AuthUser.flush()
e62f6ef7 139
df98563e 140 this.setStatus(AuthStatus.LoggedOut)
bd5c83a8
C
141 }
142
df98563e
C
143 refreshAccessToken () {
144 console.log('Refreshing token...')
bd5c83a8 145
df98563e 146 const refreshToken = this.getRefreshToken()
bd5c83a8 147
df98563e
C
148 let body = new URLSearchParams()
149 body.set('refresh_token', refreshToken)
150 body.set('client_id', this.clientId)
151 body.set('client_secret', this.clientSecret)
152 body.set('response_type', 'code')
153 body.set('grant_type', 'refresh_token')
bd5c83a8 154
df98563e
C
155 let headers = new Headers()
156 headers.append('Content-Type', 'application/x-www-form-urlencoded')
bd5c83a8
C
157
158 let options = {
159 headers: headers
df98563e 160 }
bd5c83a8
C
161
162 return this.http.post(AuthService.BASE_TOKEN_URL, body.toString(), options)
de59c48f 163 .map(this.restExtractor.extractDataGet)
bd5c83a8 164 .map(res => this.handleRefreshToken(res))
14ad0c27
C
165 .catch((res: Response) => {
166 // The refresh token is invalid?
167 if (res.status === 400 && res.json() && res.json().error === 'invalid_grant') {
df98563e
C
168 console.error('Cannot refresh token -> logout...')
169 this.logout()
170 this.router.navigate(['/login'])
14ad0c27
C
171
172 return Observable.throw({
c0a89c46
C
173 json: () => '',
174 text: () => 'You need to reconnect.'
df98563e 175 })
14ad0c27
C
176 }
177
df98563e
C
178 return this.restExtractor.handleError(res)
179 })
4fd8aa32
C
180 }
181
df98563e 182 refreshUserInformations () {
af5e743b
C
183 const obj = {
184 access_token: this.user.getAccessToken()
df98563e 185 }
af5e743b 186
df98563e 187 this.mergeUserInformations (obj)
af5e743b
C
188 .subscribe(
189 res => {
df98563e
C
190 this.user.displayNSFW = res.displayNSFW
191 this.user.role = res.role
af5e743b 192
df98563e 193 this.user.save()
af5e743b 194 }
df98563e 195 )
af5e743b
C
196 }
197
df98563e 198 private mergeUserInformations (obj: { access_token: string }) {
629d8d6f
C
199 // Do not call authHttp here to avoid circular dependencies headaches
200
df98563e
C
201 const headers = new Headers()
202 headers.set('Authorization', `Bearer ${obj.access_token}`)
629d8d6f
C
203
204 return this.http.get(AuthService.BASE_USER_INFORMATIONS_URL, { headers })
205 .map(res => res.json())
206 .map(res => {
af5e743b
C
207 const newProperties = {
208 id: res.id,
209 role: res.role,
210 displayNSFW: res.displayNSFW
df98563e 211 }
af5e743b 212
df98563e 213 return Object.assign(obj, newProperties)
629d8d6f 214 }
df98563e 215 )
b1794c53
C
216 }
217
bd5c83a8 218 private handleLogin (obj: any) {
df98563e
C
219 const id = obj.id
220 const username = obj.username
221 const role = obj.role
222 const email = obj.email
223 const displayNSFW = obj.displayNSFW
7da18e44 224 const hashTokens = {
df98563e
C
225 accessToken: obj.access_token,
226 tokenType: obj.token_type,
227 refreshToken: obj.refresh_token
228 }
bd5c83a8 229
df98563e
C
230 this.user = new AuthUser({ id, username, role, displayNSFW, email }, hashTokens)
231 this.user.save()
bd5c83a8 232
df98563e 233 this.setStatus(AuthStatus.LoggedIn)
bd5c83a8
C
234 }
235
bd5c83a8 236 private handleRefreshToken (obj: any) {
df98563e
C
237 this.user.refreshTokens(obj.access_token, obj.refresh_token)
238 this.user.save()
bd5c83a8 239 }
629d8d6f 240
df98563e
C
241 private setStatus (status: AuthStatus) {
242 this.loginChanged.next(status)
629d8d6f
C
243 }
244
b1794c53 245}