Пример #1
0
def set_bunq_oauth_response():
    """ Handles the bunq OAuth redirect """
    try:
        code = request.args["code"]
        if len(code) != 64:
            print("Invalid code: ", code)
            return render_template("message.html", msgtype="danger", msg=\
                'Invalid code! <br><br>'\
                '<a href="/">Click here to try again</a>')
        url = "https://api.oauth.bunq.com/v1/token?grant_type="\
              "authorization_code&code={}&redirect_uri={}"\
              "&client_id={}&client_secret={}"\
              .format(code,
                      request.url_root + "auth",
                      storage.retrieve("config", "bunq_client_id")["value"],
                      storage.retrieve("config", "bunq_client_secret")["value"]
                     )
        req = requests.post(url)
        key = req.json()["access_token"]
        allips = storage.retrieve("config", "bunq_allips")["value"]
        bunq.install(key, allips=allips)
        util.save_bunq_security_mode("OAuth")
        util.save_app_mode("master")
        util.retrieve_and_save_bunq_userid()
        util.update_bunq_accounts()
        return render_template("message.html", msgtype="success", msg=\
            'OAuth successfully setup <br><br>'\
            '<a href="/">Click here to return home</a>')

    except Exception:
        traceback.print_exc()
        return render_template("message.html", msgtype="danger", msg=\
            'An unknown exception occurred. See the logs. <br><br>'\
            '<a href="/">Click here to return home</a>')
Пример #2
0
def user_login():
    """ Handles password login """
    try:
        hashfunc = hashlib.sha256()
        hashfunc.update(request.form["password"].encode("utf-8"))

        stored_hash = storage.retrieve("config", "password_hash")
        if stored_hash is not None:
            salt = storage.retrieve("config", "password_salt")["value"]
            hashfunc.update(salt.encode('ascii'))
            calc_hash = base64.b64encode(hashfunc.digest()).decode('ascii')
            if calc_hash != stored_hash["value"]:
                return render_template("message.html", msgtype="danger", msg=\
                    'Invalid password! - To try again, '\
                    '<a href="/">click here</a>')
        else:
            # first time login, so store the password
            salt = secrets.token_urlsafe(32)
            hashfunc.update(salt.encode('ascii'))
            calc_hash = base64.b64encode(hashfunc.digest()).decode('ascii')
            storage.store("config", "password_salt", {"value": salt})
            storage.store("config", "password_hash", {"value": calc_hash})

        session = secrets.token_urlsafe(32)
        util.save_session_cookie(session)

        resp = make_response(redirect('/'))
        resp.set_cookie("session", session)
        return resp

    except Exception:
        traceback.print_exc()
        return render_template("message.html", msgtype="danger", msg=\
            'An unknown exception occurred. See the logs. <br><br>'\
            '<a href="/">Click here to return home</a>')
Пример #3
0
def get_private_key():
    """ Retrieves my private key from cache or the datastore """
    global _PRIVATE_KEY
    if _PRIVATE_KEY is None:
        entity = storage.retrieve("config", "bunq_private_key_1")
        private_1 = base64.a85decode(entity["value"])
        entity = storage.retrieve("config", "bunq_private_key_2")
        private_2 = base64.a85decode(entity["value"])
        _PRIVATE_KEY = serialization.load_pem_private_key(
            private_1 + private_2, password=None, backend=default_backend())
    return _PRIVATE_KEY
Пример #4
0
def get_install_token():
    """ Retrieves the install token from cache or the datastore """
    global _INSTALL_TOKEN
    if _INSTALL_TOKEN is None:
        entity = storage.retrieve("config", "bunq_install_token")
        _INSTALL_TOKEN = entity["value"]
    return _INSTALL_TOKEN
Пример #5
0
def get_access_token():
    """ Retrieves the access token from cache or the datastore """
    global _ACCESS_TOKEN
    if _ACCESS_TOKEN is None:
        entity = storage.retrieve("config", "bunq_access_token")
        _ACCESS_TOKEN = entity["value"]
    return _ACCESS_TOKEN
Пример #6
0
def get_ifttt_service_key():
    """ Return the IFTTT service key, used to secure IFTTT calls """
    global _IFTTT_SERVICE_KEY
    if _IFTTT_SERVICE_KEY is None:
        entity = storage.retrieve("config", "ifttt_service_key")
        if entity is not None:
            _IFTTT_SERVICE_KEY = entity["value"]
    return _IFTTT_SERVICE_KEY
