* [DEV] Improved XML and CSV imports

This commit is contained in:
nuxsmin
2017-01-07 21:47:45 +01:00
parent 687781a557
commit cdd89482c1
35 changed files with 911 additions and 745 deletions

View File

@@ -1,92 +0,0 @@
<?php
/**
* sysPass
*
* @author nuxsmin
* @link http://syspass.org
* @copyright 2012-2015 Rubén Domínguez nuxsmin@syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*
*/
use SP\Core\ActionsInterface;
use SP\Core\Init;
use SP\Core\SessionUtil;
use SP\Core\XmlExport;
use SP\Http\JsonResponse;
use SP\Http\Request;
use SP\Util\Checks;
use SP\Util\Json;
define('APP_ROOT', '..');
require_once APP_ROOT . DIRECTORY_SEPARATOR . 'inc' . DIRECTORY_SEPARATOR . 'Base.php';
Request::checkReferer('POST');
$Json = new JsonResponse();
if (!Init::isLoggedIn()) {
$Json->setStatus(10);
$Json->setDescription(_('La sesión no se ha iniciado o ha caducado'));
Json::returnJson($Json);
}
$sk = Request::analyze('sk', false);
if (!$sk || !SessionUtil::checkSessionKey($sk)) {
$Json->setDescription(_('CONSULTA INVÁLIDA'));
Json::returnJson($Json);
}
$actionId = Request::analyze('actionId', 0);
$onCloseAction = Request::analyze('onCloseAction');
$activeTab = Request::analyze('activeTab', 0);
$exportPassword = Request::analyzeEncrypted('exportPwd');
$exportPasswordR = Request::analyzeEncrypted('exportPwdR');
if ($actionId === ActionsInterface::ACTION_CFG_BACKUP) {
if (Checks::demoIsEnabled()) {
$Json->setDescription(_('Ey, esto es una DEMO!!'));
Json::returnJson($Json);
}
if (!\SP\Core\Backup::doBackup()) {
$Json->setDescription(_('Error al realizar el backup'));
$Json->addMessage(_('Revise el registro de eventos para más detalles'));
Json::returnJson($Json);
}
$Json->setStatus(0);
$Json->setDescription(_('Proceso de backup finalizado'));
Json::returnJson($Json);
} elseif ($actionId === ActionsInterface::ACTION_CFG_EXPORT) {
if (!empty($exportPassword) && $exportPassword !== $exportPasswordR) {
$Json->setDescription(_('Las claves no coinciden'));
Json::returnJson($Json);
}
if (!XmlExport::doExport($exportPassword)) {
$Json->setDescription(_('Error al realizar la exportación'));
$Json->addMessage(_('Revise el registro de eventos para más detalles'));
Json::returnJson($Json);
}
$Json->setStatus(0);
$Json->setDescription(_('Proceso de exportación finalizado'));
Json::returnJson($Json);
}

View File

@@ -46,7 +46,7 @@ $data = array(
'app_root' => Init::$WEBURI,
'pk' => '',
'max_file_size' => $Config->getFilesAllowedSize(),
'check_updates' => ($Config->isCheckUpdates() || $Config->isChecknotices()) && (Session::getUserData()->isUserIsAdminApp() || Checks::demoIsEnabled()),
'check_updates' => Session::getAuthCompleted() && ($Config->isCheckUpdates() || $Config->isChecknotices()) && (Session::getUserData()->isUserIsAdminApp() || Checks::demoIsEnabled()),
'timezone' => date_default_timezone_get(),
'debug' => DEBUG || $Config->isDebug()
);

View File

@@ -1,74 +0,0 @@
<?php
/**
* sysPass
*
* @author nuxsmin
* @link http://syspass.org
* @copyright 2012-2015 Rubén Domínguez nuxsmin@syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*
*/
use SP\Core\Init;
use SP\Core\SessionUtil;
use SP\Http\Request;
use SP\Http\Response;
use SP\Import\Import;
use SP\Util\Checks;
define('APP_ROOT', '..');
require_once APP_ROOT . DIRECTORY_SEPARATOR . 'inc' . DIRECTORY_SEPARATOR . 'Base.php';
Request::checkReferer('POST');
if (!Init::isLoggedIn()) {
Response::printJson(_('La sesión no se ha iniciado o ha caducado'), 10);
}
if (Checks::demoIsEnabled()) {
Response::printJson(_('Ey, esto es una DEMO!!'));
}
$sk = Request::analyze('sk', false);
$defaultUser= Request::analyze('defUser', 0);
$defaultGroup = Request::analyze('defGroup', 0);
$importPwd = Request::analyzeEncrypted('importPwd');
$csvDelimiter = Request::analyze('csvDelimiter');
if (!$sk || !SessionUtil::checkSessionKey($sk)) {
Response::printJson(_('CONSULTA INVÁLIDA'));
}
Import::setDefUser($defaultUser);
Import::setDefGroup($defaultGroup);
Import::setImportPwd($importPwd);
Import::setCsvDelimiter($csvDelimiter);
$res = Import::doImport($_FILES["inFile"]);
if (isset($res['error']) && is_array($res['error'])) {
error_log($res['error']['hint']);
$out = implode('\n\n', $res['error']);
Response::printJson($out);
} else if (is_array($res['ok'])) {
$out = implode('\n\n', $res['ok']);
Response::printJson($out, 0);
}

View File

