Improve authentication support.
authorFredrik Tolf <fredrik@dolda2000.com>
Tue, 5 Jun 2018 13:55:12 +0000 (15:55 +0200)
committerFredrik Tolf <fredrik@dolda2000.com>
Tue, 5 Jun 2018 13:55:29 +0000 (15:55 +0200)
fulbank/auth.py [new file with mode: 0644]
fulbank/fsb.py

diff --git a/fulbank/auth.py b/fulbank/auth.py
new file mode 100644 (file)
index 0000000..1a9f13d
--- /dev/null
@@ -0,0 +1,70 @@
+import sys, os, io, termios
+
+class conv(object):
+    msg_notice = 0
+    msg_info = 1
+    msg_debug = 2
+
+    def error(self, msg):
+        pass
+    def message(self, msg, level=0):
+        pass
+    def prompt(self, prompt, echo, default=None):
+        return default
+
+class termconv(conv):
+    def __init__(self, ifp, ofp):
+        self.ifp = ifp
+        self.ofp = ofp
+
+    def error(self, msg):
+        self.ofp.write("%s\n" % (msg,))
+        self.ofp.flush()
+    def message(self, msg, level=0):
+        if level <= self.msg_info:
+            self.ofp.write("%s\n" % (msg,))
+            self.ofp.flush()
+    def prompt(self, prompt, echo, default=None):
+        if echo:
+            self.ofp.write(prompt)
+            self.ofp.flush()
+            ret = self.ifp.readline()
+            assert ret[-1] == '\n'
+            return ret[:-1]
+        else:
+            attr = termios.tcgetattr(self.ifp.fileno())
+            bka = list(attr)
+            try:
+                attr[3] &= ~termios.ECHO
+                termios.tcflush(self.ifp.fileno(), termios.TCIOFLUSH)
+                termios.tcsetattr(self.ifp.fileno(), termios.TCSANOW, attr)
+                self.ofp.write(prompt)
+                self.ofp.flush()
+                ret = self.ifp.readline()
+                self.ofp.write("\n")
+                assert ret[-1] == '\n'
+                return ret[:-1]
+            finally:
+                termios.tcsetattr(self.ifp.fileno(), termios.TCSANOW, bka)
+
+class ctermconv(conv):
+    def __init__(self, fp):
+        super().__init__(fp)
+        self.cfp = fp
+
+    def close(self):
+        self.cfp.close()
+    def __enter__(self):
+        return self
+    def __exit__(self, *excinfo):
+        self.close()
+        return False
+
+null = conv()
+stdioconv = termconv(sys.stdin, sys.stdout)
+
+def ttyconv():
+    return ctermconv(io.TextIOWrapper(io.FileIO(os.open("/dev/tty", os.O_RDWR | os.O_NCTTY), "r+")))
+
+def default():
+    return null
index d908f79..eee66be 100644 (file)
@@ -1,7 +1,7 @@
 import json, http.cookiejar, binascii, time, datetime, pickle, hashlib
 from urllib import request, parse
 from bs4 import BeautifulSoup as soup
-from . import currency
+from . import currency, auth
 soupify = lambda cont: soup(cont, "html.parser")
 
 apibase = "https://online.swedbank.se/TDE_DAP_Portal_REST_WEB/api/"
@@ -168,7 +168,9 @@ class session(object):
         rolesw = linkurl(resolve(prof["banks"][0], ("privateProfile", "links", "next", "uri")))
         self._jreq(rolesw, method="POST")
 
-    def auth_bankid(self, user):
+    def auth_bankid(self, user, conv=None):
+        if conv is None:
+            conv = auth.default()
         data = self._jreq("v5/identification/bankid/mobile", data = {
             "userId": user,
             "useEasyLogin": False,
@@ -176,13 +178,15 @@ class session(object):
         if data.get("status") != "USER_SIGN":
             raise fmterror("unexpected bankid status: " + str(data.get("status")))
         vfy = linkurl(resolve(data, ("links", "next", "uri")))
+        fst = None
         while True:
             time.sleep(3)
             vdat = self._jreq(vfy)
             st = vdat.get("status")
-            if st == "USER_SIGN":
-                continue
-            elif st == "CLIENT_NOT_STARTED":
+            if st in {"USER_SIGN", "CLIENT_NOT_STARTED"}:
+                if st != fst:
+                    conv.message("Status: %s" % (st,), auth.conv.msg_info)
+                    fst = st
                 continue
             elif st == "COMPLETE":
                 self._postlogin()