From b4164e56ab017f505b005381ea78d2837455c71c Mon Sep 17 00:00:00 2001 From: Levi Date: Tue, 24 May 2016 01:19:49 -0500 Subject: [PATCH] Added next button in order detail view after the user make a payment, Avoid to regenerate SSH Key if the user refresh the page, Now the key is served to download from javascript , Added public_key attribute to VirtualVMPlan in order to store keys created by the user, Now private key has PEM format and public has OpenSSH --- .../0018_virtualmachineplan_public_key.py | 21 +++++++++ hosting/models.py | 21 ++++++--- hosting/static/hosting/js/gen-ssh-key.js | 42 +++++++++++++++++ hosting/templates/hosting/base_short.html | 3 ++ hosting/templates/hosting/order_detail.html | 8 +++- .../hosting/virtual_machine_key.html | 47 ++++++++++++++++--- hosting/views.py | 31 +++++------- 7 files changed, 140 insertions(+), 33 deletions(-) create mode 100644 hosting/migrations/0018_virtualmachineplan_public_key.py create mode 100644 hosting/static/hosting/js/gen-ssh-key.js diff --git a/hosting/migrations/0018_virtualmachineplan_public_key.py b/hosting/migrations/0018_virtualmachineplan_public_key.py new file mode 100644 index 00000000..bd869a48 --- /dev/null +++ b/hosting/migrations/0018_virtualmachineplan_public_key.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.4 on 2016-05-24 03:57 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('hosting', '0017_virtualmachinetype_location'), + ] + + operations = [ + migrations.AddField( + model_name='virtualmachineplan', + name='public_key', + field=models.TextField(default='sada'), + preserve_default=False, + ), + ] diff --git a/hosting/models.py b/hosting/models.py index 2d322aad..55709fca 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -1,12 +1,14 @@ -import json +import os from django.db import models from django.utils.translation import ugettext_lazy as _ from django.utils.functional import cached_property -from django.core import serializers from membership.models import StripeCustomer from utils.models import BillingAddress +from Crypto.PublicKey import RSA + + from .managers import VMPlansManager @@ -84,6 +86,7 @@ class VirtualMachinePlan(models.Model): disk_size = models.IntegerField() vm_type = models.ForeignKey(VirtualMachineType) price = models.FloatField() + public_key = models.TextField() objects = VMPlansManager() @@ -104,20 +107,24 @@ class VirtualMachinePlan(models.Model): instance = cls.objects.create(**data) return instance - @classmethod + @staticmethod def generate_RSA(bits=2048): ''' Generate an RSA keypair with an exponent of 65537 in PEM format param: bits The key length in bits Return private key and public key ''' - from Crypto.PublicKey import RSA - import os new_key = RSA.generate(2048, os.urandom) - public_key = new_key.publickey() - private_key = new_key.exportKey("OpenSSH") + public_key = new_key.publickey().exportKey("OpenSSH") + private_key = new_key.exportKey("PEM") return private_key, public_key + def generate_keys(self): + private_key, public_key = self.generate_RSA() + self.public_key = public_key + self.save(update_fields=['public_key']) + return private_key + class HostingOrder(models.Model): diff --git a/hosting/static/hosting/js/gen-ssh-key.js b/hosting/static/hosting/js/gen-ssh-key.js new file mode 100644 index 00000000..46e701d7 --- /dev/null +++ b/hosting/static/hosting/js/gen-ssh-key.js @@ -0,0 +1,42 @@ +$( document ).ready(function() { + + + + + + // Create a file with ssh private key info + function donwloadKeyFile(){ + + var key = $('#ssh_key').text(); + var a = window.document.createElement('a'); + + a.href = window.URL.createObjectURL(new Blob([key], {type: 'text'})); + a.download = 'private_key.pem'; + + // Append anchor to body. + document.body.appendChild(a); + a.click(); + + // Remove anchor from body + document.body.removeChild(a); + + } + + + // Create a file with ssh private key info + $('#download_ssh_key').on('click',donwloadKeyFile); + + + $('[data-toggle="tooltip"]').tooltip(); + + var clipboard = new Clipboard('#copy_to_clipboard'); + + clipboard.on('success', function(e) { + var selector = "#"; + var copy_button_id = selector.concat(e.trigger.id); + setTimeout(function(){ + $(copy_button_id).tooltip('hide'); + }, 1000); + }); + +}); \ No newline at end of file diff --git a/hosting/templates/hosting/base_short.html b/hosting/templates/hosting/base_short.html index cc41f453..a050a3d9 100644 --- a/hosting/templates/hosting/base_short.html +++ b/hosting/templates/hosting/base_short.html @@ -163,6 +163,9 @@ + + + diff --git a/hosting/templates/hosting/order_detail.html b/hosting/templates/hosting/order_detail.html index 607c3677..87b4a5e0 100644 --- a/hosting/templates/hosting/order_detail.html +++ b/hosting/templates/hosting/order_detail.html @@ -58,7 +58,13 @@

Total

{{order.vm_plan.price}} CHF

- +
+ {% url 'hosting:payment' as payment_url %} + {% if payment_url in request.META.HTTP_REFERER %} +
+ +
+ {% endif %} diff --git a/hosting/templates/hosting/virtual_machine_key.html b/hosting/templates/hosting/virtual_machine_key.html index d2c79fd4..ee2f27df 100644 --- a/hosting/templates/hosting/virtual_machine_key.html +++ b/hosting/templates/hosting/virtual_machine_key.html @@ -6,25 +6,58 @@
-

Private Key

+ +

SSH Private Key


+ {% if private_key %} +
+ Warning! You can view your SSH private key once. Copy it or if it wasn't downloaded automatically, just click on Download to start it. +
- - - + +
-
+
+ + +
+ {% else %} +
+ Warning! Your SSH private key was already generated and downloaded, if you lost it, contact us. +
+ {% endif %} + Go to my Virtual Machine Dashboard +
- + +{% if private_key %} + +{%endif%} + + {%endblock%} diff --git a/hosting/views.py b/hosting/views.py index 1f058783..ad892143 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -145,29 +145,23 @@ class SignupView(CreateView): return HttpResponseRedirect(self.get_success_url()) -class GenerateVMSSHKeysView(LoginRequiredMixin, UpdateView): +class GenerateVMSSHKeysView(LoginRequiredMixin, DetailView): model = VirtualMachinePlan template_name = 'hosting/virtual_machine_key.html' success_url = reverse_lazy('hosting:orders') + context_object_name = "virtual_machine" def get_context_data(self, **kwargs): - private_key, public_key = VirtualMachinePlan.generate_RSA() - context = { - 'private_key': private_key - } - return context - # def get(self, *args, **kwargs): - # vm = self.get_object() - # private_key, public_key = VirtualMachinePlan.generate_RSA() - # print(private_key) - # print(public_key) - # key_name = "private_key" - # response = HttpResponse(content_type='text/plain') - # response['Content-Disposition'] = 'attachment; filename="%s.pem"' % key_name - # response.write(private_key) - # return response - # return HttpResponseRedirect(reverse('')) + context = super(GenerateVMSSHKeysView, self).get_context_data(**kwargs) + vm = self.get_object() + if not vm.public_key: + private_key = vm.generate_keys() + context.update({ + 'private_key': private_key + }) + return context + return context class PaymentVMView(LoginRequiredMixin, FormView): @@ -269,7 +263,8 @@ class OrdersHostingListView(LoginRequiredMixin, ListView): self.queryset = HostingOrder.objects.filter(customer__user=user) return super(OrdersHostingListView, self).get_queryset() -class OrdersHostingDeleteView(LoginRequiredMixin,DeleteView): + +class OrdersHostingDeleteView(LoginRequiredMixin, DeleteView): login_url=reverse_lazy('hosting:login') success_url = reverse_lazy('hosting:orders') model = HostingOrder