## # This file is part of TALER # (C) 2014, 2015, 2016 Taler Systems SA # # TALER is free software; you can redistribute it and/or modify it # under the terms of the GNU Affero General Public License as # published by the Free Software Foundation; either version 3, or # (at your option) any later version. TALER is distributed in the # hope that it will be useful, but WITHOUT ANY WARRANTY; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public # License along with TALER; see the file COPYING. If not, see # # # @author Marcello Stanisci # @author Florian Dold from functools import wraps import math import json import logging import hashlib import random import re from urllib.parse import urlparse import django.contrib.auth import django.contrib.auth.views import django.contrib.auth.forms from django.db import transaction from django import forms from django.conf import settings from django.contrib.auth.decorators import login_required from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_POST, require_GET from django.views.decorators.http import require_http_methods from django.urls import reverse from django.contrib.auth.models import User from django.db.models import Q from django.http import JsonResponse, HttpResponse from django.shortcuts import render, redirect from django.core.exceptions import ObjectDoesNotExist from datetime import datetime from .models import BankAccount, BankTransaction, TalerWithdrawOperation from taler.util.amount import Amount import qrcode import qrcode.image.svg import lxml from .schemas import ( HistoryParams, HistoryRangeParams, URLParamValidationError, RejectData, AddIncomingData, JSONFieldException, PinTanParams, InvalidSession, WithdrawSessionData, WithdrawHeadless, WithdrawHeadlessUri ) LOGGER = logging.getLogger(__name__) ## # Constant value for the biggest number the bank handles. # This value is just equal to the biggest number that JavaScript # can handle (because of the wallet). UINT64_MAX = (2**64) - 1 ## # Exception raised upon failing login. # class LoginFailed(Exception): hint = "Wrong username/password" http_status_code = 401 taler_error_code = 5109 class InvalidInputData(Exception): def __init__(self, msg): super().__init__(msg) class UsernameUnavailable(Exception): pass ## # Exception raised when the public history from # a ordinary user account is tried to be accessed. class PrivateAccountException(Exception): hint = "The selected account is private" http_status_code = 402 ## # Exception raised when some financial operation goes # beyond the limit threshold. class DebitLimitException(Exception): hint = "Insufficient credit, operation not acceptable." http_status_code = 406 taler_error_code = 5103 ## # Exception raised when some financial operation is # attempted and both parties are the same account number. # class SameAccountException(Exception): hint = "Debit and credit account are the same." http_status_code = 403 taler_error_code = 5102 ## # Exception raised when someone tries to reject a # transaction, but they have no rights to accomplish # such operation. class RejectNoRightsException(Exception): hint = "You weren't the transaction credit account, " \ "no rights to reject." http_status_code = 403 taler_error_code = 5200 class UnhandledException(Exception): hint = "Unhandled exception happened!" http_status_code = 500 taler_error_code = 5300 ## # The authentication for users to log in the bank. # class TalerAuthenticationForm(django.contrib.auth.forms.AuthenticationForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields["username"].widget.attrs["autofocus"] = True self.fields["username"].widget.attrs["placeholder"] = "Username" self.fields["password"].widget.attrs["placeholder"] = "Password" ## # Return a empty response. Used in "/favicon.ico" requests. # def ignore(request): del request return HttpResponse() ## # Decode body, when it is expected to be UTF-8. # # @param request the HTTP request being served. # @return the body as string. def decode_body(request): return request.body.decode("utf-8") ## # Get a flag from the session and clear it. # # @param request the HTTP request being served. # @param name name of the session value that should be retrieved. # @return the value, if found; otherwise False. def get_session_flag(request, name): if name in request.session: ret = request.session[name] del request.session[name] return ret return False ## # Get a hint from the session and clear it. A 'hint' is a # "message" that different parts of the bank can send to each # other - via the state - communicating what is the state of # the HTTP session. # # @param request the HTTP request being served. # @param name hint name # @return the hint (a "null" one if none was found) def get_session_hint(request, name): if name in request.session: ret = request.session[name] del request.session[name] return ret # Fail message, success message, hint. return False, False, None ## # Build the list containing all the predefined accounts; the # list contains, for example, the exchange, the bank itself, and # all the public accounts (like GNUnet / Tor / FSF / ..) def predefined_accounts_list(): account = 2 ret = [] for i in settings.TALER_PREDEFINED_ACCOUNTS[1:]: ret.append((account, "%s (#%d)" % (i, account))) account += 1 return ret ## # Thanks to [1], this class provides a dropdown menu that # can be used within a