Пример #7
0
def get_app_master_url():
    """ Return the URL of the master instance """
    global _APP_MASTER_URL
    if _APP_MASTER_URL is None:
        entity = storage.retrieve("config", "app_master_url")
        if entity is not None:
            _APP_MASTER_URL = entity["value"]
    return _APP_MASTER_URL
Пример #8
0
def get_bunq_security_mode():
    """ Return the bunq security mode """
    global _BUNQ_SECURITY_MODE
    if _BUNQ_SECURITY_MODE is None:
        entity = storage.retrieve("config", "bunq_security_mode")
        if entity is not None:
            _BUNQ_SECURITY_MODE = entity["value"]
    return _BUNQ_SECURITY_MODE
Пример #9
0
def get_session_cookie():
    """ Return the users session cookie """
    global _SESSION_COOKIE
    if _SESSION_COOKIE is None:
        entity = storage.retrieve("config", "session_cookie")
        if entity is not None:
            _SESSION_COOKIE = entity["value"]
    return _SESSION_COOKIE
Пример #10
0
def get_ifttt_service_key(key=None):
    """ Return the IFTTT service key, used to secure IFTTT calls """
    global _IFTTT_SERVICE_KEY
    if key not in [None, _IFTTT_SERVICE_KEY] or _IFTTT_SERVICE_KEY is None:
        entity = storage.retrieve("bunq2IFTTT", "ifttt_service_key")
        if entity is not None:
            _IFTTT_SERVICE_KEY = entity["value"]
    return _IFTTT_SERVICE_KEY
Пример #11
0
def get_server_key():
    """ Retrieves the server public key from cache or the datastore """
    global _SERVER_KEY
    if _SERVER_KEY is None:
        entity = storage.retrieve("config", "bunq_server_key")
        server_bytes = base64.a85decode(entity["value"])
        _SERVER_KEY = serialization.load_pem_public_key(
            server_bytes, backend=default_backend())
    return _SERVER_KEY
Пример #12
0
def get_app_mode():
    """ Return the app mode (master/slave) """
    global _APP_MODE
    if _APP_MODE is None:
        entity = storage.retrieve("config", "app_mode")
        if entity is not None:
            _APP_MODE = entity["value"]
        else:
            save_app_mode('master')
    return _APP_MODE
Пример #13
0
def get_session_token(force=False):
    """ Retrieves the session token from cache or the datastore
        or get one from the server if it is the first time
    """
    global _SESSION_TOKEN
    if force:
        refresh_session_token()
    elif _SESSION_TOKEN is None:
        entity = storage.retrieve("config", "bunq_session_token")
        if entity is not None:
            _SESSION_TOKEN = entity["value"]
        else:
            refresh_session_token()
    return _SESSION_TOKEN
