from django.shortcuts import render, redirect from django.contrib import messages from django.contrib.auth import authenticate, login, logout from django.contrib.auth.decorators import login_required from django.utils.translation import gettext_lazy as _ from django.db.models import Q from django.views.decorators.csrf import csrf_exempt from django.http import HttpResponse, JsonResponse #reg from django.template.loader import render_to_string from django.contrib.sites.shortcuts import get_current_site from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode from django.utils.encoding import force_bytes, force_str from django.core.mail import EmailMessage #from django_otp.decorators import otp_required #from django.contrib.auth.views import PasswordResetView #from django.contrib.messages.views import SuccessMessageMixin #from django.core.exceptions import ValidationError #from django.urls import reverse_lazy #from django.contrib.auth.models import BaseUserManager # custom from .tokens import account_activation_token from users.models import User from .models import VendorsData, CryptoCoins, VendorsAddresses, InvoiceCreation from .forms import VendorEditForm, VendorAddrAddForm, UserRegistrationForm, PasswordResetForm, SetPasswordForm, InvoiceCreationForm, ApiPaymentCreationForm from .functions import vendor_generator, checksumCheck, UrlValidator, RPCHost, RPCXMR from .rpcs import rpcs, API_FEE import uuid, hashlib, requests # Create your views here. def activateEmail(request, user, to_email): mail_subject = 'Activate your user account.' message = render_to_string('base/template_activate_account.html', { 'user': user.username, 'domain': get_current_site(request).domain, 'uid': urlsafe_base64_encode(force_bytes(user.pk)), 'token': account_activation_token.make_token(user), 'protocol': 'https' if request.is_secure() else 'http' }) email = EmailMessage(mail_subject, message, to=[to_email]) if email.send(): messages.success(request, f'Congrats, please check your email and activate your account by \ clicking on the activation link. Rememeber to check all folders') else: messages.error(request, f' Unable to send the activation email, please check and retry.') def activate(request, uidb64, token): try: uid = force_str(urlsafe_base64_decode(uidb64)) user = User.objects.get(pk=uid) except(TypeError, ValueError, OverflowError, User.DoesNotExist): user = None if user is not None and account_activation_token.check_token(user, token): user.is_active = True user.save() messages.success(request, 'Thank you for your email confirmation. Now you can login your account.') else: messages.error(request, 'Activation link is invalid!') return redirect('login') @login_required(login_url='login') def index(request): context = {} return render(request, 'base/lp_dashboard.html', context) def RegiserUser(request): title = "Register your account" if request.method == "POST": if request.POST.get('password') != request.POST.get('password_again'): messages.error(request, 'Password does not match') return redirect('register') form = UserRegistrationForm(request.POST) if form.is_valid(): user = form.save(commit=False) user.email = form.cleaned_data['email'].lower() user.set_password(form.cleaned_data['password']) user.last_name = form.cleaned_data['last_name'] user.first_name = form.cleaned_data['first_name'] user.uuid = uuid.uuid4() user.is_active = False user.save() activateEmail(request, user, form.cleaned_data.get('email')) return redirect('login') else: form = UserRegistrationForm() context = {"form": form, 'title': title} return render(request, 'base/lp_register.html', context) def LoginPage(request): if request.method == 'POST': email = request.POST.get('email') password = request.POST.get('password') user = None error = None try: user = User.objects.get(email=email) except: error = messages.error(request, 'Wrong password or account is inactive') if user is not None and error is None: user = authenticate(request, email=email, password=password) if user is not None: login(request, user) return redirect('dashboard') else: messages.error(request, 'Wrong password or account is inactive') context = {'title': 'Sign In'} return render(request, 'base/lp_login.html', context) def LogoutPage(request): logout(request) return redirect('login') def password_reset_request(request): title = "Password reset" if request.method == 'POST': form = PasswordResetForm(request.POST) user = None if form.is_valid(): email = form.cleaned_data['email'].lower() try: user = User.objects.get(email=email) except: messages.success(request, 'If the email is registered with us, you will receive an email with instructions for resetting your password.') if user: subject = "Password reset requested on Litepay.ch" message = render_to_string("base/template_password_reset_email.html", { 'user': user, 'domain': get_current_site(request).domain, 'uid': urlsafe_base64_encode(force_bytes(user.pk)), 'token': account_activation_token.make_token(user), "protocol": 'https' if request.is_secure() else 'http' }) email = EmailMessage(subject, message, to=[user.email]) if email.send(): messages.success(request, """ If the email is registered with us, you will receive an email with instructions for resetting your password. """ ) else: messages.error(request, "Problem sending reset password email, please try again") return redirect('login') else: form = PasswordResetForm() context = {"form": form, 'title': title} return render(request, "base/lp_pswd_reset.html", context) def passwordResetConfirm(request, uidb64, token): title = "Password reset" try: uid = force_str(urlsafe_base64_decode(uidb64)) user = User.objects.get(pk=uid) except(TypeError, ValueError, OverflowError, User.DoesNotExist): user = None if user is not None and account_activation_token.check_token(user, token): if request.method == 'POST': form = SetPasswordForm(user, request.POST) if form.is_valid(): form.save() messages.success(request, "Your password has been set. You may go ahead and log in.") return redirect('login') else: for error in list(form.errors.values()): messages.error(request, error) context = {} return render(request, 'base/lp_pswd_reset_confirm.html', context) else: messages.error(request, "Link is expired") return redirect("dashboard") #### VENDOR VIEWS #### @login_required(login_url='login') def VendorPage(request): vendors = VendorsData.objects.filter(Q(vendorid_id=request.user.id) & Q(vendorDeleted=False)) context = {'vendors': vendors} return render(request, 'base/lp_vendor.html', context) @login_required(login_url='login') #@otp_required(login_url='two_factor:login') def VendorEditPage(request, vdr ): try: vendors = VendorsData.objects.get(Q(vendorid_id=request.user.id) & Q(vendorUUID=vdr)) form = VendorEditForm() vendor_title = "Edit Vendor" if request.method == 'POST': if request.POST.get('submit') == 'Submit': try: vendors = VendorsData.objects.get(Q(vendorid_id=request.user.id) & Q(vendorUUID=vdr)) form = VendorEditForm(request.POST, instance=vendors) if form.is_valid(): form.save() messages.success(request, "Vendor information saved") return redirect('vendor') else: messages.error(request, "Something wrong happened, try again.") except Exception as e: messages.error(request, "Something wrong happened, try again.") context = {'vendors': vendors, 'form': form, 'vendor_title': vendor_title} return render(request, 'base/lp_vendorEdit.html', context) except Exception as e: messages.error(request, e) return redirect('vendor') @login_required(login_url='login') def VendorCreatePage(request): vendor_title = "Create Vendor" context = {'vendor_title': vendor_title} if request.method == 'POST': try: try: vendor_accounts = len(VendorsData.objects.filter(vendorid_id=request.user.id)) if vendor_accounts > request.user.vendornr: messages.error(request, "You have reached the maximum number of vendor accounts") return redirect('vendor') except: pass form = VendorEditForm(request.POST) if form.is_valid(): # Generate vendor new_vendor = form.save(commit=False) try: vdr = vendor_generator() vendor_check = VendorsData.objects.get(vendorUUID=vdr) while vendor_check is vdr: vdr = vendor_generator() vendor_check = VendorsData.objects.get(vendorUUID=vdr) except: pass secretKey = str(uuid.uuid4()) md5s = hashlib.md5(secretKey.encode()).hexdigest() new_vendor.vendor = vdr new_vendor.vendorSecretKey = md5s new_vendor.vendorSkipScreen = False new_vendor.vendorUUID = uuid.uuid4() new_vendor.vendorid_id = request.user.id # Save vendor try: new_vendor.save() vendor_title = "Congrats!" context = {'vendor_title': vendor_title, "vendor": new_vendor, 'secret': secretKey} return render(request, 'base/lp_vendorSuccess.html', context) except Exception: messages.error(request, "Unable to create vendor") # else: messages.error(request, "The information submited is incomplete") # except Exception as e: messages.error(request, "Something wrong happened, try again.") return render(request, 'base/lp_vendorCreate.html', context) @login_required(login_url='login') def VendorAddrPage(request,vdr): try: coins = CryptoCoins.objects.filter(coinIsActive=True) try: vendors = VendorsData.objects.get(Q(vendorid_id=request.user.id) & Q(vendorUUID=vdr)) except: messages.error(request, "Vendor not found") return redirect('vendor') addresses = VendorsAddresses.objects.filter(Q(vendorUUID=vdr) & Q(vendorid_id=request.user.id)) form = VendorAddrAddForm() vendor_title = "Add a crypto address" if request.method == 'POST': if request.POST.get('submit') == 'Submit': try: if checksumCheck(request.POST.get('coin').lower(), request.POST.get('address')) == False: messages.error(request, "Invalid address, please try again") context = {'vendor_title': vendor_title, 'coins': coins, 'vendors': vendors, "addresses": addresses} return render(request, 'base/lp_vendorAddr.html', context) except: # stop here, return nothing, notify us. return redirect('vendorAddr', vdr) ##check if duplicate try: for obj in VendorsAddresses.objects.filter(Q(coin=request.POST.get('coin')) & Q(addrIsActive=True) & Q(vendorUUID=vdr) & Q(vendorid_id=request.user.id)): if obj.address == request.POST.get('address'): messages.error(request, "Address already exists") context = {'vendor_title': vendor_title, 'coins': coins, 'vendors': vendors, "addresses": addresses} return render(request, 'base/lp_vendorAddr.html', context) except: pass try: form = VendorAddrAddForm(request.POST) if form.is_valid(): new_address = form.save(commit=False) new_address.vendorUUID = vdr new_address.addrDeleted = False new_address.addrIsActive = True new_address.vendor_id = vendors.id new_address.vendorid_id = request.user.id try: for obj in VendorsAddresses.objects.filter(Q(coin=request.POST.get('coin')) & Q(addrIsActive=True) & Q(vendorid_id=request.user.id)): obj.addrIsActive = False obj.save() new_address.save() messages.success(request, "Vendor address saved") #add email notification context = {'vendor_title': vendor_title, 'coins': coins, 'vendors': vendors, "addresses": addresses} return render(request, 'base/lp_vendorAddr.html', context) except Exception as e: messages.error(request, e) # else: messages.error(request, "Something wrong happened, try again!") except Exception as e: messages.error(request, "Something wrong happened, try again!") context = {'vendor_title': vendor_title, 'coins': coins, 'vendors': vendors, "addresses": addresses} return render(request, 'base/lp_vendorAddr.html', context) except Exception as e: messages.error(request, "Something wrong happened, try again!") return redirect('vendor') @csrf_exempt def MerchInvoice(request): if request.method == 'GET': return HttpResponse(status=403) elif request.method == 'POST': required_fields = ['vendor', 'secret', 'callback', 'return', 'invoice'] for field in required_fields: if request.POST.get(field) is None or request.POST.get(field).strip() == '': return JsonResponse({'status': 'error', 'message': f'You did not send the {field} field, try again.'}, status=400) price = request.POST.get('price') currency = request.POST.get('currency') callbackurl = requests.utils.unquote(request.POST.get('callback')) returnurl = requests.utils.unquote(request.POST.get('return')) email = request.POST.get('email') if not currency: currency = 'USD' if price is None or not price.isdigit() or int(price) <= 0: return JsonResponse({'status': 'error', 'message': 'You did not send a valid price, try again.'}, status=400) if UrlValidator.validate(requests.utils.unquote(request.POST.get('callback')))!= True: return JsonResponse({'status': 'error', 'message': 'Invalid callback URL'}, status=400) if UrlValidator.validate(requests.utils.unquote(request.POST.get('return'))) != True: return JsonResponse({'status': 'error', 'message': 'Invalid return URL'}, status=400) try: vendor = VendorsData.objects.get(vendor=request.POST.get('vendor')) except: return JsonResponse({'status': 'error', 'message':'Vendor ID unknown'}, status=400) if vendor.vendorSecretKey != hashlib.md5(request.POST.get('secret').encode()).hexdigest(): return JsonResponse({'status': 'error', 'message': 'Invalid secret key'}, status=400) invUUID = uuid.uuid5(uuid.NAMESPACE_URL,request.POST.get('invoice')+request.POST.get('vendor')) if InvoiceCreation.objects.filter(Q(invoiceUUID=invUUID)): protocol = 'https' if request.is_secure() else 'http' domain = get_current_site(request).domain + '/v2/i/' + str(invUUID) return JsonResponse({'status': 'success', 'url': protocol +'://'+ domain }, status=200) try: form = InvoiceCreationForm() newForm = form.save(commit=False) newForm.invoiceUUID = invUUID newForm.invoiceID = request.POST.get('invoice') newForm.invoiceAmount = request.POST.get('price') newForm.invoiceCoin = currency newForm.invoiceState = 0 newForm.invoiceCallbackLink = callbackurl newForm.invoiceReturnLink = returnurl newForm.invoiceBuyerEmail = email newForm.invoiceDeleteLink = None newForm.invoiceDeleted = 0 newForm.invoiceVendor_id = vendor.id newForm.invoiceVendorid_id = vendor.vendorid_id try: newForm.save() protocol = 'https' if request.is_secure() else 'http' domain = get_current_site(request).domain + '/v2/i/' + str(invUUID) return JsonResponse({'status': 'success', 'url': protocol +'://'+ domain }, status=200) except Exception as e: return JsonResponse({'status': 'error', 'message': 'Unable to save the invoice, try again'}, status=400) except Exception as e: return JsonResponse({'status': 'error', 'message': 'Unable to create the invoice, try again'}, status=400) else: return HttpResponse(status=403) @csrf_exempt def ApiInvoice(request): if request.method == 'GET': required_fields = ['method', 'address'] for field in required_fields: if request.GET.get(field) is None or request.GET.get(field).strip() == '': return JsonResponse({'status': 'error', 'message': f'You did not send the {field} field, try again.'}, status=400) try: if not CryptoCoins.objects.filter(Q(coinAPI=True) & Q(coinIsActive=True) & Q(coinSymbol = request.GET.get('method').upper())): return JsonResponse({'status': 'error', 'message': 'Invalid method used'}, status=400) except Exception: return JsonResponse({'status': 'error', 'message': 'Something wrong happened, try again!'}, status=400) if checksumCheck(request.GET.get('method').lower(), request.GET.get('address')) == False: return JsonResponse({'status': 'error', 'message': 'Invalid destination address'}, status=400) if request.GET.get('callback_url'): if UrlValidator.validate(requests.utils.unquote(request.GET.get('callback_url'))) != True: return JsonResponse({'status': 'error', 'message': 'Invalid callback URL'}, status=400) statusFlag = 0 callbackurl = requests.utils.unquote(request.GET.get('callback_url')) else: statusFlag = 1 callbackurl = None ## RPC connection to Demons match request.GET.get('method').upper(): case 'BTC' | 'LTC' | 'ZEC' | 'BCH' | 'BTCT' | 'DOGE': rpc = RPCHost("http://%s:%s@%s:%s" % (rpcs[request.GET.get('method').upper()]['user'], rpcs[request.GET.get('method').upper()]['pass'], rpcs[request.GET.get('method').upper()]['host'], rpcs[request.GET.get('method').upper()]['port'])) case 'XMR': rpc = RPCXMR(rpcs[request.GET.get('method').upper()]['host'], rpcs[request.GET.get('method').upper()]['user'], rpcs[request.GET.get('method').upper()]['pass']) case _: return JsonResponse({'status': 'error', 'message': 'RPC undergoing maintenance'}, status=400) try: match request.GET.get('method').upper(): case 'XMR': wallet = rpc.call('create_address',{"account_index": 0}) wallet = wallet['address'] case 'LTC' | 'ZEC' | 'DOGE': #wallet = rpc.call('createwallet','test',False,False,'exdTHnRJ1BxZfBvU',False,False,True) wallet = rpc.call('getnewaddress') case 'BTC' | 'BTCT': #wallet = rpc.call('createwallet','test',False,False,'exdTHnRJ1BxZfBvU',False,True,True,False) wallet = rpc.call('getnewaddress', '', 'p2sh-segwit') case 'BCH': wallet = rpc.call('getnewaddress') wallet = wallet.replace('bitcoincash:', '') case _: ## notify admin about the error return JsonResponse({'status': 'error', 'message': 'CryptoCoin unavailable'}, status=400) except Exception as error: ## notify admin about the error # Failed to connect for remote procedure call. return JsonResponse({'status': 'error', 'message': 'RPC unavailable'}, status=400) try: form = ApiPaymentCreationForm() newForm = form.save(commit=False) newForm.userUUID = uuid.uuid5(uuid.NAMESPACE_URL,request.GET.get('address')) newForm.userAddr = request.GET.get('address') newForm.userCoin = request.GET.get('method').upper() newForm.usercallbackUrl = callbackurl newForm.userIP = request.META.get("REMOTE_ADDR") newForm.ourAddr = wallet newForm.userAmount = 0.00000000 newForm.statusFlag = statusFlag newForm.paidFlag = 0 try: newForm.save() return JsonResponse( {'status': 'success', 'callback_url': callbackurl, 'address': wallet, 'destination': request.GET.get('address'), 'fee': API_FEE }, status=200) except Exception as e: return JsonResponse({'status': 'error', 'message': 'Unable to save the invoice, try again'}, status=400) except Exception as e: return JsonResponse({'status': 'error', 'message': 'Unable to create the invoice, try again'}, status=400) elif request.method == 'POST': return HttpResponse(status=403) else: return HttpResponse(status=403) def InvoicePage(request, inv): try: invoice = InvoiceCreation.objects.get(invoiceUUID=inv) vendor = VendorsData.objects.get(Q(id=invoice.invoiceVendor_id)) vendorCryptoCoins = VendorsAddresses.objects.filter(Q(addrIsActive=True) & Q(vendor_id=invoice.invoiceVendor_id)) context = {'invoice': invoice, 'coins': vendorCryptoCoins, "vendor": vendor} return render(request, 'base/lp_invoice.html', context) except Exception as e: return HttpResponse(e) #return redirect('dashboard')