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
					
						
							
								d160344130
							
						
					
				
			
			
				commit
				
					
						8376d0106c
					
				
			
		
					 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="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>
 | 
						    </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,7 +263,8 @@ 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')
 | 
				
			||||||
    model = HostingOrder
 | 
					    model = HostingOrder
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue