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 @@ <!-- Proccess payment lib --> <script type="text/javascript" src="{% static 'hosting/js/payment.js' %}"></script> + <!-- Gen SSH Key lib --> + <script type="text/javascript" src="{% static 'hosting/js/gen-ssh-key.js' %}"></script> + </body> </html> 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 @@ <hr> <h4>Total<p class="pull-right"><b>{{order.vm_plan.price}} CHF</b></p></h4> </div> - <a href="{% url 'hosting:virtual_machines' order.vm_plan.id %}" class="pull-right"><button class="btn-info">View instance</button></a> + <br/> + {% url 'hosting:payment' as payment_url %} + {% if payment_url in request.META.HTTP_REFERER %} + <div class=" content pull-right"> + <a href="{% url 'hosting:virtual_machine_key' order.vm_plan.id %}" ><button class="btn btn-info">Finish Configuration</button></a> + </div> + {% endif %} </div> </div> </div> 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 @@ <div class="row"> <div class="col-md-9 col-md-offset-2"> <div class="col-sm-12"> - <h3><i class="fa fa-key" aria-hidden="true"></i> Private Key</h3> + + <h3><i class="fa fa-key" aria-hidden="true"></i> SSH Private Key</h3> <hr/> + {% if private_key %} + <div class="alert alert-warning"> + <strong>Warning!</strong> You can view your SSH private key once. Copy it or if it wasn't downloaded automatically, just click on Download to start it. + </div> <div class="form-group"> <label for="comment">private_key.pem</label> - <textarea class="form-control" rows="8" id="ssh_key">{{private_key}}</textarea> - <span class="h3 pull-right"><button type="button" class="btn btn-default"><a href=""> Download </a></button></span> - <span class="h3 pull-right"><button type="button" data-clipboard-target="#ssh_key" class="btn btn-default">Copy to Clipboard</button></span> + <textarea class="form-control" rows="6" id="ssh_key">{{private_key}}</textarea> + </div> - <div class="clearfix"></div> + <div class="form-group pull-right"> + <button type="button" id="copy_to_clipboard" data-clipboard-target="#ssh_key" class="btn btn-warning" + data-toggle="tooltip" data-placement="bottom" title="Copied" data-trigger="click">Copy to Clipboard</button> + <button type="button" id="download_ssh_key" class="btn btn-warning">Download</button> + </div> + {% else %} + <div class="alert alert-warning"> + <strong>Warning!</strong> Your SSH private key was already generated and downloaded, if you lost it, contact us. + </div> + {% endif %} + <a class="btn btn-success" href="{% url 'hosting:virtual_machines' virtual_machine.id %}"> Go to my Virtual Machine Dashboard</a> + <div class="clearfix"></div> </div> </div> </div> </div> - </div> + +{% if private_key %} +<!-- Force to download ssh key on page load --> <script type="text/javascript"> - (function () {new Clipboard('.btn');})(); + + var key = window.document.getElementById('ssh_key'); + 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); + </script> +{%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