MonitoringWebTraffic / GiftcardSite / LegacySite / views.py
views.py
Raw
import json
from django.shortcuts import render, redirect
from django.http import HttpResponse
from LegacySite.models import User, Product, Card
from . import extras
from django.views.decorators.csrf import csrf_protect as csrf_protect
from django.contrib.auth import login, authenticate, logout
from django.core.exceptions import ObjectDoesNotExist
import prometheus_client
from prometheus_client.core import CollectorRegistry
from prometheus_client import Summary, Counter, Histogram, Gauge

SALT_LEN = 16


# Prometheus stuff!
graphs = {}
graphs['r_counter'] = Counter('python_request_r_posts', 'The total number'\
  + ' of register posts.')
graphs['l_counter'] = Counter('python_request_l_posts', 'The total number'\
  + ' of login posts.')
graphs['b_counter'] = Counter('python_request_b_posts', 'The total number'\
  + ' of card buy posts.')
graphs['g_counter'] = Counter('python_request_g_posts', 'The total number'\
  + ' of card gift posts.')
graphs['u_counter'] = Counter('python_request_u_posts', 'The total number'\
  + ' of card use posts.')
#Return the total number of times that the website return 404.
graphs['e_counters'] =  Counter('python_request_e_posts', 'The total number'\
  + ' of database_error_return_404.')


# Create your views here.
# Landing page. Nav bar, most recently bought cards, etc.
def index(request):
    context= {'user': request.user}
    return render(request, "index.html", context)

# Register for the service.
def register_view(request):
    if request.method == 'GET':
        return render(request, "register.html", {'method':'GET'})
    else:
        graphs['r_counter'].inc()
        context = {'method':'POST'}
        uname = request.POST.get('uname', None)
        pword = request.POST.get('pword', None)
        
        # KG: Uh... I'm not sure this makes sense.
        # Collect data to ensure good password use.
        #if pword not in graphs.keys():
        #    graphs[pword] = Counter(f'counter_{pword}', 'The total number of '\
        #      + f'times {pword} was used')
        #graphs[pword].inc()
        pword2 = request.POST.get('pword2', None)
        assert (None not in [uname, pword, pword2])
        if pword != pword2:
            context["success"] = False
            return render(request, "register.html", context)
        salt = extras.generate_salt(SALT_LEN)
        hashed_pword = extras.hash_pword(salt, pword)
        hashed_pword = salt.decode('utf-8') + '$' + hashed_pword
        u = User(username=uname, password=hashed_pword)
        u.save()
        return redirect("index.html")
        

# Log into the service.
def login_view(request):
    if request.method == "GET":
        return render(request, "login.html", {'method':'GET', 'failed':False})
    else:
        graphs['l_counter'].inc()
        context = {'method':'POST'}
        uname = request.POST.get('uname', None)
        pword = request.POST.get('pword', None)
        assert (None not in [uname, pword])
        user = authenticate(username=uname, password=pword)
        if user is not None:
            context['failed'] = False
            login(request, user)
            print("Logged in user")
        else:
            context['failed'] = True
            return render(request, "login.html", context)
        return redirect("index.html")

# Log out of the service.
def logout_view(request):
    if request.user.is_authenticated:
        logout(request)
    return redirect("index.html")

def buy_card_view(request, prod_num=0):
    if request.method == 'GET':
        context = {"prod_num" : prod_num}
        director = request.GET.get('director', None)
        if director is not None:
            # KG: Wait, what is this used for? Need to check the template.
            context['director'] = director
        if prod_num != 0:
            try:
                prod = Product.objects.get(product_id=prod_num) 
            except:
                graphs['e_counters'].inc()
                return HttpResponse("ERROR: 404 Not Found.")
        else:
            try:
                prod = Product.objects.get(product_id=1) 
            except:
                graphs['e_counters'].inc()
                return HttpResponse("ERROR: 404 Not Found.")
        context['prod_name'] = prod.product_name
        context['prod_path'] = prod.product_image_path
        context['price'] = prod.recommended_price
        context['description'] = prod.description
        return render(request, "item-single.html", context)
    elif request.method == 'POST':
        graphs['b_counter'].inc()
        if prod_num == 0:
            prod_num = 1
        num_cards = len(Card.objects.filter(user=request.user))
        # Generate a card here, based on amount sent. Need binary for this.
        card_file_path = f"/tmp/addedcard_{request.user.id}_{num_cards + 1}.gftcrd'"
        card_file_name = "newcard.gftcrd"
        # Use binary to write card here.
        # Create card record with data.
        # For now, until we get binary, write random data.
        prod = Product.objects.get(product_id=prod_num)
        amount = request.POST.get('amount', None)
        if amount is None or amount == '':
            amount = prod.recommended_price
        extras.write_card_data(card_file_path, prod, amount, request.user)
        card_file = open(card_file_path, 'rb')
        card = Card(data=card_file.read(), product=prod, amount=amount, fp=card_file_path, user=request.user)
        card.save()
        card_file.seek(0)
        response = HttpResponse(card_file, content_type="application/octet-stream")
        response['Content-Disposition'] = f"attachment; filename={card_file_name}"
        return response
        #return render(request, "item-single.html", {})
    else:
        return redirect("/buy/1")

