gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [taler-bank] 01/04: checking withdraw session via json vali


From: gnunet
Subject: [GNUnet-SVN] [taler-bank] 01/04: checking withdraw session via json validation and moving all the exception handlers for wire_transfer() into one decorator.
Date: Wed, 08 Nov 2017 19:44:48 +0100

This is an automated email from the git hooks/post-receive script.

marcello pushed a commit to branch master
in repository bank.

commit 55d9006f5feb427e15d143fa50372bf671cb60ca
Author: Marcello Stanisci <address@hidden>
AuthorDate: Wed Nov 8 09:00:01 2017 +0100

    checking withdraw session via json validation
    and moving all the exception handlers for wire_transfer()
    into one decorator.
---
 talerbank/app/schemas.py |  42 ++++++++++++-----
 talerbank/app/tests.py   |  17 ++++---
 talerbank/app/views.py   | 114 ++++++++++++++++++++++++++---------------------
 3 files changed, 102 insertions(+), 71 deletions(-)

diff --git a/talerbank/app/schemas.py b/talerbank/app/schemas.py
index 9effaa9..73ce80c 100644
--- a/talerbank/app/schemas.py
+++ b/talerbank/app/schemas.py
@@ -23,6 +23,34 @@ from django.conf import settings
 import validictory
 import json
 
