mirror of
https://github.com/nextcloud/passman.git
synced 2025-11-10 06:01:32 +08:00
commit
994c9839fa
19 changed files with 577 additions and 272 deletions
15
css/app.css
15
css/app.css
|
|
@ -282,13 +282,6 @@
|
|||
#app-content #app-content-wrapper .edit_credential .custom_fields table tr td, #app-content #app-content-wrapper .edit_credential .files table tr td {
|
||||
height: 50px;
|
||||
vertical-align: middle; }
|
||||
#app-content #app-content-wrapper .edit_credential .file_tab .progress {
|
||||
margin-top: 10px;
|
||||
height: 10px; }
|
||||
#app-content #app-content-wrapper .edit_credential .file_tab .progress .progress-bar {
|
||||
height: 10px;
|
||||
background-image: none;
|
||||
background-color: #0082c9; }
|
||||
#app-content #app-content-wrapper .app_sidebar {
|
||||
padding: 10px;
|
||||
overflow-y: auto; }
|
||||
|
|
@ -331,6 +324,14 @@
|
|||
cursor: pointer;
|
||||
margin-right: 4px; }
|
||||
|
||||
.progress {
|
||||
margin-top: 10px;
|
||||
height: 10px; }
|
||||
.progress .progress-bar {
|
||||
height: 10px;
|
||||
background-image: none;
|
||||
background-color: #0082c9; }
|
||||
|
||||
.settings-container div {
|
||||
padding-left: 15px; }
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -51,8 +51,12 @@ angular.module('passmanApp')
|
|||
};
|
||||
|
||||
var parsed_data;
|
||||
$scope.current_import_index = 0;
|
||||
$scope.current_import_length = 0;
|
||||
|
||||
$scope.import_progress = {
|
||||
progress: 0,
|
||||
loaded: 0,
|
||||
total: 0
|
||||
};
|
||||
var addCredential = function(parsed_data_index){
|
||||
if(!parsed_data[parsed_data_index]){
|
||||
return;
|
||||
|
|
@ -66,34 +70,59 @@ angular.module('passmanApp')
|
|||
return
|
||||
}
|
||||
_log('Adding '+ _credential.label);
|
||||
$scope.current_import_index = parsed_data_index;
|
||||
_credential.vault_id = $scope.active_vault.vault_id;
|
||||
CredentialService.createCredential(_credential).then(function (result) {
|
||||
if(result.credential_id){
|
||||
_log('Added '+ _credential.label);
|
||||
if(parsed_data[ parsed_data_index +1]) {
|
||||
$scope.import_progress = {
|
||||
progress: parsed_data_index / parsed_data.length * 100,
|
||||
loaded: parsed_data_index,
|
||||
total: parsed_data.length
|
||||
};
|
||||
|
||||
addCredential(parsed_data_index +1)
|
||||
} else {
|
||||
$scope.import_progress = {
|
||||
progress: 100,
|
||||
loaded: parsed_data.length-1,
|
||||
total: parsed_data.length-1
|
||||
};
|
||||
_log('DONE!');
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
$scope.file_read_progress = {
|
||||
percent: 0,
|
||||
loaded: 0,
|
||||
total: 0
|
||||
};
|
||||
$scope.startImport = function(){
|
||||
$scope.import_progress = 0;
|
||||
$scope.file_read_percent = 0;
|
||||
if(file_data){
|
||||
$window.PassmanImporter[$scope.selectedImporter.id].readFile(file_data, function(parseddata){
|
||||
$window.PassmanImporter[$scope.selectedImporter.id]
|
||||
.readFile(file_data)
|
||||
.then(function(parseddata){
|
||||
parsed_data = parseddata;
|
||||
$scope.file_read_progress = {
|
||||
percent: 100,
|
||||
loaded: parsed_data.length,
|
||||
total: parsed_data.length
|
||||
};
|
||||
_log('Parsed '+ parsed_data.length + ' credentials, starting to import');
|
||||
$scope.current_import_length = parsed_data.length;
|
||||
if( parsed_data.length > 0){
|
||||
addCredential(0);
|
||||
} else {
|
||||
// @TODO Show message no data found
|
||||
}
|
||||
}).progress(function(progress){
|
||||
$scope.file_read_progress = progress;
|
||||
$scope.$apply();
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,32 +5,29 @@ angular.module('passmanApp')
|
|||
.controller('SharingSettingsCtrl', ['$scope', 'VaultService', 'CredentialService', 'SettingsService', '$location', '$routeParams', 'ShareService', 'EncryptService',
|
||||
function ($scope, VaultService, CredentialService, SettingsService, $location, $routeParams, ShareService, EncryptService) {
|
||||
$scope.active_vault = VaultService.getActiveVault();
|
||||
$scope.sharing_keys = ShareService.getSharingKeys();
|
||||
|
||||
$scope.progress = 1;
|
||||
$scope.generating = false;
|
||||
|
||||
$scope.sharing_keys = ShareService.getSharingKeys();
|
||||
|
||||
$scope.generateKeys = function (length) {
|
||||
$scope.progress = 1;
|
||||
$scope.generating = true;
|
||||
|
||||
ShareService.generateRSAKeys(length, function(progress){
|
||||
ShareService.generateRSAKeys(length).progress(function(progress){
|
||||
$scope.progress = progress > 0 ? 2:1;
|
||||
$scope.$apply();
|
||||
console.log($scope.progress);
|
||||
}, function(kp){
|
||||
}).then(function(kp){
|
||||
console.log('stuff done');
|
||||
$scope.generating = false;
|
||||
|
||||
var pem = ShareService.rsaKeyPairToPEM(kp)
|
||||
|
||||
$scope.active_vault.private_sharing_key = pem.privateKey;
|
||||
$scope.active_vault.private_sharing_key = EncryptService.encryptString(pem.privateKey);
|
||||
$scope.active_vault.public_sharing_key = pem.publicKey;
|
||||
|
||||
|
||||
var _vault = angular.copy($scope.active_vault);
|
||||
_vault.private_sharing_key = EncryptService.encryptString(_vault.private_sharing_key);
|
||||
VaultService.updateSharingKeys(_vault).then(function (result) {
|
||||
console.log('done')
|
||||
VaultService.updateSharingKeys($scope.active_vault).then(function (result) {
|
||||
$scope.sharing_keys = ShareService.getSharingKeys();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,11 @@
|
|||
*/
|
||||
angular.module('passmanApp')
|
||||
.service('ShareService', ['$http', 'VaultService', 'EncryptService', function ($http, VaultService, EncryptService) {
|
||||
// Setup sjcl random engine to max paranoia level and start collecting data
|
||||
var paranoia_level = 10
|
||||
sjcl.random.setDefaultParanoia(paranoia_level);
|
||||
sjcl.random.startCollectors();
|
||||
|
||||
return {
|
||||
search: function (string) {
|
||||
var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/search');
|
||||
|
|
@ -21,24 +26,43 @@ angular.module('passmanApp')
|
|||
});
|
||||
},
|
||||
generateRSAKeys: function(key_length, progress, callback){
|
||||
var p = new C_Promise(function(){
|
||||
var state = forge.pki.rsa.createKeyPairGenerationState(key_length, 0x10001);
|
||||
var step = function() {
|
||||
// run for 100 ms
|
||||
if(!forge.pki.rsa.stepKeyPairGenerationState(state, 100)) {
|
||||
// console.log(state);
|
||||
if (state.p !== null) {
|
||||
progress(50);
|
||||
// progress(50);
|
||||
this.call_progress(50);
|
||||
}
|
||||
else {
|
||||
progress(0);
|
||||
// progress(0);
|
||||
this.call_progress(0);
|
||||
}
|
||||
setTimeout(step, 1);
|
||||
setTimeout(step.bind(this), 1);
|
||||
}
|
||||
else {
|
||||
callback(state.keys);
|
||||
// callback(state.keys);
|
||||
this.call_then(state.keys);
|
||||
}
|
||||
};
|
||||
setTimeout(step, 100);
|
||||
setTimeout(step.bind(this), 100);
|
||||
});
|
||||
return p;
|
||||
},
|
||||
generateSharedKey: function(size){
|
||||
size = size || 20;
|
||||
return new C_Promise(function(){
|
||||
CRYPTO.PASSWORD.generate(size,
|
||||
function(pass) {
|
||||
this.call_then(pass);
|
||||
},
|
||||
function(progress) {
|
||||
this.call_progress(progress);
|
||||
}
|
||||
);
|
||||
})
|
||||
},
|
||||
rsaKeyPairToPEM: function(keypair){
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ PassmanImporter.clippers = {
|
|||
};
|
||||
|
||||
PassmanImporter.clippers.readFile = function (file_data, callback) {
|
||||
return new C_Promise(function() {
|
||||
var credential_list = [];
|
||||
var re = /<textarea>(.*?)<\/textarea>/gi;
|
||||
var matches = re.exec(file_data);
|
||||
|
|
@ -44,7 +45,14 @@ PassmanImporter.clippers.readFile = function (file_data, callback) {
|
|||
if(_credential.label){
|
||||
credential_list.push(_credential);
|
||||
}
|
||||
}
|
||||
}
|
||||
callback(credential_list);
|
||||
var progress = {
|
||||
percent: i/json_objects.length*100,
|
||||
loaded: i,
|
||||
total: json_objects.length
|
||||
};
|
||||
this.call_progress(progress);
|
||||
}
|
||||
}
|
||||
this.call_then(credential_list);
|
||||
});
|
||||
};
|
||||
|
|
@ -12,6 +12,7 @@ PassmanImporter.dashLaneCsv = {
|
|||
};
|
||||
|
||||
PassmanImporter.dashLaneCsv.readFile = function (file_data, callback) {
|
||||
return new C_Promise(function(){
|
||||
var rows = file_data.split('\n');
|
||||
var credential_list = [];
|
||||
for (var i = 1, row; row = rows[i]; i++) {
|
||||
|
|
@ -34,6 +35,14 @@ PassmanImporter.dashLaneCsv.readFile = function (file_data, callback) {
|
|||
if(_credential.label){
|
||||
credential_list.push(_credential);
|
||||
}
|
||||
}
|
||||
callback(credential_list);
|
||||
|
||||
var progress = {
|
||||
percent: i/rows.length*100,
|
||||
loaded: i,
|
||||
total: rows.length
|
||||
};
|
||||
this.call_progress(progress);
|
||||
}
|
||||
this.call_then(credential_list);
|
||||
});
|
||||
};
|
||||
|
|
@ -12,6 +12,7 @@ PassmanImporter.keepassCsv = {
|
|||
};
|
||||
|
||||
PassmanImporter.keepassCsv.readFile = function (file_data, callback) {
|
||||
var p = new C_Promise(function(){
|
||||
var parsed_csv = PassmanImporter.readCsv(file_data);
|
||||
var credential_list = [];
|
||||
for (var i = 0; i < parsed_csv.length; i++) {
|
||||
|
|
@ -34,6 +35,16 @@ PassmanImporter.keepassCsv.readFile = function (file_data, callback) {
|
|||
}
|
||||
_credential.tags = tags;
|
||||
credential_list.push(_credential);
|
||||
}
|
||||
callback(credential_list);
|
||||
|
||||
var progress = {
|
||||
percent: i/parsed_csv.length*100,
|
||||
loaded: i,
|
||||
total: parsed_csv.length
|
||||
};
|
||||
|
||||
this.call_progress(progress);
|
||||
}
|
||||
this.call_then(credential_list);
|
||||
});
|
||||
return p;
|
||||
};
|
||||
|
|
@ -12,6 +12,7 @@ PassmanImporter.lastpassCsv = {
|
|||
};
|
||||
|
||||
PassmanImporter.lastpassCsv.readFile = function (file_data, callback) {
|
||||
return new C_Promise(function(){
|
||||
var parsed_csv = PassmanImporter.readCsv(file_data);
|
||||
var credential_list = [];
|
||||
for (var i = 0; i < parsed_csv.length; i++) {
|
||||
|
|
@ -26,6 +27,13 @@ PassmanImporter.lastpassCsv.readFile = function (file_data, callback) {
|
|||
if(_credential.label){
|
||||
credential_list.push(_credential);
|
||||
}
|
||||
}
|
||||
callback(credential_list);
|
||||
var progress = {
|
||||
percent: i/parsed_csv.length*100,
|
||||
loaded: i,
|
||||
total: parsed_csv.length
|
||||
};
|
||||
this.call_progress(progress);
|
||||
}
|
||||
this.call_then(credential_list)
|
||||
});
|
||||
};
|
||||
|
|
@ -12,6 +12,7 @@ PassmanImporter.passmanJson = {
|
|||
};
|
||||
|
||||
PassmanImporter.passmanJson.readFile = function (file_data, callback) {
|
||||
return new C_Promise(function(){
|
||||
var parsed_json = PassmanImporter.readJson(file_data);
|
||||
var credential_list = [];
|
||||
for (var i = 0; i < parsed_json.length; i++) {
|
||||
|
|
@ -55,6 +56,14 @@ PassmanImporter.passmanJson.readFile = function (file_data, callback) {
|
|||
if(_credential.label){
|
||||
credential_list.push(_credential);
|
||||
}
|
||||
}
|
||||
callback(credential_list);
|
||||
var progress = {
|
||||
percent: i/parsed_json.length*100,
|
||||
loaded: i,
|
||||
total: parsed_json.length
|
||||
};
|
||||
|
||||
this.call_progress(progress);
|
||||
}
|
||||
this.call_then(credential_list);
|
||||
});
|
||||
};
|
||||
|
|
@ -12,6 +12,7 @@ PassmanImporter.passpackCsv = {
|
|||
};
|
||||
|
||||
PassmanImporter.passpackCsv.readFile = function (file_data, callback) {
|
||||
return new C_Promise(function(){
|
||||
var parsed_csv = PassmanImporter.readCsv(file_data, false);
|
||||
var credential_list = [];
|
||||
for (var i = 0; i < parsed_csv.length; i++) {
|
||||
|
|
@ -37,6 +38,15 @@ PassmanImporter.passpackCsv.readFile = function (file_data, callback) {
|
|||
if (_credential.label) {
|
||||
credential_list.push(_credential);
|
||||
}
|
||||
}
|
||||
callback(credential_list);
|
||||
|
||||
var progress = {
|
||||
percent: i/parsed_csv.length*100,
|
||||
loaded: i,
|
||||
total: parsed_csv.length
|
||||
};
|
||||
|
||||
this.call_progress(progress);
|
||||
}
|
||||
this.call_then(credential_list);
|
||||
})
|
||||
};
|
||||
|
|
@ -12,7 +12,7 @@ PassmanImporter.randomData = {
|
|||
};
|
||||
|
||||
PassmanImporter.randomData.readFile = function (file_data, callback) {
|
||||
var credential_list = [];
|
||||
return new C_Promise(function () {
|
||||
var tags =
|
||||
['Social media',
|
||||
'Hosting',
|
||||
|
|
@ -30,7 +30,9 @@ PassmanImporter.randomData.readFile = function (file_data,callback) {
|
|||
'Serials'
|
||||
];
|
||||
var label;
|
||||
var generateCredential = function (max, i, cb) {
|
||||
var credential_list = [];
|
||||
var _this = this;
|
||||
var generateCredential = function (max, i, callback) {
|
||||
if (jQuery) {
|
||||
var url = OC.generateUrl('apps/passman/api/internal/generate_person');
|
||||
$.ajax({
|
||||
|
|
@ -56,15 +58,24 @@ PassmanImporter.randomData.readFile = function (file_data,callback) {
|
|||
}
|
||||
credential_list.push(_credential);
|
||||
if (i <= max) {
|
||||
var progress = {
|
||||
percent: i / max * 100,
|
||||
loaded: i,
|
||||
total: max
|
||||
};
|
||||
_this.call_progress(progress);
|
||||
generateCredential(max, i + 1, callback)
|
||||
} else {
|
||||
cb(credential_list)
|
||||
callback(credential_list)
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
generateCredential(9, 0,function(credential_list){
|
||||
callback(credential_list);
|
||||
|
||||
|
||||
generateCredential(10, 1, function (credential_list) {
|
||||
_this.call_then(credential_list);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ PassmanImporter.zohoCsv = {
|
|||
};
|
||||
|
||||
PassmanImporter.zohoCsv.readFile = function (file_data, callback) {
|
||||
return new C_Promise(function(){
|
||||
var parsed_csv = PassmanImporter.readCsv(file_data, false);
|
||||
var credential_list = [];
|
||||
for (var i = 0; i < parsed_csv.length; i++) {
|
||||
|
|
@ -25,6 +26,15 @@ PassmanImporter.zohoCsv.readFile = function (file_data, callback) {
|
|||
if(_credential.label){
|
||||
credential_list.push(_credential);
|
||||
}
|
||||
}
|
||||
callback(credential_list);
|
||||
|
||||
var progress = {
|
||||
percent: i/parsed_csv.length*100,
|
||||
loaded: i,
|
||||
total: parsed_csv.length
|
||||
};
|
||||
|
||||
this.call_progress(progress);
|
||||
}
|
||||
this.call_then(credential_list);
|
||||
})
|
||||
};
|
||||
129
js/lib/crypto_wrap.js
Normal file
129
js/lib/crypto_wrap.js
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/**
|
||||
* ownCloud/NextCloud - passman
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Marcos Zuriaga <wolfi@wolfi.es>
|
||||
* @copyright Marcos Zuriarga 2015
|
||||
*/
|
||||
var CRYPTO = { // Global variables of the object:
|
||||
paranoia_level: null,
|
||||
|
||||
PASSWORD : {
|
||||
/**
|
||||
* Callback will be called once the password its generated, it should accept one parameter, and the parameter will be the key (
|
||||
* CRYPTO.PASSWORD.generate(100, function(password){
|
||||
* console.log("The generated password is: " + password);
|
||||
* // Do more stuff here
|
||||
* }, function (current_percentage){
|
||||
* console.log("The current password generation progress it's: " + current_percentage + "%");
|
||||
* // Do real stuff here, update a progressbar, etc.
|
||||
* }
|
||||
* );
|
||||
* )
|
||||
* @param length The minium length of the generated password (it generates in packs of 4 characters,
|
||||
* so it can end up being up to 3 characters longer)
|
||||
* @param callback The function to be called after the password generation its done
|
||||
* @param progress The process of the generation, optional, called each 4 characters generated.
|
||||
*/
|
||||
generate : function (length, callback, progress, start_string) {
|
||||
if (!sjcl.random.isReady(paranoia_level)) {
|
||||
setTimeout(this.generate(length, callback, progress, start_string), 500);
|
||||
return;
|
||||
}
|
||||
|
||||
if (start_string == null) start_string = "";
|
||||
if (start_string.length < length) {
|
||||
start_string += CRYPTO.RANDOM.getRandomASCII();
|
||||
if (progress != null) progress(start_string.length / length * 100);
|
||||
}
|
||||
else {
|
||||
callback(start_string);
|
||||
if (progress != null) progress(100);
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(this.generate(length, callback, progress, start_string), 100);
|
||||
},
|
||||
|
||||
logRepeatedCharCount: function (str) {
|
||||
var chars = [];
|
||||
|
||||
for (i = 0; i < str.length; i++) {
|
||||
chars[str.charAt(i)] = (chars[str.charAt(i)] == null) ? 0 : chars[str.charAt(i)] + 1;
|
||||
}
|
||||
return chars;
|
||||
},
|
||||
},
|
||||
|
||||
RANDOM: {
|
||||
/**
|
||||
* Returns a random string of 4 characters length
|
||||
*/
|
||||
getRandomASCII : function () {
|
||||
// console.warn(paranoia_level);
|
||||
|
||||
var ret = "";
|
||||
while (ret.length < 4) {
|
||||
var int = sjcl.random.randomWords(1, paranoia_level);
|
||||
int = int[0];
|
||||
|
||||
var tmp = this._isASCII((int & 0xFF000000) >> 24);
|
||||
if (tmp) ret += tmp;
|
||||
|
||||
tmp = this._isASCII((int & 0x00FF0000) >> 16);
|
||||
if (tmp) ret += tmp;
|
||||
|
||||
tmp = this._isASCII((int & 0x0000FF00) >> 8);
|
||||
if (tmp) ret += tmp;
|
||||
|
||||
tmp = this._isASCII(int & 0x000000FF);
|
||||
if (tmp) ret += tmp;
|
||||
}
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks whether the given data it's an ascii character, returning the corresponding character; returns false otherwise
|
||||
*
|
||||
* @param data
|
||||
* @returns {string}
|
||||
* @private
|
||||
*/
|
||||
_isASCII : function (data) {
|
||||
return (data > 31 && data < 127) ? String.fromCharCode(data) : false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes the random and other cryptographic engines needed for this library to work
|
||||
* The default paranoia, in case no paranoia level it's provided, it's 10 (1024).
|
||||
* The higher paranoia level allowed by sjcl.
|
||||
*
|
||||
* PARANOIA_LEVELS:
|
||||
* 0 = 0
|
||||
* 1 = 48
|
||||
* 2 = 64
|
||||
* 3 = 96
|
||||
* 4 = 128
|
||||
* 5 = 192
|
||||
* 6 = 256
|
||||
* 7 = 384
|
||||
* 8 = 512
|
||||
* 9 = 768
|
||||
* 10 = 1024
|
||||
*
|
||||
* @param default_paranoia (0-10 integer)
|
||||
*/
|
||||
initEngines : function (default_paranoia) {
|
||||
paranoia_level = default_paranoia || 10;
|
||||
|
||||
sjcl.random.setDefaultParanoia(this.paranoia_level);
|
||||
sjcl.random.startCollectors();
|
||||
|
||||
console.warn('Crypto stuff initialized');
|
||||
}
|
||||
};
|
||||
CRYPTO.initEngines();
|
||||
36
js/lib/promise.js
Normal file
36
js/lib/promise.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* ownCloud/NextCloud - passman
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Marcos Zuriaga <wolfi@wolfi.es>
|
||||
* @copyright Marcos Zuriarga 2016
|
||||
*/
|
||||
|
||||
function C_Promise(workload){
|
||||
this.update = null; this.finally = null; this.error_function = null;
|
||||
this.then = function(callback){
|
||||
this.finally = callback;
|
||||
return this;
|
||||
};
|
||||
this.progress = function(callback){
|
||||
this.update = callback;
|
||||
return this;
|
||||
};
|
||||
this.error = function (callback){
|
||||
this.error_function = callback;
|
||||
return this;
|
||||
};
|
||||
this.call_then = function(data){
|
||||
if (this.finally !== null) this.finally(data);
|
||||
};
|
||||
this.call_progress = function(data){
|
||||
if (this.update !== null) this.update(data);
|
||||
};
|
||||
this.call_error = function(data){
|
||||
if(this.error_function !== null) this.error_function(data);
|
||||
};
|
||||
|
||||
setTimeout(workload.bind(this), 100);
|
||||
}
|
||||
|
|
@ -57,7 +57,7 @@ angular.module('views/partials/forms/settings/general_settings.html', []).run(['
|
|||
angular.module('views/partials/forms/settings/import.html', []).run(['$templateCache', function($templateCache) {
|
||||
'use strict';
|
||||
$templateCache.put('views/partials/forms/settings/import.html',
|
||||
'<div ng-controller="ImportCtrl"><div class="row"><div class="col-xs-6"><label>Import type<select ng-init="importerType" ng-model="importerType" ng-change="setImporter(importerType)"><option ng-repeat="importer in available_importers" value="{{importer}}">{{importer.name}}</option></select></label><div><b>{{selectedImporter.description}}</b></div><input ng-if="selectedImporter" type="file" file-select success="fileLoaded" error="fileLoadError" progress="fileSelectProgress"><br><button class="button" ng-click="startImport()" ng-if="selectedImporter">Import</button><div ng-if="current_import_length">{{ current_import_index }} / {{ current_import_length - 1}}</div></div><div class="col-xs-6"><div ng-if="log" class="import_log"><textarea id="import_log" auto-scroll="log">{{log.join(\'\\n\')}}</textarea></div></div></div></div>');
|
||||
'<div ng-controller="ImportCtrl"><div class="row"><div class="col-xs-6"><label>Import type<select ng-init="importerType" ng-model="importerType" ng-change="setImporter(importerType)"><option ng-repeat="importer in available_importers" value="{{importer}}">{{importer.name}}</option></select></label><div><b>{{selectedImporter.description}}</b></div><input ng-if="selectedImporter" type="file" file-select success="fileLoaded" error="fileLoadError" progress="fileSelectProgress"><br><button class="button" ng-click="startImport()" ng-if="selectedImporter">Import</button><div ng-if="file_read_progress.percent > 0">Read progress<div progress-bar="file_read_progress.percent"></div><br>{{ file_read_progress.loaded }} / {{ file_read_progress.total }}</div><div ng-if="import_progress.progress > 0">Upload progress<div progress-bar="import_progress.progress"></div><br>{{ import_progress.loaded }} / {{ import_progress.total }}</div></div><div class="col-xs-6"><div ng-if="log" class="import_log"><textarea id="import_log" auto-scroll="log">{{log.join(\'\\n\')}}</textarea></div></div></div></div>');
|
||||
}]);
|
||||
|
||||
angular.module('views/partials/forms/settings/sharing.html', []).run(['$templateCache', function($templateCache) {
|
||||
|
|
|
|||
|
|
@ -197,15 +197,7 @@
|
|||
}
|
||||
}
|
||||
.file_tab {
|
||||
.progress {
|
||||
margin-top: 10px;
|
||||
height: 10px;
|
||||
.progress-bar {
|
||||
height: 10px;
|
||||
background-image: none;
|
||||
background-color: #0082c9;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
.app_sidebar {
|
||||
|
|
@ -270,3 +262,12 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
.progress {
|
||||
margin-top: 10px;
|
||||
height: 10px;
|
||||
.progress-bar {
|
||||
height: 10px;
|
||||
background-image: none;
|
||||
background-color: #0082c9;
|
||||
}
|
||||
}
|
||||
|
|
@ -22,6 +22,8 @@ script('passman', 'vendor/angular-xeditable/xeditable.min');
|
|||
script('passman', 'vendor/sha/sha');
|
||||
script('passman', 'vendor/llqrcode/llqrcode');
|
||||
script('passman', 'vendor/forge.0.6.9.min');
|
||||
script('passman', 'lib/promise');
|
||||
script('passman', 'lib/crypto_wrap');
|
||||
|
||||
|
||||
script('passman', 'app/app');
|
||||
|
|
|
|||
|
|
@ -16,8 +16,18 @@
|
|||
<button class="button" ng-click="startImport()"
|
||||
ng-if="selectedImporter">Import
|
||||
</button>
|
||||
<div ng-if="current_import_length">
|
||||
{{ current_import_index }} / {{ current_import_length - 1}}
|
||||
|
||||
<div ng-if="file_read_progress.percent > 0">
|
||||
Read progress
|
||||
<div progress-bar="file_read_progress.percent"></div>
|
||||
<br />
|
||||
{{ file_read_progress.loaded }} / {{ file_read_progress.total }}
|
||||
</div>
|
||||
<div ng-if="import_progress.progress > 0">
|
||||
Upload progress
|
||||
<div progress-bar="import_progress.progress"></div>
|
||||
<br />
|
||||
{{ import_progress.loaded }} / {{ import_progress.total }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue