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
This commit is contained in:
parent
35e312411f
commit
b4164e56ab
7 changed files with 140 additions and 33 deletions
21
hosting/migrations/0018_virtualmachineplan_public_key.py
Normal file
21
hosting/migrations/0018_virtualmachineplan_public_key.py
Normal file
|
@ -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,
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,12 +1,14 @@
|
||||||
import json
|
import os
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.core import serializers
|
|
||||||
from membership.models import StripeCustomer
|
from membership.models import StripeCustomer
|
||||||
from utils.models import BillingAddress
|
from utils.models import BillingAddress
|
||||||
|
|
||||||
|
from Crypto.PublicKey import RSA
|
||||||
|
|
||||||
|
|
||||||
from .managers import VMPlansManager
|
from .managers import VMPlansManager
|
||||||
|
|
||||||
|
|
||||||
|
@ -84,6 +86,7 @@ class VirtualMachinePlan(models.Model):
|
||||||
disk_size = models.IntegerField()
|
disk_size = models.IntegerField()
|
||||||
vm_type = models.ForeignKey(VirtualMachineType)
|
vm_type = models.ForeignKey(VirtualMachineType)
|
||||||
price = models.FloatField()
|
price = models.FloatField()
|
||||||
|
public_key = models.TextField()
|
||||||
|
|
||||||
objects = VMPlansManager()
|
objects = VMPlansManager()
|
||||||
|
|
||||||
|
@ -104,20 +107,24 @@ class VirtualMachinePlan(models.Model):
|
||||||
instance = cls.objects.create(**data)
|
instance = cls.objects.create(**data)
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
@classmethod
|
@staticmethod
|
||||||
def generate_RSA(bits=2048):
|
def generate_RSA(bits=2048):
|
||||||
'''
|
'''
|
||||||
Generate an RSA keypair with an exponent of 65537 in PEM format
|
Generate an RSA keypair with an exponent of 65537 in PEM format
|
||||||
param: bits The key length in bits
|
param: bits The key length in bits
|
||||||
Return private key and public key
|
Return private key and public key
|
||||||
'''
|
'''
|
||||||
from Crypto.PublicKey import RSA
|
|
||||||
import os
|
|
||||||
new_key = RSA.generate(2048, os.urandom)
|
new_key = RSA.generate(2048, os.urandom)
|
||||||
public_key = new_key.publickey()
|
public_key = new_key.publickey().exportKey("OpenSSH")
|
||||||
private_key = new_key.exportKey("OpenSSH")
|
private_key = new_key.exportKey("PEM")
|
||||||
return private_key, public_key
|
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):
|
class HostingOrder(models.Model):
|
||||||
|
|
||||||
|
|
42
hosting/static/hosting/js/gen-ssh-key.js
Normal file
42
hosting/static/hosting/js/gen-ssh-key.js
Normal file
|
@ -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);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -163,6 +163,9 @@
|
||||||
<!-- Proccess payment lib -->
|
<!-- Proccess payment lib -->
|
||||||
<script type="text/javascript" src="{% static 'hosting/js/payment.js' %}"></script>
|
<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>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -58,7 +58,13 @@
|
||||||
<hr>
|
<hr>
|
||||||
<h4>Total<p class="pull-right"><b>{{order.vm_plan.price}} CHF</b></p></h4>
|
<h4>Total<p class="pull-right"><b>{{order.vm_plan.price}} CHF</b></p></h4>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,25 +6,58 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-9 col-md-offset-2">
|
<div class="col-md-9 col-md-offset-2">
|
||||||
<div class="col-sm-12">
|
<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/>
|
<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">
|
<div class="form-group">
|
||||||
<label for="comment">private_key.pem</label>
|
<label for="comment">private_key.pem</label>
|
||||||
<textarea class="form-control" rows="8" id="ssh_key">{{private_key}}</textarea>
|
<textarea class="form-control" rows="6" 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>
|
|
||||||
</div>
|
</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 class="clearfix"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% if private_key %}
|
||||||
|
<!-- Force to download ssh key on page load -->
|
||||||
<script type="text/javascript">
|
<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>
|
</script>
|
||||||
|
{%endif%}
|
||||||
|
|
||||||
|
|
||||||
{%endblock%}
|
{%endblock%}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -145,29 +145,23 @@ class SignupView(CreateView):
|
||||||
return HttpResponseRedirect(self.get_success_url())
|
return HttpResponseRedirect(self.get_success_url())
|
||||||
|
|
||||||
|
|
||||||
class GenerateVMSSHKeysView(LoginRequiredMixin, UpdateView):
|
class GenerateVMSSHKeysView(LoginRequiredMixin, DetailView):
|
||||||
model = VirtualMachinePlan
|
model = VirtualMachinePlan
|
||||||
template_name = 'hosting/virtual_machine_key.html'
|
template_name = 'hosting/virtual_machine_key.html'
|
||||||
success_url = reverse_lazy('hosting:orders')
|
success_url = reverse_lazy('hosting:orders')
|
||||||
|
context_object_name = "virtual_machine"
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
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):
|
context = super(GenerateVMSSHKeysView, self).get_context_data(**kwargs)
|
||||||
# vm = self.get_object()
|
vm = self.get_object()
|
||||||
# private_key, public_key = VirtualMachinePlan.generate_RSA()
|
if not vm.public_key:
|
||||||
# print(private_key)
|
private_key = vm.generate_keys()
|
||||||
# print(public_key)
|
context.update({
|
||||||
# key_name = "private_key"
|
'private_key': private_key
|
||||||
# response = HttpResponse(content_type='text/plain')
|
})
|
||||||
# response['Content-Disposition'] = 'attachment; filename="%s.pem"' % key_name
|
return context
|
||||||
# response.write(private_key)
|
return context
|
||||||
# return response
|
|
||||||
# return HttpResponseRedirect(reverse(''))
|
|
||||||
|
|
||||||
|
|
||||||
class PaymentVMView(LoginRequiredMixin, FormView):
|
class PaymentVMView(LoginRequiredMixin, FormView):
|
||||||
|
@ -269,6 +263,7 @@ class OrdersHostingListView(LoginRequiredMixin, ListView):
|
||||||
self.queryset = HostingOrder.objects.filter(customer__user=user)
|
self.queryset = HostingOrder.objects.filter(customer__user=user)
|
||||||
return super(OrdersHostingListView, self).get_queryset()
|
return super(OrdersHostingListView, self).get_queryset()
|
||||||
|
|
||||||
|
|
||||||
class OrdersHostingDeleteView(LoginRequiredMixin, DeleteView):
|
class OrdersHostingDeleteView(LoginRequiredMixin, DeleteView):
|
||||||
login_url=reverse_lazy('hosting:login')
|
login_url=reverse_lazy('hosting:login')
|
||||||
success_url = reverse_lazy('hosting:orders')
|
success_url = reverse_lazy('hosting:orders')
|
||||||
|
|
Loading…
Reference in a new issue