+AMOUNT_SCHEMA = {
+    "type": "object",
+    "properties": {
+        "value": {"type": "integer"},
+        "fraction": {"type": "integer"},
+        "currency": {"type": "string",
+                     "pattern": "^"+settings.TALER_CURRENCY+"$"}
+    }
+}
+
+WITHDRAW_SESSION_SCHEMA = {
+    "type": "object",
+    "properties": {
+        "amount": {"type": AMOUNT_SCHEMA},
+        "exchange_url": {"type": "string"},
+        "reserve_pub": {"type": "string"},
+        "exchange_account_number": {"type": "integer"},
+        "sender_wiredetails": {
+            "type": "object",
+            "properties": {
+                "type": {"type": "string"},
+                "bank_uri": {"type": "string"},
+                "account_number": {"type": "integer"}
+            }
+        }
+    }
+}
+
 WIREDETAILS_SCHEMA = {
     "type": "object",
     "properties": {
@@ -46,16 +74,6 @@ AUTH_SCHEMA = {
     }
 }
 
-AMOUNT_SCHEMA = {
-    "type": "object",
-    "properties": {
-        "value": {"type": "integer"},
-        "fraction": {"type": "integer"},
-        "currency": {"type": "string",
-                     "pattern": "^"+settings.TALER_CURRENCY+"$"}
-    }
-}
-
 INCOMING_REQUEST_SCHEMA = {
     "type": "object",
     "properties": {
@@ -104,3 +122,7 @@ def validate_wiredetails(wiredetails):
 
 def validate_incoming_request(incoming_request):
     validictory.validate(incoming_request, INCOMING_REQUEST_SCHEMA)
+
+def check_withdraw_session(session):
+    validictory.validate(session, WITHDRAW_SESSION_SCHEMA)
+
diff --git a/talerbank/app/tests.py b/talerbank/app/tests.py
index 2e5a83b..c055a72 100644
--- a/talerbank/app/tests.py
+++ b/talerbank/app/tests.py
@@ -180,7 +180,6 @@ class AddIncomingTestCase(TestCase):
                                follow=True, **{"HTTP_X_TALER_BANK_USERNAME": 
"user_user",
                                                "HTTP_X_TALER_BANK_PASSWORD": 
"user_password"})
         self.assertEqual(406, response.status_code)
-
         # Try to go debit
         data = '{"auth": {"type": "basic"}, \
                  "credit_account": 1, \
@@ -214,14 +213,14 @@ class HistoryTestCase(TestCase):
         user_bankaccount_p.account_no = 2
         user_bankaccount_p.save()
         one = Amount(settings.TALER_CURRENCY, 1)
-        wire_transfer(one, user_bankaccount, user_bankaccount_p, subject="a")
-        wire_transfer(one, user_bankaccount, user_bankaccount_p, subject="b")
-        wire_transfer(one, user_bankaccount, user_bankaccount_p, subject="c")
-        wire_transfer(one, user_bankaccount, user_bankaccount_p, subject="d")
-        wire_transfer(one, user_bankaccount, user_bankaccount_p, subject="e")
-        wire_transfer(one, user_bankaccount, user_bankaccount_p, subject="f")
-        wire_transfer(one, user_bankaccount, user_bankaccount_p, subject="g")
-        wire_transfer(one, user_bankaccount, user_bankaccount_p, subject="h")
+        wire_transfer(one, user_bankaccount, user_bankaccount_p, "a")
+        wire_transfer(one, user_bankaccount, user_bankaccount_p, "b")
+        wire_transfer(one, user_bankaccount, user_bankaccount_p, "c")
+        wire_transfer(one, user_bankaccount, user_bankaccount_p, "d")
+        wire_transfer(one, user_bankaccount, user_bankaccount_p, "e")
+        wire_transfer(one, user_bankaccount, user_bankaccount_p, "f")
+        wire_transfer(one, user_bankaccount, user_bankaccount_p, "g")
+        wire_transfer(one, user_bankaccount, user_bankaccount_p, "h")
 
     def tearDown(self):
         clear_db()
diff --git a/talerbank/app/views.py b/talerbank/app/views.py
index 2093d2f..58580af 100644
--- a/talerbank/app/views.py
+++ b/talerbank/app/views.py
@@ -15,6 +15,16 @@
 #  @author Marcello Stanisci
 #  @author Florian Dold
 
+# wire_transfer() needs to be wrapped in such a way that
+# any possible exception is caught in *one* place.  It is used when:
+#
+# 1. withdrawing is finalized (pin_tan_verify())
+# 2. a new user is registered (register())
+# 3. the exchange moves money to account X (add_incoming())
+#
+# NOTE: this abstracting function needs _sometimes_ to update the
+# session, depending on the situation.
+
 from urllib.parse import urljoin
 from functools import wraps
 import json
@@ -64,7 +74,6 @@ def ignore(request):
     del request
     return HttpResponse()
 
-
 def javascript_licensing(request):
     return render(request, "javascript.html")
 
@@ -139,7 +148,7 @@ def pin_tan_question(request):
         schemas.validate_pin_tan_args(request.GET.dict())
         # Currency is not checked, as any mismatches will be
         # detected afterwards
-    except validictory.FieldValidationError as err:
+    except (FVE, RFVE) as err:
         return HRBR("invalid '%s'" % err.fieldname)
     user_account = BankAccount.objects.get(user=request.user)
     request.session["exchange_account_number"] = \
@@ -163,9 +172,6 @@ def pin_tan_question(request):
         exchange=request.GET["exchange"])
     return render(request, "pin_tan.html", context)
 
-def err_ctx(resp, msg):
-    return dict(resp=resp, msg=msg)
-
 @require_POST
 @login_required
 def pin_tan_verify(request):
@@ -178,31 +184,26 @@ def pin_tan_verify(request):
         request.session["captcha_failed"] = True
         return redirect(request.POST.get("question_url", "profile"))
     # Check the session is a "pin tan" one
-    for i in ("amount", "exchange_url", "reserve_pub",
-              "exchange_account_number", "sender_wiredetails"):
-        if i not in request.session:
-            LOGGER.warning("Apparently NOT a withdraw session")
-            return redirect("profile")
-    amount = Amount(**request.session["amount"])
     try:
+        schemas.check_withdraw_session(request.session)
+        amount = Amount(**request.session["amount"])
         exchange_bank_account = BankAccount.objects.get(
             account_no=request.session["exchange_account_number"])
         wire_transfer(amount,
                       BankAccount.objects.get(user=request.user),
                       exchange_bank_account,
-                      request.session["reserve_pub"])
+                      request.session["reserve_pub"],
+                      request,
+                      session_expand=dict(debt_limit=True))
+    except (FVE, RFVE) as exc:
+        LOGGER.warning("Not a withdrawing session")
+        return redirect("profile")
+
     except BankAccount.DoesNotExist as exc:
-        err = err_ctx(HRBR("That exchange is unknown to this bank"),
-                      exc)
-    except DebtLimitExceededException as exc:
-        request.session["debt_limit"] = True
-        err = err_ctx(redirect("profile"), exc)
-    except (SameAccountException, BadFormatAmount, CurrencyMismatch) as exc:
-        err = err_ctx(JsonResponse({"error": "Internal server error"}, 
status=500),
-                      exc)
-    if "err" in locals():
-        LOGGER.error(err["msg"])
-        return err["resp"]()
+        return JsonResponse({"error": "That exchange is unknown to this bank"},
+                            status=404)
+    except WireTransferException as exc:
+        return exc.response
     res = requests.post(
         urljoin(request.session["exchange_url"],
                 "admin/add/incoming"),
@@ -250,18 +251,13 @@ def register(request):
     bank_internal_account = BankAccount.objects.get(account_no=1)
     try:
         wire_transfer(Amount(settings.TALER_CURRENCY, 100, 0),
-                      bank_internal_account, user_account,
-                      "Joining bonus")
-    except (CurrencyMismatch,
-            BadFormatAmount,
-            SameAccountException) as exc:
-        err = err_ctx(HttpResponseServerError(), exc)
-    except DebtLimitExceededException as exc:
-        request.session["no_initial_bonus"] = True
-        err = err_ctx(HttpResponseServerError(), exc)
-    if "err" in locals():
-        LOGGER.error(err["msg"])
-        return err["resp"]
+                      bank_internal_account,
+                      user_account,
+                      "Joining bonus",
+                      request=request,
+                      session_expand=dict(no_initial_bobus=True))
+    except WireTransferException as exc:
+        return exc.response
     request.session["just_registered"] = True
     user = django.contrib.auth.authenticate(username=username, 
password=password)
     django.contrib.auth.login(request, user)
@@ -447,9 +443,9 @@ def add_incoming(request, user_account):
     except (FVE, RFVE) as exc:
         return JsonResponse({"error": "invalid '%s'" % exc.fieldname},
                             status=406 if exc.fieldname == "currency" else 400)
+
     try:
         credit_account = BankAccount.objects.get(user=data["credit_account"])
-        schemas.validate_amount(data["amount"])
         wtrans = wire_transfer(Amount(**data["amount"]),
                                user_account.bankaccount,
                                credit_account,
@@ -457,22 +453,8 @@ def add_incoming(request, user_account):
     except BankAccount.DoesNotExist:
         return JsonResponse({"error": "credit_account not found"},
                             status=404)
-    except ValueError as exc:
-        err = err_ctx(JsonResponse({"error": exc}, status=400), exc)
-    except (CurrencyMismatch, BadFormatAmount) as exc:
-        err = err_ctx(JsonResponse({"error": "Internal server error"},
-                                   status=500),
-                      exc)
-    except SameAccountException:
-        err = err_ctx(JsonResponse({"error":"same debit and credit account"},
-                                   status=422),
-                      exc)
-    except DebtLimitExceededException as exc:
-        err = err_ctx(JsonResponse({"error": "debt situation"}, status=403),
-                      exc)
-    if "err" in locals():
-        LOGGER.error(err["msg"])
-        return err["resp"]
+    except WireTransferException as exc:
+        return exc.response
     return JsonResponse({"serial_id": wtrans.id,
                          "timestamp":
                              "/Date(%s)/" % int(wtrans.date.timestamp())})
@@ -503,7 +485,35 @@ def withdraw_nojs(request):
         response["X-Taler-Suggested-Exchange"] = 
settings.TALER_SUGGESTED_EXCHANGE
     return response
 
+class WireTransferException(Exception):
+    def __init__(self, response):
+        self.response = response
+
+def wire_transfer_exc_handler(view_func):
+    def err_cb(exc, resp):
+        LOGGER.error(str(exc))
+        raise WireTransferException(resp)
+    def _decorator(*args, request=None, session_expand=None):
+        try:
+            return view_func(*args)
+        except (CurrencyMismatch, BadFormatAmount) as exc:
+            err_cb(exc, JsonResponse({"error": "internal server error"},
+                                     status=500))
+        except DebtLimitExceededException as exc:
+            if request:
+                if session_expand:
+                    request.session.update(session_expand)
+                if request.path == "/pin/verify":
+                    err_cb(exc, redirect("profile"))
+            else:
+                err_cb(exc, JsonResponse({"error": "Unallowed debit"},
+                                         status=403))
+        except SameAccountException as exc:
+            err_cb(exc, JsonResponse({"error": "sender account == receiver 
account"},
+                                     status=422))
+    return wraps(view_func)(_decorator)
 
address@hidden
 def wire_transfer(amount, debit_account, credit_account, subject):
     LOGGER.info("%s => %s, %s, %s" %
                 (debit_account.account_no,

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]