mirror of
https://github.com/nextcloud/passman.git
synced 2025-11-07 03:26:06 +08:00
Working passman import
This commit is contained in:
parent
b916ce4290
commit
a991302777
14 changed files with 229 additions and 23 deletions
|
|
@ -371,6 +371,13 @@
|
||||||
padding-left: 0px;
|
padding-left: 0px;
|
||||||
padding-right: 15px; }
|
padding-right: 15px; }
|
||||||
|
|
||||||
|
.import_log {
|
||||||
|
max-height: 600px;
|
||||||
|
overflow-y: auto; }
|
||||||
|
.import_log textarea {
|
||||||
|
width: 90%;
|
||||||
|
height: 200px; }
|
||||||
|
|
||||||
#app-settings-content:not(.ng-hide) {
|
#app-settings-content:not(.ng-hide) {
|
||||||
height: 60px;
|
height: 60px;
|
||||||
display: inherit !important;
|
display: inherit !important;
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -88,7 +88,7 @@ jQuery(document).ready(function () {
|
||||||
angular.element('#app-content-wrapper').scope().deleteCredential(credential);
|
angular.element('#app-content-wrapper').scope().deleteCredential(credential);
|
||||||
angular.element('#app-content-wrapper').scope().$apply();
|
angular.element('#app-content-wrapper').scope().$apply();
|
||||||
});
|
});
|
||||||
var adjustControlsWidth = function() {
|
var adjustControlsWidth = function(r) {
|
||||||
if($('#controls').length) {
|
if($('#controls').length) {
|
||||||
var controlsWidth;
|
var controlsWidth;
|
||||||
// if there is a scrollbar …
|
// if there is a scrollbar …
|
||||||
|
|
@ -111,12 +111,17 @@ jQuery(document).ready(function () {
|
||||||
controlsWidth = $('#content').width();
|
controlsWidth = $('#content').width();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$('#controls').css('width', controlsWidth);
|
if(r){
|
||||||
$('#controls').css('min-width', controlsWidth);
|
var magic = 0;
|
||||||
|
} else {
|
||||||
|
var magic = 85;
|
||||||
|
}
|
||||||
|
$('#controls').css('width', controlsWidth+magic);
|
||||||
|
$('#controls').css('min-width', controlsWidth+magic);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
$(window).resize(_.debounce(adjustControlsWidth, 256));
|
$(window).resize(_.debounce(adjustControlsWidth, 400));
|
||||||
setTimeout(function(){
|
setTimeout(function(){
|
||||||
adjustControlsWidth()
|
adjustControlsWidth(true)
|
||||||
},200)
|
},200)
|
||||||
});
|
});
|
||||||
|
|
@ -8,11 +8,12 @@
|
||||||
* Controller of the passmanApp
|
* Controller of the passmanApp
|
||||||
*/
|
*/
|
||||||
angular.module('passmanApp')
|
angular.module('passmanApp')
|
||||||
.controller('ImportCtrl', ['$scope', '$window', function ($scope, $window) {
|
.controller('ImportCtrl', ['$scope', '$window', 'CredentialService', 'VaultService', function ($scope, $window, CredentialService, VaultService) {
|
||||||
//@TODo read the available importers from $window.PassmanImporter
|
//@TODo read the available importers from $window.PassmanImporter
|
||||||
$scope.available_importers = [
|
$scope.available_importers = [
|
||||||
|
|
||||||
];
|
];
|
||||||
|
$scope.active_vault = VaultService.getActiveVault();
|
||||||
|
|
||||||
|
|
||||||
$scope.$watch(function(){
|
$scope.$watch(function(){
|
||||||
|
|
@ -25,16 +26,21 @@ angular.module('passmanApp')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, true);
|
}, true);
|
||||||
|
$scope.log = [];
|
||||||
$scope.setImporter = function (importer) {
|
$scope.setImporter = function (importer) {
|
||||||
importer = JSON.parse(importer);
|
importer = JSON.parse(importer);
|
||||||
$scope.selectedImporter = importer;
|
$scope.selectedImporter = importer;
|
||||||
};
|
};
|
||||||
|
var _log = function(str){
|
||||||
|
$scope.log.push(str);
|
||||||
|
};
|
||||||
|
|
||||||
var file_data;
|
var file_data;
|
||||||
$scope.fileLoaded = function (file) {
|
$scope.fileLoaded = function (file) {
|
||||||
file_data = file.data.split(',');
|
file_data = file.data.split(',');
|
||||||
file_data = decodeURIComponent(escape(window.atob( file_data[1] ))); //window.atob();
|
file_data = decodeURIComponent(escape(window.atob( file_data[1] ))); //window.atob();
|
||||||
|
_log('File read successfully!')
|
||||||
|
$scope.$apply();
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.fileLoadError = function (file) {
|
$scope.fileLoadError = function (file) {
|
||||||
|
|
@ -44,11 +50,49 @@ angular.module('passmanApp')
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var parsed_data;
|
||||||
|
$scope.current_import_index = 0;
|
||||||
|
$scope.current_import_length = 0;
|
||||||
|
var addCredential = function(parsed_data_index){
|
||||||
|
if(!parsed_data[parsed_data_index]){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var _credential = parsed_data[parsed_data_index];
|
||||||
|
if(!_credential.label){
|
||||||
|
if(parsed_data[ parsed_data_index +1]) {
|
||||||
|
_log('Credential has no label, skipping');
|
||||||
|
addCredential(parsed_data_index +1)
|
||||||
|
}
|
||||||
|
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]) {
|
||||||
|
addCredential(parsed_data_index +1)
|
||||||
|
} else {
|
||||||
|
_log('DONE!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
$scope.startImport = function(){
|
$scope.startImport = function(){
|
||||||
if(file_data){
|
if(file_data){
|
||||||
var parsed_data = $window.PassmanImporter[$scope.selectedImporter.id].readFile(file_data);
|
parsed_data = $window.PassmanImporter[$scope.selectedImporter.id].readFile(file_data);
|
||||||
console.log('Data parsed!', parsed_data);
|
_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
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
|
|
|
||||||
22
js/app/directives/autoscroll.js
Normal file
22
js/app/directives/autoscroll.js
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc directive
|
||||||
|
* @name passmanApp.directive:autoScroll
|
||||||
|
* @description
|
||||||
|
* # autoScroll
|
||||||
|
*/
|
||||||
|
angular.module('passmanApp')
|
||||||
|
.directive('autoScroll', function () {
|
||||||
|
return {
|
||||||
|
restrict: 'A',
|
||||||
|
scope: {
|
||||||
|
autoScroll: '='
|
||||||
|
},
|
||||||
|
link: function postLink(scope, element, attrs) {
|
||||||
|
scope.$watch('autoScroll', function () {
|
||||||
|
$('#import_log').scrollTop($('#import_log')[0].scrollHeight);
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
@ -24,7 +24,11 @@ PassmanImporter.parseRow_ = function(row, isHeading) {
|
||||||
}
|
}
|
||||||
return row;
|
return row;
|
||||||
};
|
};
|
||||||
|
PassmanImporter.htmlDecode = function(input){
|
||||||
|
var e = document.createElement('div');
|
||||||
|
e.innerHTML = input;
|
||||||
|
return e.childNodes[0].nodeValue;
|
||||||
|
};
|
||||||
PassmanImporter.toObject_ = function(headings, row) {
|
PassmanImporter.toObject_ = function(headings, row) {
|
||||||
var result = {};
|
var result = {};
|
||||||
for (var i = 0, ii = row.length; i < ii; i++) {
|
for (var i = 0, ii = row.length; i < ii; i++) {
|
||||||
|
|
@ -87,4 +91,8 @@ PassmanImporter.readCsv = function( csv, hasHeadings ){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return lines;
|
return lines;
|
||||||
|
};
|
||||||
|
|
||||||
|
PassmanImporter.readJson = function (string){
|
||||||
|
return JSON.parse(string);
|
||||||
};
|
};
|
||||||
|
|
@ -31,7 +31,9 @@ PassmanImporter.dashLaneCsv.readFile = function (file_data) {
|
||||||
_credential.password = row_data[row_data.length - 2];
|
_credential.password = row_data[row_data.length - 2];
|
||||||
_credential.url = row_data[0];
|
_credential.url = row_data[0];
|
||||||
_credential.description = row_data[row_data.length - 1];
|
_credential.description = row_data[row_data.length - 1];
|
||||||
credential_list.push(_credential);
|
if(_credential.label){
|
||||||
|
credential_list.push(_credential);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return credential_list;
|
return credential_list;
|
||||||
};
|
};
|
||||||
|
|
@ -17,13 +17,15 @@ PassmanImporter.lastpassCsv.readFile = function (file_data) {
|
||||||
for (var i = 0; i < parsed_csv.length; i++) {
|
for (var i = 0; i < parsed_csv.length; i++) {
|
||||||
var row = parsed_csv[i];
|
var row = parsed_csv[i];
|
||||||
var _credential = PassmanImporter.newCredential();
|
var _credential = PassmanImporter.newCredential();
|
||||||
_credential.label = row.name;
|
_credential.label = PassmanImporter.htmlDecode(row.name);
|
||||||
_credential.username = row.username;
|
_credential.username = row.username;
|
||||||
_credential.password = row.password;
|
_credential.password = row.password;
|
||||||
_credential.url = row.url;
|
_credential.url = row.url;
|
||||||
_credential.tags = [{text: row.grouping}];
|
_credential.tags = [{text: row.grouping}];
|
||||||
_credential.description = row.extra;
|
_credential.description = row.extra;
|
||||||
credential_list.push(_credential);
|
if(_credential.label){
|
||||||
|
credential_list.push(_credential);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return credential_list;
|
return credential_list;
|
||||||
};
|
};
|
||||||
60
js/importers/importer-passmanjson.js
Normal file
60
js/importers/importer-passmanjson.js
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
// Importers should always start with this
|
||||||
|
if (!window['PassmanImporter']) {
|
||||||
|
var PassmanImporter = {}
|
||||||
|
}
|
||||||
|
// Define the importer
|
||||||
|
PassmanImporter.passmanJson = {
|
||||||
|
info: {
|
||||||
|
name: 'Passman JSON',
|
||||||
|
id: 'passmanJson',
|
||||||
|
description: 'Export the item in passman as passman json, with all fields enabled'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
PassmanImporter.passmanJson.readFile = function (file_data) {
|
||||||
|
var parsed_json = PassmanImporter.readJson(file_data);
|
||||||
|
var credential_list = [];
|
||||||
|
for (var i = 0; i < parsed_json.length; i++) {
|
||||||
|
var item = parsed_json[i];
|
||||||
|
var _credential = PassmanImporter.newCredential();
|
||||||
|
_credential.label = item.label;
|
||||||
|
_credential.username = item.account;
|
||||||
|
_credential.password = item.password;
|
||||||
|
_credential.email = item.email;
|
||||||
|
_credential.url = item.url;
|
||||||
|
_credential.tags = item.tags;
|
||||||
|
//Check for custom fields
|
||||||
|
if (item.hasOwnProperty('customFields')) {
|
||||||
|
//Check for otp
|
||||||
|
if (item.customFields.length > 0) {
|
||||||
|
for (var cf = 0; cf < item.customFields.length; cf++) {
|
||||||
|
_credential.custom_fields.push(
|
||||||
|
{
|
||||||
|
'label': item.customFields[cf].label,
|
||||||
|
'value': item.customFields[cf].value,
|
||||||
|
'secret': (item.customFields[cf].clicktoshow == '1')
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (item.hasOwnProperty('otpsecret')) {
|
||||||
|
if (item.otpsecret) {
|
||||||
|
_credential.otp = {
|
||||||
|
'issuer': item.otpsecret.issuer,
|
||||||
|
'label': item.otpsecret.label,
|
||||||
|
'qr_uri': {
|
||||||
|
'image': item.otpsecret.qrCode,
|
||||||
|
'qrData': ''
|
||||||
|
},
|
||||||
|
'secret': item.otpsecret.secret,
|
||||||
|
'type': item.otpsecret.type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(_credential.label){
|
||||||
|
credential_list.push(_credential);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return credential_list;
|
||||||
|
};
|
||||||
30
js/importers/importer-zohocsv.js
Normal file
30
js/importers/importer-zohocsv.js
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
// Importers should always start with this
|
||||||
|
if (!window['PassmanImporter']) {
|
||||||
|
var PassmanImporter = {}
|
||||||
|
}
|
||||||
|
// Define the importer
|
||||||
|
PassmanImporter.zohoCsv = {
|
||||||
|
info: {
|
||||||
|
name: 'ZOHO csv',
|
||||||
|
id: 'zohoCsv',
|
||||||
|
description: 'Create an csv export. Go to Tools -> Export secrets -> Select "General CSV" and click "Export Secrets"'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
PassmanImporter.zohoCsv.readFile = function (file_data) {
|
||||||
|
var parsed_csv = PassmanImporter.readCsv(file_data, false);
|
||||||
|
var credential_list = [];
|
||||||
|
for (var i = 0; i < parsed_csv.length; i++) {
|
||||||
|
var row = parsed_csv[i];
|
||||||
|
var _credential = PassmanImporter.newCredential();
|
||||||
|
_credential.label = row[0];
|
||||||
|
_credential.username = row[3];
|
||||||
|
_credential.password = row[4];
|
||||||
|
_credential.url = row[1];
|
||||||
|
_credential.description = row[2];
|
||||||
|
if(_credential.label){
|
||||||
|
credential_list.push(_credential);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return credential_list;
|
||||||
|
};
|
||||||
|
|
@ -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) {
|
angular.module('views/partials/forms/settings/import.html', []).run(['$templateCache', function($templateCache) {
|
||||||
'use strict';
|
'use strict';
|
||||||
$templateCache.put('views/partials/forms/settings/import.html',
|
$templateCache.put('views/partials/forms/settings/import.html',
|
||||||
'<div ng-controller="ImportCtrl"><div class="row"><div class="col-xs-12"><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></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="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>');
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
angular.module('views/partials/forms/settings/tool.html', []).run(['$templateCache', function($templateCache) {
|
angular.module('views/partials/forms/settings/tool.html', []).run(['$templateCache', function($templateCache) {
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,13 @@
|
||||||
padding-left: 0px;
|
padding-left: 0px;
|
||||||
padding-right: 15px;
|
padding-right: 15px;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.import_log {
|
||||||
|
max-height: 600px;
|
||||||
|
overflow-y: auto;
|
||||||
|
textarea{
|
||||||
|
width: 90%;
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -58,10 +58,13 @@ script('passman', 'app/directives/tooltip');
|
||||||
script('passman', 'app/directives/use-theme');
|
script('passman', 'app/directives/use-theme');
|
||||||
script('passman', 'app/directives/credentialfield');
|
script('passman', 'app/directives/credentialfield');
|
||||||
script('passman', 'app/directives/ngenter');
|
script('passman', 'app/directives/ngenter');
|
||||||
|
script('passman', 'app/directives/autoscroll');
|
||||||
script('passman', 'importers/import-main');
|
script('passman', 'importers/import-main');
|
||||||
script('passman', 'importers/importer-keepasscsv');
|
script('passman', 'importers/importer-keepasscsv');
|
||||||
script('passman', 'importers/importer-lastpasscsv');
|
script('passman', 'importers/importer-lastpasscsv');
|
||||||
script('passman', 'importers/importer-dashlanecsv');
|
script('passman', 'importers/importer-dashlanecsv');
|
||||||
|
script('passman', 'importers/importer-zohocsv');
|
||||||
|
script('passman', 'importers/importer-passmanjson');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Styles
|
* Styles
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,29 @@
|
||||||
<div ng-controller="ImportCtrl">
|
<div ng-controller="ImportCtrl">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-12" >
|
<div class="col-xs-6">
|
||||||
<label>Import type
|
<label>Import type
|
||||||
<select ng-init="importerType" ng-model="importerType" ng-change="setImporter(importerType)">
|
<select ng-init="importerType" ng-model="importerType"
|
||||||
<option ng-repeat="importer in available_importers" value="{{importer}}">
|
ng-change="setImporter(importerType)">
|
||||||
{{importer.name}}
|
<option ng-repeat="importer in available_importers"
|
||||||
</option>
|
value="{{importer}}">
|
||||||
</select></label>
|
{{importer.name}}
|
||||||
|
</option>
|
||||||
|
</select></label>
|
||||||
<div><b>{{selectedImporter.description}}</b></div>
|
<div><b>{{selectedImporter.description}}</b></div>
|
||||||
<input ng-if="selectedImporter" type="file" file-select success="fileLoaded" error="fileLoadError" progress="fileSelectProgress"><br />
|
<input ng-if="selectedImporter" type="file" file-select
|
||||||
<button class="button" ng-click="startImport()" ng-if="selectedImporter">Import</button>
|
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>
|
||||||
</div>
|
</div>
|
||||||
Loading…
Add table
Reference in a new issue