';
echo '

';
- echo ($strAccNotes) ? '

' : '';
+ echo ($strAccNotes) ? '

' : '';
if ($filesEnabled) {
$intNumFiles = SP_Files::countFiles($account->account_id);
diff --git a/inc/account.class.php b/inc/account.class.php
index 0edaab6f..c5402ff8 100644
--- a/inc/account.class.php
+++ b/inc/account.class.php
@@ -550,16 +550,20 @@ class SP_Account
$message['action'] = __FUNCTION__;
- if (!SP_Groups::addGroupsForAccount($this->accountId, $this->accountUserGroupsId)) {
- $message['text'][] = _('Error al actualizar los grupos secundarios');
- SP_Log::wrLogInfo($message);
- $message['text'] = array();
+ if ( is_array($this->accountUserGroupsId) ){
+ if (!SP_Groups::addGroupsForAccount($this->accountId, $this->accountUserGroupsId)) {
+ $message['text'][] = _('Error al actualizar los grupos secundarios');
+ SP_Log::wrLogInfo($message);
+ $message['text'] = array();
+ }
}
- if (!SP_Users::addUsersForAccount($this->accountId, $this->accountUsersId)) {
- $message['text'][] = _('Error al actualizar los usuarios de la cuenta');
- SP_Log::wrLogInfo($message);
- $message['text'] = array();
+ if ( is_array($this->accountUsersId) ){
+ if (!SP_Users::addUsersForAccount($this->accountId, $this->accountUsersId)) {
+ $message['text'][] = _('Error al actualizar los usuarios de la cuenta');
+ SP_Log::wrLogInfo($message);
+ $message['text'] = array();
+ }
}
$accountInfo = array('customer_name');
diff --git a/inc/common.class.php b/inc/common.class.php
index be360c5b..f7ed9530 100644
--- a/inc/common.class.php
+++ b/inc/common.class.php
@@ -225,7 +225,7 @@ class SP_Common
$msgHelp[20] = _('Guarda las acciones realizadas en la aplicación');
$msgHelp[21] = _('Comprobar actualizaciones de la aplicación (sólo para los usuarios administradores)');
$msgHelp[22] = _('Extensiones de máximo 4 caracteres.') . "
" . _('Escribir extensión y pulsar intro para añadir.');
- $msgHelp[23] = _('Importar desde un archivo CSV con el formato') . ":
" . _('nombre_de_cuenta;cliente;categoría;url;usuario;clave;notas') . "
" . _('Si el cliente o la categoría no están creados, se crean automáticamente.');
+ $msgHelp[23] = _('Importar desde KeePass o KeePassX. El nombre del cliente será igual a KeePass o KeePassX')."
"._('Importar desde un archivo CSV con el formato') . ":
" . _('nombre_de_cuenta;cliente;categoría;url;usuario;clave;notas') . "
" . _('Si el cliente o la categoría no están creados, se crean automáticamente.');
$msgHelp[24] = _('Permite que las cuentas sin acceso sean visibles sólo para las búsquedas.');
$msgHelp[25] = _('Muestra los resultados de búsqueda de cuentas en formato tarjeta.');
diff --git a/inc/import.class.php b/inc/import.class.php
index 149e30f3..b3746589 100644
--- a/inc/import.class.php
+++ b/inc/import.class.php
@@ -65,6 +65,7 @@ class SP_Import
{
private static $result = array();
private static $fileContent;
+ private static $tmpFile;
/**
* @brief Iniciar la importación de cuentas
@@ -75,7 +76,6 @@ class SP_Import
{
try {
self::readDataFromFile($fileData);
- self::parseData();
} catch (ImportException $e) {
$message['action'] = _('Importar Cuentas');
$message['text'][] = $e->getMessage();
@@ -99,22 +99,21 @@ class SP_Import
*/
private static function readDataFromFile(&$fileData)
{
-
if (!is_array($fileData)) {
throw new ImportException('critical', _('Archivo no subido correctamente'), _('Verifique los permisos del usuario del servidor web'));
}
- if ($fileData['inFile']['name']) {
+ if ($fileData['name']) {
// Comprobamos la extensión del archivo
- $fileExtension = strtoupper(pathinfo($_FILES['inFile']['name'], PATHINFO_EXTENSION));
+ $fileExtension = strtoupper(pathinfo($fileData['name'], PATHINFO_EXTENSION));
- if ($fileExtension != 'csv') {
+ if ($fileExtension != 'CSV' && $fileExtension != 'XML') {
throw new ImportException('critical', _('Tipo de archivo no soportado'), _('Compruebe la extensión del archivo'));
}
}
// Variables con información del archivo
- $tmpName = $_FILES['inFile']['tmp_name'];
+ $tmpName = $fileData['tmp_name'];
if (!file_exists($tmpName) || !is_readable($tmpName)) {
// Registramos el máximo tamaño permitido por PHP
@@ -123,12 +122,21 @@ class SP_Import
throw new ImportException('critical', _('Error interno al leer el archivo'), _('Compruebe la configuración de PHP para subir archivos'));
}
+ if ($fileData['type'] === 'text/csv'){
+ // Leemos el archivo a un array
+ self::$fileContent = file($tmpName);
- // Leemos el archivo a una variable
- self::$fileContent = file($tmpName);
-
- if (!is_array(self::$fileContent)) {
- throw new ImportException('critical', _('Error interno al leer el archivo'), _('Compruebe los permisos del directorio temporal'));
+ if (!is_array(self::$fileContent)) {
+ throw new ImportException('critical', _('Error interno al leer el archivo'), _('Compruebe los permisos del directorio temporal'));
+ }
+ // Obtenemos las cuentas desde el archivo CSV
+ self::parseFileData();
+ } elseif ($fileData['type'] === 'text/xml'){
+ self::$tmpFile = $tmpName;
+ // Analizamos el XML y seleccionamos el formato a importar
+ self::detectXMLFormat();
+ } else{
+ throw new ImportException('critical', _('Tipo mime no soportado'), _('Compruebe el formato del archivo'));
}
return true;
@@ -139,52 +147,16 @@ class SP_Import
* @throws ImportException
* @return bool
*/
- private static function parseData()
+ private static function parseFileData()
{
- // Datos del Usuario
- $userId = SP_Common::parseParams('s', 'uid', 0);
- $groupId = SP_Common::parseParams('s', 'ugroup', 0);
-
- $account = new SP_Account;
-
foreach (self::$fileContent as $data) {
$fields = explode(';', $data);
- if (count($fields) != 7) {
+ if (count($fields) < 7) {
throw new ImportException('critical', _('El número de campos es incorrecto'), _('Compruebe el formato del archivo CSV'));
}
- list($accountName, $customerName, $categoryName, $url, $username, $password, $notes) = $fields;
-
- SP_Customer::$customerName = $customerName;
- if (!SP_Customer::checkDupCustomer()) {
- $customerId = SP_Customer::getCustomerByName();
- } else {
- SP_Customer::addCustomer();
- $customerId = SP_Customer::$customerLastId;
- }
-
- $categoryId = SP_Category::getCategoryIdByName($categoryName);
- if ($categoryId === 0 || $categoryId === false) {
- SP_Category::$categoryName = $categoryName;
- SP_Category::addCategory($categoryName);
- $categoryId = SP_Category::$categoryLastId;
- }
-
- $pass = self::encryptPass($password);
-
- $account->accountName = $accountName;
- $account->accountCustomerId = $customerId;
- $account->accountCategoryId = $categoryId;
- $account->accountLogin = $username;
- $account->accountUrl = $url;
- $account->accountPass = $pass['pass'];
- $account->accountIV = $pass['IV'];
- $account->accountNotes = $notes;
- $account->accountUserId = $userId;
- $account->accountUserGroupId = $groupId;
-
- if (!$account->createAccount()) {
+ if (!self::addAccountData($fields)){
$message['action'] = _('Importar Cuentas');
$message['text'][] = _('Error importando cuenta');
$message['text'][] = $data;
@@ -196,6 +168,56 @@ class SP_Import
return true;
}
+ /**
+ * @brief Crear una cuenta con los datos obtenidos
+ * @param array $data con los datos de la cuenta
+ * @throws ImportException
+ * @return bool
+ */
+ public static function addAccountData($data)
+ {
+ // Datos del Usuario
+ $userId = SP_Common::parseParams('s', 'uid', 0);
+ $groupId = SP_Common::parseParams('s', 'ugroup', 0);
+
+ // Asignamos los valores del array a variables
+ list($accountName, $customerName, $categoryName, $url, $username, $password, $notes) = $data;
+
+ // Comprobamos si existe el cliente o lo creamos
+ SP_Customer::$customerName = $customerName;
+ if (!SP_Customer::checkDupCustomer()) {
+ $customerId = SP_Customer::getCustomerByName();
+ } else {
+ SP_Customer::addCustomer();
+ $customerId = SP_Customer::$customerLastId;
+ }
+
+ // Comprobamos si existe la categoría o la creamos
+ $categoryId = SP_Category::getCategoryIdByName($categoryName);
+ if ($categoryId == 0) {
+ SP_Category::$categoryName = $categoryName;
+ SP_Category::addCategory($categoryName);
+ $categoryId = SP_Category::$categoryLastId;
+ }
+
+ $pass = self::encryptPass($password);
+
+ $account = new SP_Account;
+ $account->accountName = $accountName;
+ $account->accountCustomerId = $customerId;
+ $account->accountCategoryId = $categoryId;
+ $account->accountLogin = $username;
+ $account->accountUrl = $url;
+ $account->accountPass = $pass['pass'];
+ $account->accountIV = $pass['IV'];
+ $account->accountNotes = $notes;
+ $account->accountUserId = $userId;
+ $account->accountUserGroupId = $groupId;
+
+ // Creamos la cuenta
+ return $account->createAccount();
+ }
+
/**
* @brief Encriptar la clave de una cuenta
* @param string $password con la clave de la cuenta
@@ -223,4 +245,72 @@ class SP_Import
return $data;
}
-}
+ /**
+ * @brief Leer el archivo de KeePass a un objeto XML
+ * @throws ImportException
+ * @return bool
+ */
+ private static function readXMLFile()
+ {
+ if ($xmlFile = simplexml_load_file(self::$tmpFile)){
+ return $xmlFile;
+ } else{
+ throw new ImportException('critical', _('Error interno'), _('No es posible procesar el archivo XML'));
+ }
+ }
+
+ /**
+ * @brief Detectar la aplicación que generó el XML
+ * @throws ImportException
+ * @return bool
+ */
+ private static function detectXMLFormat()
+ {
+ $xml = self::readXMLFile();
+
+ if ( $xml->Meta->Generator == 'KeePass' ){
+ SP_KeePassImport::addKeepassAccounts($xml);
+ } else if ($xmlApp = self::parseFileHeader()){
+ switch ($xmlApp) {
+ case 'keepassx_database':
+ SP_KeePassXImport::addKeepassXAccounts($xml);
+ break;
+ case 'revelationdata':
+ error_log('REVELATION');
+ break;
+ default:
+ break;
+ }
+ } else{
+ throw new ImportException('critical', _('Archivo XML no soportado'), _('No es posible detectar la aplicación que exportó los datos'));
+ }
+ }
+
+ /**
+ * @brief Leer la cabecera del archivo XML y obtener patrones de aplicaciones conocidas
+ * @return bool
+ */
+ private static function parseFileHeader()
+ {
+ $handle = @fopen(self::$tmpFile, "r");
+ $headersRegex = '/(KEEPASSX_DATABASE|revelationdata)/i';
+
+ if ( $handle ){
+ // No. de líneas a leer como máximo
+ $maxLines = 5;
+ $count = 0;
+
+ while (($buffer = fgets($handle, 4096)) !== false && $count <= $maxLines){
+ if ( preg_match($headersRegex,$buffer,$app) ){
+ fclose($handle);
+ return strtolower($app[0]);
+ }
+ $count++;
+ }
+
+ fclose($handle);
+ }
+
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/inc/keepassimport.class.php b/inc/keepassimport.class.php
new file mode 100644
index 00000000..466123f0
--- /dev/null
+++ b/inc/keepassimport.class.php
@@ -0,0 +1,112 @@
+.
+ *
+ */
+
+defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo'));
+
+/**
+ * Esta clase es la encargada de importar cuentas desde KeePass
+ */
+class SP_KeePassImport
+{
+
+ /**
+ * @brief Iniciar la importación desde KeePass
+ * @param object $xml
+ * @return bool
+ */
+ public static function addKeepassAccounts($xml)
+ {
+ self::getGroups($xml->Root->Group);
+ }
+
+ /**
+ * @brief Obtener los datos de las entradas de KeePass
+ * @param object $entries con el objeto XML con las entradas
+ * @param string $groupName con nombre del grupo a procesar
+ * @throws ImportException
+ * @return bool
+ */
+ private static function getEntryData($entries, $groupName)
+ {
+ foreach ( $entries as $entry ){
+ foreach ( $entry->String as $account ){
+ switch ($account->Key){
+ case 'Notes':
+ $notes = $account->Value;
+ break;
+ case 'Password':
+ $password = $account->Value;
+ break;
+ case 'Title':
+ $name = $account->Value;
+ break;
+ case 'url':
+ $url = $account->Value;
+ break;
+ case 'UserName':
+ $username = $account->Value;
+ break;
+ }
+ }
+
+ $accountData = array($name,'KeePass',$groupName,$url,$username,$password,$notes);
+ SP_Import::addAccountData($accountData);
+ }
+ }
+
+ /**
+ * @brief Obtener los grupos y procesar lan entradas de KeePass
+ * @param object $xml con objeto XML del archivo de KeePass
+ * @throws ImportException
+ * @return bool
+ */
+ private static function getGroups($xml)
+ {
+ foreach($xml as $node){
+ if ( $node->Group ){
+ foreach ( $node->Group as $group ){
+ $groupName = $group->Name;
+ // Analizar grupo
+ if ( $node->Group->Entry ){
+ // Obtener entradas
+ self::getEntryData($group->Entry,$groupName);
+ }
+
+ if ( $group->Group ){
+ // Analizar subgrupo
+ self::getGroups($group);
+ }
+ }
+ }
+
+ if ( $node->Entry ){
+ $groupName = $node->Name;
+ // Obtener entradas
+ self::getEntryData($node->Entry,$groupName);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/inc/keepassximport.class.php b/inc/keepassximport.class.php
new file mode 100644
index 00000000..275cefb5
--- /dev/null
+++ b/inc/keepassximport.class.php
@@ -0,0 +1,98 @@
+.
+ *
+ */
+
+defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo'));
+
+/**
+ * Esta clase es la encargada de importar cuentas desde KeePassX
+ */
+class SP_KeePassXImport
+{
+
+ /**
+ * @brief Iniciar la importación desde KeePass
+ * @param object $xml
+ * @return bool
+ */
+ public static function addKeepassXAccounts($xml)
+ {
+ self::getGroups($xml);
+ }
+
+ /**
+ * @brief Obtener los datos de las entradas de KeePass
+ * @param object $entries con el objeto XML con las entradas
+ * @param string $groupName con nombre del grupo a procesar
+ * @throws ImportException
+ * @return bool
+ */
+ private static function getEntryData($entries, $groupName)
+ {
+ foreach ( $entries as $entry ){
+ $notes = $entry->comment;
+ $password = $entry->password;
+ $name = $entry->title;
+ $url = $entry->url;
+ $username = $entry->username;
+
+ $accountData = array($name,'KeePassX',$groupName,$url,$username,$password,$notes);
+ SP_Import::addAccountData($accountData);
+ }
+ }
+
+ /**
+ * @brief Obtener los grupos y procesar lan entradas de KeePass
+ * @param object $xml con objeto XML del archivo de KeePass
+ * @throws ImportException
+ * @return bool
+ */
+ private static function getGroups($xml)
+ {
+ foreach($xml as $node){
+ if ( $node->group ){
+ foreach ( $node->group as $group ){
+ $groupName = $group->title;
+ // Analizar grupo
+ if ( $node->group->entry ){
+ // Obtener entradas
+ self::getEntryData($group->entry,$groupName);
+ }
+
+ if ( $group->group ){
+ // Analizar subgrupo
+ self::getGroups($group);
+ }
+ }
+ }
+
+ if ( $node->entry ){
+ $groupName = $node->title;
+ // Obtener entradas
+ self::getEntryData($node->entry,$groupName);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/inc/locales/de_DE/LC_MESSAGES/messages.mo b/inc/locales/de_DE/LC_MESSAGES/messages.mo
index f7be5a18..240437e1 100644
Binary files a/inc/locales/de_DE/LC_MESSAGES/messages.mo and b/inc/locales/de_DE/LC_MESSAGES/messages.mo differ
diff --git a/inc/locales/en_US/LC_MESSAGES/messages.mo b/inc/locales/en_US/LC_MESSAGES/messages.mo
index 08b782e1..533d6e7f 100644
Binary files a/inc/locales/en_US/LC_MESSAGES/messages.mo and b/inc/locales/en_US/LC_MESSAGES/messages.mo differ
diff --git a/inc/locales/hu_HU/LC_MESSAGES/messages.mo b/inc/locales/hu_HU/LC_MESSAGES/messages.mo
index 149170c5..a2063698 100644
Binary files a/inc/locales/hu_HU/LC_MESSAGES/messages.mo and b/inc/locales/hu_HU/LC_MESSAGES/messages.mo differ
diff --git a/inc/tpl/migrate.php b/inc/tpl/migrate.php
index 54839d99..8e57a645 100644
--- a/inc/tpl/migrate.php
+++ b/inc/tpl/migrate.php
@@ -100,7 +100,7 @@ $onCloseAction = $data['onCloseAction'];
diff --git a/inc/util.class.php b/inc/util.class.php
index 9d49d617..c4befb3b 100644
--- a/inc/util.class.php
+++ b/inc/util.class.php
@@ -254,7 +254,7 @@ class SP_Util
*/
public static function getVersion($retBuild = false)
{
- $build = 7;
+ $build = 8;
$version = array(1, 1, 2);
if ($retBuild) {
diff --git a/js/functions.js b/js/functions.js
index 8ab5395d..487b179d 100644
--- a/js/functions.js
+++ b/js/functions.js
@@ -557,7 +557,7 @@ function dropFile(accountId, sk, maxsize) {
// Función para activar el Drag&Drop de archivos en la importación de cuentas
function importFile(sk) {
var dropfiles = $('#dropzone');
- var file_exts_ok = ['csv'];
+ var file_exts_ok = ['csv','xml'];
dropfiles.filedrop({
fallback_id: 'inFile',