enhance(sync): check token not expired before api-calls (#7267)

* enhance(sync): check token not expired before api-calls

* fix(sync): ensure id-token exists when calling user/user-uuid

* enhance(sync): add <wrap-ensure-id&access-token, remove refresh-token-loop

* fix: check exception before using the result of <user-uuid

* fix: notify users ex message instead of ex info

Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
pull/7279/head
rcmerci 2022-11-09 11:06:45 +08:00 committed by GitHub
parent 4aeaaeb01e
commit decd47c8a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 291 additions and 256 deletions

View File

@ -370,9 +370,13 @@
(state/pub-event! [:file-sync/onboarding-tip :unavailable])
;; current graph belong to other user, do nothing
(and (first @graphs-txid)
(not (fs-sync/check-graph-belong-to-current-user (user-handler/user-uuid)
(first @graphs-txid))))
(let [user-uuid (async/<! (user-handler/<user-uuid))
user-uuid (when-not (instance? ExceptionInfo user-uuid) user-uuid)]
(and (first @graphs-txid)
user-uuid
(not (fs-sync/check-graph-belong-to-current-user
user-uuid
(first @graphs-txid)))))
nil
(and synced-file-graph?

View File

@ -278,8 +278,8 @@
"max retry count is 5.
*stop: volatile var, stop retry-request when it's true,
and return :stop"
([api-name body token refresh-token-fn *stop] (<request* api-name body token refresh-token-fn 0 *stop))
([api-name body token refresh-token-fn retry-count *stop]
([api-name body token *stop] (<request* api-name body token 0 *stop))
([api-name body token retry-count *stop]
(go
(if (and *stop @*stop (contains? stoppable-apis api-name))
:stop
@ -291,8 +291,7 @@
(throw (js/Error. :file-sync-request))
(do (println "will retry after" (min 60000 (* 1000 retry-count)) "ms")
(<! (timeout (min 60000 (* 1000 retry-count))))
(let [token (<! (refresh-token-fn))]
(<! (<request* api-name body token refresh-token-fn (inc retry-count) *stop)))))
(<! (<request* api-name body token (inc retry-count) *stop))))
(:resp resp)))))))
(defn <request [api-name & args]
@ -721,8 +720,7 @@
(<upload-graph-encrypt-keys [this graph-uuid public-key encrypted-private-key]))
(defprotocol IToken
(<get-token [this])
(<refresh-token [this]))
(<get-token [this]))
(defn <case-different-local-file-exist?
@ -767,14 +765,9 @@
(deftype RSAPI [^:mutable graph-uuid' ^:mutable private-key' ^:mutable public-key']
IToken
(<get-token [this]
(go
(or (state/get-auth-id-token)
(<! (<refresh-token this)))))
(<refresh-token [_]
(go
(<! (user/<refresh-id-token&access-token))
(state/get-auth-id-token)))
(<get-token [_this]
(user/<wrap-ensure-id&access-token
(state/get-auth-id-token)))
IRSAPI
(rsapi-ready? [_ graph-uuid] (and (= graph-uuid graph-uuid') private-key' public-key'))
@ -855,14 +848,9 @@
(deftype ^:large-vars/cleanup-todo CapacitorAPI [^:mutable graph-uuid' ^:mutable private-key ^:mutable public-key']
IToken
(<get-token [this]
(go
(or (state/get-auth-id-token)
(<! (<refresh-token this)))))
(<refresh-token [_]
(go
(<! (user/<refresh-id-token&access-token))
(state/get-auth-id-token)))
(<get-token [_this]
(user/<wrap-ensure-id&access-token
(state/get-auth-id-token)))
IRSAPI
(rsapi-ready? [_ graph-uuid] (and (= graph-uuid graph-uuid') private-key public-key'))
@ -1128,7 +1116,7 @@
(<request [this api-name body]
(go
(let [resp (<! (<request api-name body (<! (<get-token this)) #(<refresh-token this) *stopped?))]
(let [resp (<! (<request api-name body (<! (<get-token this)) *stopped?))]
(if (http/unexceptional-status? (:status resp))
(get-resp-json-body resp)
(let [exp (ex-info "request failed"
@ -1147,186 +1135,189 @@
(.<request this "update_files" {:GraphUUID graph-uuid :TXId txid :Files files}))
IToken
(<get-token [this]
(go
(or (state/get-auth-id-token)
(<! (<refresh-token this)))))
(<refresh-token [_]
(go
(<! (user/<refresh-id-token&access-token))
(state/get-auth-id-token))))
(<get-token [_this]
(user/<wrap-ensure-id&access-token
(state/get-auth-id-token))))
(extend-type RemoteAPI
IRemoteAPI
(<user-info [this] (.<request this "user_info" {}))
(<user-info [this]
(user/<wrap-ensure-id&access-token
(<! (.<request this "user_info" {}))))
(<get-remote-all-files-meta [this graph-uuid]
(go
(let [file-meta-list (transient #{})
encrypted-path-list (transient [])
exp-r
(<!
(go-loop [continuation-token nil]
(let [r (<! (.<request this "get_all_files"
(into
{}
(remove (comp nil? second)
{:GraphUUID graph-uuid :ContinuationToken continuation-token}))))]
(if (instance? ExceptionInfo r)
r
(let [next-continuation-token (:NextContinuationToken r)
objs (:Objects r)]
(apply conj! encrypted-path-list (map (comp remove-user-graph-uuid-prefix :Key) objs))
(apply conj! file-meta-list
(map
#(hash-map :checksum (:checksum %)
:encrypted-path (remove-user-graph-uuid-prefix (:Key %))
:size (:Size %)
:last-modified (:LastModified %))
objs))
(when-not (empty? next-continuation-token)
(recur next-continuation-token)))))))]
(if (instance? ExceptionInfo exp-r)
exp-r
(let [file-meta-list* (persistent! file-meta-list)
encrypted-path-list* (persistent! encrypted-path-list)
path-list-or-exp (<! (<decrypt-fnames rsapi graph-uuid encrypted-path-list*))]
(if (instance? ExceptionInfo path-list-or-exp)
path-list-or-exp
(let [encrypted-path->path-map (zipmap encrypted-path-list* path-list-or-exp)]
(set
(mapv
#(->FileMetadata (:size %)
(:checksum %)
(get encrypted-path->path-map (:encrypted-path %))
(:encrypted-path %)
(:last-modified %)
true nil)
file-meta-list*)))))))))
(user/<wrap-ensure-id&access-token
(let [file-meta-list (transient #{})
encrypted-path-list (transient [])
exp-r
(<!
(go-loop [continuation-token nil]
(let [r (<! (.<request this "get_all_files"
(into
{}
(remove (comp nil? second)
{:GraphUUID graph-uuid :ContinuationToken continuation-token}))))]
(if (instance? ExceptionInfo r)
r
(let [next-continuation-token (:NextContinuationToken r)
objs (:Objects r)]
(apply conj! encrypted-path-list (map (comp remove-user-graph-uuid-prefix :Key) objs))
(apply conj! file-meta-list
(map
#(hash-map :checksum (:checksum %)
:encrypted-path (remove-user-graph-uuid-prefix (:Key %))
:size (:Size %)
:last-modified (:LastModified %))
objs))
(when-not (empty? next-continuation-token)
(recur next-continuation-token)))))))]
(if (instance? ExceptionInfo exp-r)
exp-r
(let [file-meta-list* (persistent! file-meta-list)
encrypted-path-list* (persistent! encrypted-path-list)
path-list-or-exp (<! (<decrypt-fnames rsapi graph-uuid encrypted-path-list*))]
(if (instance? ExceptionInfo path-list-or-exp)
path-list-or-exp
(let [encrypted-path->path-map (zipmap encrypted-path-list* path-list-or-exp)]
(set
(mapv
#(->FileMetadata (:size %)
(:checksum %)
(get encrypted-path->path-map (:encrypted-path %))
(:encrypted-path %)
(:last-modified %)
true nil)
file-meta-list*)))))))))
(<get-remote-files-meta [this graph-uuid filepaths]
{:pre [(coll? filepaths)]}
(go
(let [encrypted-paths* (<! (<encrypt-fnames rsapi graph-uuid filepaths))
r (<! (.<request this "get_files_meta" {:GraphUUID graph-uuid :Files encrypted-paths*}))]
(if (instance? ExceptionInfo r)
r
(let [encrypted-paths (mapv :FilePath r)
paths-or-exp (<! (<decrypt-fnames rsapi graph-uuid encrypted-paths))]
(if (instance? ExceptionInfo paths-or-exp)
paths-or-exp
(let [encrypted-path->path-map (zipmap encrypted-paths paths-or-exp)]
(into #{}
(comp
(filter #(not= "filepath too long" (:Error %)))
(map #(->FileMetadata (:Size %)
(:Checksum %)
(get encrypted-path->path-map (:FilePath %))
(:FilePath %)
(:LastModified %)
true nil)))
r))))))))
(user/<wrap-ensure-id&access-token
(let [encrypted-paths* (<! (<encrypt-fnames rsapi graph-uuid filepaths))
r (<! (.<request this "get_files_meta" {:GraphUUID graph-uuid :Files encrypted-paths*}))]
(if (instance? ExceptionInfo r)
r
(let [encrypted-paths (mapv :FilePath r)
paths-or-exp (<! (<decrypt-fnames rsapi graph-uuid encrypted-paths))]
(if (instance? ExceptionInfo paths-or-exp)
paths-or-exp
(let [encrypted-path->path-map (zipmap encrypted-paths paths-or-exp)]
(into #{}
(comp
(filter #(not= "filepath too long" (:Error %)))
(map #(->FileMetadata (:Size %)
(:Checksum %)
(get encrypted-path->path-map (:FilePath %))
(:FilePath %)
(:LastModified %)
true nil)))
r))))))))
(<get-remote-graph [this graph-name-opt graph-uuid-opt]
{:pre [(or graph-name-opt graph-uuid-opt)]}
(.<request this "get_graph" (cond-> {}
(seq graph-name-opt)
(assoc :GraphName graph-name-opt)
(seq graph-uuid-opt)
(assoc :GraphUUID graph-uuid-opt))))
(user/<wrap-ensure-id&access-token
(<! (.<request this "get_graph" (cond-> {}
(seq graph-name-opt)
(assoc :GraphName graph-name-opt)
(seq graph-uuid-opt)
(assoc :GraphUUID graph-uuid-opt))))))
(<get-remote-file-versions [this graph-uuid filepath]
(go
(let [encrypted-path (first (<! (<encrypt-fnames rsapi graph-uuid [filepath])))]
(<! (.<request this "get_file_version_list" {:GraphUUID graph-uuid :File encrypted-path})))))
(user/<wrap-ensure-id&access-token
(let [encrypted-path (first (<! (<encrypt-fnames rsapi graph-uuid [filepath])))]
(<! (.<request this "get_file_version_list" {:GraphUUID graph-uuid :File encrypted-path})))))
(<list-remote-graphs [this]
(.<request this "list_graphs"))
(user/<wrap-ensure-id&access-token
(<! (.<request this "list_graphs"))))
(<get-deletion-logs [this graph-uuid from-txid]
(go
(let [r (<! (.<request this "get_deletion_log" {:GraphUUID graph-uuid :FromTXId from-txid}))]
(if (instance? ExceptionInfo r)
r
(let [txns-with-encrypted-paths (mapv #(update % :path remove-user-graph-uuid-prefix) (:Transactions r))
encrypted-paths (mapv :path txns-with-encrypted-paths)
encrypted-path->path-map
(zipmap
encrypted-paths
(<! (<decrypt-fnames rsapi graph-uuid encrypted-paths)))
txns
(mapv
(fn [txn] (update txn :path #(get encrypted-path->path-map %)))
txns-with-encrypted-paths)]
txns)))))
(user/<wrap-ensure-id&access-token
(let [r (<! (.<request this "get_deletion_log" {:GraphUUID graph-uuid :FromTXId from-txid}))]
(if (instance? ExceptionInfo r)
r
(let [txns-with-encrypted-paths (mapv #(update % :path remove-user-graph-uuid-prefix) (:Transactions r))
encrypted-paths (mapv :path txns-with-encrypted-paths)
encrypted-path->path-map
(zipmap
encrypted-paths
(<! (<decrypt-fnames rsapi graph-uuid encrypted-paths)))
txns
(mapv
(fn [txn] (update txn :path #(get encrypted-path->path-map %)))
txns-with-encrypted-paths)]
txns)))))
(<get-diff [this graph-uuid from-txid]
;; TODO: path in transactions should be relative path(now s3 key, which includes graph-uuid and user-uuid)
(go
(let [r (<! (.<request this "get_diff" {:GraphUUID graph-uuid :FromTXId from-txid}))]
(if (instance? ExceptionInfo r)
r
(let [txns-with-encrypted-paths (sort-by :TXId (:Transactions r))
txns-with-encrypted-paths*
(mapv
(fn [txn]
(assoc txn :TXContent
(mapv
(fn [[to-path from-path checksum]]
[(remove-user-graph-uuid-prefix to-path)
(some-> from-path remove-user-graph-uuid-prefix)
checksum])
(:TXContent txn))))
txns-with-encrypted-paths)
(user/<wrap-ensure-id&access-token
(let [r (<! (.<request this "get_diff" {:GraphUUID graph-uuid :FromTXId from-txid}))]
(if (instance? ExceptionInfo r)
r
(let [txns-with-encrypted-paths (sort-by :TXId (:Transactions r))
txns-with-encrypted-paths*
(mapv
(fn [txn]
(assoc txn :TXContent
(mapv
(fn [[to-path from-path checksum]]
[(remove-user-graph-uuid-prefix to-path)
(some-> from-path remove-user-graph-uuid-prefix)
checksum])
(:TXContent txn))))
txns-with-encrypted-paths)
encrypted-paths
(mapcat
(fn [txn]
(remove
#(or (nil? %) (not (string/starts-with? % "e.")))
(mapcat
(fn [[to-path from-path _checksum]] [to-path from-path])
(:TXContent txn))))
txns-with-encrypted-paths*)
encrypted-path->path-map
(zipmap
encrypted-paths
(mapcat
(fn [txn]
(remove
#(or (nil? %) (not (string/starts-with? % "e.")))
(mapcat
(fn [[to-path from-path _checksum]] [to-path from-path])
(:TXContent txn))))
txns-with-encrypted-paths*)
encrypted-path->path-map
(zipmap
encrypted-paths
(<! (<decrypt-fnames rsapi graph-uuid encrypted-paths)))
txns
(mapv
(fn [txn]
(assoc
txn :TXContent
(mapv
(fn [[to-path from-path checksum]]
[(get encrypted-path->path-map to-path to-path)
(some->> from-path (get encrypted-path->path-map))
checksum])
(:TXContent txn))))
txns-with-encrypted-paths*)]
[txns
(:TXId (last txns))
(:TXId (first txns))])))))
(<! (<decrypt-fnames rsapi graph-uuid encrypted-paths)))
txns
(mapv
(fn [txn]
(assoc
txn :TXContent
(mapv
(fn [[to-path from-path checksum]]
[(get encrypted-path->path-map to-path to-path)
(some->> from-path (get encrypted-path->path-map))
checksum])
(:TXContent txn))))
txns-with-encrypted-paths*)]
[txns
(:TXId (last txns))
(:TXId (first txns))])))))
(<create-graph [this graph-name]
(.<request this "create_graph" {:GraphName graph-name}))
(user/<wrap-ensure-id&access-token
(<! (.<request this "create_graph" {:GraphName graph-name}))))
(<delete-graph [this graph-uuid]
(.<request this "delete_graph" {:GraphUUID graph-uuid}))
(user/<wrap-ensure-id&access-token
(<! (.<request this "delete_graph" {:GraphUUID graph-uuid}))))
(<get-graph-salt [this graph-uuid]
(.<request this "get_graph_salt" {:GraphUUID graph-uuid}))
(user/<wrap-ensure-id&access-token
(<! (.<request this "get_graph_salt" {:GraphUUID graph-uuid}))))
(<create-graph-salt [this graph-uuid]
(.<request this "create_graph_salt" {:GraphUUID graph-uuid}))
(user/<wrap-ensure-id&access-token
(<! (.<request this "create_graph_salt" {:GraphUUID graph-uuid}))))
(<get-graph-encrypt-keys [this graph-uuid]
(.<request this "get_graph_encrypt_keys" {:GraphUUID graph-uuid}))
(user/<wrap-ensure-id&access-token
(<! (.<request this "get_graph_encrypt_keys" {:GraphUUID graph-uuid}))))
(<upload-graph-encrypt-keys [this graph-uuid public-key encrypted-private-key]
(.<request this "upload_graph_encrypt_keys" {:GraphUUID graph-uuid
:public-key public-key
:encrypted-private-key encrypted-private-key})))
(user/<wrap-ensure-id&access-token
(<! (.<request this "upload_graph_encrypt_keys" {:GraphUUID graph-uuid
:public-key public-key
:encrypted-private-key encrypted-private-key})))))
(def remoteapi (->RemoteAPI nil))
@ -3049,43 +3040,44 @@
(when (false? @*sync-entered?)
(reset! *sync-entered? true)
(let [*sync-state (atom (sync-state))
current-user-uuid (user/user-uuid)
current-user-uuid (<! (user/<user-uuid))
;; put @graph-uuid & get-current-repo together,
;; prevent to get older repo dir and current graph-uuid.
_ (<! (p->c (persist-var/-load graphs-txid)))
[user-uuid graph-uuid txid] @graphs-txid
txid (or txid 0)
repo (state/get-current-repo)]
(when (and repo
(graph-sync-off? repo) @network-online-cursor
user-uuid graph-uuid txid
(user/logged-in?)
(not (config/demo-graph? repo)))
(try
(when-let [sm (sync-manager-singleton current-user-uuid graph-uuid
(config/get-repo-dir repo) repo
txid *sync-state)]
(when (check-graph-belong-to-current-user current-user-uuid user-uuid)
(if-not (<! (<check-remote-graph-exists graph-uuid)) ; remote graph has been deleted
(clear-graphs-txid! repo)
(do
(state/set-file-sync-state graph-uuid @*sync-state)
(state/set-file-sync-manager graph-uuid sm)
(when-not (instance? ExceptionInfo current-user-uuid)
(when (and repo
(graph-sync-off? repo) @network-online-cursor
user-uuid graph-uuid txid
(user/logged-in?)
(not (config/demo-graph? repo)))
(try
(when-let [sm (sync-manager-singleton current-user-uuid graph-uuid
(config/get-repo-dir repo) repo
txid *sync-state)]
(when (check-graph-belong-to-current-user current-user-uuid user-uuid)
(if-not (<! (<check-remote-graph-exists graph-uuid)) ; remote graph has been deleted
(clear-graphs-txid! repo)
(do
(state/set-file-sync-state graph-uuid @*sync-state)
(state/set-file-sync-manager graph-uuid sm)
;; update global state when *sync-state changes
(add-watch *sync-state ::update-global-state
(fn [_ _ _ n]
(state/set-file-sync-state graph-uuid n)))
;; update global state when *sync-state changes
(add-watch *sync-state ::update-global-state
(fn [_ _ _ n]
(state/set-file-sync-state graph-uuid n)))
(state/set-state! [:file-sync/graph-state :current-graph-uuid] graph-uuid)
(state/set-state! [:file-sync/graph-state :current-graph-uuid] graph-uuid)
(.start sm)
(.start sm)
(offer! remote->local-full-sync-chan true)
(offer! full-sync-chan true)))))
(catch :default e
(prn "Sync start error: ")
(log/error :exception e))))
(offer! remote->local-full-sync-chan true)
(offer! full-sync-chan true)))))
(catch :default e
(prn "Sync start error: ")
(log/error :exception e)))))
(reset! *sync-entered? false)))))
;;; ### some add-watches

View File

@ -236,7 +236,6 @@
(el/listen!))
(persist-var/load-vars)
(user-handler/restore-tokens-from-localstorage)
(user-handler/refresh-tokens-loop)
(js/setTimeout instrument! (* 60 1000)))
(defn stop! []

View File

@ -44,28 +44,33 @@
[name]
(go
(let [r* (<! (sync/<create-graph sync/remoteapi name))
r (if (instance? ExceptionInfo r*) r* (:GraphUUID r*))]
(if (and (not (instance? ExceptionInfo r))
(string? r))
(let [tx-info [0 r (user/user-uuid) (state/get-current-repo)]]
(<! (apply sync/<update-graphs-txid! tx-info))
(swap! refresh-file-sync-component not)
tx-info)
(do
(state/set-state! [:ui/loading? :graph/create-remote?] false)
(cond
;; already processed this exception by events
;; - :file-sync/storage-exceed-limit
;; - :file-sync/graph-count-exceed-limit
(or (sync/storage-exceed-limit? r)
(sync/graph-count-exceed-limit? r))
nil
user-uuid-or-exp (<! (user/<user-uuid))
r (if (instance? ExceptionInfo r*) r*
(if (instance? ExceptionInfo user-uuid-or-exp)
user-uuid-or-exp
(:GraphUUID r*)))]
(when-not (instance? ExceptionInfo user-uuid-or-exp)
(if (and (not (instance? ExceptionInfo r))
(string? r))
(let [tx-info [0 r user-uuid-or-exp (state/get-current-repo)]]
(<! (apply sync/<update-graphs-txid! tx-info))
(swap! refresh-file-sync-component not)
tx-info)
(do
(state/set-state! [:ui/loading? :graph/create-remote?] false)
(cond
;; already processed this exception by events
;; - :file-sync/storage-exceed-limit
;; - :file-sync/graph-count-exceed-limit
(or (sync/storage-exceed-limit? r)
(sync/graph-count-exceed-limit? r))
nil
(contains? #{400 404} (get-in (ex-data r) [:err :status]))
(notification/show! (str "Create graph failed: already existed graph: " name) :warning true nil 4000)
(contains? #{400 404} (get-in (ex-data r) [:err :status]))
(notification/show! (str "Create graph failed: already existed graph: " name) :warning true nil 4000)
:else
(notification/show! (str "Create graph failed:" r) :warning true nil 4000)))))))
:else
(notification/show! (str "Create graph failed: " (ex-message r)) :warning true nil 4000))))))))
(defn <delete-graph
[graph-uuid]
@ -100,11 +105,14 @@
(defn init-graph [graph-uuid]
(go
(let [repo (state/get-current-repo)
user-uuid (user/user-uuid)]
(state/set-state! :sync-graph/init? true)
(<! (sync/<update-graphs-txid! 0 graph-uuid user-uuid repo))
(swap! refresh-file-sync-component not)
(state/pub-event! [:graph/switch repo {:persist? false}]))))
user-uuid-or-exp (<! (user/<user-uuid))]
(if (instance? ExceptionInfo user-uuid-or-exp)
(notification/show! (ex-message user-uuid-or-exp) :error)
(do
(state/set-state! :sync-graph/init? true)
(<! (sync/<update-graphs-txid! 0 graph-uuid user-uuid-or-exp repo))
(swap! refresh-file-sync-component not)
(state/pub-event! [:graph/switch repo {:persist? false}]))))))
(defn download-version-file
([graph-uuid file-uuid version-uuid]

View File

@ -0,0 +1,9 @@
(ns frontend.handler.user
"Macros.")
(defmacro <wrap-ensure-id&access-token
[& body]
`(cljs.core.async/go
(if-some [exp# (cljs.core.async/<! (<ensure-id&access-token))]
exp#
(do ~@body))))

View File

@ -1,5 +1,6 @@
(ns frontend.handler.user
"Provides user related handler fns like login and logout"
(:require-macros [frontend.handler.user])
(:require [frontend.config :as config]
[frontend.handler.config :as config-handler]
[frontend.state :as state]
@ -8,7 +9,7 @@
[cljs-time.core :as t]
[cljs-time.coerce :as tc]
[cljs-http.client :as http]
[cljs.core.async :as async :refer [go go-loop <! timeout]]))
[cljs.core.async :as async :refer [go <!]]))
(defn set-preferred-format!
[format]
@ -57,19 +58,14 @@
parse-jwt
:email))
(defn user-uuid []
(defn- user-uuid []
(some->
(state/get-auth-id-token)
parse-jwt
:sub))
(defn logged-in? []
(boolean
(some->
(state/get-auth-id-token)
parse-jwt
expired?
not)))
(some? (state/get-auth-refresh-token)))
(defn- set-token-to-localstorage!
([id-token access-token]
@ -83,12 +79,19 @@
(js/localStorage.setItem "refresh-token" refresh-token)))
(defn- clear-tokens
[]
(state/set-auth-id-token nil)
(state/set-auth-access-token nil)
(state/set-auth-refresh-token nil)
(set-token-to-localstorage! "" "" ""))
([]
(state/set-auth-id-token nil)
(state/set-auth-access-token nil)
(state/set-auth-refresh-token nil)
(set-token-to-localstorage! "" "" ""))
([except-refresh-token?]
(state/set-auth-id-token nil)
(state/set-auth-access-token nil)
(when-not except-refresh-token?
(state/set-auth-refresh-token nil))
(if except-refresh-token?
(set-token-to-localstorage! "" "")
(set-token-to-localstorage! "" "" ""))))
(defn- set-tokens!
([id-token access-token]
@ -109,8 +112,25 @@
(when-let [refresh-token (state/get-auth-refresh-token)]
(let [resp (<! (http/get (str "https://" config/API-DOMAIN "/auth_refresh_token?refresh_token=" refresh-token)
{:with-credentials? false}))]
(cond
(and (<= 400 (:status resp))
(> 500 (:status resp)))
;; invalid refresh-token
(clear-tokens)
;; e.g. api return 500, server internal error
;; we shouldn't clear tokens if they aren't expired yet
;; the `refresh-tokens-loop` will retry soon
(and (not (http/unexceptional-status? (:status resp)))
(not (-> (state/get-auth-id-token) parse-jwt expired?)))
nil ; do nothing
(not (http/unexceptional-status? (:status resp)))
(clear-tokens true)
:else ; ok
(when (and (:id_token (:body resp)) (:access_token (:body resp)))
(set-tokens! (:id_token (:body resp)) (:access_token (:body resp))))))))
(set-tokens! (:id_token (:body resp)) (:access_token (:body resp)))))))))
(defn restore-tokens-from-localstorage
"Restore id-token, access-token, refresh-token from localstorage,
@ -148,22 +168,25 @@
(clear-tokens)
(state/pub-event! [:user/logout]))
(defn <ensure-id&access-token
[]
(go
(when (or (nil? (state/get-auth-id-token))
(-> (state/get-auth-id-token) parse-jwt almost-expired-or-expired?))
(debug/pprint (str "refresh tokens... " (tc/to-string (t/now))))
(<! (<refresh-id-token&access-token))
(when (or (nil? (state/get-auth-id-token))
(-> (state/get-auth-id-token) parse-jwt expired?))
(ex-info "empty or expired token and refresh failed" {})))))
(defn <user-uuid
[]
(go
(if-some [exp (<! (<ensure-id&access-token))]
exp
(user-uuid))))
;;; refresh tokens loop
(def stop-refresh false)
(defn refresh-tokens-loop []
(debug/pprint "start refresh-tokens-loop")
(go-loop []
(<! (timeout 60000))
(when (state/get-auth-refresh-token)
(let [id-token (state/get-auth-id-token)]
(when (or (nil? id-token)
(-> id-token (parse-jwt) (almost-expired-or-expired?)))
(debug/pprint (str "refresh tokens... " (tc/to-string(t/now))))
(<! (<refresh-id-token&access-token)))))
(when-not stop-refresh
(recur))))
;;; user groups
(defn alpha-user?
[]