* [MOD] XML import (work in progress)

This commit is contained in:
nuxsmin
2015-07-15 15:19:37 +02:00
committed by nuxsmin
parent 972c9d8652
commit 8907976c86
7 changed files with 378 additions and 389 deletions

View File

@@ -210,4 +210,42 @@ class Crypt
{
return mcrypt_module_open(MCRYPT_RIJNDAEL_256, '', MCRYPT_MODE_CBC, '');
}
/**
* Encriptar datos. Devuelve un array con los datos encriptados y el IV.
*
* @param $data string Los datos a encriptar
* @throws SPException
* @return array
*/
public static function encryptData($data)
{
if (empty($data)) {
return array('pass' => '', 'IV' => '');
}
// Comprobar el módulo de encriptación
if (!Crypt::checkCryptModule()) {
throw new SPException(
SPException::SP_CRITICAL,
_('Error interno'),
_('No se puede usar el módulo de encriptación')
);
}
// Encriptar clave
$encData['pass'] = Crypt::mkEncrypt($data);
if (!empty($data) && ($encData['pass'] === false || is_null($encData['pass']))) {
throw new SPException(
SPException::SP_CRITICAL,
_('Error interno'),
_('Error al generar datos cifrados')
);
}
$encData['IV'] = Crypt::$strInitialVector;
return $encData;
}
}

View File

@@ -75,18 +75,7 @@ class Import
// Analizamos el XML y seleccionamos el formato a importar
$xml = new XmlImport($file);
$format = $xml->detectXMLFormat();
if ($format == 'syspass') {
$xmlSyspass = new SyspassImport($file);
$xmlSyspass->doImport();
} elseif ($format == 'keepass') {
$xmlKeepass = new KeepassImport($file);
$xmlKeepass->doImport();
} elseif ($format == 'keepassx') {
$xmlKeepassx = new KeepassXImport($file);
$xmlKeepassx->doImport();
}
$xml->doImport();
} else {
throw new SPException(
SPException::SP_WARNING,
@@ -170,7 +159,7 @@ class Import
$categoryId = Category::$categoryLastId;
}
$pass = self::encryptPass($password);
$pass = Crypt::encryptData($password);
$account = new Account;
$account->setAccountName($accountName);
@@ -187,42 +176,4 @@ class Import
// Creamos la cuenta
return $account->createAccount();
}
/**
* Encriptar la clave de una cuenta.
*
* @param string $password con la clave de la cuenta
* @throws SPException
* @return array con la clave y el IV
*/
private static function encryptPass($password)
{
if (empty($password)) {
return array('pass' => '', 'IV' => '');
}
// Comprobar el módulo de encriptación
if (!Crypt::checkCryptModule()) {
throw new SPException(
SPException::SP_CRITICAL,
_('Error interno'),
_('No se puede usar el módulo de encriptación')
);
}
// Encriptar clave
$data['pass'] = Crypt::mkEncrypt($password);
if (!empty($password) && ($data['pass'] === false || is_null($data['pass']))) {
throw new SPException(
SPException::SP_CRITICAL,
_('Error interno'),
_('Error al generar datos cifrados')
);
}
$data['IV'] = Crypt::$strInitialVector;
return $data;
}
}

View File

