auth-http.ts 3.4 KB

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