Adding final touches to #125
This commit is contained in:
parent
8eeed821d3
commit
ec896461a7
|
@ -32,7 +32,8 @@
|
||||||
"angularjs-toaster": "~0.4.14",
|
"angularjs-toaster": "~0.4.14",
|
||||||
"ngletteravatar": "~3.0.1",
|
"ngletteravatar": "~3.0.1",
|
||||||
"angular-ui-router": "~0.2.15",
|
"angular-ui-router": "~0.2.15",
|
||||||
"angular-clipboard": "~1.1.1"
|
"angular-clipboard": "~1.1.1",
|
||||||
|
"angular-file-saver": "~1.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"angular-mocks": "~1.3",
|
"angular-mocks": "~1.3",
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
:license: Apache, see LICENSE for more details.
|
:license: Apache, see LICENSE for more details.
|
||||||
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
|
.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
|
||||||
"""
|
"""
|
||||||
|
import base64
|
||||||
from builtins import str
|
from builtins import str
|
||||||
|
|
||||||
from flask import Blueprint, make_response, jsonify
|
from flask import Blueprint, make_response, jsonify
|
||||||
|
@ -817,10 +818,9 @@ class CertificateExport(AuthenticatedResource):
|
||||||
permission = UpdateCertificatePermission(certificate_id, getattr(role, 'name', None))
|
permission = UpdateCertificatePermission(certificate_id, getattr(role, 'name', None))
|
||||||
|
|
||||||
if permission.can():
|
if permission.can():
|
||||||
passphrase, data = service.export(cert, args['export']['plugin'])
|
extension, passphrase, data = service.export(cert, args['export']['plugin'])
|
||||||
response = make_response(data)
|
# we take a hit in message size when b64 encoding
|
||||||
response.headers['content-type'] = 'application/octet-stream'
|
return dict(extension=extension, passphrase=passphrase, data=base64.b64encode(data))
|
||||||
return response
|
|
||||||
|
|
||||||
return dict(message='You are not authorized to export this certificate'), 403
|
return dict(message='You are not authorized to export this certificate'), 403
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ class JavaExportPlugin(ExportPlugin):
|
||||||
'type': 'str',
|
'type': 'str',
|
||||||
'required': False,
|
'required': False,
|
||||||
'helpMessage': 'If no passphrase is given one will be generated for you, we highly recommend this. Minimum length is 8.',
|
'helpMessage': 'If no passphrase is given one will be generated for you, we highly recommend this. Minimum length is 8.',
|
||||||
'validation': '^.{8}$'
|
'validation': '^(?=.*[A-Za-z])(?=.*\d)(?=.*[$@$!%*#?&])[A-Za-z\d$@$!%*#?&]{8,}$'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'name': 'alias',
|
'name': 'alias',
|
||||||
|
@ -105,9 +105,13 @@ class JavaExportPlugin(ExportPlugin):
|
||||||
else:
|
else:
|
||||||
alias = "blah"
|
alias = "blah"
|
||||||
|
|
||||||
|
if not key:
|
||||||
|
raise Exception("Unable to export, no private key found.")
|
||||||
|
|
||||||
with mktempfile() as cert_tmp:
|
with mktempfile() as cert_tmp:
|
||||||
with open(cert_tmp, 'w') as f:
|
with open(cert_tmp, 'w') as f:
|
||||||
f.write(body)
|
f.write(body)
|
||||||
|
|
||||||
with mktempfile() as key_tmp:
|
with mktempfile() as key_tmp:
|
||||||
with open(key_tmp, 'w') as f:
|
with open(key_tmp, 'w') as f:
|
||||||
f.write(key)
|
f.write(key)
|
||||||
|
@ -168,4 +172,4 @@ class JavaExportPlugin(ExportPlugin):
|
||||||
with open(jks_tmp, 'rb') as f:
|
with open(jks_tmp, 'rb') as f:
|
||||||
raw = f.read()
|
raw = f.read()
|
||||||
|
|
||||||
return passphrase, raw
|
return "jks", passphrase, raw
|
||||||
|
|
|
@ -15,7 +15,8 @@ var lemur = angular
|
||||||
'mgo-angular-wizard',
|
'mgo-angular-wizard',
|
||||||
'satellizer',
|
'satellizer',
|
||||||
'ngLetterAvatar',
|
'ngLetterAvatar',
|
||||||
'angular-clipboard'
|
'angular-clipboard',
|
||||||
|
'ngFileSaver'
|
||||||
])
|
])
|
||||||
.config(function ($stateProvider, $urlRouterProvider, $authProvider) {
|
.config(function ($stateProvider, $urlRouterProvider, $authProvider) {
|
||||||
$urlRouterProvider.otherwise('/welcome');
|
$urlRouterProvider.otherwise('/welcome');
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('lemur')
|
angular.module('lemur')
|
||||||
.controller('CertificateExportController', function ($scope, $modalInstance, CertificateApi, CertificateService, PluginService, toaster, editId) {
|
.controller('CertificateExportController', function ($scope, $modalInstance, CertificateApi, CertificateService, PluginService, FileSaver, Blob, toaster, editId) {
|
||||||
CertificateApi.get(editId).then(function (certificate) {
|
CertificateApi.get(editId).then(function (certificate) {
|
||||||
$scope.certificate = certificate;
|
$scope.certificate = certificate;
|
||||||
});
|
});
|
||||||
|
@ -16,13 +16,26 @@ angular.module('lemur')
|
||||||
|
|
||||||
$scope.save = function (certificate) {
|
$scope.save = function (certificate) {
|
||||||
CertificateService.export(certificate).then(
|
CertificateService.export(certificate).then(
|
||||||
function () {
|
function (response) {
|
||||||
toaster.pop({
|
var byteCharacters = atob(response.data);
|
||||||
type: 'success',
|
var byteArrays = [];
|
||||||
title: certificate.name,
|
|
||||||
body: 'Successfully exported!'
|
for (var offset = 0; offset < byteCharacters.length; offset += 512) {
|
||||||
});
|
var slice = byteCharacters.slice(offset, offset + 512);
|
||||||
$modalInstance.close();
|
|
||||||
|
var byteNumbers = new Array(slice.length);
|
||||||
|
for (var i = 0; i < slice.length; i++) {
|
||||||
|
byteNumbers[i] = slice.charCodeAt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
var byteArray = new Uint8Array(byteNumbers);
|
||||||
|
|
||||||
|
byteArrays.push(byteArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
var blob = new Blob(byteArrays, {type: 'application/octet-stream'});
|
||||||
|
saveAs(blob, certificate.name + "." + response.extension);
|
||||||
|
$scope.passphrase = response.passphrase;
|
||||||
},
|
},
|
||||||
function (response) {
|
function (response) {
|
||||||
toaster.pop({
|
toaster.pop({
|
||||||
|
|
Loading…
Reference in New Issue