Pārlūkot izejas kodu

[revolut] Fix token refresh

Innokentiy Enikeev 3 gadi atpakaļ
vecāks
revīzija
bfa04b3a82
1 mainītis faili ar 59 papildinājumiem un 15 dzēšanām
  1. 59 15
      plugins/revolut.lisp

+ 59 - 15
plugins/revolut.lisp

@@ -37,26 +37,50 @@
       (cl-cookie:make-cookie
        :name "credentials"
        :value (base64:string-to-base64-string
-               (format nil "~a:~a" (agets token "user" "id") (agets token "accessToken")))
+               (format nil "~a:~a" (agets token "user" "id")
+		       (agets token "accessToken")))
+       :domain +api-domain+)
+      (cl-cookie:make-cookie
+       :name "refresh-token"
+       :value (base64:string-to-base64-string
+               (format nil "~a:~a" (agets token "user" "id")
+		       (agets token "refreshCode")))
        :domain +api-domain+)))))
 
+(defun need-to-refresh-token (method)
+  (unless (or (string-equal method "signin")
+	      (string-equal method "token"))
+    (when-let (expire (agets *poller-token* "tokenExpiryDate"))
+      (let* ((expire-ts (local-time:unix-to-timestamp (round expire 1000)))
+	     (expire-5-min (local-time:timestamp- expire-ts 5 :minute))
+	     (now (local-time:now)))
+	(when (local-time:timestamp< expire-5-min now expire-ts)
+	  (log:info "Refreshing token" expire-ts)
+	  (error 'dex:http-request-unauthorized
+		 :method :post :uri (quri:uri "expire")
+		 :headers nil :status 422 :body nil))))))
+
 (defmethod poller-request ((module (eql :revolut)) method &rest params)
   (handler-case
       (let* ((uri (if (listp method) (car method) method))             
              (rest-method (if (listp method) (cdr method) :get))
+	     (refresh (need-to-refresh-token uri))
              (is-content (is-content rest-method))
+	     (cookie-jar (make-cookie-jar *poller-token*))
              (res
                (json-request (concatenate 'string +api-uri+ uri)
                              :headers `((:x-device-id . ,+device-id+)
                                         (:x-browser-application . "WEB_CLIENT"))
                              :user-agent +user-agent+
-                             :cookie-jar (make-cookie-jar *poller-token*)
+                             :cookie-jar cookie-jar
                              :method rest-method
                              :json-content is-content
                              (if is-content :content :parameters)
                              (rest-parameters params t))))
-        res)
-    (dex:http-request-failed (e) e)))
+        (values res cookie-jar))
+    (dex:http-request-failed (e)
+      (let ((*print-escape*)) (log:warn "Revolut request failed" e))
+      e)))
 
 (defmethod poller-validate ((module (eql :revolut)) response)
   (not (typep response 'dex:http-request-unauthorized)))
@@ -75,25 +99,45 @@
             when (listp res) do (return res)
             unless (= (dex:response-status res) 422) do (return)
             when (> (- (get-universal-time) start) 30) do (return)
-            do (sleep 2)))))
-
-(defun refresh-token (user-id refresh-code)
-  (let* ((res (poller-request :revolut '("token" . :put)
-                              :|userId| user-id
-                              :|refreshCode| refresh-code)))
-    (when (listp res) res)))
+              do (sleep 2)))))
+
+(defun get-cookie-value (jar name)
+  (when jar
+    (let ((cookie (find name (cl-cookie:cookie-jar-cookies jar)
+			:from-end t
+			:key 'cl-cookie:cookie-name
+			:test 'equal)))
+      (when cookie (cl-cookie:cookie-value cookie)))))
+
+(defun decode-cookie-token (value)
+  (when value
+    (let ((decoded (base64:base64-string-to-string value)))
+      (when (> (length decoded) 37)
+	(subseq decoded 37)))))
+
+(defun refresh-token ()
+  (multiple-value-bind (res jar)
+      (poller-request :revolut '("token" . :put))
+    ;;(let ((*print-escape*)) (log:info "Token refresh" res jar))
+    (when (listp res)
+      `(("user" . (("id" . ,(agets res "userId"))))
+	("tokenExpiryDate" . ,(agets res "expireAt"))
+	("accessToken" . ,(decode-cookie-token (get-cookie-value jar "credentials")))
+	("refreshCode" . ,(decode-cookie-token (get-cookie-value jar "refresh-token")))))))
  
 (defmethod poller-get-token ((module (eql :revolut)) secret)
   (let ((user-id (agets *poller-token* "user" "id"))
         (refresh-code (agets *poller-token* "refreshCode")))
     ;; Try to refresh old token
     (when (and user-id refresh-code)
-      (when-let (token (refresh-token user-id refresh-code))
-        (return-from poller-get-token
-          (append token `(("user" . (("id" . ,user-id))))))))
+      (when-let (token (refresh-token))
+	(log:info "Refreshed" token)
+        (return-from poller-get-token token)))
     ;; Signin for a new token
     (destructuring-bind (phone . passcode) secret
-      (signin phone passcode))))
+      (let ((token (signin phone passcode)))
+	(log:info "Signin" token)
+	token))))
 
 (defun get-user ()
   (poller-call :revolut "user/current"))