@@ -37,42 +37,10 @@ class KeepassImport extends XmlImportBase
*/
public function doImport()
{
$this->getGroups($this->_xml->Root->Group);
}
$this->setCustomerName('KeePass');
$this->setCustomerId($this->addCustomer());
/**
* Obtener los datos de las entradas de KeePass.
*
* @param \SimpleXMLElement $entries El objeto XML con las entradas
* @param string $groupName con nombre del grupo a procesar
*/
protected function getEntryData(\SimpleXMLElement $entries, $groupName)
{
foreach ($entries as $entry) {
foreach ($entry->String as $account) {
$value = (isset($account->Value)) ? (string)$account->Value : '';
switch ($account->Key) {
case 'Notes':
$notes = $value;
break;
case 'Password':
$password = $value;
break;
case 'Title':
$name = $value;
break;
case 'URL':
$url = $value;
break;
case 'UserName':
$username = $value;
break;
}
}
$accountData = array($name, 'KeePass', $groupName, $url, $username, $password, $notes);
Import::addAccountData($accountData);
}
$this->processCategories($this->_xml->Root->Group);
}
/**
@@ -80,48 +48,72 @@ class KeepassImport extends XmlImportBase
*
* @param \SimpleXMLElement $xml El objeto XML del archivo de KeePass
*/
protected function getGroups(\SimpleXMLElement $xml)
protected function processCategories(\SimpleXMLElement $xml)
{
foreach ($xml as $node) {
if ($node->Group) {
foreach ($node->Group as $group) {
$groupName = $group->Name;
// Analizar grupo
if ($node->Group->Entry) {
// Obtener entradas
$this->getEntryData($group->Entry, $groupName);
// Crear la categoría
$this->setCategoryName($group->Name);
$this->setCategoryId($this->addCategory());
// Crear cuentas
$this->processAccounts($group->Entry);
}
if ($group->Group) {
// Analizar subgrupo
$this->getGroups($group);
$this->processCategories($group);
}
}
}
if ($node->Entry) {
$groupName = $node->Name;
// Obtener entradas
$this->getEntryData($node->Entry, $groupName);
// Crear la categoría
$this->setCategoryName($node->Name);
$this->setCategoryId($this->addCategory());
// Crear cuentas
$this->processAccounts($node->Entry);
}
}
}
/**
* Obtener los datos de las entradas.
*/
protected function getAccountData()
{
// TODO: Implement getAccountData() method.
}
/**
* Añadir una cuenta en sysPass desde XML
* Obtener los datos de las entradas de KeePass.
*
* @return mixed
* @param \SimpleXMLElement $entries El objeto XML con las entradas
*/
protected function addAccount()
protected function processAccounts(\SimpleXMLElement $entries)
{
// TODO: Implement addAccount() method.
foreach ($entries as $entry) {
foreach ($entry->String as $account) {
$value = (isset($account->Value)) ? (string)$account->Value : '';
switch ($account->Key) {
case 'Notes':
$this->setAccountNotes($value);
break;
case 'Password':
$passData = Crypt::encryptData($value);
$this->setAccountPass($passData['pass']);
$this->setAccountPassIV($passData['IV']);
break;
case 'Title':
$this->setAccountName($value);
break;
case 'URL':
$this->setAccountUrl($value);
break;
case 'UserName':
$this->setAccountLogin($value);
break;
}
}
$this->addAccount();
}
}
}

View File