@@ -325,9 +325,11 @@ class Account extends AccountBase implements AccountInterface
* @return $this
* @throws \SP\Core\Exceptions\SPException
*/
public function createAccount()
public function createAccount($encryptPass = true)
{
$this->setPasswordEncrypted();
if ($encryptPass === true) {
$this->setPasswordEncrypted();
}
$query = /** @lang SQL */
'INSERT INTO accounts SET '

View File

@@ -489,8 +489,9 @@ class AccountHistory extends AccountBase implements AccountInterface
* Crear una cuenta en el historial
*
* @return bool
* @throws \SP\Core\Exceptions\SPException
*/
public function createAccount()
public function createAccount($encryptPass = true)
{
$query = /** @lang SQL */
'INSERT INTO accHistory SET '

View File

@@ -42,9 +42,10 @@ interface AccountInterface
public function getData();
/**
* @param bool $encryptPass Si se encripta la clave de la cuenta
* @return mixed
*/
public function createAccount();
public function createAccount($encryptPass = true);
/**
* @param $id

View File

@@ -29,12 +29,16 @@ use SP\Account\AccountHistory;
use SP\Config\Config;
use SP\Config\ConfigDB;
use SP\Core\ActionsInterface;
use SP\Core\Backup;
use SP\Core\Crypt;
use SP\Core\CryptMasterPass;
use SP\Core\Exceptions\SPException;
use SP\Core\Session;
use SP\Core\XmlExport;
use SP\Html\Html;
use SP\Http\Request;
use SP\Import\Import;
use SP\Import\ImportParams;
use SP\Log\Email;
use SP\Log\Log;
use SP\Mgmt\CustomFields\CustomFieldsUtil;
@@ -87,6 +91,15 @@ class ConfigActionController implements ItemControllerInterface
case ActionsInterface::ACTION_CFG_ENCRYPTION_TEMPPASS:
$this->tempMasterPassAction();
break;
case ActionsInterface::ACTION_CFG_IMPORT:
$this->importAction();
break;
case ActionsInterface::ACTION_CFG_EXPORT:
$this->exportAction();
break;
case ActionsInterface::ACTION_CFG_BACKUP:
$this->backupAction();
break;
default:
$this->invalidAction();
}
@@ -508,7 +521,7 @@ class ConfigActionController implements ItemControllerInterface
}
/**
* Acción para generarclave maestra temporal
* Acción para generar clave maestra temporal
*/
protected function tempMasterPassAction()
{
@@ -533,4 +546,74 @@ class ConfigActionController implements ItemControllerInterface
$Log->writeLog();
Email::sendEmail($Log);
}
/**
* Acción para importar cuentas
*
* @throws \SP\Core\Exceptions\SPException
*/
protected function importAction()
{
if (Checks::demoIsEnabled()) {
$this->jsonResponse->setDescription(_('Ey, esto es una DEMO!!'));
return;
}
$ImportParams = new ImportParams();
$ImportParams->setDefaultUser(Request::analyze('defUser', Session::getUserData()->getUserId()));
$ImportParams->setDefaultGroup(Request::analyze('defGroup', Session::getUserData()->getUserGroupId()));
$ImportParams->setImportPwd(Request::analyzeEncrypted('importPwd'));
$ImportParams->setImportMasterPwd(Request::analyzeEncrypted('importMasterPwd'));
$ImportParams->setCsvDelimiter(Request::analyze('csvDelimiter'));
$Import = new Import($ImportParams);
$Message = $Import->doImport($_FILES['inFile']);
$this->jsonResponse->setDescription($Message->getDescription());
$this->jsonResponse->addMessage($Message->getHint());
$this->jsonResponse->setStatus(0);
}
/**
* Acción para exportar cuentas
*/
protected function exportAction()
{
$exportPassword = Request::analyzeEncrypted('exportPwd');
$exportPasswordR = Request::analyzeEncrypted('exportPwdR');
if (!empty($exportPassword) && $exportPassword !== $exportPasswordR) {
$this->jsonResponse->setDescription(_('Las claves no coinciden'));
return;
}
if (!XmlExport::doExport($exportPassword)) {
$this->jsonResponse->setDescription(_('Error al realizar la exportación'));
$this->jsonResponse->addMessage(_('Revise el registro de eventos para más detalles'));
return;
}
$this->jsonResponse->setStatus(0);
$this->jsonResponse->setDescription(_('Proceso de exportación finalizado'));
}
/**
* Acción para realizar el backup de sysPass
*/
protected function backupAction()
{
if (Checks::demoIsEnabled()) {
$this->jsonResponse->setDescription(_('Ey, esto es una DEMO!!'));
return;
}
if (!Backup::doBackup()) {
$this->jsonResponse->setDescription(_('Error al realizar el backup'));
$this->jsonResponse->addMessage(_('Revise el registro de eventos para más detalles'));
return;
}
$this->jsonResponse->setStatus(0);
$this->jsonResponse->setDescription(_('Proceso de backup finalizado'));
}
}

View File

@@ -55,7 +55,7 @@ class Backup
$backupDir = Init::$SERVERROOT;
// Generar hash unico para evitar descargas no permitidas
$backupUniqueHash = uniqid();
$backupUniqueHash = sha1(uniqid('sysPassBackup', true));
Config::getConfig()->setBackupHash($backupUniqueHash);
Config::saveConfig();
@@ -86,12 +86,43 @@ class Backup
return true;
}
/**
* Comprobar y crear el directorio de backups.
*
* @param string $backupDir ruta del directorio de backup
* @throws SPException
* @return bool
*/
private static function checkBackupDir($backupDir)
{
if (@mkdir($backupDir, 0750) === false && is_dir($backupDir) === false) {
throw new SPException(SPException::SP_CRITICAL, sprintf(_('No es posible crear el directorio de backups ("%s")'), $backupDir));
}
if (!is_writable($backupDir)) {
throw new SPException(SPException::SP_CRITICAL, _('Compruebe los permisos del directorio de backups'));
}
return true;
}
/**
* Eliminar las copias de seguridad anteriores
*
* @param string $backupDir El directorio de backups
*/
private static function deleteOldBackups($backupDir)
{
array_map('unlink', glob($backupDir . DIRECTORY_SEPARATOR . '*.tar.gz'));
array_map('unlink', glob($backupDir . DIRECTORY_SEPARATOR . '*.sql'));
}
/**
* Backup de las tablas de la BBDD.
* Utilizar '*' para toda la BBDD o 'table1 table2 table3...'
*
* @param string $tables
* @param string $backupFile
* @param string|array $tables
* @param string $backupFile
* @throws SPException
* @return bool
*/
@@ -104,10 +135,8 @@ class Backup
$Data = new QueryData();
if ($tables == '*') {
$Data->setQuery('SHOW TABLES');
$resTables = DB::getResults($Data);
if ($tables === '*') {
$resTables = DBUtil::$tables;
} else {
$resTables = is_array($tables) ? $tables : explode(',', $tables);
}
@@ -121,52 +150,63 @@ class Backup
$sqlOut .= 'USE `' . $dbname . '`;' . PHP_EOL . PHP_EOL;
fwrite($handle, $sqlOut);
$sqlOutViews = '';
// Recorrer las tablas y almacenar los datos
foreach ($resTables as $table) {
$tableName = $table->{'Tables_in_' . $dbname};
$tableName = is_object($table) ? $table->{'Tables_in_' . $dbname} : $table;
$Data->setQuery('SHOW CREATE TABLE ' . $tableName);
$sqlOut = '-- ' . PHP_EOL;
$sqlOut .= '-- Table ' . strtoupper($tableName) . PHP_EOL;
$sqlOut .= '-- ' . PHP_EOL;
// Consulta para crear la tabla
$sqlOut .= 'DROP TABLE IF EXISTS `' . $tableName . '`;' . PHP_EOL . PHP_EOL;
$txtCreate = DB::getResults($Data);
$sqlOut .= $txtCreate->{'Create Table'} . ';' . PHP_EOL . PHP_EOL;
fwrite($handle, $sqlOut);
$Data->setQuery('SELECT * FROM ' . $tableName);
if (isset($txtCreate->{'Create Table'})) {
$sqlOut = '-- ' . PHP_EOL;
$sqlOut .= '-- Table ' . strtoupper($tableName) . PHP_EOL;
$sqlOut .= '-- ' . PHP_EOL;
$sqlOut .= 'DROP TABLE IF EXISTS `' . $tableName . '`;' . PHP_EOL . PHP_EOL;
$sqlOut .= $txtCreate->{'Create Table'} . ';' . PHP_EOL . PHP_EOL;
fwrite($handle, $sqlOut);
// Consulta para obtener los registros de la tabla
$queryRes = DB::getResultsRaw($Data);
$Data->setQuery('SELECT * FROM ' . $tableName);
$numColumns = $queryRes->columnCount();
// Consulta para obtener los registros de la tabla
$queryRes = DB::getResultsRaw($Data);
while ($row = $queryRes->fetch(\PDO::FETCH_NUM)) {
fwrite($handle, 'INSERT INTO `' . $tableName . '` VALUES(');
$numColumns = $queryRes->columnCount();
$field = 1;
foreach ($row as $value) {
if (is_numeric($value)) {
fwrite($handle, $value);
} else {
fwrite($handle, DBUtil::escape($value));
while ($row = $queryRes->fetch(\PDO::FETCH_NUM)) {
fwrite($handle, 'INSERT INTO `' . $tableName . '` VALUES(');
$field = 1;
foreach ($row as $value) {
if (is_numeric($value)) {
fwrite($handle, $value);
} else {
fwrite($handle, DBUtil::escape($value));
}
if ($field < $numColumns) {
fwrite($handle, ',');
}
$field++;
}
if ($field < $numColumns) {
fwrite($handle, ',');
}
$field++;
fwrite($handle, ');' . PHP_EOL);
}
fwrite($handle, ');' . PHP_EOL);
} elseif ($txtCreate->{'Create View'}) {
$sqlOutViews .= '-- ' . PHP_EOL;
$sqlOutViews .= '-- View ' . strtoupper($tableName) . PHP_EOL;
$sqlOutViews .= '-- ' . PHP_EOL;
$sqlOutViews .= 'DROP TABLE IF EXISTS `' . $tableName . '`;' . PHP_EOL . PHP_EOL;
$sqlOutViews .= $txtCreate->{'Create View'} . ';' . PHP_EOL . PHP_EOL;
}
fwrite($handle, PHP_EOL . PHP_EOL);
}
fwrite($handle, $sqlOutViews);
$sqlOut = '--' . PHP_EOL;
$sqlOut .= '-- sysPass DB dump generated on ' . time() . ' (END)' . PHP_EOL;
$sqlOut .= '--' . PHP_EOL;
@@ -191,7 +231,7 @@ class Backup
*/
private static function backupApp($backupFile)
{
if (!class_exists('PharData')) {
if (!class_exists(\PharData::class)) {
if (Checks::checkIsWindows()) {
throw new SPException(SPException::SP_CRITICAL, _('Esta operación sólo es posible en entornos Linux'));
} elseif (!self::backupAppLegacyLinux($backupFile)) {
@@ -237,37 +277,4 @@ class Backup
return $resBakApp;
}
/**
* Comprobar y crear el directorio de backups.
*
* @param string $backupDir ruta del directorio de backup
* @throws SPException
* @return bool
*/
private static function checkBackupDir($backupDir)
{
if (!is_dir($backupDir)) {
if (!@mkdir($backupDir, 0550)) {
throw new SPException(SPException::SP_CRITICAL, _('No es posible crear el directorio de backups') . ' (' . $backupDir . ')');
}
}
if (!is_writable($backupDir)) {
throw new SPException(SPException::SP_CRITICAL, _('Compruebe los permisos del directorio de backups'));
}
return true;
}
/**
* Eliminar las copias de seguridad anteriores
*
* @param string $backupDir El directorio de backups
*/
private static function deleteOldBackups($backupDir)
{
array_map('unlink', glob($backupDir . DIRECTORY_SEPARATOR . '*.tar.gz'));
array_map('unlink', glob($backupDir . DIRECTORY_SEPARATOR . '*.sql'));
}
}

View File

@@ -254,7 +254,6 @@ class Crypt
if (null === $password) {
$password = SessionUtil::getSessionMPass();
// self::getSessionMasterPass();
}
$mcryptRes = self::getMcryptResource();

View File

@@ -33,6 +33,7 @@ use SP\Log\Email;
use SP\Mgmt\Customers\Customer;
use SP\Log\Log;
use SP\Mgmt\Categories\Category;
use SP\Mgmt\Tags\Tag;
use SP\Util\Util;
defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo'));
@@ -132,6 +133,7 @@ class XmlExport
$this->createMeta();
$this->createCategories();
$this->createCustomers();
$this->createTags();
$this->createAccounts();
$this->createHash();
$this->writeXML();
@@ -316,16 +318,14 @@ class XmlExport
foreach ($customers as $CustomerData) {
$customerName = $this->xml->createElement('name', $this->escapeChars($CustomerData->getCustomerName()));
$customerDescription = $this->xml->createElement('description', $this->escapeChars($CustomerData->getCustomerDescription()));
$customerHash = $this->xml->createElement('hash', $this->escapeChars($CustomerData->getCustomerHash()));
// Crear el nodo de categoría
// Crear el nodo de clientes
$nodeCustomer = $this->xml->createElement('Customer');
$nodeCustomer->setAttribute('id', $CustomerData->getCustomerId());
$nodeCustomer->appendChild($customerName);
$nodeCustomer->appendChild($customerDescription);
$nodeCustomer->appendChild($customerHash);
// Añadir categoría al nodo de categorías
// Añadir cliente al nodo de clientes
$nodeCustomers->appendChild($nodeCustomer);
}
@@ -335,6 +335,41 @@ class XmlExport
}
}
/**
* Crear el nodo con los datos de las etiquetas
*
* #@throws SPException
*/
private function createTags()
{
$Tags = Tag::getItem()->getAll();
if (count($Tags) === 0) {
return;
}
try {
// Crear el nodo de etiquetas
$nodeTags= $this->xml->createElement('Tags');
foreach ($Tags as $TagData) {
$tagName = $this->xml->createElement('name', $this->escapeChars($TagData->getTagName()));
// Crear el nodo de etiquetas
$nodeTag = $this->xml->createElement('Tag');
$nodeTag->setAttribute('id', $TagData->getTagId());
$nodeTag->appendChild($tagName);
// Añadir etiqueta al nodo de etiquetas
$nodeTags->appendChild($nodeTag);
}
$this->appendNode($nodeTags);
} catch (\DOMException $e) {
throw new SPException(SPException::SP_WARNING, $e->getMessage(), __FUNCTION__);
}
}
/**
* Crear el nodo con los datos de las cuentas
*
@@ -473,8 +508,8 @@ class XmlExport
*/
private function checkExportDir()
{
if (!is_dir($this->exportDir) && !@mkdir($this->exportDir, 0750)) {
throw new SPException(SPException::SP_CRITICAL, _('No es posible crear el directorio de backups') . ' (' . $this->exportDir . ')');
if (@mkdir($this->exportDir, 0750) === false && is_dir($this->exportDir) === false) {
throw new SPException(SPException::SP_CRITICAL, sprintf(_('No es posible crear el directorio de backups ("%s")'), $this->exportDir));
}
clearstatcache(true, $this->exportDir);

View File

@@ -0,0 +1,98 @@
<?php
/**
* sysPass
*
* @author nuxsmin
* @link http://syspass.org
* @copyright 2012-2017, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
namespace SP\Http;
/**
* Class Message
*
* @package SP\Http
*/
class Message
{
const TYPE_OK = 0;
const TYPE_ERROR = 1;
const TYPE_WARNING = 2;
/**
* @var int
*/
protected $type = 0;
/**
* @var string
*/
protected $description;
/**
* @var string
*/
protected $hint;
/**
* @return int
*/
public function getType()
{
return $this->type;
}
/**
* @param int $type
*/
public function setType($type)
{
$this->type = $type;
}
/**
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* @param string $description
*/
public function setDescription($description)
{
$this->description = $description;
}
/**
* @return string
*/
public function getHint()
{
return $this->hint;
}
/**
* @param string $hint
*/
public function setHint($hint)
{
$this->hint = $hint;
}
}

View File

@@ -49,12 +49,13 @@ abstract class XMLRPCResponseParse
/**
* @var array
*/
private $data = array();
private $data = [];
/**
* Constructor
*
* @param string $xml El documento XML
* @throws \InvalidArgumentException
*/
public function __construct($xml)
{
@@ -125,7 +126,7 @@ abstract class XMLRPCResponseParse
*/
private function parseStruct(DOMElement $xmlStruct)
{
$dataStruct = array();
$dataStruct = [];
$nStruct = 0;
foreach ($xmlStruct->childNodes as $struct) {
@@ -179,20 +180,18 @@ abstract class XMLRPCResponseParse
*/
private function parseArray(DOMElement $xmlArray)
{
$arrayData = array();
$arrayData = [];
foreach ($xmlArray->childNodes as $array) {
foreach ($array->childNodes as $data) {
if ($data instanceof DOMElement) {
/**
* @var $data DOMElement
*/
if ($data->nodeName === 'value') {
$values = $this->parseValues($data);
/**
* @var $data DOMElement
*/
if ($data instanceof DOMElement && $data->nodeName === 'value') {
$values = $this->parseValues($data);
if (is_array($values)) {
$arrayData[] = $values;
}
if (is_array($values)) {
$arrayData[] = $values;
}
}
}
@@ -209,13 +208,13 @@ abstract class XMLRPCResponseParse
*/
private function parseValues(DOMElement $xmlValues)
{
$valuesData = array();
$valuesData = [];
foreach ($xmlValues->childNodes as $xmlValue) {
if ($xmlValue instanceof DOMElement) {
$val = $this->parseNodeType($xmlValue);
if (is_null($val)) {
if (null === $val) {
return $this->parseNodes($xmlValues->childNodes);
} else {
$valuesData[] = $val;
@@ -234,19 +233,17 @@ abstract class XMLRPCResponseParse
*/
private function parseFault(DOMElement $xmlFault)
{
$faultData = array();
$faultData = [];
foreach ($xmlFault->childNodes as $fault) {
if ($fault instanceof DOMElement) {
/**
* @var $fault DOMElement
*/
if ($fault->nodeName === 'value') {
$values = $this->parseValues($fault);
/**
* @var $fault DOMElement
*/
if ($fault instanceof DOMElement && $fault->nodeName === 'value') {
$values = $this->parseValues($fault);
if (is_array($values)) {
return $values;
}
if (is_array($values)) {
return $values;
}
}
}

View File

@@ -25,8 +25,7 @@
namespace SP\Import;
use SP\DataModel\AccountData;
use SP\Core\Crypt;
use SP\DataModel\AccountExtData;
use SP\DataModel\CategoryData;
use SP\DataModel\CustomerData;
use SP\Mgmt\Customers\Customer;
@@ -50,34 +49,7 @@ abstract class CsvImportBase extends ImportBase
/**
* @var array
*/
protected $mapFields = array();
/**
* @var string
*/
protected $fieldDelimiter = ';';
/**
* Constructor
*
* @param $file FileImport Instancia de la clase FileImport
* @throws SPException
*/
public function __construct($file)
{
try {
$this->file = $file;
} catch (SPException $e) {
throw $e;
}
}
/**
* @param string $fieldDelimiter
*/
public function setFieldDelimiter($fieldDelimiter)
{
$this->fieldDelimiter = $fieldDelimiter;
}
protected $mapFields = [];
/**
* @param int $numFields
@@ -99,6 +71,7 @@ abstract class CsvImportBase extends ImportBase
* Obtener los datos de las entradas de sysPass y crearlas
*
* @throws SPException
* @throws \SP\Core\Exceptions\InvalidClassException
*/
protected function processAccounts()
{
@@ -108,7 +81,7 @@ abstract class CsvImportBase extends ImportBase
foreach ($this->file->getFileContent() as $data) {
$line++;
$fields = explode($this->fieldDelimiter, $data);
$fields = str_getcsv($data, $this->ImportParams->getCsvDelimiter());
$numfields = count($fields);
// Comprobar el número de campos de la línea
@@ -121,30 +94,31 @@ abstract class CsvImportBase extends ImportBase
}
// Eliminar las " del principio/fin de los campos
array_walk($fields,
function (&$value, $key) {
$value = trim($value, '"');
}
);
// array_walk($fields,
// function (&$value, $key) {
// $value = trim($value, '"');
// }
// );
// Asignar los valores del array a variables
list($accountName, $customerName, $categoryName, $url, $login, $password, $notes) = $fields;
// Obtener los ids de cliente, categoría y la clave encriptada
$customerId = Customer::getItem(new CustomerData(null, $customerName))->add()->getItemData()->getCustomerId();
$categoryId = Category::getItem(new CategoryData(null, $categoryName))->add()->getItemData()->getCategoryId();
$pass = Crypt::encryptData($password);
// Obtener los ids de cliente y categoría
$CustomerData = new CustomerData(null, $customerName);
Customer::getItem($CustomerData)->add();
$CategoryData = new CategoryData(null, $categoryName);
Category::getItem($CategoryData)->add();
// Crear la nueva cuenta
$AccountData = new AccountData();
$AccountData = new AccountExtData();
$AccountData->setAccountName($accountName);
$AccountData->setAccountLogin($login);
$AccountData->setAccountCategoryId($categoryId);
$AccountData->setAccountCustomerId($customerId);
$AccountData->setAccountCategoryId($CategoryData->getCategoryId());
$AccountData->setAccountCustomerId($CustomerData->getCustomerId());
$AccountData->setAccountNotes($notes);
$AccountData->setAccountUrl($url);
$AccountData->setAccountPass($pass['data']);
$AccountData->setAccountIV($pass['iv']);
$AccountData->setAccountPass($password);
try {
$this->addAccount($AccountData);

View File

@@ -85,6 +85,9 @@ class FileImport
/**
* FileImport constructor.
*
* @param array $fileData Datos del archivo a importar
* @throws SPException
*/
public function __construct(&$fileData)
{
@@ -100,7 +103,6 @@ class FileImport
*
* @param array $fileData con los datos del archivo
* @throws SPException
* @return bool
*/
private function checkFile(&$fileData)
{
@@ -112,7 +114,7 @@ class FileImport
// Comprobamos la extensión del archivo
$fileExtension = strtoupper(pathinfo($fileData['name'], PATHINFO_EXTENSION));
if ($fileExtension != 'CSV' && $fileExtension != 'XML') {
if ($fileExtension !== 'CSV' && $fileExtension !== 'XML') {
throw new SPException(
SPException::SP_CRITICAL,
_('Tipo de archivo no soportado'),
@@ -123,7 +125,7 @@ class FileImport
// Variables con información del archivo
$this->tmpFile = $fileData['tmp_name'];
$this->fileType = $fileData['type'];
$this->fileType = strtolower($fileData['type']);
if (!file_exists($this->tmpFile) || !is_readable($this->tmpFile)) {
// Registramos el máximo tamaño permitido por PHP
@@ -144,6 +146,8 @@ class FileImport
*/
public function readFileToArray()
{
$this->autodetectEOL();
$this->fileContent = file($this->tmpFile, FILE_SKIP_EMPTY_LINES);
if ($this->fileContent === false){
@@ -162,6 +166,8 @@ class FileImport
*/
public function readFileToString()
{
$this->autodetectEOL();
$this->fileContent = file_get_contents($this->tmpFile);
if ($this->fileContent === false){
@@ -172,4 +178,12 @@ class FileImport
);
}
}
/**
* Activar la autodetección de fin de línea
*/
protected function autodetectEOL()
{
ini_set('auto_detect_line_endings', true);
}
}

View File

@@ -26,6 +26,7 @@
namespace SP\Import;
use SP\Http\Message;
use SP\Log\Email;
use SP\Log\Log;
use SP\Core\Exceptions\SPException;
@@ -38,61 +39,28 @@ defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo'
class Import
{
/**
* @var string
* @var ImportParams Parámetros de importación
*/
public static $importPwd = '';
/**
* @var int
*/
public static $defUser = 0;
/**
* @var int
*/
public static $defGroup = 0;
/**
* @var string
*/
public static $csvDelimiter = '';
protected $ImportParams;
/**
* @param string $importPwd
* Import constructor.
*
* @param ImportParams $ImportParams
*/
public static function setImportPwd($importPwd)
public function __construct(ImportParams $ImportParams)
{
self::$importPwd = $importPwd;
}
/**
* @param int $defUser
*/
public static function setDefUser($defUser)
{
self::$defUser = $defUser;
}
/**
* @param int $defGroup
*/
public static function setDefGroup($defGroup)
{
self::$defGroup = $defGroup;
}
/**
* @param string $csvDelimiter
*/
public static function setCsvDelimiter($csvDelimiter)
{
self::$csvDelimiter = $csvDelimiter;
$this->ImportParams = $ImportParams;
}
/**
* Iniciar la importación de cuentas.
*
* @param array $fileData Los datos del archivo
* @return array resultado del proceso
* @param array $fileData Los datos del archivo
* @return Message
* @throws \SP\Core\Exceptions\SPException
*/
public static function doImport(&$fileData)
public function doImport(&$fileData)
{
$Log = new Log(_('Importar Cuentas'));
@@ -102,32 +70,27 @@ class Import
switch ($file->getFileType()) {
case 'text/csv':
case 'application/vnd.ms-excel':
$import = new CsvImport($file);
$import->setFieldDelimiter(self::$csvDelimiter);
$Import = new CsvImport($file, $this->ImportParams);
break;
case 'text/xml':
$import = new XmlImport($file);
$import->setImportPass(self::$importPwd);
$Import = new XmlImport($file, $this->ImportParams);
break;
default:
throw new SPException(
SPException::SP_WARNING,
_('Tipo mime no soportado'),
sprintf(_('Tipo mime no soportado ("%s")'), $file->getFileType()),
_('Compruebe el formato del archivo')
);
}
$import->setUserId(self::$defUser);
$import->setUserGroupId(self::$defGroup);
$import->doImport();
$Import->doImport();
} catch (SPException $e) {
$Log->setLogLevel(Log::ERROR);
$Log->addDescription($e->getMessage());
$Log->addDetails(_('Ayuda'), $e->getHint());
$Log->writeLog();
$result['error'] = array('description' => $e->getMessage(), 'hint' => $e->getHint());
return $result;
throw $e;
}
$Log->addDescription(_('Importación finalizada'));
@@ -135,11 +98,10 @@ class Import
Email::sendEmail($Log);
$result['ok'] = array(
_('Importación finalizada'),
_('Revise el registro de eventos para más detalles')
);
$Message = new Message();
$Message->setDescription(_('Importación finalizada'));
$Message->setHint(_('Revise el registro de eventos para más detalles'));
return $result;
return $Message;
}
}

View File

@@ -26,15 +26,16 @@
namespace SP\Import;
use SP\Account\Account;
use SP\Core\Crypt;
use SP\Core\Exceptions\SPException;
use SP\DataModel\AccountData;
use SP\DataModel\AccountExtData;
use SP\DataModel\CategoryData;
use SP\DataModel\CustomerData;
use SP\DataModel\TagData;
use SP\Log\Log;
use SP\Mgmt\Customers\Customer;
use SP\Mgmt\Categories\Category;
use SP\Core\Session;
use SP\Mgmt\Tags\Tag;
defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo'));
@@ -46,66 +47,24 @@ defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo'
abstract class ImportBase
{
/**
* El id de usuario propietario de la cuenta.
*
* @var int
* @var ImportParams
*/
public $userId;
/**
* El id del grupo propietario de la cuenta.
*
* @var int
*/
public $userGroupId;
/**
* Nombre de la categoría.
*
* @var string
*/
protected $categoryName = '';
/**
* Nombre del cliente.
*
* @var string
*/
protected $customerName = '';
/**
* Descrición de la categoría.
*
* @var string
*/
protected $categoryDescription = '';
/**
* Descripción del cliente.
*
* @var string
*/
protected $customerDescription = '';
protected $ImportParams;
/**
* @var FileImport
*/
protected $file;
/**
* La clave de importación
* ImportBase constructor.
*
* @var string
* @param FileImport $File
* @param ImportParams $ImportParams
*/
protected $importPass;
/**
* @return string
*/
public function getImportPass()
public function __construct(FileImport $File, ImportParams $ImportParams)
{
return $this->importPass;
}
/**
* @param string $importPass
*/
public function setImportPass($importPass)
{
$this->importPass = $importPass;
$this->file = $File;
$this->ImportParams = $ImportParams;
}
/**
@@ -116,38 +75,6 @@ abstract class ImportBase
*/
public abstract function doImport();
/**
* @return string
*/
public function getCategoryName()
{
return $this->categoryName;
}
/**
* @param string $categoryName
*/
public function setCategoryName($categoryName)
{
$this->categoryName = $categoryName;
}
/**
* @return string
*/
public function getCategoryDescription()
{
return $this->categoryDescription;
}
/**
* @param string $categoryDescription
*/
public function setCategoryDescription($categoryDescription)
{
$this->categoryDescription = $categoryDescription;
}
/**
* Leer la cabecera del archivo XML y obtener patrones de aplicaciones conocidas.
*
@@ -186,122 +113,85 @@ abstract class ImportBase
*/
protected function addAccount(AccountExtData $AccountData)
{
$userId = $this->getUserId();
$groupId = $this->getUserGroupId();
if (null === $userId || $userId === 0) {
$this->setUserId(Session::getUserData()->getUserId());
if ($AccountData->getAccountCategoryId() === 0) {
Log::writeNewLog(__FUNCTION__, _('Id de categoría no definido. No es posible importar cuenta.'), Log::INFO);
return false;
} elseif ($AccountData->getAccountCustomerId() === 0) {
Log::writeNewLog(__FUNCTION__, _('Id de cliente no definido. No es posible importar cuenta.'), Log::INFO);
return false;
}
if (null === $groupId || $groupId === 0) {
$this->setUserGroupId(Session::getUserData()->getUserGroupId());
$encryptPass = false;
if ($this->ImportParams->getImportMasterPwd() !== '') {
$pass = Crypt::getDecrypt($AccountData->getAccountPass(), $AccountData->getAccountIV(), $this->ImportParams->getImportMasterPwd());
$AccountData->setAccountPass($pass);
$encryptPass = true;
}
$AccountData->setAccountUserId($this->getUserId());
$AccountData->setAccountUserGroupId($this->getUserGroupId());
$AccountData->setAccountUserId($this->ImportParams->getDefaultUser());
$AccountData->setAccountUserGroupId($this->ImportParams->getDefaultGroup());
$Account = new Account($AccountData);
$Account->createAccount();
}
$Account->createAccount($encryptPass);
/**
* @return int
*/
public function getUserId()
{
return $this->userId;
}
/**
* @param int $userId
*/
public function setUserId($userId)
{
$this->userId = $userId;
}
/**
* @return int
*/
public function getUserGroupId()
{
return $this->userGroupId;
}
/**
* @param int $userGroupId
*/
public function setUserGroupId($userGroupId)
{
$this->userGroupId = $userGroupId;
return true;
}
/**
* Añadir una categoría y devolver el Id
*
* @param $name
* @param $description
* @return int
* @param CategoryData $CategoryData
* @return Category|null
* @throws \SP\Core\Exceptions\InvalidClassException
* @throws \SP\Core\Exceptions\SPException
*/
protected function addCategory($name, $description = null)
protected function addCategory(CategoryData $CategoryData)
{
$CategoryData = new CategoryData(null, $name, $description);
try {
return Category::getItem($CategoryData)->add()->getItemData()->getCategoryId();
return Category::getItem($CategoryData)->add();
} catch (SPException $e) {
Log::writeNewLog(__FUNCTION__, $e->getMessage(), Log::ERROR);
}
return null;
}
/**
* Añadir un cliente y devolver el Id
*
* @param $name
* @param $description
* @return int
* @param CustomerData $CustomerData
* @return Customer|null
* @throws \SP\Core\Exceptions\InvalidClassException
*/
protected function addCustomer($name, $description = null)
protected function addCustomer(CustomerData $CustomerData)
{
$CustomerData = new CustomerData(null, $name, $description);
try {
return Customer::getItem($CustomerData)->add()->getItemData()->getCustomerId();
return Customer::getItem($CustomerData)->add();
} catch (SPException $e) {
Log::writeNewLog(__FUNCTION__, $e->getMessage(), Log::ERROR);
}
return null;
}
/**
* @return string
* Añadir una etiqueta y devolver el Id
*
* @param TagData $TagData
* @return Tag|null
* @throws \SP\Core\Exceptions\InvalidClassException
* @throws \SP\Core\Exceptions\SPException
*/
public function getCustomerName()
protected function addTag(TagData $TagData)
{
return $this->customerName;
}
try {
return Tag::getItem($TagData)->add();
} catch (SPException $e) {
Log::writeNewLog(__FUNCTION__, $e->getMessage(), Log::ERROR);
}
/**
* @param string $customerName
*/
public function setCustomerName($customerName)
{
$this->customerName = $customerName;
}
/**
* @return string
*/
public function getCustomerDescription()
{
return $this->customerDescription;
}
/**
* @param string $customerDescription
*/
public function setCustomerDescription($customerDescription)
{
$this->customerDescription = $customerDescription;
return null;
}
}

View File

@@ -0,0 +1,135 @@
<?php
/**
* sysPass
*
* @author nuxsmin
* @link http://syspass.org
* @copyright 2012-2017, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
namespace SP\Import;
/**
* Class ImportParams
*
* @package SP\Import
*/
class ImportParams
{
/**
* @var string
*/
protected $importPwd;
/**
* @var string
*/
protected $importMasterPwd;
/**
* @var int
*/
protected $defaultUser = 0;
/**
* @var int
*/
protected $defaultGroup = 0;
/**
* @var string
*/
protected $csvDelimiter = ';';
/**
* @return string
*/
public function getImportPwd()
{
return $this->importPwd;
}
/**
* @param string $importPwd
*/
public function setImportPwd($importPwd)
{
$this->importPwd = $importPwd;
}
/**
* @return int
*/
public function getDefaultGroup()
{
return $this->defaultGroup;
}
/**
* @param int $defaultGroup
*/
public function setDefaultGroup($defaultGroup)
{
$this->defaultGroup = (int)$defaultGroup;
}
/**
* @return string
*/
public function getCsvDelimiter()
{
return $this->csvDelimiter;
}
/**
* @param string $csvDelimiter
*/
public function setCsvDelimiter($csvDelimiter)
{
$this->csvDelimiter = $csvDelimiter;
}
/**
* @return string
*/
public function getImportMasterPwd()
{
return $this->importMasterPwd;
}
/**
* @param string $importMasterPwd
*/
public function setImportMasterPwd($importMasterPwd)
{
$this->importMasterPwd = $importMasterPwd;
}
/**
* @return int
*/
public function getDefaultUser()
{
return $this->defaultUser;
}
/**
* @param int $defaultUser
*/
public function setDefaultUser($defaultUser)
{
$this->defaultUser = (int)$defaultUser;
}
}

View File

@@ -26,8 +26,9 @@
namespace SP\Import;
use SimpleXMLElement;
use SP\DataModel\AccountData;
use SP\Core\Crypt;
use SP\DataModel\AccountExtData;
use SP\DataModel\CategoryData;
use SP\DataModel\CustomerData;
defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo'));
@@ -39,20 +40,20 @@ class KeepassImport extends XmlImportBase
/**
* @var int
*/
private $customerId = 0;
/**
* @var int
*/
private $categoryId = 0;
protected $customerId = 0;
/**
* Iniciar la importación desde KeePass
*
* @throws \SP\Core\Exceptions\SPException
* @throws \SP\Core\Exceptions\InvalidClassException
*/
public function doImport()
{
$this->customerId = $this->addCustomer('KeePass');
$customerData = new CustomerData(null, 'KeePass');
$this->addCustomer($customerData);
$this->customerId = $customerData->getCustomerId();
$this->processCategories($this->xml->Root->Group);
}
@@ -62,6 +63,7 @@ class KeepassImport extends XmlImportBase
*
* @param SimpleXMLElement $xml El objeto XML del archivo de KeePass
* @throws \SP\Core\Exceptions\SPException
* @throws \SP\Core\Exceptions\InvalidClassException
*/
protected function processCategories(SimpleXMLElement $xml)
{
@@ -71,10 +73,11 @@ class KeepassImport extends XmlImportBase
// Analizar grupo
if ($node->Group->Entry) {
// Crear la categoría
$this->categoryId = $this->addCategory($group->Name, 'KeePass');
$CategoryData = new CategoryData(null, $group->Name, 'KeePass');
$this->addCategory($CategoryData);
// Crear cuentas
$this->processAccounts($group->Entry);
$this->processAccounts($group->Entry, $CategoryData->getCategoryId());
}
if ($group->Group) {
@@ -86,10 +89,11 @@ class KeepassImport extends XmlImportBase
if ($node->Entry) {
// Crear la categoría
$this->categoryId = $this->addCategory($node->Name, 'KeePass');
$CategoryData = new CategoryData(null, $node->Name, 'KeePass');
$this->addCategory($CategoryData);
// Crear cuentas
$this->processAccounts($node->Entry);
$this->processAccounts($node->Entry, $CategoryData->getCategoryId());
}
}
}
@@ -97,25 +101,24 @@ class KeepassImport extends XmlImportBase
/**
* Obtener los datos de las entradas de KeePass.
*
* @param SimpleXMLElement $entries El objeto XML con las entradas
* @param SimpleXMLElement $entries El objeto XML con las entradas
* @param int $categoryId Id de la categoría
* @throws \SP\Core\Exceptions\SPException
*/
protected function processAccounts(SimpleXMLElement $entries)
protected function processAccounts(SimpleXMLElement $entries, $categoryId)
{
foreach ($entries as $entry) {
$AccountData = new AccountData();
$AccountData = new AccountExtData();
foreach ($entry->String as $account) {
$value = isset($account->Value) ? (string)$account->Value : '';
switch ($account->Key) {
case 'Notes':
$AccountData->setAccountNotes($value);
break;
case 'Password':
$passData = Crypt::encryptData($value);
$AccountData->setAccountPass($passData['data']);
$AccountData->setAccountIV($passData['iv']);
$AccountData->setAccountPass($value);
break;
case 'Title':
$AccountData->setAccountName($value);
@@ -129,7 +132,7 @@ class KeepassImport extends XmlImportBase
}
}
$AccountData->setAccountCategoryId($this->categoryId);
$AccountData->setAccountCategoryId($categoryId);
$AccountData->setAccountCustomerId($this->customerId);
$this->addAccount($AccountData);

View File

@@ -26,8 +26,9 @@
namespace SP\Import;
use SimpleXMLElement;
use SP\DataModel\AccountData;
use SP\Core\Crypt;
use SP\DataModel\AccountExtData;
use SP\DataModel\CategoryData;
use SP\DataModel\CustomerData;
defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo'));
@@ -39,21 +40,21 @@ class KeepassXImport extends XmlImportBase
/**
* @var int
*/
private $customerId = 0;
/**
* @var int
*/
private $categoryId = 0;
protected $customerId = 0;
/**
* Iniciar la importación desde KeePassX.
*
* @throws \SP\Core\Exceptions\SPException
* @return bool
* @throws \SP\Core\Exceptions\InvalidClassException
*/
public function doImport()
{
$this->customerId = $this->addCustomer('KeePassX');
$customerData = new CustomerData(null, 'KeePassX');
$this->addCustomer($customerData);
$this->customerId = $customerData->getCustomerId();
$this->processCategories($this->xml);
}
@@ -63,6 +64,7 @@ class KeepassXImport extends XmlImportBase
*
* @param SimpleXMLElement $xml con objeto XML del archivo de KeePass
* @throws \SP\Core\Exceptions\SPException
* @throws \SP\Core\Exceptions\InvalidClassException
*/
protected function processCategories(SimpleXMLElement $xml)
{
@@ -72,10 +74,11 @@ class KeepassXImport extends XmlImportBase
// Analizar grupo
if ($node->group->entry) {
// Crear la categoría
$this->categoryId = $this->addCategory($group->title, 'KeePassX');
$CategoryData = new CategoryData(null, $group->title, 'KeePassX');
$this->addCategory($CategoryData);
// Crear cuentas
$this->processAccounts($group->entry);
$this->processAccounts($group->entry, $CategoryData->getCategoryId());
}
if ($group->group) {
@@ -86,11 +89,11 @@ class KeepassXImport extends XmlImportBase
}
if ($node->entry) {
// Crear la categoría
$this->categoryId = $this->addCategory($node->title, 'KeePassX');
$CategoryData = new CategoryData(null, $node->title, 'KeePassX');
$this->addCategory($CategoryData);
// Crear cuentas
$this->processAccounts($node->entry);
$this->processAccounts($node->entry, $CategoryData->getCategoryId());
}
}
}
@@ -98,29 +101,27 @@ class KeepassXImport extends XmlImportBase
/**
* Obtener los datos de las entradas de KeePass.
*
* @param SimpleXMLElement $entries El objeto XML con las entradas
* @param SimpleXMLElement $entries El objeto XML con las entradas
* @param int $categoryId Id de la categoría
* @throws \SP\Core\Exceptions\SPException
*/
protected function processAccounts(SimpleXMLElement $entries)
protected function processAccounts(SimpleXMLElement $entries, $categoryId)
{
foreach ($entries as $entry) {
$notes = isset($entry->comment) ? (string)$entry->comment : '';
$password = isset($entry->password) ? (string)$entry->password : '';
$name = isset($entry->title) ? (string)$entry->title : '';
$password = isset($entry->password) ? (string)$entry->password : '';
$url = isset($entry->url) ? (string)$entry->url : '';
$notes = isset($entry->comment) ? (string)$entry->comment : '';
$username = isset($entry->username) ? (string)$entry->username : '';
$passData = Crypt::encryptData($password);
$AccountData = new AccountData();
$AccountData->setAccountPass($passData['data']);
$AccountData->setAccountIV($passData['iv']);
$AccountData = new AccountExtData();
$AccountData->setAccountPass($password);
$AccountData->setAccountNotes($notes);
$AccountData->setAccountName($name);
$AccountData->setAccountUrl($url);
$AccountData->setAccountLogin($username);
$AccountData->setAccountCustomerId($this->customerId);
$AccountData->setAccountCategoryId($this->categoryId);
$AccountData->setAccountCategoryId($categoryId);
$this->addAccount($AccountData);
}

View File

@@ -28,6 +28,9 @@ namespace SP\Import;
use SP\Core\Crypt;
use SP\Core\Exceptions\SPException;
use SP\DataModel\AccountExtData;
use SP\DataModel\CategoryData;
use SP\DataModel\CustomerData;
use SP\DataModel\TagData;
defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo'));
@@ -36,18 +39,24 @@ defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo'
*/
class SyspassImport extends XmlImportBase
{
/**
* Mapeo de etiquetas
*
* @var array
*/
protected $tags = [];
/**
* Mapeo de categorías.
*
* @var array
*/
private $categories = [];
protected $categories = [];
/**
* Mapeo de clientes.
*
* @var array
*/
private $customers = [];
protected $customers = [];
/**
* Iniciar la importación desde sysPass.
@@ -57,11 +66,16 @@ class SyspassImport extends XmlImportBase
public function doImport()
{
try {
if ($this->detectEncrypted() && null !== $this->getImportPass()) {
if ($this->detectEncrypted()) {
if ($this->ImportParams->getImportPwd() === '') {
throw new SPException(SPException::SP_ERROR, _('Clave de encriptación no indicada'));
}
$this->processEncrypted();
}
$this->processCategories();
$this->processCustomers();
$this->processTags();
$this->processAccounts();
} catch (SPException $e) {
throw $e;
@@ -90,7 +104,7 @@ class SyspassImport extends XmlImportBase
$data = base64_decode($node->nodeValue);
$iv = base64_decode($node->getAttribute('iv'));
$xmlDecrypted = Crypt::getDecrypt($data, $iv, $this->getImportPass());
$xmlDecrypted = Crypt::getDecrypt($data, $iv, $this->ImportParams->getImportPwd());
$newXmlData = new \DOMDocument();
// $newXmlData->preserveWhiteSpace = true;
@@ -110,117 +124,148 @@ class SyspassImport extends XmlImportBase
/**
* Obtener las categorías y añadirlas a sysPass.
*
* @throws \SP\Core\Exceptions\SPException
* @param \DOMElement $Category
* @throws SPException
* @throws \SP\Core\Exceptions\InvalidClassException
*/
protected function processCategories()
protected function processCategories(\DOMElement $Category = null)
{
if ($this->xmlDOM->getElementsByTagName('Categories')->length === 0) {
throw new SPException(SPException::SP_WARNING, _('Formato de XML inválido'), _('No hay categorías para importar'));
if ($Category === null) {
$this->getNodesData('Categories', 'Category', __FUNCTION__);
return;
}
/** @var \DOMElement $category */
foreach ($this->xmlDOM->getElementsByTagName('Category') as $category) {
$name = '';
$description = '';
$CategoryData = new CategoryData();
foreach ($category->childNodes as $node) {
if (isset($node->tagName)) {
switch ($node->tagName) {
case 'name':
$name = $node->nodeValue;
break;
case 'description':
$description = $node->nodeValue;
break;
}
foreach ($Category->childNodes as $categoryNode) {
if (isset($categoryNode->tagName)) {
switch ($categoryNode->tagName) {
case 'name':
$CategoryData->setCategoryName($categoryNode->nodeValue);
break;
case 'description':
$CategoryData->setCategoryDescription($categoryNode->nodeValue);
break;
}
}
$this->categories[$category->getAttribute('id')] = $this->addCategory($name, $description);
}
$this->addCategory($CategoryData);
$this->categories[$Category->getAttribute('id')] = $CategoryData->getCategoryId();
}
/**
* Obtener los clientes y añadirlos a sysPass.
*
* @throws \SP\Core\Exceptions\SPException
* @param \DOMElement $Customer
* @throws SPException
* @throws \SP\Core\Exceptions\InvalidClassException
*/
protected function processCustomers()
protected function processCustomers(\DOMElement $Customer = null)
{
if ($this->xmlDOM->getElementsByTagName('Customers')->length === 0) {
throw new SPException(SPException::SP_WARNING, _('Formato de XML inválido'), _('No hay clientes para importar'));
if ($Customer === null) {
$this->getNodesData('Customers', 'Customer', __FUNCTION__);
return;
}
/** @var \DOMElement $customer */
foreach ($this->xmlDOM->getElementsByTagName('Customer') as $customer) {
$name = '';
$description = '';
$CustomerData = new CustomerData();
foreach ($customer->childNodes as $node) {
if (isset($node->tagName)) {
switch ($node->tagName) {
case 'name':
$name = $node->nodeValue;
break;
case 'description':
$description = $node->nodeValue;
break;
}
foreach ($Customer->childNodes as $customerNode) {
if (isset($customerNode->tagName)) {
switch ($customerNode->tagName) {
case 'name':
$CustomerData->setCustomerName($customerNode->nodeValue);
break;
case 'description':
$CustomerData->setCustomerDescription($customerNode->nodeValue);
break;
}
}
$this->customers[$customer->getAttribute('id')] = $this->addCustomer($name, $description);
}
$this->addCustomer($CustomerData);
$this->customers[$Customer->getAttribute('id')] = $CustomerData->getCustomerId();
}
/**
* Obtener los datos de las entradas de sysPass y crearlas.
* Obtener las etiquetas y añadirlas a sysPass.
*
* @throws \SP\Core\Exceptions\SPException
* @param \DOMElement $Tag
* @throws SPException
* @throws \SP\Core\Exceptions\InvalidClassException
*/
protected function processAccounts()
protected function processTags(\DOMElement $Tag = null)
{
if ($this->xmlDOM->getElementsByTagName('Accounts')->length === 0) {
throw new SPException(SPException::SP_WARNING, _('Formato de XML inválido'), _('No hay cuentas para importar'));
if ($Tag === null) {
$this->getNodesData('Tags', 'Tag', __FUNCTION__);
return;
}
$TagData = new TagData();
foreach ($Tag->childNodes as $tagNode) {
if (isset($tagNode->tagName)) {
switch ($tagNode->tagName) {
case 'name':
$TagData->setTagName($tagNode->nodeValue);
break;
}
}
}
$this->addTag($TagData);
$this->tags[$Tag->getAttribute('id')] = $TagData->getTagId();
}
/**
* Obtener los datos de las cuentas de sysPass y crearlas.
*
* @param \DOMElement $Account
* @throws SPException
*/
protected function processAccounts(\DOMElement $Account = null)
{
if ($Account === null) {
$this->getNodesData('Accounts', 'Account', __FUNCTION__);
return;
}
$AccountData = new AccountExtData();
foreach ($this->xmlDOM->getElementsByTagName('Account') as $account) {
$AccountDataClone = clone $AccountData;
foreach ($account->childNodes as $node) {
if (isset($node->tagName)) {
switch ($node->tagName) {
case 'name';
$AccountDataClone->setAccountName($node->nodeValue);
break;
case 'login';
$AccountDataClone->setAccountLogin($node->nodeValue);
break;
case 'categoryId';
$AccountDataClone->setAccountCategoryId($this->categories[(int)$node->nodeValue]);
break;
case 'customerId';
$AccountDataClone->setAccountCustomerId($this->customers[(int)$node->nodeValue]);
break;
case 'url';
$AccountDataClone->setAccountUrl($node->nodeValue);
break;
case 'pass';
$AccountDataClone->setAccountPass(base64_decode($node->nodeValue));
break;
case 'passiv';
$AccountDataClone->setAccountIV(base64_decode($node->nodeValue));
break;
case 'notes';
$AccountDataClone->setAccountNotes($node->nodeValue);
break;
}
foreach ($Account->childNodes as $accountNode) {
if (isset($accountNode->tagName)) {
switch ($accountNode->tagName) {
case 'name';
$AccountData->setAccountName($accountNode->nodeValue);
break;
case 'login';
$AccountData->setAccountLogin($accountNode->nodeValue);
break;
case 'categoryId';
$AccountData->setAccountCategoryId($this->categories[(int)$accountNode->nodeValue]);
break;
case 'customerId';
$AccountData->setAccountCustomerId($this->customers[(int)$accountNode->nodeValue]);
break;
case 'url';
$AccountData->setAccountUrl($accountNode->nodeValue);
break;
case 'pass';
$AccountData->setAccountPass(base64_decode($accountNode->nodeValue));
break;
case 'passiv';
$AccountData->setAccountIV(base64_decode($accountNode->nodeValue));
break;
case 'notes';
$AccountData->setAccountNotes($accountNode->nodeValue);
break;
}
}
$this->addAccount($AccountDataClone);
}
$this->addAccount($AccountData);
}
}

View File

@@ -46,29 +46,26 @@ class XmlImport extends XmlImportBase
*/
public function doImport()
{
$import = null;
$Import = null;
$format = $this->detectXMLFormat();
switch ($format) {
case 'syspass':
$import = new SyspassImport($this->file);
$Import = new SyspassImport($this->file, $this->ImportParams);
break;
case 'keepass':
$import = new KeepassImport($this->file);
$Import = new KeepassImport($this->file, $this->ImportParams);
break;
case 'keepassx':
$import = new KeepassXImport($this->file);
$Import = new KeepassXImport($this->file, $this->ImportParams);
break;
}
if (is_object($import)){
if (is_object($Import)){
Log::writeNewLog(_('Importar Cuentas'), _('Inicio'));
Log::writeNewLog(_('Importar Cuentas'), _('Formato detectado') . ': ' . strtoupper($format));
Log::writeNewLog(_('Importar Cuentas'), sprintf(_('Formato detectado: %s'), strtoupper($format)));
$import->setUserId($this->getUserId());
$import->setUserGroupId($this->getUserGroupId());
$import->setImportPass($this->getImportPass());
$import->doImport();
$Import->doImport();
}
}
}

View File

@@ -46,26 +46,28 @@ abstract class XmlImportBase extends ImportBase
protected $xmlDOM;
/**
* Constructor
* ImportBase constructor.
*
* @param $file FileImport Instancia de la clase FileImport
* @param FileImport $File
* @param ImportParams $ImportParams
* @throws SPException
*/
public function __construct($file)
public function __construct(FileImport $File, ImportParams $ImportParams)
{
parent::__construct($File, $ImportParams);
try {
$this->file = $file;
$this->readXMLFile();
} catch (SPException $e) {
throw $e;
}
}
/**
* Leer el archivo a un objeto XML.
*
* @throws SPException
* @return \SimpleXMLElement Con los datos del archivo XML
*/
protected function readXMLFile()
{
@@ -91,9 +93,9 @@ abstract class XmlImportBase extends ImportBase
*/
public function detectXMLFormat()
{
if ($this->xml->Meta->Generator == 'KeePass') {
if ((string)$this->xml->Meta->Generator === 'KeePass') {
return 'keepass';
} else if ($this->xml->Meta->Generator == 'sysPass') {
} else if ((string)$this->xml->Meta->Generator === 'sysPass') {
return 'syspass';
} else if ($xmlApp = $this->parseFileHeader()) {
switch ($xmlApp) {
@@ -114,4 +116,30 @@ abstract class XmlImportBase extends ImportBase
return '';
}
/**
* Obtener los datos de los nodos
*
* @param string $nodeName Nombre del nodo principal
* @param string $childNodeName Nombre de los nodos hijos
* @throws SPException
*/
protected function getNodesData($nodeName, $childNodeName, $callback)
{
$ParentNode = $this->xmlDOM->getElementsByTagName($nodeName);
if ($ParentNode->length === 0) {
throw new SPException(SPException::SP_WARNING, _('Formato de XML inválido'), sprintf(_('El nodo "%s" no existe'), $nodeName));
} elseif (!is_callable([$this, $callback])) {
throw new SPException(SPException::SP_WARNING, _('Método inválido'));
}
/** @var \DOMElement $nodes */
foreach ($ParentNode as $nodes) {
/** @var \DOMElement $Account */
foreach ($nodes->getElementsByTagName($childNodeName) as $Node) {
$this->$callback($Node);
}
}
}
}

View File

@@ -57,7 +57,7 @@ class Category extends CategoryBase implements ItemInterface, ItemSelectInterfac
public function add()
{
if ($this->checkDuplicatedOnAdd()) {
throw new SPException(SPException::SP_WARNING, _('Nombre de categoría duplicado'));
throw new SPException(SPException::SP_WARNING, _('Categoría duplicada'));
}
$query = /** @lang SQL */
@@ -100,7 +100,17 @@ class Category extends CategoryBase implements ItemInterface, ItemSelectInterfac
$Data->addParam($this->makeItemHash($this->itemData->getCategoryName()));
$Data->addParam($this->itemData->getCategoryName());
return (DB::getQuery($Data) === false || $Data->getQueryNumRows() >= 1);
$queryRes = DB::getResults($Data);
if ($queryRes !== false) {
if ($Data->getQueryNumRows() === 0) {
return false;
} elseif ($Data->getQueryNumRows() === 1) {
$this->itemData->setCategoryId($queryRes->category_id);
}
}
return true;
}
/**
@@ -252,7 +262,7 @@ class Category extends CategoryBase implements ItemInterface, ItemSelectInterfac
public function getAll()
{
$query = /** @lang SQL */
'SELECT category_id, category_name, category_description FROM categories ORDER BY category_name';
'SELECT category_id, category_name, category_description, category_hash FROM categories ORDER BY category_name';
$Data = new QueryData();
$Data->setMapClassName($this->getDataModel());

View File

@@ -99,7 +99,17 @@ class Customer extends CustomerBase implements ItemInterface, ItemSelectInterfac
$Data->setQuery($query);
$Data->addParam($this->makeItemHash($this->itemData->getCustomerName()));
return (DB::getQuery($Data) === false || $Data->getQueryNumRows() >= 1);
$queryRes = DB::getResults($Data);
if ($queryRes !== false) {
if ($Data->getQueryNumRows() === 0) {
return false;
} elseif ($Data->getQueryNumRows() === 1) {
$this->itemData->setCustomerId($queryRes->customer_id);
}
}
return true;
}
/**

View File

@@ -65,6 +65,7 @@ abstract class ItemBase
*
* @param $itemData
* @return static
* @throws \SP\Core\Exceptions\InvalidClassException
*/
public final static function getItem($itemData = null)
{

View File

@@ -76,12 +76,22 @@ class Tag extends TagBase implements ItemInterface, ItemSelectInterface
public function checkDuplicatedOnAdd()
{
$query = /** @lang SQL */
'SELECT tag_hash FROM tags WHERE tag_hash = ?';
'SELECT tag_id FROM tags WHERE tag_hash = ?';
$Data = new QueryData();
$Data->setQuery($query);
$Data->addParam($this->itemData->getTagHash());
return (DB::getQuery($Data) === false || $Data->getQueryNumRows() > 0);
$queryRes = DB::getResults($Data);
if ($queryRes !== false) {
if ($Data->getQueryNumRows() === 0) {
return false;
} elseif ($Data->getQueryNumRows() === 1) {
$this->itemData->setTagId($queryRes->tag_id);
}
}
return true;
}
/**
@@ -185,7 +195,7 @@ class Tag extends TagBase implements ItemInterface, ItemSelectInterface
public function getAll()
{
$query = /** @lang SQL */
'SELECT tag_id, tag_name FROM tags ORDER BY tag_name';
'SELECT tag_id, tag_name, tag_hash FROM tags ORDER BY tag_name';
$Data = new QueryData();
$Data->setQuery($query);

View File

@@ -37,6 +37,37 @@ use SP\Core\Exceptions\SPException;
*/
class DBUtil
{
/**
* @var array Tablas de la BBDD
*/
public static $tables = [
'customers',
'categories',
'usrGroups',
'usrProfiles',
'usrData',
'accounts',
'accFavorites',
'accFiles',
'accGroups',
'accHistory',
'accTags',
'accUsers',
'authTokens',
'config',
'customFieldsData',
'customFieldsDef',
'log',
'publicLinks',
'tags',
'usrPassRecover',
'usrToGroups',
'plugins',
'notices',
'account_data_v',
'account_search_v'
];
/**
* Comprobar que la base de datos existe.
*
@@ -51,17 +82,12 @@ class DBUtil
$query = /** @lang SQL */
'SELECT COUNT(*)
FROM information_schema.tables
WHERE table_schema = \'' . Config::getConfig()->getDbName() . '\'
AND table_name = \'usrData\'';
WHERE table_schema = \'' . Config::getConfig()->getDbName() . '\'';
if ((int)$db->query($query)->fetchColumn() !== 0) {
return true;
}
return (int)$db->query($query)->fetchColumn() === count(self::$tables);
} catch (\Exception $e) {
throw new SPException(SPException::SP_CRITICAL, $e->getMessage(), $e->getCode());
}
return false;
}
/**

View File

@@ -24,12 +24,16 @@
<?php if (file_exists($backupFile['absolute']) && file_exists($backupDbFile['absolute'])): ?>
<a href="<?php echo $backupDbFile['relative']; ?>"
download="<?php echo $backupDbFile['filename']; ?>" class="download">
Backup BBDD
<button type="button" class="mdl-button mdl-js-button">
<?php echo _('Copia BBDD'); ?>
</button>
</a>
<a href="<?php echo $backupFile['relative']; ?>"
download="<?php echo $backupFile['filename']; ?>" class="download">
Backup <?php echo $siteName; ?>
<button type="button" class="mdl-button mdl-js-button">
<?php echo _('Copia sysPass'); ?>
</button>
</a>
<?php else: echo _('No hay backups para descargar'); ?>
<?php endif; ?>
@@ -100,7 +104,9 @@
<a href="<?php echo $exportFile['relative']; ?>"
download="<?php echo $exportFile['filename']; ?>"
class="download">
XML <?php echo $siteName; ?></>
<button type="button" class="mdl-button mdl-js-button">
XML <?php echo $siteName; ?>
</button>
</a>
<?php else: echo _('No hay archivos XML para descargar'); ?>
<?php endif; ?>

View File

@@ -9,7 +9,7 @@ use SP\Core\Session; ?>
</div>
<table class="data round">
<form method="post" name="frmImport" id="form-action" data-onsubmit="config/import" data-hash="">
<form method="post" name="frmImport" id="frmImport">
<tr>
<td class="descField">
<?php echo _('Usuario por Defecto'); ?>
@@ -78,11 +78,11 @@ use SP\Core\Session; ?>
</td>
<td class="valField">
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input id="masterPwd" name="masterPwd" type="password"
<input id="importMasterPwd" name="importMasterPwd" type="password"
class="mdl-textfield__input mdl-color-text--indigo-400 passwordfield__input-show"
maxlength="255" />
<label class="mdl-textfield__label"
for="masterPwd"><?php echo _('Clave Maestra'); ?></label>
for="importMasterPwd"><?php echo _('Clave Maestra'); ?></label>
</div>
</td>
</tr>

View File

@@ -50,8 +50,8 @@ sysPass.Actions = function (Common) {
checks: "/ajax/ajax_checkConnection.php",
config: {
save: "/ajax/ajax_configSave.php",
export: "/ajax/ajax_export.php",
import: "/ajax/ajax_import.php"
export: "/ajax/ajax_configSave.php",
import: "/ajax/ajax_configSave.php"
},
file: "/ajax/ajax_filesMgmt.php",
link: "/ajax/ajax_itemSave.php",

10
js/app-actions.min.js vendored
View File

@@ -1,11 +1,11 @@
var $jscomp={scope:{},findInternal:function(c,d,h){c instanceof String&&(c=String(c));for(var e=c.length,g=0;g<e;g++){var m=c[g];if(d.call(h,m,g,c))return{i:g,v:m}}return{i:-1,v:void 0}}};$jscomp.defineProperty="function"==typeof Object.defineProperties?Object.defineProperty:function(c,d,h){if(h.get||h.set)throw new TypeError("ES3 does not support getters and setters.");c!=Array.prototype&&c!=Object.prototype&&(c[d]=h.value)};
$jscomp.getGlobal=function(c){return"undefined"!=typeof window&&window===c?c:"undefined"!=typeof global?global:c};$jscomp.global=$jscomp.getGlobal(this);$jscomp.polyfill=function(c,d,h,e){if(d){h=$jscomp.global;c=c.split(".");for(e=0;e<c.length-1;e++){var g=c[e];g in h||(h[g]={});h=h[g]}c=c[c.length-1];e=h[c];d=d(e);d!=e&&null!=d&&$jscomp.defineProperty(h,c,{configurable:!0,writable:!0,value:d})}};
$jscomp.polyfill("Array.prototype.find",function(c){return c?c:function(c,h){return $jscomp.findInternal(this,c,h).v}},"es6-impl","es3");
sysPass.Actions=function(c){var d=c.log,h=0,e={doAction:"/ajax/ajax_getContent.php",updateItems:"/ajax/ajax_getItems.php",user:{savePreferences:"/ajax/ajax_userPrefsSave.php",password:"/ajax/ajax_usrpass.php",passreset:"/ajax/ajax_passReset.php"},main:{login:"/ajax/ajax_doLogin.php",install:"/ajax/ajax_install.php",twofa:"/ajax/ajax_2fa.php",getUpdates:"/ajax/ajax_checkUpds.php"},checks:"/ajax/ajax_checkConnection.php",config:{save:"/ajax/ajax_configSave.php","export":"/ajax/ajax_export.php","import":"/ajax/ajax_import.php"},
file:"/ajax/ajax_filesMgmt.php",link:"/ajax/ajax_itemSave.php",plugin:"/ajax/ajax_itemSave.php",account:{save:"/ajax/ajax_itemSave.php",showPass:"/ajax/ajax_accViewPass.php",saveFavorite:"/ajax/ajax_itemSave.php",request:"/ajax/ajax_sendRequest.php",getFiles:"/ajax/ajax_accGetFiles.php",search:"/ajax/ajax_accSearch.php"},appMgmt:{show:"/ajax/ajax_itemShow.php",save:"/ajax/ajax_itemSave.php",search:"/ajax/ajax_itemSearch.php"},eventlog:"/ajax/ajax_eventlog.php",wiki:{show:"/ajax/ajax_wiki.php"}},g=
function(a){a={actionId:a.actionId,itemId:"undefined"!==a.itemId?a.itemId:0,isAjax:1};var b=c.appRequests().getRequestOpts();b.url=e.doAction;b.type="html";b.addHistory=!0;b.data=a;c.appRequests().getActionCall(b,function(a){$("#content").empty().html(a)})},m=function(a){d.info("updateItems");var b=$("#"+a.data("item-dst"))[0].selectize;b.clearOptions();b.load(function(b){var f=c.appRequests().getRequestOpts();f.url=e.updateItems;f.method="get";f.data={sk:c.sk.get(),itemType:a.data("item-type")};
c.appRequests().getActionCall(f,function(a){b(a.items)})})},p=function(a,b){$.magnificPopup.open({items:{src:b,type:"inline"},callbacks:{open:function(){c.appTriggers().views.common("#box-popup")},close:function(){a.data("item-dst")&&m(a)}},showCloseBtn:!1})},r=function(a,b){var f=$('<div id="fancyContainer" class="image">'+b+"</div>"),d=f.find("img");d.hide();$.magnificPopup.open({items:{src:f,type:"inline"},callbacks:{open:function(){var a=this;d.on("click",function(){a.close()});setTimeout(function(){var a=
c.resizeImage(d);f.css({backgroundColor:"#fff",width:a.width,height:"auto"});d.show("slow")},500)}}})},q={logout:function(){var a=window.location.search;c.redirect(0<a.length?"index.php"+a+"&logout=1":"index.php?logout=1")},login:function(a){d.info("main:login");var b=c.appRequests().getRequestOpts();b.url=e.main.login;b.data=a.serialize();c.appRequests().getActionCall(b,function(b){switch(b.status){case 0:c.redirect(b.data.url);break;case 2:c.msg.out(b);a.find("input[type='text'],input[type='password']").val("");
sysPass.Actions=function(c){var d=c.log,h=0,e={doAction:"/ajax/ajax_getContent.php",updateItems:"/ajax/ajax_getItems.php",user:{savePreferences:"/ajax/ajax_userPrefsSave.php",password:"/ajax/ajax_usrpass.php",passreset:"/ajax/ajax_passReset.php"},main:{login:"/ajax/ajax_doLogin.php",install:"/ajax/ajax_install.php",twofa:"/ajax/ajax_2fa.php",getUpdates:"/ajax/ajax_checkUpds.php"},checks:"/ajax/ajax_checkConnection.php",config:{save:"/ajax/ajax_configSave.php","export":"/ajax/ajax_configSave.php",
"import":"/ajax/ajax_configSave.php"},file:"/ajax/ajax_filesMgmt.php",link:"/ajax/ajax_itemSave.php",plugin:"/ajax/ajax_itemSave.php",account:{save:"/ajax/ajax_itemSave.php",showPass:"/ajax/ajax_accViewPass.php",saveFavorite:"/ajax/ajax_itemSave.php",request:"/ajax/ajax_sendRequest.php",getFiles:"/ajax/ajax_accGetFiles.php",search:"/ajax/ajax_accSearch.php"},appMgmt:{show:"/ajax/ajax_itemShow.php",save:"/ajax/ajax_itemSave.php",search:"/ajax/ajax_itemSearch.php"},eventlog:"/ajax/ajax_eventlog.php",
wiki:{show:"/ajax/ajax_wiki.php"}},g=function(a){a={actionId:a.actionId,itemId:"undefined"!==a.itemId?a.itemId:0,isAjax:1};var b=c.appRequests().getRequestOpts();b.url=e.doAction;b.type="html";b.addHistory=!0;b.data=a;c.appRequests().getActionCall(b,function(a){$("#content").empty().html(a)})},m=function(a){d.info("updateItems");var b=$("#"+a.data("item-dst"))[0].selectize;b.clearOptions();b.load(function(b){var f=c.appRequests().getRequestOpts();f.url=e.updateItems;f.method="get";f.data={sk:c.sk.get(),
itemType:a.data("item-type")};c.appRequests().getActionCall(f,function(a){b(a.items)})})},p=function(a,b){$.magnificPopup.open({items:{src:b,type:"inline"},callbacks:{open:function(){c.appTriggers().views.common("#box-popup")},close:function(){a.data("item-dst")&&m(a)}},showCloseBtn:!1})},r=function(a,b){var f=$('<div id="fancyContainer" class="image">'+b+"</div>"),d=f.find("img");d.hide();$.magnificPopup.open({items:{src:f,type:"inline"},callbacks:{open:function(){var a=this;d.on("click",function(){a.close()});
setTimeout(function(){var a=c.resizeImage(d);f.css({backgroundColor:"#fff",width:a.width,height:"auto"});d.show("slow")},500)}}})},q={logout:function(){var a=window.location.search;c.redirect(0<a.length?"index.php"+a+"&logout=1":"index.php?logout=1")},login:function(a){d.info("main:login");var b=c.appRequests().getRequestOpts();b.url=e.main.login;b.data=a.serialize();c.appRequests().getActionCall(b,function(b){switch(b.status){case 0:c.redirect(b.data.url);break;case 2:c.msg.out(b);a.find("input[type='text'],input[type='password']").val("");
a.find("input:first").focus();$("#mpass").prop("disabled",!1).val("");$("#smpass").show();break;case 5:c.msg.out(b);a.find("input[type='text'],input[type='password']").val("");a.find("input:first").focus();$("#oldpass").prop("disabled",!1).val("");$("#soldpass").show();break;default:c.msg.out(b),a.find("input[type='text'],input[type='password']").val(""),a.find("input:first").focus()}})},install:function(a){d.info("main:install");var b=c.appRequests().getRequestOpts();b.url=e.main.install;b.data=
a.serialize();c.appRequests().getActionCall(b,function(a){c.msg.out(a);0==a.status&&setTimeout(function(){c.redirect("index.php")},1E3)})},getUpdates:function(a){d.info("main:getUpdates");a=c.appRequests().getRequestOpts();a.url=e.main.getUpdates;a.type="html";a.method="get";a.timeout=1E4;a.useLoading=!1;a.data={isAjax:1};c.appRequests().getActionCall(a,function(a){$("#updates").html(a);"undefined"!==typeof componentHandler&&componentHandler.upgradeDom()},function(){$("#updates").html("!")})}},l=
{show:function(a){d.info("account:show");g({actionId:a.data("action-id"),itemId:a.data("item-id")})},showHistory:function(a){d.info("account:showHistory");g({actionId:a.data("action-id"),itemId:a.val()})},edit:function(a){d.info("account:edit");g({actionId:a.data("action-id"),itemId:a.data("item-id")})},"delete":function(a){d.info("account:delete");var b='<div id="alert"><p id="alert-text">'+c.config().LANG[3]+"</p></div>";showDialog({text:b,negative:{title:c.config().LANG[44],onClick:function(a){a.preventDefault();

View File

@@ -141,7 +141,7 @@ sysPass.Main = function () {
appTriggers.views.footer();
}
$('#btnBack').click(function () {
$("#btnBack").click(function () {
redirect("index.php");
});
};
@@ -165,7 +165,7 @@ sysPass.Main = function () {
var status = data.status;
var description = data.description;
if (typeof data.messages !== "undefined" && data.messages.length > 0) {
if (data.messages !== undefined && data.messages.length > 0) {
description = description + "<br>" + data.messages.join("<br>");
}
@@ -329,20 +329,19 @@ sysPass.Main = function () {
// Función para habilitar la subida de archivos en una zona o formulario
var fileUpload = function ($obj) {
var requestData = function () {
return {
actionId: $obj.data("action-id"),
itemId: $obj.data("item-id"),
sk: sk.get()
};
var requestData = {
actionId: $obj.data("action-id"),
itemId: $obj.data("item-id"),
sk: sk.get()
};
var options = {
requestDoneAction: "",
requestData: function (data) {
requestData = function () {
return data;
};
setRequestData: function (data) {
$.extend(requestData, data);
},
getRequestData: function () {
return requestData;
},
beforeSendAction: "",
url: ""
@@ -350,7 +349,7 @@ sysPass.Main = function () {
// Subir un archivo
var sendFile = function (file) {
if (typeof options.url === "undefined" || options.url === "") {
if (options.url === undefined || options.url === "") {
return false;
}
@@ -359,12 +358,10 @@ sysPass.Main = function () {
fd.append("inFile", file);
fd.append("isAjax", 1);
var data = requestData();
Object.keys(data).forEach(function (key) {
Object.keys(requestData).forEach(function (key) {
log.info(key);
fd.append(key, data[key]);
fd.append(key, requestData[key]);
});
var opts = appRequests.getRequestOpts();
@@ -442,7 +439,6 @@ sysPass.Main = function () {
$obj.on("drop", function (e) {
log.info("fileUpload:drop");
log.info(e);
e.stopPropagation();
e.preventDefault();
@@ -451,7 +447,7 @@ sysPass.Main = function () {
options.beforeSendAction();
}
handleFiles(e.dataTransfer.files);
handleFiles(e.originalEvent.dataTransfer.files);
});
$obj.on("click", function () {

14
js/app-main.min.js vendored
View File

@@ -4,18 +4,18 @@ $jscomp.initSymbolIterator=function(){$jscomp.initSymbol();var a=$jscomp.global.
$jscomp.iteratorPrototype=function(a){$jscomp.initSymbolIterator();a={next:a};a[$jscomp.global.Symbol.iterator]=function(){return this};return a};$jscomp.array=$jscomp.array||{};$jscomp.iteratorFromArray=function(a,f){$jscomp.initSymbolIterator();a instanceof String&&(a+="");var e=0,c={next:function(){if(e<a.length){var g=e++;return{value:f(g,a[g]),done:!1}}c.next=function(){return{done:!0,value:void 0}};return c.next()}};c[Symbol.iterator]=function(){return c};return c};
$jscomp.polyfill=function(a,f,e,c){if(f){e=$jscomp.global;a=a.split(".");for(c=0;c<a.length-1;c++){var g=a[c];g in e||(e[g]={});e=e[g]}a=a[a.length-1];c=e[a];f=f(c);f!=c&&null!=f&&$jscomp.defineProperty(e,a,{configurable:!0,writable:!0,value:f})}};$jscomp.polyfill("Array.prototype.keys",function(a){return a?a:function(){return $jscomp.iteratorFromArray(this,function(a){return a})}},"es6-impl","es3");
$jscomp.findInternal=function(a,f,e){a instanceof String&&(a=String(a));for(var c=a.length,g=0;g<c;g++){var m=a[g];if(f.call(e,m,g,a))return{i:g,v:m}}return{i:-1,v:void 0}};$jscomp.polyfill("Array.prototype.find",function(a){return a?a:function(a,e){return $jscomp.findInternal(this,a,e).v}},"es6-impl","es3");
sysPass.Main=function(){var a={APP_ROOT:"",LANG:[],PK:"",MAX_FILE_SIZE:1024,CRYPT:new JSEncrypt,CHECK_UPDATES:!1,TIMEZONE:"",LOCALE:"",DEBUG:""},f={passLength:0,minPasswordLength:8,complexity:{numbers:!0,symbols:!0,uppercase:!0,numlength:12}},e={},c={},g={},m={},r={},q={},h={log:function(b){!0===a.DEBUG&&console.log(b)},info:function(b){!0===a.DEBUG&&console.info(b)},error:function(a){console.error(a)},warn:function(a){console.warn(a)}};toastr.options={closeButton:!0,debug:!1,newestOnTop:!1,progressBar:!1,
sysPass.Main=function(){var a={APP_ROOT:"",LANG:[],PK:"",MAX_FILE_SIZE:1024,CRYPT:new JSEncrypt,CHECK_UPDATES:!1,TIMEZONE:"",LOCALE:"",DEBUG:""},f={passLength:0,minPasswordLength:8,complexity:{numbers:!0,symbols:!0,uppercase:!0,numlength:12}},e={},c={},g={},m={},r={},p={},h={log:function(b){!0===a.DEBUG&&console.log(b)},info:function(b){!0===a.DEBUG&&console.info(b)},error:function(a){console.error(a)},warn:function(a){console.warn(a)}};toastr.options={closeButton:!0,debug:!1,newestOnTop:!1,progressBar:!1,
positionClass:"toast-top-center",preventDuplicates:!1,onclick:null,showDuration:"300",hideDuration:"1000",timeOut:"5000",extendedTimeOut:"1000",showEasing:"swing",hideEasing:"linear",showMethod:"fadeIn",hideMethod:"fadeOut"};var x=function(){h.info("setupCallbacks");switch($("#container").data("page")){case "login":c.views.login();break;case "2fa":c.views.twofa();break;case "passreset":c.views.passreset()}0<$("footer").length&&c.views.footer();$("#btnBack").click(function(){u("index.php")})},l={ok:function(a){toastr.success(a)},
error:function(a){toastr.error(a)},warn:function(a){toastr.warning(a)},info:function(a){toastr.info(a)},out:function(a){if("object"===typeof a){var b=a.status,d=a.description;"undefined"!==typeof a.messages&&0<a.messages.length&&(d=d+"<br>"+a.messages.join("<br>"));switch(b){case 0:l.ok(d);break;case 1:case 2:l.error(d);break;case 3:l.warn(d);break;case 10:g.main.logout()}}},html:{error:function(b){return'<p class="error round">Oops...<br>'+a.LANG[1]+"<br>"+b+"</p>"}}},y=function(b){h.info("getEnvironment");
error:function(a){toastr.error(a)},warn:function(a){toastr.warning(a)},info:function(a){toastr.info(a)},out:function(a){if("object"===typeof a){var b=a.status,d=a.description;void 0!==a.messages&&0<a.messages.length&&(d=d+"<br>"+a.messages.join("<br>"));switch(b){case 0:l.ok(d);break;case 1:case 2:l.error(d);break;case 3:l.warn(d);break;case 10:g.main.logout()}}},html:{error:function(b){return'<p class="error round">Oops...<br>'+a.LANG[1]+"<br>"+b+"</p>"}}},y=function(b){h.info("getEnvironment");
var k=window.location.pathname.split("/"),d=window.location.protocol+"//"+window.location.host+function(){for(var a="",b=1;b<=k.length-2;b++)a+="/"+k[b];return a}(),n=m.getRequestOpts();n.url=d+"/ajax/ajax_getEnvironment.php";n.method="get";n.async=!1;n.useLoading=!1;n.data={isAjax:1};m.getActionCall(n,function(d){a.APP_ROOT=d.app_root;a.LANG=d.lang;a.PK=d.pk;a.CHECK_UPDATES=d.check_updates;a.CRYPT.setPublicKey(d.pk);a.TIMEZONE=d.timezone;a.LOCALE=d.locale;a.DEBUG=d.debug;"function"===typeof b&&b()})},
v={get:function(){h.info("sk:get");return $("#container").attr("data-sk")},set:function(a){h.info("sk:set");$("#container").attr("data-sk",a)}},z=function(){var a=$("#container");if(!a.hasClass("content-no-auto-resize")){var k=$("#content").height()+200;a.css("height",k)}},A=function(){$("html, body").animate({scrollTop:0},"slow")},u=function(a){window.location.replace(a)},B=function(b){var k=function(){return{actionId:b.data("action-id"),itemId:b.data("item-id"),sk:v.get()}},d={requestDoneAction:"",
requestData:function(a){k=function(){return a}},beforeSendAction:"",url:""},n=function(a){if("undefined"===typeof d.url||""===d.url)return!1;var b=new FormData;b.append("inFile",a);b.append("isAjax",1);var p=k();Object.keys(p).forEach(function(a){h.info(a);b.append(a,p[a])});a=m.getRequestOpts();a.url=d.url;a.processData=!1;a.contentType=!1;a.data=b;m.getActionCall(a,function(a){var b=a.status;a=a.description;0===b?("function"===typeof d.requestDoneAction&&d.requestDoneAction(),l.ok(a)):10===b?g.main.logout():
l.error(a)})},c=function(d){if(5<d.length)l.error(a.LANG[17]+" (Max: 5)");else for(var k=0;k<d.length;k++){var p=d[k];if(p.size/1E3>a.MAX_FILE_SIZE)l.error(a.LANG[18]+"<br>"+p.name+" (Max: "+a.MAX_FILE_SIZE+")");else{var c;a:{c=p.name;for(var e=b.data("files-ext").toLowerCase().split(","),f=0;f<=e.length;f++)if(-1!==c.indexOf(e[f])){c=!0;break a}c=!1}c?n(d[k]):l.error(a.LANG[19]+"<br>"+p.name)}}},e=function(a){var b=$("#fileUploadForm");!1===a&&b.hide();a=b.find("input[type='file']");a.on("change",
function(){"function"===typeof d.beforeSendAction&&d.beforeSendAction();c(this.files)});return a};window.File&&window.FileList&&window.FileReader?function(){h.info("fileUpload:init");var a=e(!1);b.on("dragover dragenter",function(a){h.info("fileUpload:drag");a.stopPropagation();a.preventDefault()});b.on("drop",function(a){h.info("fileUpload:drop");h.info(a);a.stopPropagation();a.preventDefault();"function"===typeof d.beforeSendAction&&d.beforeSendAction();c(a.dataTransfer.files)});b.on("click",function(){a.click()})}():
v={get:function(){h.info("sk:get");return $("#container").attr("data-sk")},set:function(a){h.info("sk:set");$("#container").attr("data-sk",a)}},z=function(){var a=$("#container");if(!a.hasClass("content-no-auto-resize")){var k=$("#content").height()+200;a.css("height",k)}},A=function(){$("html, body").animate({scrollTop:0},"slow")},u=function(a){window.location.replace(a)},B=function(b){var k={actionId:b.data("action-id"),itemId:b.data("item-id"),sk:v.get()},d={requestDoneAction:"",setRequestData:function(a){$.extend(k,
a)},getRequestData:function(){return k},beforeSendAction:"",url:""},n=function(a){if(void 0===d.url||""===d.url)return!1;var b=new FormData;b.append("inFile",a);b.append("isAjax",1);Object.keys(k).forEach(function(a){h.info(a);b.append(a,k[a])});a=m.getRequestOpts();a.url=d.url;a.processData=!1;a.contentType=!1;a.data=b;m.getActionCall(a,function(a){var b=a.status;a=a.description;0===b?("function"===typeof d.requestDoneAction&&d.requestDoneAction(),l.ok(a)):10===b?g.main.logout():l.error(a)})},c=
function(d){if(5<d.length)l.error(a.LANG[17]+" (Max: 5)");else for(var k=0;k<d.length;k++){var q=d[k];if(q.size/1E3>a.MAX_FILE_SIZE)l.error(a.LANG[18]+"<br>"+q.name+" (Max: "+a.MAX_FILE_SIZE+")");else{var c;a:{c=q.name;for(var e=b.data("files-ext").toLowerCase().split(","),f=0;f<=e.length;f++)if(-1!==c.indexOf(e[f])){c=!0;break a}c=!1}c?n(d[k]):l.error(a.LANG[19]+"<br>"+q.name)}}},e=function(a){var b=$("#fileUploadForm");!1===a&&b.hide();a=b.find("input[type='file']");a.on("change",function(){"function"===
typeof d.beforeSendAction&&d.beforeSendAction();c(this.files)});return a};window.File&&window.FileList&&window.FileReader?function(){h.info("fileUpload:init");var a=e(!1);b.on("dragover dragenter",function(a){h.info("fileUpload:drag");a.stopPropagation();a.preventDefault()});b.on("drop",function(a){h.info("fileUpload:drop");a.stopPropagation();a.preventDefault();"function"===typeof d.beforeSendAction&&d.beforeSendAction();c(a.originalEvent.dataTransfer.files)});b.on("click",function(){a.click()})}():
e(!0);return d},C=function(a){h.info("checkPassLevel");f.passLength=a.val().length;w(zxcvbn(a.val()),a)},w=function(b,k){h.info("outputResult");var d=$(".passLevel-"+k.attr("id")),c=b.score;d.show();d.removeClass("weak good strong strongest");0===f.passLength?d.attr("title","").empty():f.passLength<f.minPasswordLength?d.attr("title",a.LANG[11]).addClass("weak"):0===c?d.attr("title",a.LANG[9]+" - "+b.feedback.warning).addClass("weak"):1===c||2===c?d.attr("title",a.LANG[8]+" - "+b.feedback.warning).addClass("good"):
3===c?d.attr("title",a.LANG[7]).addClass("strong"):4===c&&d.attr("title",a.LANG[10]).addClass("strongest")},D=function(b){$(b).find(".checkbox").button({icons:{primary:"ui-icon-transferthick-e-w"}}).click(function(){var b=$(this);!0===b.prop("checked")?b.button("option","label",a.LANG[40]):b.button("option","label",a.LANG[41])})},t=function(b){h.info("encryptFormValue");var c=b.val();""!==c&&parseInt(b.attr("data-length"))!==c.length&&(c=a.CRYPT.encrypt(c),b.val(c),b.attr("data-length",c.length))},
E=function(){h.info("initializeClipboard");var b=new Clipboard(".clip-pass-button",{text:function(a){return g.account.copypass($(a)).responseJSON.data.accpass}});b.on("success",function(b){l.ok(a.LANG[45])});b.on("error",function(b){l.error(a.LANG[46])});var b=new Clipboard(".dialog-clip-pass-button"),c=new Clipboard(".dialog-clip-user-button");b.on("success",function(a){$(".dialog-user-text").removeClass("dialog-clip-copy");$(".dialog-pass-text").addClass("dialog-clip-copy");a.clearSelection()});
c.on("success",function(a){$(".dialog-pass-text").removeClass("dialog-clip-copy");$(".dialog-user-text").addClass("dialog-clip-copy");a.clearSelection()})},F=function(){h.info("bindPassEncrypt");$("body").on("blur",":input[type=password]",function(a){a=$(this);a.hasClass("passwordfield__no-pki")||t(a)}).on("keypress",":input[type=password]",function(a){13===a.keyCode&&(a.preventDefault(),a=$(this),t(a),a.closest("form").submit())})},G=function(a,c){console.info("Eval: "+a);if("function"===typeof a)a(c);
else throw Error("Function not found: "+a);},H=function(a){h.info("resizeImage");var b=.9*$(window).width(),c=.9*$(window).height(),e={width:a.width(),height:a.height()},f={calc:0,main:0,secondary:0,factor:.9,rel:e.width/e.height},g=function(a){a.main>a.secondary?a.calc=a.main/a.rel:a.main<a.secondary&&(a.calc=a.main*a.rel);a.calc>a.secondary&&(a.main*=a.factor,g(a));return a},l=function(){f.main=b;f.secondary=c;var d=g(f);a.css({width:d.main,height:d.calc});e.width=d.main;e.height=d.calc},m=function(){f.main=
c;f.secondary=b;var d=g(f);a.css({width:d.calc,height:d.main});e.width=d.calc;e.height=d.main};e.width>b?l():e.height>c&&(h.info("height"),m());return e},I=function(){return $.extend({log:h,config:function(){return a},appTheme:function(){return e},appActions:function(){return g},appTriggers:function(){return c},appRequests:function(){return m},evalAction:G,resizeImage:H},r)},J=function(){return{actions:function(){return g},triggers:function(){return c},theme:function(){return e},sk:v,msg:l,log:h,
passToClip:0,passwordData:f,outputResult:w,checkboxDetect:D,checkPassLevel:C,encryptFormValue:t,fileUpload:B,redirect:u,scrollUp:A,setContentSize:z}};(function(){h.info("init");r=J();q=I();c=sysPass.Triggers(q);g=sysPass.Actions(q);m=sysPass.Requests(q);y(function(){""!==a.PK&&F();"function"===typeof sysPass.Theme&&(e=sysPass.Theme(q));!0===a.CHECK_UPDATES&&g.main.getUpdates();E();x()})})();return r};
passToClip:0,passwordData:f,outputResult:w,checkboxDetect:D,checkPassLevel:C,encryptFormValue:t,fileUpload:B,redirect:u,scrollUp:A,setContentSize:z}};(function(){h.info("init");r=J();p=I();c=sysPass.Triggers(p);g=sysPass.Actions(p);m=sysPass.Requests(p);y(function(){""!==a.PK&&F();"function"===typeof sysPass.Theme&&(e=sysPass.Theme(p));!0===a.CHECK_UPDATES&&g.main.getUpdates();E();x()})})();return r};

View File

@@ -298,10 +298,11 @@ sysPass.Triggers = function (Common) {
upload.url = Common.appActions().ajaxUrl.config.import;
upload.beforeSendAction = function () {
upload.requestData({
upload.setRequestData({
sk: Common.sk.get(),
csvDelimiter: $("#csvDelimiter").val(),
importPwd: $("#importPwd").val(),
importMasterPwd: $("#importMasterPwd").val(),
import_defaultuser: $("#import_defaultuser").val(),
import_defaultgroup: $("#import_defaultgroup").val()
});

View File

@@ -1,5 +1,5 @@
var $jscomp={scope:{},findInternal:function(b,d,e){b instanceof String&&(b=String(b));for(var g=b.length,a=0;a<g;a++){var c=b[a];if(d.call(e,c,a,b))return{i:a,v:c}}return{i:-1,v:void 0}}};$jscomp.defineProperty="function"==typeof Object.defineProperties?Object.defineProperty:function(b,d,e){if(e.get||e.set)throw new TypeError("ES3 does not support getters and setters.");b!=Array.prototype&&b!=Object.prototype&&(b[d]=e.value)};
$jscomp.getGlobal=function(b){return"undefined"!=typeof window&&window===b?b:"undefined"!=typeof global&&null!=global?global:b};$jscomp.global=$jscomp.getGlobal(this);$jscomp.polyfill=function(b,d,e,g){if(d){e=$jscomp.global;b=b.split(".");for(g=0;g<b.length-1;g++){var a=b[g];a in e||(e[a]={});e=e[a]}b=b[b.length-1];g=e[b];d=d(g);d!=g&&null!=d&&$jscomp.defineProperty(e,b,{configurable:!0,writable:!0,value:d})}};
$jscomp.getGlobal=function(b){return"undefined"!=typeof window&&window===b?b:"undefined"!=typeof global?global:b};$jscomp.global=$jscomp.getGlobal(this);$jscomp.polyfill=function(b,d,e,g){if(d){e=$jscomp.global;b=b.split(".");for(g=0;g<b.length-1;g++){var a=b[g];a in e||(e[a]={});e=e[a]}b=b[b.length-1];g=e[b];d=d(g);d!=g&&null!=d&&$jscomp.defineProperty(e,b,{configurable:!0,writable:!0,value:d})}};
$jscomp.polyfill("Array.prototype.find",function(b){return b?b:function(b,e){return $jscomp.findInternal(this,b,e).v}},"es6-impl","es3");
sysPass.Triggers=function(b){var d=b.log,e=function(a){var c={valueField:"id",labelField:"name",searchField:["name"]};a.find(".select-box").each(function(a){var f=$(this);c.plugins=f.hasClass("select-box-deselect")?{clear_selection:{title:b.config().LANG[51]}}:{};if(f.data("onchange")){var d=f.data("onchange").split("/");c.onChange=function(a){if(0<a)if(2===d.length)sysPassApp.actions()[d[0]][d[1]](f);else sysPassApp.actions()[d[0]](f)}}f.selectize(c)});a.find("#allowed_exts").selectize({create:function(a){return{value:a.toUpperCase(),
text:a.toUpperCase()}},createFilter:/^[a-z0-9]{1,4}$/i,plugins:["remove_button"]});a.find("#wikifilter").selectize({create:!0,createFilter:/^[a-z0-9._-]+$/i,plugins:["remove_button"]})},g=function(){d.info("bodyHooks");$("body").on("click",".btn-action[data-onclick],.btn-action-pager[data-onclick]",function(){var a=$(this),c=a.data("onclick").split("/"),f=b.appActions();if(2===c.length)f[c[0]][c[1]](a);else f[c[0]](a)}).on("click",".btn-back",function(){var a=b.appRequests();if(0<a.history.length()){d.info("back");
@@ -8,7 +8,7 @@ a=$("#"+a.data("help")).html();showDialog({title:b.config().LANG[54],text:a,posi
a.submit()})};return{views:{main:function(){d.info("views:main");g();$(".btn-menu").click(function(){"1"===$(this).attr("data-history-reset")&&b.appRequests().history.reset();b.appActions().doAction({actionId:$(this).data("action-id")})});b.appActions().doAction({actionId:1})},search:function(){d.info("views:search");var a=$("#frmSearch");a.find("select, #rpp").on("change",function(){a.submit()});a.find("button.btn-clear").on("click",function(b){b.preventDefault();a.find('input[name="searchfav"]').val(0);
a[0].reset()});a.find("input:text:visible:first").focus();$("#chkgsearch").click(function(){var b=1==$(this).prop("checked")?1:0;a.find("input[name='gsearch']").val(b);a.submit()});"function"===typeof b.appTheme().viewsTriggers.search&&b.appTheme().viewsTriggers.search()},login:function(){d.info("views:login");g();$("#boxLogout").fadeOut(1500,function(){location.href=b.config().APP_ROOT+"/index.php"})},twofa:function(){d.info("views:twofa");g()},passreset:function(){d.info("views:passreset");g()},
footer:function(){d.info("views:footer");$("#btnLogout").click(function(a){b.appActions().main.logout()});$("#btnPrefs").click(function(a){b.appActions().doAction({actionId:$(this).data("action-id")})})},common:function(a){d.info("views:common");a=$(a);e(a);"function"===typeof b.appTheme().viewsTriggers.common&&b.appTheme().viewsTriggers.common(a)},datatabs:function(a){d.info("views:datatabs");$(".datagrid-action-search>form").each(function(){var a=$(this);a.find("button.btn-clear").on("click",function(b){b.preventDefault();
a.trigger("reset")})})},config:function(){d.info("views:config");var a=$("#drop-import-files");if(0<a.length){var c=b.fileUpload(a);c.url=b.appActions().ajaxUrl.config["import"];c.beforeSendAction=function(){c.requestData({sk:b.sk.get(),csvDelimiter:$("#csvDelimiter").val(),importPwd:$("#importPwd").val(),import_defaultuser:$("#import_defaultuser").val(),import_defaultgroup:$("#import_defaultgroup").val()})}}a=$(".form-action");0<a.length&&a.each(function(){var a=$(this);"undefined"!==typeof a.attr("data-hash")&&
a.attr("data-hash",SparkMD5.hash(a.serialize(),!1))})},account:function(){d.info("views:account");var a=$("#list-account-files");0<a.length&&b.appActions().account.getfiles(a);var c=$("#drop-account-files");0<c.length&&(c=b.fileUpload(c),c.url=b.appActions().ajaxUrl.file,c.requestDoneAction=function(){b.appActions().account.getfiles(a)});c=$(".form-action");0<c.length&&c.attr("data-hash",SparkMD5.hash(c.serialize(),!1));c=$(".show-extra-info");if(0<c.length)c.on("click",function(){var a=$(this),b=
$(a.data("target"));0==a.data("state")?(b.show("blind","slow"),a.data("state","1"),a.html(a.data("icon-up"))):(b.hide("blind","slow"),a.data("state","0"),a.html(a.data("icon-down")))});$("#selParentAccount").on("change",function(){var a=$(this),b=$("#accountpass,#accountpassR");0<a[0].value?b.each(function(){$(this).prop("disabled","true")}):b.each(function(){$(this).prop("disabled","")})})},install:function(){d.info("views:install");g();var a=$("#frmInstall");b.appTheme().passwordDetect(a);e(a)}},
selectDetect:e,updateSk:function(){$("#content").find("[data-sk]").each(function(){d.info("updateSk");$(this).data("sk",b.sk.get())})}}};
a.trigger("reset")})})},config:function(){d.info("views:config");var a=$("#drop-import-files");if(0<a.length){var c=b.fileUpload(a);c.url=b.appActions().ajaxUrl.config["import"];c.beforeSendAction=function(){c.setRequestData({sk:b.sk.get(),csvDelimiter:$("#csvDelimiter").val(),importPwd:$("#importPwd").val(),importMasterPwd:$("#importMasterPwd").val(),import_defaultuser:$("#import_defaultuser").val(),import_defaultgroup:$("#import_defaultgroup").val()})}}a=$(".form-action");0<a.length&&a.each(function(){var a=
$(this);"undefined"!==typeof a.attr("data-hash")&&a.attr("data-hash",SparkMD5.hash(a.serialize(),!1))})},account:function(){d.info("views:account");var a=$("#list-account-files");0<a.length&&b.appActions().account.getfiles(a);var c=$("#drop-account-files");0<c.length&&(c=b.fileUpload(c),c.url=b.appActions().ajaxUrl.file,c.requestDoneAction=function(){b.appActions().account.getfiles(a)});c=$(".form-action");0<c.length&&c.attr("data-hash",SparkMD5.hash(c.serialize(),!1));c=$(".show-extra-info");if(0<
c.length)c.on("click",function(){var a=$(this),b=$(a.data("target"));0==a.data("state")?(b.show("blind","slow"),a.data("state","1"),a.html(a.data("icon-up"))):(b.hide("blind","slow"),a.data("state","0"),a.html(a.data("icon-down")))});$("#selParentAccount").on("change",function(){var a=$(this),b=$("#accountpass,#accountpassR");0<a[0].value?b.each(function(){$(this).prop("disabled","true")}):b.each(function(){$(this).prop("disabled","")})})},install:function(){d.info("views:install");g();var a=$("#frmInstall");
b.appTheme().passwordDetect(a);e(a)}},selectDetect:e,updateSk:function(){$("#content").find("[data-sk]").each(function(){d.info("updateSk");$(this).data("sk",b.sk.get())})}}};