* [ADD] Closes #91. New feature that allows to generate an image for the account password . Thanks to @TitovLab

This commit is contained in:
nuxsmin
2015-08-03 03:23:23 +02:00
parent ebae60bc3f
commit 4d0ea598ba
15 changed files with 229 additions and 50 deletions

View File

@@ -79,11 +79,13 @@ if ($actionId === SP\Controller\ActionsInterface::ACTION_CFG_GENERAL
// Accounts
$globalSearchEnabled = SP\Request::analyze('globalsearch', false, false, true);
$accountPassToImageEnabled = SP\Request::analyze('account_passtoimage', false, false, true);
$accountLinkEnabled = SP\Request::analyze('account_link', false, false, true);
$accountCount = SP\Request::analyze('account_count', 10);
$resultsAsCardsEnabled = SP\Request::analyze('resultsascards', false, false, true);
SP\Config::setValue('globalsearch', $globalSearchEnabled);
SP\Config::setValue('account_passtoimage', $accountPassToImageEnabled);
SP\Config::setValue('account_link', $accountLinkEnabled);
SP\Config::setValue('account_count', $accountCount);
SP\Config::setValue('resultsascards', $resultsAsCardsEnabled);

View File

@@ -74,10 +74,13 @@ if (!$isHistory) {
//$accountPass = htmlspecialchars(trim($accountClearPass));
$useImage = intval(\SP\Util::accountPassToImageIsEnabled());
$data = array(
'title' => _('Clave de Cuenta'),
'acclogin' => $accountData->login,
'accpass' => trim($accountClearPass)
'accpass' => (!$useImage) ? trim($accountClearPass) : \SP\ImageUtil::convertText($accountClearPass),
'useimage' => $useImage
);
SP\Common::printJSON($data, 0);

BIN
imgs/NotoSansUI-Regular.ttf Normal file

Binary file not shown.

77
inc/ImageUtil.class.php Normal file
View File

@@ -0,0 +1,77 @@
<?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/>.
*
*/
namespace SP;
defined('APP_ROOT') || die(_('No es posible acceder directamente a este archivo'));
/**
* Class ImageUtil para la manipulación de imágenes
*
* @package SP
*/
class ImageUtil
{
/**
* Convertir un texto a imagen
*
* @param $text string El texto a convertir
* @return bool|string
*/
public static function convertText($text)
{
if(!function_exists('imagepng')){
return false;
}
$im = imagecreatetruecolor(strlen($text) * 20, 30);
// Colores de la imagen
$bgColor = imagecolorallocate($im, 255, 255, 255);
// $shadowColor = imagecolorallocate($im, 128, 128, 128);
$fgColor = imagecolorallocate($im, 128, 128, 128);
imagefilledrectangle($im, 0, 0, strlen($text) * 20, 29, $bgColor);
// Ruta de la fuente
$font = Init::$SERVERROOT . '/imgs/NotoSansUI-Regular.ttf';
// Sombra
// imagettftext($im, 14, 0, 13, 23, $shadowColor, $font, $text);
// Crear el texto
imagettftext($im, 12, 0, 10, 20, $fgColor, $font, $text);
// Guardar la imagen
ob_start();
imagepng($im);
$image = ob_get_contents();
ob_end_clean();
imagedestroy($im);
return base64_encode($image);
}
}

View File

@@ -444,6 +444,16 @@ class Util
return self::boolval(Config::getValue('resultsascards', false));
}
/**
* Comprobar si está habilitado usar imagen para claves de cuentas
*
* @return bool
*/
public static function accountPassToImageIsEnabled()
{
return self::boolval(Config::getValue('account_passtoimage', false));
}
/**
* Establecer variable de sesión para recargar la aplicación.
*/

View File

@@ -348,11 +348,13 @@
<img src="<?php \SP\Init::$WEBURI; ?>imgs/user-pass.png" alt="save" />
</button>
<?php if(!\SP\Util::accountPassToImageIsEnabled()): ?>
<button type="button" title="<?php echo _('Copiar Clave en Portapapeles'); ?>" class="button-action clip-pass-button"
onmousedown="viewPass(<?php echo $accountId; ?>, false, <?php echo $accountIsHistory; ?>)"
data-clipboard-target="clip-pass-text">
<img src="<?php \SP\Init::$WEBURI; ?>imgs/clipboard.png" alt="save" />
</button>
<?php endif; ?>
<?php endif; ?>
<?php if ($showEditPass): ?>

View File

@@ -222,6 +222,25 @@
class="checkbox" <?php echo $chkResultsAsCards, ' ', $isDisabled; ?> />
</td>
</tr>
<tr>
<td class="descField">
<?php echo _('Imagen para mostrar clave'); ?>
<img src="imgs/help.png" title="" class="inputImgMini help-tooltip" />
<div class="tooltip" style="display:none;">
<p>
<?php echo _('Generar una imagen con el texto de la clave de la cuenta.'); ?>
</p>
<p>
<?php echo _('Util para entornos donde copiar la clave supone un riesgo de seguridad.'); ?>
</p>
</div>
</td>
<td class="valField">
<label for="account_passtoimage"><?php echo ($chkAccountPassToImage) ? 'SI' : 'NO'; ?></label>
<input type="checkbox" name="account_passtoimage" id="account_passtoimage"
class="checkbox" <?php echo $chkAccountPassToImage, ' ', $isDisabled; ?> />
</td>
</tr>
</table>
<?php if ($isDemoMode): ?>

View File

@@ -37,7 +37,9 @@ jQuery.extend(jQuery.fancybox.defaults, {
$(document).ready(function () {
"use strict";
$('input[type="text"], select, textarea').placeholder().mouseenter(function () {$(this).focus();});
$('input[type="text"], select, textarea').placeholder().mouseenter(function () {
$(this).focus();
});
setContentSize();
setWindowAdjustSize();
@@ -48,14 +50,16 @@ $(document).ready(function () {
}).ajaxComplete(function () {
"use strict";
$('input[type="text"], select, textarea').placeholder().mouseenter(function () {$(this).focus();});
$('input[type="text"], select, textarea').placeholder().mouseenter(function () {
$(this).focus();
});
// Activar tooltips
activeTooltip();
});
function activeTooltip(){
function activeTooltip() {
"use strict";
// Activar tooltips
@@ -67,7 +71,7 @@ function activeTooltip(){
});
$('.help-tooltip').tooltip({
content: function(){
content: function () {
return $(this).next('div').html();
},
tooltipClass: "tooltip"
@@ -321,16 +325,28 @@ function viewPass(id, full, history) {
width: 'auto',
open: function () {
var content;
var pass = '';
var clipboardUserButton =
'<button id="dialog-clip-user-button-' + id + '" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-icon-primary">' +
'<span class="ui-button-icon-primary ui-icon ui-icon-clipboard"></span>' +
'<span class="ui-button-text">' + LANG[33] + '</span>' +
'</button>';
var clipboardPassButton =
'<button id="dialog-clip-pass-button-' + id + '" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-icon-primary">' +
'<span class="ui-button-icon-primary ui-icon ui-icon-clipboard"></span>' +
'<span class="ui-button-text">' + LANG[34] + '</span>' +
'</button>';
var useImage = json.useimage;
if (json.status === 0) {
content = '<p class="dialog-pass-text">' + json.accpass + '</p>' +
'<br>' +
'<div class="dialog-buttons">' +
'<button id="dialog-clip-pass-button-' + id + '" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-icon-primary">' +
'<span class="ui-button-icon-primary ui-icon ui-icon-clipboard"></span>' +
'<span class="ui-button-text">Copiar</span>' +
'</button>' +
'</div>';
if (useImage === 0) {
pass = '<p class="dialog-pass-text">' + json.accpass + '</p>';
} else {
pass = '<img class="dialog-pass-text" src="data:image/png;base64,' + json.accpass + '" />';
clipboardPassButton = '';
}
content = pass + '<br>' + '<div class="dialog-buttons">' + clipboardUserButton + clipboardPassButton + '</div>';
} else {
content = '<span class="altTxtRed">' + json.description + '</span>';
@@ -350,26 +366,34 @@ function viewPass(id, full, history) {
$(this).dialog('option', 'position', 'center');
// Carga de objeto flash para copiar al portapapeles
var client = new ZeroClipboard($("#dialog-clip-pass-button-" + id), {swfPath: "js/ZeroClipboard.swf"});
var clientPass = new ZeroClipboard($("#dialog-clip-pass-button-" + id), {swfPath: APP_ROOT + "/js/ZeroClipboard.swf"});
var clientUser = new ZeroClipboard($("#dialog-clip-user-button-" + id), {swfPath: APP_ROOT + "/js/ZeroClipboard.swf"});
client.on('ready', function (e) {
clientPass.on('ready', function (e) {
$("#dialog-clip-pass-button-" + id).attr("data-clip", 1);
client.on('copy', function (e) {
e.clipboardData.setData('text/plain', json.accpass);
clientPass.on('copy', function (e) {
//e.clipboardData.setData('text/plain', json.accpass);
clientPass.setText(json.accpass);
});
client.on('aftercopy', function (e) {
clientPass.on('aftercopy', function (e) {
$('.dialog-pass-text').addClass('dialog-clip-pass-copy round');
});
});
client.on('error', function (e) {
clientPass.on('error', function (e) {
ZeroClipboard.destroy();
});
clientUser.on('ready', function (e) {
clientUser.on('copy', function (e) {
clientUser.setText(json.acclogin);
});
});
// Timeout del mensaje
var $this = $(this);
var thisDialog = $(this);
timeout = setTimeout(function () {
$this.dialog('close');
thisDialog.dialog('close');
}, 30000);
},
// Forzar la eliminación del objeto para que ZeroClipboard siga funcionando al abrirlo de nuevo
@@ -1149,21 +1173,21 @@ function complexityDialog(targetId) {
$('<div id="dialog-complexity"></div>').dialog({
modal: true,
title: 'Opciones de Complejidad',
width: '400px',
width: '450px',
open: function () {
var thisDialog = $(this);
var content =
'<div class="dialog-btns-complexity">' +
'<label for="checkbox-numbers">Incluir números</label>' +
'<label for="checkbox-numbers">' + LANG[35] + '</label>' +
'<input type="checkbox" id="checkbox-numbers" name="checkbox-numbers"/>' +
'<label for="checkbox-uppercase">Incluir mayúculas</label>' +
'<label for="checkbox-uppercase">' + LANG[36] + '</label>' +
'<input type="checkbox" id="checkbox-uppercase" name="checkbox-uppercase"/>' +
'<label for="checkbox-symbols">Incluir símbolos</label>' +
'<label for="checkbox-symbols">' + LANG[37] + '</label>' +
'<input type="checkbox" id="checkbox-symbols" name="checkbox-symbols"/>' +
'</div>' +
'<div class="dialog-length-complexity">' +
'<label for="passlength">Longitud</label>' +
'<label for="passlength">' + LANG[38] + '</label>' +
'<input class="inputNumber" pattern="[0-9]*" id="passlength" />' +
'</div>' +
'<div class="dialog-buttons">' +
@@ -1252,7 +1276,7 @@ function chosenDetect() {
width: selectWidth
});
$(".sel-chosen-customer").each(function(){
$(".sel-chosen-customer").each(function () {
var deselect = $(this).hasClass('sel-chosen-deselect');
$(this).chosen({
@@ -1264,7 +1288,7 @@ function chosenDetect() {
});
});
$(".sel-chosen-category").each(function(){
$(".sel-chosen-category").each(function () {
var deselect = $(this).hasClass('sel-chosen-deselect');
$(this).chosen({
@@ -1288,7 +1312,7 @@ function passwordDetect() {
var thisInput = $(this);
var targetId = $(this).attr('id');
if ( thisInput.next().hasClass('password-actions') ){
if (thisInput.next().hasClass('password-actions')) {
return;
}

View File

@@ -101,9 +101,11 @@
<?php if ($account['showViewPass']): ?>
<img src="imgs/user-pass.png" title="<?php echo _('Ver Clave'); ?>"
onClick="viewPass(<?php echo $account['id']; ?>, 1)"/>
<?php if(!\SP\Util::accountPassToImageIsEnabled()): ?>
<img src="imgs/clipboard.png" title="<?php echo _('Copiar Clave en Portapapeles'); ?>"
onmousedown="viewPass(<?php echo $account['id']; ?>, false)"
class="actions-optional clip-pass-button" data-clipboard-target="clip-pass-text"/>
<?php endif; ?>
<?php endif ?>
<?php if ($account['showEdit'] || $account['showCopy'] || $account['showDel'] || $account['showViewPass']): ?>

View File

@@ -370,10 +370,12 @@
<button id="btnViewPass" type="button" class="mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab mdl-button--colored" onClick="viewPass(<?php echo $accountId; ?>,1,<?php echo $accountIsHistory; ?>)" title="<?php echo _('Ver Clave'); ?>">
<i class="material-icons">lock_open</i>
</button>
<?php if(!\SP\Util::accountPassToImageIsEnabled()): ?>
<button id="btnClipPass" class="mdl-button mdl-js-button mdl-button--fab mdl-button--mini-fab mdl-button--colored" onmousedown="viewPass(<?php echo $accountId; ?>, false, <?php echo $accountIsHistory; ?>)" title="<?php echo _('Copiar Clave en Portapapeles'); ?>">
<i class="material-icons clip-pass-button"
data-clipboard-target="clip-pass-text">content_paste</i>
</button>
<?php endif; ?>
<?php endif; ?>
<?php if ($showEditPass): ?>

View File

@@ -180,6 +180,28 @@
</div>
</td>
</tr>
<tr>
<td class="descField">
<?php echo _('Imagen para mostrar clave'); ?>
<div id="help-account_passtoimage" class="icon material-icons fg-blue80">help_outline</div>
<div class="mdl-tooltip mdl-tooltip--large" for="help-account_passtoimage">
<p>
<?php echo _('Generar una imagen con el texto de la clave de la cuenta.'); ?>
</p>
<p>
<?php echo _('Util para entornos donde copiar la clave supone un riesgo de seguridad.'); ?>
</p>
</div>
</td>
<td class="valField">
<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect" for="account_passtoimage">
<input type="checkbox" id="account_passtoimage" class="mdl-switch__input fg-blue100"
name="account_passtoimage"
<?php echo $chkAccountPassToImage, ' ', $isDisabled; ?>/>
<span class="mdl-switch__label"></span>
</label>
</td>
</tr>
</table>
<div id="title" class="midroundup titleNormal">

View File

@@ -316,20 +316,28 @@ function viewPass(id, full, history) {
width: 'auto',
open: function () {
var content;
var pass = '';
var clipboardUserButton =
'<button id="dialog-clip-user-button-' + id + '" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-icon-primary">' +
'<span class="ui-button-icon-primary ui-icon ui-icon-clipboard"></span>' +
'<span class="ui-button-text">' + LANG[33] + '</span>' +
'</button>';
var clipboardPassButton =
'<button id="dialog-clip-pass-button-' + id + '" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-icon-primary">' +
'<span class="ui-button-icon-primary ui-icon ui-icon-clipboard"></span>' +
'<span class="ui-button-text">' + LANG[34] + '</span>' +
'</button>';
var useImage = json.useimage;
if (json.status === 0) {
content = '<p class="dialog-pass-text">' + json.accpass + '</p>' +
'<br>' +
'<div class="dialog-buttons">' +
'<button id="dialog-clip-user-button-' + id + '" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-icon-primary">' +
'<span class="ui-button-icon-primary ui-icon ui-icon-clipboard"></span>' +
'<span class="ui-button-text">Copiar Usuario</span>' +
'</button>' +
'<button id="dialog-clip-pass-button-' + id + '" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-icon-primary">' +
'<span class="ui-button-icon-primary ui-icon ui-icon-clipboard"></span>' +
'<span class="ui-button-text">Copiar Clave</span>' +
'</button>' +
'</div>';
if (useImage === 0) {
pass = '<p class="dialog-pass-text">' + json.accpass + '</p>';
} else {
pass = '<img class="dialog-pass-text" src="data:image/png;base64,' + json.accpass + '" />';
clipboardPassButton = '';
}
content = pass + '<br>' + '<div class="dialog-buttons">' + clipboardUserButton + clipboardPassButton + '</div>';
} else {
content = '<span class="altTxtRed">' + json.description + '</span>';
@@ -373,14 +381,13 @@ function viewPass(id, full, history) {
});
});
// Cerrar Dialog a los 30s
var $this = $(this);
var thisDialog = $(this);
$(this).parent().on('mouseleave', function () {
clearTimeout(timeout);
timeout = setTimeout(function () {
$this.dialog('close');
thisDialog.dialog('close');
}, 30000);
});
},
@@ -1187,19 +1194,19 @@ function complexityDialog() {
var content =
'<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="checkbox-numbers">' +
'<input type="checkbox" id="checkbox-numbers" class="mdl-checkbox__input" name="checkbox-numbers"/>' +
'<span class="mdl-checkbox__label">Incluir números</span>' +
'<span class="mdl-checkbox__label">' + LANG[35] + '</span>' +
'</label>' +
'<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="checkbox-uppercase">' +
'<input type="checkbox" id="checkbox-uppercase" class="mdl-checkbox__input" name="checkbox-uppercase"/>' +
'<span class="mdl-checkbox__label">Incluir mayúculas</span>' +
'<span class="mdl-checkbox__label">' + LANG[36] + '</span>' +
'</label>' +
'<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="checkbox-symbols">' +
'<input type="checkbox" id="checkbox-symbols" class="mdl-checkbox__input" name="checkbox-symbols"/>' +
'<span class="mdl-checkbox__label">Incluir símbolos</span>' +
'<span class="mdl-checkbox__label">' + LANG[37] + '</span>' +
'</label>' +
'<div class="mdl-textfield mdl-js-textfield textfield-passlength">' +
'<input class="mdl-textfield__input" type="number" pattern="[0-9]*" id="passlength" />' +
'<label class="mdl-textfield__label" for="passlength">Longitud</label>' +
'<label class="mdl-textfield__label" for="passlength">' + LANG[38] + '</label>' +
'</div>' +
'<button id="btn-complexity" class="mdl-button mdl-js-button mdl-button--raised">Ok</button>';

View File

@@ -112,10 +112,12 @@
<?php if ($account['showViewPass']): ?>
<i id="viewpass" class="material-icons fg-blue80" title="<?php echo _('Ver Clave'); ?>"
onClick="viewPass(<?php echo $account['id']; ?>, 1)">lock_open</i>
<?php if(!\SP\Util::accountPassToImageIsEnabled()): ?>
<i id="clipboard" class="material-icons fg-blue80 actions-optional clip-pass-button"
data-clipboard-target="clip-pass-text"
title="<?php echo _('Copiar Clave en Portapapeles'); ?>"
onmousedown="viewPass(<?php echo $account['id']; ?>, false)">content_paste</i>
<?php endif ?>
<?php endif ?>
<?php if ($account['showEdit'] || $account['showCopy'] || $account['showDel'] || $account['showViewPass']): ?>

View File

@@ -56,7 +56,13 @@ $stringsJsLang = array(
29 => _('Complejidad'),
30 => _('Reset'),
31 => _('Nivel de fortaleza de la clave'),
32 => _('Mostrar Clave')
32 => _('Mostrar Clave'),
33 => _('Copiar Usuario'),
34 => _('Copiar Clave'),
35 => _('Incluir Números'),
36 => _('Incluir Mayúsculas'),
37 => _('Incluir Símbolos'),
38 => _('Longitud'),
);

View File

@@ -104,6 +104,7 @@ class ConfigC extends Controller implements ActionsInterface
// Accounts
$this->view->assign('chkGlobalSearch', (\SP\Config::getValue('globalsearch')) ? 'checked="checked"' : '');
$this->view->assign('chkResultsAsCards', (\SP\Config::getValue('resultsascards')) ? 'checked="checked"' : '');
$this->view->assign('chkAccountPassToImage', (\SP\Config::getValue('account_passtoimage')) ? 'checked="checked"' : '');
$this->view->assign('chkAccountLink', (\SP\Config::getValue('account_link')) ? 'checked="checked"' : '');
$this->view->assign('accountCount', \SP\Config::getValue('account_count'));