@@ -32,13 +32,66 @@ defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo'
*/
class KeepassXImport extends XmlImportBase
{
/**
* Iniciar la importación desde KeePassX.
*
* @throws SPException
* @return bool
*/
public function doImport()
{
$this->setCustomerName('KeePassX');
$this->setCustomerId($this->addCustomer());
self::processCategories($this->_xml);
}
/**
* Obtener los grupos y procesar lan entradas de KeePass.
*
* @param \SimpleXMLElement $xml con objeto XML del archivo de KeePass
*/
protected function processCategories(\SimpleXMLElement $xml)
{
foreach ($xml as $node) {
if ($node->group) {
foreach ($node->group as $group) {
// Analizar grupo
if ($node->group->entry) {
// Crear la categoría
$this->setCategoryName($group->title);
$this->setCategoryId($this->addCategory());
// Crear cuentas
$this->processAccounts($group->entry);
}
if ($group->group) {
// Analizar subgrupo
$this->processCategories($group);
}
}
}
if ($node->entry) {
// Crear la categoría
$this->setCategoryName($node->title);
$this->setCategoryId($this->addCategory());
// Crear cuentas
$this->processAccounts($node->entry);
}
}
}
/**
* 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 string $groupName con nombre del grupo a procesar
*/
protected function getEntryData(\SimpleXMLElement $entries, $groupName)
protected function processAccounts(\SimpleXMLElement $entries, $groupName)
{
foreach ($entries as $entry) {
$notes = (isset($entry->comment)) ? (string)$entry->comment : '';
@@ -47,69 +100,16 @@ class KeepassXImport extends XmlImportBase
$url = (isset($entry->url)) ? (string)$entry->url : '';
$username = (isset($entry->username)) ? (string)$entry->username : '';
$accountData = array($name, 'KeePassX', $groupName, $url, $username, $password, $notes);
Import::addAccountData($accountData);
$passData = Crypt::encryptData($password);
$this->setAccountPass($passData['pass']);
$this->setAccountPassIV($passData['IV']);
$this->setAccountNotes($notes);
$this->setAccountName($name);
$this->setAccountUrl($url);
$this->setAccountLogin($username);
$this->addAccount();
}
}
/**
* Obtener los grupos y procesar lan entradas de KeePass.
*
* @param \SimpleXMLElement $xml con objeto XML del archivo de KeePass
*/
protected function getGroups(\SimpleXMLElement $xml)
{
foreach ($xml as $node) {
if ($node->group) {
foreach ($node->group as $group) {
$groupName = $group->title;
// Analizar grupo
if ($node->group->entry) {
// Obtener entradas
$this->getEntryData($group->entry, $groupName);
}
if ($group->group) {
// Analizar subgrupo
$this->getGroups($group);
}
}
}
if ($node->entry) {
$groupName = $node->title;
// Obtener entradas
$this->getEntryData($node->entry, $groupName);
}
}
}
/**
* Obtener los datos de las entradas.
*/
protected function getAccountData()
{
// TODO: Implement getAccountData() method.
}
/**
* Añadir una cuenta en sysPass desde XML
*
* @return mixed
*/
protected function addAccount()
{
// TODO: Implement addAccount() method.
}
/**
* Iniciar la importación desde KeePassX.
*
* @throws SPException
* @return bool
*/
public function doImport()
{
self::getGroups($this->_xml);
}
}

View File

