[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