user.cljs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. (ns frontend.handler.user
  2. (:require [frontend.config :as config]
  3. [frontend.db :as db]
  4. [frontend.handler.config :as config-handler]
  5. [frontend.handler.notification :as notification]
  6. [frontend.idb :as idb]
  7. [frontend.state :as state]
  8. [frontend.util :as util]
  9. [frontend.debug :as debug]
  10. [lambdaisland.glogi :as log]
  11. [promesa.core :as p]))
  12. (defn set-cors!
  13. [cors-proxy]
  14. (util/post (str config/api "cors_proxy")
  15. {:cors-proxy cors-proxy}
  16. (fn [_result]
  17. (db/transact! [{:me/cors_proxy cors-proxy}])
  18. (swap! state/state assoc-in [:me :cors_proxy] cors-proxy))
  19. (fn [error]
  20. (notification/show! "Set cors proxy failed." :error)
  21. (js/console.dir error))))
  22. (defn set-preferred-format!
  23. [format]
  24. (when format
  25. (config-handler/set-config! :preferred-format format)
  26. (state/set-preferred-format! format)
  27. ;; (when (:name (:me @state/state))
  28. ;; (when (state/logged?)
  29. ;; (util/post (str config/api "set_preferred_format")
  30. ;; {:preferred_format (name format)}
  31. ;; (fn [_result]
  32. ;; (notification/show! "Format set successfully!" :success))
  33. ;; (fn [_e]))))
  34. ))
  35. (defn set-preferred-workflow!
  36. [workflow]
  37. (when workflow
  38. (config-handler/set-config! :preferred-workflow workflow)
  39. (state/set-preferred-workflow! workflow)
  40. ;; (when (:name (:me @state/state))
  41. ;; (util/post (str config/api "set_preferred_workflow")
  42. ;; {:preferred_workflow (name workflow)}
  43. ;; (fn [_result]
  44. ;; (notification/show! "Workflow set successfully!" :success))
  45. ;; (fn [_e])))
  46. ))
  47. (defn sign-out!
  48. {:deprecated "-"}
  49. ([]
  50. (sign-out! true))
  51. ([confirm?]
  52. (when (or (not confirm?)
  53. (js/confirm "Your local notes will be completely removed after signing out. Continue?"))
  54. (->
  55. (idb/clear-local-storage-and-idb!)
  56. (p/catch (fn [e]
  57. (println "sign out error: ")
  58. (js/console.dir e)))
  59. (p/finally (fn []
  60. (set! (.-href js/window.location) "/logout")))))))
  61. (defn delete-account!
  62. []
  63. (p/let [_ (idb/clear-local-storage-and-idb!)]
  64. (util/delete (str config/api "account")
  65. (fn []
  66. (sign-out! false))
  67. (fn [error]
  68. (log/error :user/delete-account-failed error)))))
  69. ;;; userinfo, token, login/logout, ...
  70. (defn- parse-jwt [jwt]
  71. (some-> jwt
  72. (string/split ".")
  73. (second)
  74. (js/atob)
  75. (js/JSON.parse)
  76. (js->clj :keywordize-keys true)))
  77. (defn- expired? [parsed-jwt]
  78. (some->
  79. (* 1000 (:exp parsed-jwt))
  80. (tc/from-long)
  81. (t/before? (t/now))))
  82. (defn- almost-expired? [parsed-jwt]
  83. "return true when jwt will expire after 1h"
  84. (some->
  85. (* 1000 (:exp parsed-jwt))
  86. (tc/from-long)
  87. (t/before? (-> 1 t/hours t/from-now))))
  88. (defn email []
  89. (some->
  90. (state/get-auth-id-token)
  91. (parse-jwt)
  92. (:email)))
  93. (defn logged? []
  94. (boolean
  95. (some->
  96. (state/get-auth-id-token)
  97. (parse-jwt)
  98. (expired?)
  99. (not))))
  100. (defn- clear-tokens []
  101. (state/set-auth-id-token nil)
  102. (state/set-auth-access-token nil)
  103. (state/set-auth-refresh-token nil))
  104. (defn- set-tokens!
  105. ([id-token access-token]
  106. (state/set-auth-id-token id-token)
  107. (state/set-auth-access-token access-token))
  108. ([id-token access-token refresh-token]
  109. (state/set-auth-id-token id-token)
  110. (state/set-auth-access-token access-token)
  111. (state/set-auth-refresh-token refresh-token)))
  112. (defn login-callback [code]
  113. (go
  114. (let [resp (<! (http/get (str "https://api.logseq.com/auth_callback?code=" code)))]
  115. (if (= 200 (:status resp))
  116. (-> resp
  117. (:body)
  118. (js/JSON.parse)
  119. (js->clj :keywordize-keys true)
  120. (as-> $ (set-tokens! (:id_token $) (:access_token $) (:refresh_token $))))
  121. (debug/pprint "login-callback" resp)))))
  122. (defn refresh-id-token&access-token []
  123. "refresh id-token and access-token, if refresh_token expired, clear all tokens
  124. return true if success, else false"
  125. (when-let [refresh-token (state/get-auth-refresh-token)]
  126. (go
  127. (let [resp (<! (http/get (str "https://api.logseq.com/auth_refresh_token?refresh_token=" refresh-token)))]
  128. (if (= 400 (:status resp))
  129. ;; invalid refresh_token
  130. (do
  131. (clear-tokens)
  132. false)
  133. (do
  134. (->
  135. resp
  136. (as-> $ (and (http/unexceptional-status? (:status $)) $))
  137. (:body)
  138. (js/JSON.parse)
  139. (js->clj :keywordize-keys true)
  140. (as-> $ (set-tokens! (:id_token $) (:access_token $))))
  141. true))))))
  142. ;;; refresh tokens loop
  143. (def stop-refresh false)
  144. (defn refresh-tokens-loop []
  145. (debug/pprint "start refresh-tokens-loop")
  146. (go-loop []
  147. (<! (timeout 60000))
  148. (when-some [refresh-token (state/get-auth-refresh-token)]
  149. (let [id-token (state/get-auth-id-token)]
  150. (when (or (nil? id-token)
  151. (-> id-token (parse-jwt) (almost-expired?)))
  152. (debug/pprint (str "refresh tokens... " (tc/to-string(t/now))))
  153. (refresh-id-token&access-token))))
  154. (when-not stop-refresh
  155. (recur))))