@@ -53,18 +53,10 @@ class SyspassImport extends XmlImportBase
*/
public function doImport()
{
if ($this->getUserId() === 0){
$this->setUserId(Session::getUserId());
}
if ($this->getUserGroupId() === 0){
$this->setUserGroupId(Session::getUserGroupId());
}
try {
$this->addCategories();
$this->addCustomers();
$this->getAccountData();
$this->processCategories();
$this->processCustomers();
$this->processAccounts();
} catch (SPException $e){
return false;
}
@@ -73,11 +65,10 @@ class SyspassImport extends XmlImportBase
}
/**
* Obtener los datos de las entradas de KeePass.
* Obtener los datos de las entradas de sysPass y crearlas.
*/
protected function getAccountData()
protected function processAccounts()
{
foreach ($this->_xml->Accounts as $entry) {
$account = $entry->Account;
@@ -98,42 +89,26 @@ class SyspassImport extends XmlImportBase
/**
* Obtener las categorías y añadirlas a sysPass.
*/
protected function addCategories()
protected function processCategories()
{
foreach ($this->_xml->Categories as $category) {
$this->_categories[$category['id']] = Category::addCategoryReturnId($category->name, $category->description);
$this->setCustomerName($category->name);
$this->setCategoryDescription($category->description);
$this->_categories[$category['id']] = $this->addCategory();
}
}
/**
* Obtener los clientes y añadirlos a sysPass.
*/
protected function addCustomers()
protected function processCustomers()
{
foreach ($this->_xml->Customers as $customer) {
$this->_customers[$customer['id']] = Customer::addCustomerReturnId($customer->name, $customer->description);
$this->setCustomerName($customer->name);
$this->setCustomerDescription($customer->description);
$this->_customers[$customer['id']] = $this->addCustomer();
}
}
/**
* Añadir una cuenta en sysPass desde XML
*
* @return mixed
*/
protected function addAccount()
{
$account = new Account;
$account->setAccountName($this->getAccountName());
$account->setAccountCustomerId($this->getCustomerId());
$account->setAccountCategoryId($this->getCategoryId());
$account->setAccountLogin($this->getAccountLogin());
$account->setAccountUrl($this->getAccountUrl());
$account->setAccountPass($this->getAccountPass());
$account->setAccountIV($this->getAccountPassIV());
$account->setAccountNotes($this->getAccountNotes());
$account->setAccountUserId($this->getUserId());
$account->setAccountUserGroupId($this->getUserGroupId());
return $account->createAccount();
}
}

View File

@@ -29,33 +29,30 @@ defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo'
class XmlImport extends XmlImportBase
{
/**
* Obtener los datos de las entradas.
*/
protected function getAccountData()
{
// TODO: Implement getAccountData() method.
}
/**
* Añadir una cuenta en sysPass desde XML
*
* @return mixed
*/
protected function addAccount()
{
// TODO: Implement addAccount() method.
}
/**
* Iniciar la importación desde XML.
*
* @throws SPException
* @return bool
*/
protected function doImport()
public function doImport()
{
// TODO: Implement doImport() method.
$format = $this->detectXMLFormat();
switch ($format) {
case 'syspass':
$import = new SyspassImport($this->_file);
break;
case 'keepass':
$import = new KeepassImport($this->_file);
break;
case 'keepassx':
$import = new KeepassXImport($this->_file);
break;
}
if (is_object($import)){
$import->doImport();
}
}
}

View File

@@ -139,6 +139,123 @@ abstract class XmlImportBase
}
}
/**
* Leer el archivo a un objeto XML.
*
* @throws SPException
* @return \SimpleXMLElement Con los datos del archivo XML
*/
protected function readXMLFile()
{
$this->_xml = simplexml_load_file($this->_file->getTmpFile());
if ($this->_xml === false) {
throw new SPException(
SPException::SP_CRITICAL,
_('Error interno'),
_('No es posible procesar el archivo XML')
);
}
}
/**
* Detectar la aplicación que generó el XML.
*
* @throws SPException
*/
public function detectXMLFormat()
{
if ($this->_xml->Meta->Generator == 'KeePass') {
return 'keepass';
} else if ($this->_xml->Meta->Generator == 'sysPass') {
return 'syspass';
} else if ($xmlApp = $this->parseFileHeader()) {
switch ($xmlApp) {
case 'keepassx_database':
return 'keepassx';
case 'revelationdata':
return 'revelation';
default:
break;
}
} else {
throw new SPException(
SPException::SP_CRITICAL,
_('Archivo XML no soportado'),
_('No es posible detectar la aplicación que exportó los datos')
);
}
return '';
}
/**
* Leer la cabecera del archivo XML y obtener patrones de aplicaciones conocidas.
*
* @return bool
*/
protected function parseFileHeader()
{
$handle = @fopen($this->_file->getTmpFile(), "r");
$headersRegex = '/(KEEPASSX_DATABASE|revelationdata)/i';
if ($handle) {
// No. de líneas a leer como máximo
$maxLines = 5;
$count = 0;
while (($buffer = fgets($handle, 4096)) !== false && $count <= $maxLines) {
if (preg_match($headersRegex, $buffer, $app)) {
fclose($handle);
return strtolower($app[0]);
}
$count++;
}
fclose($handle);
}
return false;
}
/**
* Iniciar la importación desde XML.
*
* @throws SPException
* @return bool
*/
public abstract function doImport();
/**
* Añadir una cuenta desde XML.
*
* @return bool
*/
protected function addAccount()
{
if ($this->getUserId() === 0) {
$this->setUserId(Session::getUserId());
}
if ($this->getUserGroupId() === 0) {
$this->setUserGroupId(Session::getUserGroupId());
}
$account = new Account;
$account->setAccountName($this->getAccountName());
$account->setAccountCustomerId($this->getCustomerId());
$account->setAccountCategoryId($this->getCategoryId());
$account->setAccountLogin($this->getAccountLogin());
$account->setAccountUrl($this->getAccountUrl());
$account->setAccountPass($this->getAccountPass());
$account->setAccountIV($this->getAccountPassIV());
$account->setAccountNotes($this->getAccountNotes());
$account->setAccountUserId($this->getUserId());
$account->setAccountUserGroupId($this->getUserGroupId());
return $account->createAccount();
}
/**
* @return int
*/
@@ -171,70 +288,6 @@ abstract class XmlImportBase
$this->userGroupId = $userGroupId;
}
/**
* @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;
}
/**
* @return string
*/
public function getCustomerDescription()
{
return $this->_customerDescription;
}
/**
* @param string $customerDescription
*/
public function setCustomerDescription($customerDescription)
{
$this->_customerDescription = $customerDescription;
}
/**
* @return string
*/
public function getCustomerName()
{
return $this->_customerName;
}
/**
* @param string $_customerName
*/
public function setCustomerName($_customerName)
{
$this->_customerName = $_customerName;
}
/**
* @return string
*/
@@ -315,22 +368,6 @@ abstract class XmlImportBase
$this->_accountUrl = $_accountUrl;
}
/**
* @return string
*/
public function getAccountNotes()
{
return $this->_accountNotes;
}
/**
* @param string $_accountNotes
*/
public function setAccountNotes($_accountNotes)
{
$this->_accountNotes = $_accountNotes;
}
/**
* @return string
*/
@@ -364,101 +401,100 @@ abstract class XmlImportBase
}
/**
* Obtener los datos de las entradas.
* @return string
*/
protected abstract function getAccountData();
/**
* Añadir una cuenta en sysPass desde XML
*
* @return mixed
*/
protected abstract function addAccount();
/**
* Detectar la aplicación que generó el XML.
*
* @throws SPException
*/
public function detectXMLFormat()
public function getAccountNotes()
{
if ($this->_xml->Meta->Generator == 'KeePass') {
return 'keepass';
} else if ($this->_xml->Meta->Generator == 'sysPass') {
return 'syspass';
} else if ($xmlApp = $this->parseFileHeader()) {
switch ($xmlApp) {
case 'keepassx_database':
return 'keepassx';
case 'revelationdata':
return 'revelation';
default:
break;
}
} else {
throw new SPException(
SPException::SP_CRITICAL,
_('Archivo XML no soportado'),
_('No es posible detectar la aplicación que exportó los datos')
);
}
return '';
return $this->_accountNotes;
}
/**
* Leer el archivo a un objeto XML.
*
* @throws SPException
* @return \SimpleXMLElement Con los datos del archivo XML
* @param string $_accountNotes
*/
protected function readXMLFile()
public function setAccountNotes($_accountNotes)
{
$this->_xml = simplexml_load_file($this->_file->getTmpFile());
if ($this->_xml === false) {
throw new SPException(
SPException::SP_CRITICAL,
_('Error interno'),
_('No es posible procesar el archivo XML')
);
}
$this->_accountNotes = $_accountNotes;
}
/**
* Iniciar la importación desde XML.
*
* @throws SPException
* @return bool
* Añadir una categoría y devolver el Id
* @return int
*/
public abstract function doImport();
protected function addCategory()
{
return Category::addCategoryReturnId($this->getCategoryName(), $this->getCategoryDescription());
}
/**
* Leer la cabecera del archivo XML y obtener patrones de aplicaciones conocidas.
*
* @return bool
* @return string
*/
protected function parseFileHeader()
public function getCategoryName()
{
$handle = @fopen($this->_file->getTmpFile(), "r");
$headersRegex = '/(KEEPASSX_DATABASE|revelationdata)/i';
return $this->_categoryName;
}
if ($handle) {
// No. de líneas a leer como máximo
$maxLines = 5;
$count = 0;
/**
* @param string $_categoryName
*/
public function setCategoryName($_categoryName)
{
$this->_categoryName = $_categoryName;
}
while (($buffer = fgets($handle, 4096)) !== false && $count <= $maxLines) {
if (preg_match($headersRegex, $buffer, $app)) {
fclose($handle);
return strtolower($app[0]);
}
$count++;
}
/**
* @return string
*/
public function getCategoryDescription()
{
return $this->_categoryDescription;
}
fclose($handle);
}
/**
* @param string $categoryDescription
*/
public function setCategoryDescription($categoryDescription)
{
$this->_categoryDescription = $categoryDescription;
}
return false;
/**
* Añadir un cliente y devolver el Id
* @return int
*/
protected function addCustomer()
{
return Customer::addCustomerReturnId($this->getCustomerName(), $this->getCustomerDescription());
}
/**
* @return string
*/
public function getCustomerName()
{
return $this->_customerName;
}
/**
* @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;
}
}