# KG: What stops an attacker from making me buy a card for him?
def gift_card_view(request, prod_num=0):
    context = {"prod_num" : prod_num}
    if request.method == "GET":
        context['user'] = None
        director = request.GET.get('director', None)
        if director is not None:
            context['director'] = director
        if prod_num != 0:
            try:
                prod = Product.objects.get(product_id=prod_num) 
            except:
                graphs['e_counters'].inc()
                return HttpResponse("ERROR: 404 Not Found.")
        else:
            try:
                graphs['e_counters'].inc()
                prod = Product.objects.get(product_id=1) 
            except:
                graphs['e_counters'].inc()
                return HttpResponse("ERROR: 404 Not Found.")
        context['prod_name'] = prod.product_name
        context['prod_path'] = prod.product_image_path
        context['price'] = prod.recommended_price
        context['description'] = prod.description
        return render(request, "gift.html", context)
    elif request.method == "POST":
        graphs['g_counter'].inc()
        if prod_num == 0:
            prod_num = 1
        user = request.POST.get('username', None)
        if user is None:
            graphs['e_counters'].inc()
            return HttpResponse("ERROR 404")
        try:
            user_account = User.objects.get(username=user)
        except:
            user_account = None
        if user_account is None:
            context['user'] = None
            return render(request, f"gift.html", context)
        context['user'] = user_account
        num_cards = len(Card.objects.filter(user=user_account))
        card_file_path = f"/tmp/addedcard_{user_account.id}_{num_cards + 1}.gftcrd'"
        prod = Product.objects.get(product_id=prod_num)
        extras.write_card_data(card_file_path, prod, request.POST.get('amount', prod.recommended_price, user))
        card_file = open(card_file_path, 'rb')
        card = Card(data=card_file.read(), product=prod, amount=request.POST.get('amount', prod.recommended_price), fp=card_file_path, user=user_account)
        card.save()
        card_file.close()
        return render(request, f"gift.html", context)

def use_card_view(request):
    context = {'card_found':None}
    if request.method == 'GET':
        if not request.user.is_authenticated:
            return redirect("login.html")
        try:
            user_cards = Card.objects.filter(user=request.user).filter(used=False)
        except ObjectDoesNotExist:
            user_cards = None
        context['card_list'] = user_cards
        context['card'] = None
        return render(request, 'use-card.html', context)
    elif request.method == "POST" and request.POST.get('card_supplied', False):
        graphs['u_counter'].inc()
        # Post with specific card, use this card.
        context['card_list'] = None
        # Need to write this to parse card type.
        card_file_data = request.FILES['card_data']
        card_fname = request.POST.get('card_fname', None)
        if card_fname is None or card_fname == '':
            card_file_path = f'/tmp/newcard_{request.user.id}_parser.gftcrd'
        else:
            card_file_path = f'/tmp/{card_fname}_{request.user.id}_parser.gftcrd'
        card_data = extras.parse_card_data(card_file_data.read(), card_file_path)
        # check if we know about card.
        # KG: Where is this data coming from? RAW SQL usage with unkown
        # KG: data seems dangerous.
        signature = json.loads(card_data)['records'][0]['signature']
        # signatures should be pretty unique, right?
        card_query = Card.objects.raw('select id from LegacySite_card where data = \'%s\'' % signature)
        user_cards = Card.objects.raw('select id, count(*) as count from LegacySite_card where LegacySite_card.user_id = %s' % str(request.user.id))
        card_query_string = ""
        for thing in card_query:
            # print cards as strings
            card_query_string += str(thing) + '\n'
        if len(card_query) is 0:
            # card not known, add it.
            if card_fname is not None:
                card_file_path = f'/tmp/{card_fname}_{request.user.id}_{user_cards[0].count + 1}.gftcrd'
            else:
                card_file_path = f'/tmp/newcard_{request.user.id}_{user_cards[0].count + 1}.gftcrd'
            fp = open(card_file_path, 'w')
            fp.write(card_data)
            fp.close()
            card = Card(data=card_data, fp=card_file_path, user=request.user, used=True)
        else:
            context['card_found'] = card_query_string
            try:
                card = Card.objects.get(data=card_data)
                card.used = True
            except ObjectDoesNotExist:
                card = None
        context['card'] = card
        return render(request, "use-card.html", context) 
    elif request.method == "POST":
        graphs['u_counter'].inc()
        card = Card.objects.get(id=request.POST.get('card_id', None))
        card.used=True
        card.save()
        context['card'] = card
        try:
            user_cards = Card.objects.filter(user=request.user).filter(used=False)
        except ObjectDoesNotExist:
            user_cards = None
        context['card_list'] = user_cards
        return render(request, "use-card.html", context)
    graphs['e_counters'].inc()
    return HttpResponse("Error 404: Internal Server Error")

def metrics_view(request):
    res = []
    for key, value in graphs.items():
        res.append(prometheus_client.generate_latest(value))
    return HttpResponse(res, content_type="text/plain")