Пример #14
0
def trigger_request():
    """ Callback for IFTTT trigger bunq_request """
    try:
        data = request.get_json()
        print("[trigger_request] input: {}".format(json.dumps(data)))

        if "triggerFields" not in data or \
                "account" not in data["triggerFields"]:
            print("[trigger_request] ERROR: account field missing!")
            return json.dumps({"errors": [{"message": "Invalid data"}]}), 400
        account = data["triggerFields"]["account"]
        fields = data["triggerFields"]
        fieldsstr = json.dumps(fields)

        if "trigger_identity" not in data:
            print("[trigger_request] ERROR: trigger_identity field missing!")
            return json.dumps({"errors": [{"message": "Invalid data"}]}), 400
        identity = data["trigger_identity"]

        limit = 50
        if "limit" in data:
            limit = data["limit"]

        if account == "NL42BUNQ0123456789":
            return trigger_request_test(limit)

        timezone = "UTC"
        if "user" in data and "timezone" in data["user"]:
            timezone = data["user"]["timezone"]

        entity = storage.retrieve("trigger_request", identity)
        if entity is not None:
            if entity["account"] != account or \
                    json.dumps(entity["fields"]) != fieldsstr:
                storage.store("trigger_request", identity, {
                    "account": account,
                    "identity": identity,
                    "fields": fields
                })
                print("[trigger_request] updating trigger {} {}".format(
                    account, fieldsstr))
        else:
            storage.store("trigger_request", identity, {
                "account": account,
                "identity": identity,
                "fields": fields
            })
            storage.store(
                "request_" + identity, "0", {
                    "value": {
                        "created_at": "2018-01-05T11:25:15+00:00",
                        "date": "2018-01-05",
                        "amount": "0.00",
                        "account": account,
                        "counterparty_account": "NL11BANK1111111111",
                        "counterparty_name": "Dummy Transaction",
                        "description": "This is a dummy transaction",
                        "request_id": "123e4567-e89b-12d3-a456-426655440001",
                        "meta": {
                            "id": "0",
                            "timestamp": "1515151515"
                        }
                    }
                })
            print("[trigger_request] storing new trigger {} {}".format(
                account, fieldsstr))

        transactions = []
        for entity in storage.query_all("request_" + identity):
            entity["value"]["created_at"] = arrow.get(\
                entity["value"]["created_at"]).to(timezone).isoformat()
            transactions.append(entity["value"])
        transactions = sorted(transactions,
                              key=lambda k: -int(k["meta"]["timestamp"]))

        if len(transactions) > 50:
            for trans in transactions[50:]:
                storage.remove("request_" + identity, str(trans["meta"]["id"]))

        print("[trigger_request] Found {} transactions".format(
            len(transactions)))
        return json.dumps({"data": transactions[:limit]})
    except Exception:
        traceback.print_exc()
        print("[trigger_request] ERROR: cannot retrieve requests")
        return json.dumps({"errors": [{"message": \
                           "Cannot retrieve requests"}]}), 400
Пример #15
0
def get_session_cookie():
    """ Return the users session cookie """
    entity = storage.retrieve("config", "session_cookie")
    if entity is not None:
        return entity["value"]
    return None
Пример #16
0
def get_bunq_userid():
    """ Return the bunq userid """
    global _BUNQ_USERID
    if _BUNQ_USERID is None:
        _BUNQ_USERID = storage.retrieve("config", "bunq_userid")["value"]
    return _BUNQ_USERID
Пример #17
0
def trigger_request():
    """ Callback for IFTTT trigger bunq_request """
    try:
        data = request.get_json()
        print("[trigger_request] input: {}".format(json.dumps(data)))

        if "triggerFields" not in data or \
                "account" not in data["triggerFields"]:
            print("[trigger_request] ERROR: account field missing!")
            return json.dumps({"errors": [{"message": "Invalid data"}]}), 400
        account = data["triggerFields"]["account"]
        fields = data["triggerFields"]
        fieldsstr = json.dumps(fields)

        if "trigger_identity" not in data:
            print("[trigger_request] ERROR: trigger_identity field missing!")
            return json.dumps({"errors": [{"message": "Invalid data"}]}), 400
        identity = data["trigger_identity"]

        limit = 50
        if "limit" in data:
            limit = data["limit"]

        if account == "NL42BUNQ0123456789":
            return trigger_request_test(limit)

        timezone = "UTC"
        if "user" in data and "timezone" in data["user"]:
            timezone = data["user"]["timezone"]

        entity = storage.retrieve("trigger_request", identity)
        if entity is not None:
            if entity["account"] != account or \
                    json.dumps(entity["fields"]) != fieldsstr:
                storage.store("trigger_request", identity, {
                    "account": account,
                    "identity": identity,
                    "fields": fields
                })
                print("[trigger_request] updating trigger {} {}".format(
                    account, fieldsstr))
        else:
            storage.store("trigger_request", identity, {
                "account": account,
                "identity": identity,
                "fields": fields
            })
            print("[trigger_request] storing new trigger {} {}".format(
                account, fieldsstr))

        transactions = storage.get_value("trigger_request", identity + "_t")
        if transactions is None:
            transactions = []
        for trans in transactions:
            trans["created_at"] = arrow.get(trans["created_at"])\
                                  .to(timezone).isoformat()

        print("[trigger_request] Found {} transactions".format(
            len(transactions)))
        return json.dumps({"data": transactions[:limit]})
    except Exception:
        traceback.print_exc()
        print("[trigger_request] ERROR: cannot retrieve requests")
        return json.dumps({"errors": [{"message": \
                           "Cannot retrieve requests"}]}), 400