]>
Commit | Line | Data |
---|---|---|
f1a0f3b7 C |
1 | import { HttpStatusCode, OAuth2ErrorCode, UserRefreshToken } from '../../../../../shared/models' |
2 | import { objectToUrlEncoded, UserTokens } from '../../../root-helpers' | |
3 | import { peertubeLocalStorage } from '../../../root-helpers/peertube-web-storage' | |
4 | ||
5 | export class AuthHTTP { | |
6 | private readonly LOCAL_STORAGE_OAUTH_CLIENT_KEYS = { | |
7 | CLIENT_ID: 'client_id', | |
8 | CLIENT_SECRET: 'client_secret' | |
9 | } | |
10 | ||
11 | private userTokens: UserTokens | |
12 | ||
13 | private headers = new Headers() | |
14 | ||
15 | constructor () { | |
16 | this.userTokens = UserTokens.getUserTokens(peertubeLocalStorage) | |
17 | ||
18 | if (this.userTokens) this.setHeadersFromTokens() | |
19 | } | |
20 | ||
21 | fetch (url: string, { optionalAuth }: { optionalAuth: boolean }) { | |
22 | const refreshFetchOptions = optionalAuth | |
23 | ? { headers: this.headers } | |
24 | : {} | |
25 | ||
26 | return this.refreshFetch(url.toString(), refreshFetchOptions) | |
27 | } | |
28 | ||
29 | getHeaderTokenValue () { | |
30 | return `${this.userTokens.tokenType} ${this.userTokens.accessToken}` | |
31 | } | |
32 | ||
33 | isLoggedIn () { | |
34 | return !!this.userTokens | |
35 | } | |
36 | ||
37 | private refreshFetch (url: string, options?: RequestInit) { | |
38 | return fetch(url, options) | |
39 | .then((res: Response) => { | |
40 | if (res.status !== HttpStatusCode.UNAUTHORIZED_401) return res | |
41 | ||
42 | const refreshingTokenPromise = new Promise<void>((resolve, reject) => { | |
43 | const clientId: string = peertubeLocalStorage.getItem(this.LOCAL_STORAGE_OAUTH_CLIENT_KEYS.CLIENT_ID) | |
44 | const clientSecret: string = peertubeLocalStorage.getItem(this.LOCAL_STORAGE_OAUTH_CLIENT_KEYS.CLIENT_SECRET) | |
45 | ||
46 | const headers = new Headers() | |
47 | headers.set('Content-Type', 'application/x-www-form-urlencoded') | |
48 | ||
49 | const data = { | |
50 | refresh_token: this.userTokens.refreshToken, | |
51 | client_id: clientId, | |
52 | client_secret: clientSecret, | |
53 | response_type: 'code', | |
54 | grant_type: 'refresh_token' | |
55 | } | |
56 | ||
57 | fetch('/api/v1/users/token', { | |
58 | headers, | |
59 | method: 'POST', | |
60 | body: objectToUrlEncoded(data) | |
61 | }).then(res => { | |
62 | if (res.status === HttpStatusCode.UNAUTHORIZED_401) return undefined | |
63 | ||
64 | return res.json() | |
65 | }).then((obj: UserRefreshToken & { code?: OAuth2ErrorCode }) => { | |
66 | if (!obj || obj.code === OAuth2ErrorCode.INVALID_GRANT) { | |
67 | UserTokens.flushLocalStorage(peertubeLocalStorage) | |
68 | this.removeTokensFromHeaders() | |
69 | ||
70 | return resolve() | |
71 | } | |
72 | ||
73 | this.userTokens.accessToken = obj.access_token | |
74 | this.userTokens.refreshToken = obj.refresh_token | |
75 | UserTokens.saveToLocalStorage(peertubeLocalStorage, this.userTokens) | |
76 | ||
77 | this.setHeadersFromTokens() | |
78 | ||
79 | resolve() | |
80 | }).catch((refreshTokenError: any) => { | |
81 | reject(refreshTokenError) | |
82 | }) | |
83 | }) | |
84 | ||
85 | return refreshingTokenPromise | |
86 | .catch(() => { | |
87 | UserTokens.flushLocalStorage(peertubeLocalStorage) | |
88 | ||
89 | this.removeTokensFromHeaders() | |
90 | }).then(() => fetch(url, { | |
91 | ...options, | |
92 | ||
93 | headers: this.headers | |
94 | })) | |
95 | }) | |
96 | } | |
97 | ||
98 | private setHeadersFromTokens () { | |
99 | this.headers.set('Authorization', this.getHeaderTokenValue()) | |
100 | } | |
101 | ||
102 | private removeTokensFromHeaders () { | |
103 | this.headers.delete('Authorization') | |
104 | } | |
105 | } |