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