Merge branch 'Dolibarr:develop' into develop

This commit is contained in:
Marc 2023-01-17 12:33:48 +01:00 committed by GitHub
commit a10d889374
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 117 additions and 66 deletions

View File

@ -36,9 +36,10 @@ if (!defined('NOREQUIREAJAX')) {
if (!defined('NOREQUIRESOC')) { if (!defined('NOREQUIRESOC')) {
define('NOREQUIRESOC', '1'); define('NOREQUIRESOC', '1');
} }
if (!defined('NOREQUIRETRAN')) { // We need langs because the getRandomPassword may use user language to define some rules of pass generation
/*if (!defined('NOREQUIRETRAN')) {
define('NOREQUIRETRAN', '1'); define('NOREQUIRETRAN', '1');
} }*/
// Load Dolibarr environment // Load Dolibarr environment
require '../../main.inc.php'; require '../../main.inc.php';
@ -55,9 +56,9 @@ top_httphead();
//print '<!-- Ajax page called with url '.dol_escape_htmltag($_SERVER["PHP_SELF"]).'?'.dol_escape_htmltag($_SERVER["QUERY_STRING"]).' -->'."\n"; //print '<!-- Ajax page called with url '.dol_escape_htmltag($_SERVER["PHP_SELF"]).'?'.dol_escape_htmltag($_SERVER["QUERY_STRING"]).' -->'."\n";
// Registering the location of boxes // Return a new generated password
if ($action) { if ($action) {
if ($action == 'getrandompassword' && ($user->admin || $user->rights->api->apikey->generate)) { if ($action == 'getrandompassword') {
require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
$generic = GETPOST('generic') ? true : false; $generic = GETPOST('generic') ? true : false;
echo getRandomPassword($generic); echo getRandomPassword($generic);

View File

@ -8583,21 +8583,21 @@ abstract class CommonObject
/** /**
* Show photos of an object (nbmax maximum), into several columns * Show photos of an object (nbmax maximum), into several columns
* *
* @param string $modulepart 'product', 'ticket', ... * @param string $modulepart 'product', 'ticket', ...
* @param string $sdir Directory to scan (full absolute path) * @param string $sdir Directory to scan (full absolute path)
* @param int $size 0=original size, 1='small' use thumbnail if possible * @param int $size 0=original size, 1='small' use thumbnail if possible
* @param int $nbmax Nombre maximum de photos (0=pas de max) * @param int $nbmax Nombre maximum de photos (0=pas de max)
* @param int $nbbyrow Number of image per line or -1 to use div separator or 0 to use no separator. Used only if size=1 or 'small'. * @param int $nbbyrow Number of image per line or -1 to use div separator or 0 to use no separator. Used only if size=1 or 'small'.
* @param int $showfilename 1=Show filename * @param int $showfilename 1=Show filename
* @param int $showaction 1=Show icon with action links (resize, delete) * @param int $showaction 1=Show icon with action links (resize, delete)
* @param int $maxHeight Max height of original image when size='small' (so we can use original even if small requested). If 0, always use 'small' thumb image. * @param int $maxHeight Max height of original image when size='small' (so we can use original even if small requested). If 0, always use 'small' thumb image.
* @param int $maxWidth Max width of original image when size='small' * @param int $maxWidth Max width of original image when size='small'
* @param int $nolink Do not add a href link to view enlarged imaged into a new tab * @param int $nolink Do not add a href link to view enlarged imaged into a new tab
* @param int $notitle Do not add title tag on image * @param int|string $overwritetitle Do not add title tag on image
* @param int $usesharelink Use the public shared link of image (if not available, the 'nophoto' image will be shown instead) * @param int $usesharelink Use the public shared link of image (if not available, the 'nophoto' image will be shown instead)
* @return string Html code to show photo. Number of photos shown is saved in this->nbphoto * @return string Html code to show photo. Number of photos shown is saved in this->nbphoto
*/ */
public function show_photos($modulepart, $sdir, $size = 0, $nbmax = 0, $nbbyrow = 5, $showfilename = 0, $showaction = 0, $maxHeight = 120, $maxWidth = 160, $nolink = 0, $notitle = 0, $usesharelink = 0) public function show_photos($modulepart, $sdir, $size = 0, $nbmax = 0, $nbbyrow = 5, $showfilename = 0, $showaction = 0, $maxHeight = 120, $maxWidth = 160, $nolink = 0, $overwritetitle = 0, $usesharelink = 0)
{ {
// phpcs:enable // phpcs:enable
global $conf, $user, $langs; global $conf, $user, $langs;
@ -8700,8 +8700,12 @@ abstract class CommonObject
// Si fichier vignette disponible et image source trop grande, on utilise la vignette, sinon on utilise photo origine // Si fichier vignette disponible et image source trop grande, on utilise la vignette, sinon on utilise photo origine
$alt = $langs->transnoentitiesnoconv('File').': '.$relativefile; $alt = $langs->transnoentitiesnoconv('File').': '.$relativefile;
$alt .= ' - '.$langs->transnoentitiesnoconv('Size').': '.$imgarray['width'].'x'.$imgarray['height']; $alt .= ' - '.$langs->transnoentitiesnoconv('Size').': '.$imgarray['width'].'x'.$imgarray['height'];
if ($notitle) { if ($overwritetitle) {
$alt = ''; if (is_numeric($overwritetitle)) {
$alt = '';
} else {
$alt = $overwritetitle;
}
} }
$addphotorefcss = 1; $addphotorefcss = 1;

View File

@ -164,7 +164,7 @@ class HookManager
// Define type of hook ('output' or 'addreplace'). // Define type of hook ('output' or 'addreplace').
$hooktype = 'addreplace'; $hooktype = 'addreplace';
// TODO Remove hooks with type 'output' (exemple createFrom). All hooks must be converted into 'addreplace' hooks. // TODO Remove hooks with type 'output' (exemple createFrom). All hooks must be converted into 'addreplace' hooks.
if (!in_array($method, array( if (in_array($method, array(
'createFrom', 'createFrom',
'dashboardMembers', 'dashboardMembers',
'dashboardEmailings', 'dashboardEmailings',

View File

@ -2122,14 +2122,14 @@ function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldi
$maxvisiblephotos = 1; $maxvisiblephotos = 1;
} }
if ($showimage) { if ($showimage) {
$morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$object->show_photos('product', $conf->product->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, $width, 0).'</div>'; $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$object->show_photos('product', $conf->product->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, 0, $width, 0, '').'</div>';
} else { } else {
if (!empty($conf->global->PRODUCT_NODISPLAYIFNOPHOTO)) { if (!empty($conf->global->PRODUCT_NODISPLAYIFNOPHOTO)) {
$nophoto = ''; $nophoto = '';
$morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>'; $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
} else { // Show no photo link } else { // Show no photo link
$nophoto = '/public/theme/common/nophoto.png'; $nophoto = '/public/theme/common/nophoto.png';
$morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><img class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" alt="No photo"'.($width ? ' style="width: '.$width.'px"' : '').' src="'.DOL_URL_ROOT.$nophoto.'"></div>'; $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><img class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" title="'.dol_escape_htmltag($langs->trans("UploadAnImageToSeeAPhotoHere", $langs->transnoentitiesnoconv("Documents"))).'" alt="No photo"'.($width ? ' style="width: '.$width.'px"' : '').' src="'.DOL_URL_ROOT.$nophoto.'"></div>';
} }
} }
} elseif ($object->element == 'ticket') { } elseif ($object->element == 'ticket') {

View File

@ -560,10 +560,11 @@ function getRandomPassword($generic = false, $replaceambiguouschars = null, $len
* *
* @param string $htmlname HTML name of element to insert key into * @param string $htmlname HTML name of element to insert key into
* @param string $htmlnameofbutton HTML name of button * @param string $htmlnameofbutton HTML name of button
* @param int $generic 1=Return a generic pass, 0=Return a pass following setup rules
* @return string HTML javascript code to set a password * @return string HTML javascript code to set a password
* @see getRandomPassword() * @see getRandomPassword()
*/ */
function dolJSToSetRandomPassword($htmlname, $htmlnameofbutton = 'generate_token') function dolJSToSetRandomPassword($htmlname, $htmlnameofbutton = 'generate_token', $generic = 1)
{ {
global $conf; global $conf;
@ -571,10 +572,10 @@ function dolJSToSetRandomPassword($htmlname, $htmlnameofbutton = 'generate_token
print "\n".'<!-- Js code to suggest a security key --><script type="text/javascript">'; print "\n".'<!-- Js code to suggest a security key --><script type="text/javascript">';
print '$(document).ready(function () { print '$(document).ready(function () {
$("#'.dol_escape_js($htmlnameofbutton).'").click(function() { $("#'.dol_escape_js($htmlnameofbutton).'").click(function() {
console.log("We click on the button to suggest a key"); console.log("We click on the button '.dol_escape_js($htmlnameofbutton).' to suggest a key. We will fill '.dol_escape_js($htmlname).'");
$.get( "'.DOL_URL_ROOT.'/core/ajax/security.php", { $.get( "'.DOL_URL_ROOT.'/core/ajax/security.php", {
action: \'getrandompassword\', action: \'getrandompassword\',
generic: true, generic: '.($generic ? '1' : '0').',
token: \''.dol_escape_js(newToken()).'\' token: \''.dol_escape_js(newToken()).'\'
}, },
function(result) { function(result) {

View File

@ -91,18 +91,6 @@ function check_user_password_dolibarr($usertotest, $passwordtotest, $entitytotes
dol_syslog("functions_dolibarr::check_user_password_dolibarr bad date end validity", LOG_WARNING); dol_syslog("functions_dolibarr::check_user_password_dolibarr bad date end validity", LOG_WARNING);
return '--bad-login-validity--'; return '--bad-login-validity--';
} }
// If there is an invalidation date, check that the current session date is not before this date
if ($obj->flagdelsessionsbefore && !empty($_SESSION["dol_logindate"])) {
dol_syslog("functions_dolibarr::check_user_password_dolibarr user has a date for session invalidation = ".$obj->flagdelsessionsbefore." and session date = ".$_SESSION["dol_logindate"]);
$datetmp = $db->jdate($obj->flagdelsessionsbefore, 'gmt');
if ($datetmp > $now) {
// Load translation files required by the page
$langs->loadLangs(array('main', 'errors'));
$_SESSION["dol_loginmesg"] = $langs->transnoentitiesnoconv("ErrorSessionInvalidatedAfterPasswordChange");
dol_syslog("functions_dolibarr::check_user_password_dolibarr session was invalidated", LOG_WARNING);
return '--bad-login-validity--';
}
}
$passclear = $obj->pass; $passclear = $obj->pass;
$passcrypted = $obj->pass_crypted; $passcrypted = $obj->pass_crypted;

View File

@ -63,3 +63,25 @@ function check_user_password_http($usertotest, $passwordtotest, $entitytotest)
return $login; return $login;
} }
/**
* Decode the value found into the Authorization HTTP header.
* Ex: "Authorization: Basic bG9naW46cGFzcw==", $value is "Basic bG9naW46cGFzcw==" and after base64decode is "login:pass"
* Note: the $_SERVER["REMOTE_USER"] contains only the login used in the HTTP Basic form
* Method not used yet, but we keep it for some dev/test purposes.
*
* @param string $value Ex: $_SERVER["REMOTE_USER"]
* @return Object object.login & object.password
*/
function decodeHttpBasicAuth($value)
{
$encoded_basic_auth = substr($value, 6); // Remove the "Basic " string
$decoded_basic_auth = base64_decode($encoded_basic_auth);
$credentials_basic_auth = explode(':', $decoded_basic_auth);
return (object) [
'username'=> $credentials_basic_auth[0],
'password' => $credentials_basic_auth[1]
];
}

View File

@ -931,7 +931,7 @@ class InterfaceActionsAuto extends DolibarrTriggers
$object->sendtoid = 0; $object->sendtoid = 0;
} else { } else {
// TODO Merge all previous cases into this generic one // TODO Merge all previous cases into this generic one
// $action = BILL_DELETE, TICKET_CREATE, TICKET_MODIFY, TICKET_DELETE, CONTACT_SENTBYMAIL, RECRUITMENTCANDIDATURE_MODIFY, ... // $action = PASSWORD, BILL_DELETE, TICKET_CREATE, TICKET_MODIFY, TICKET_DELETE, CONTACT_SENTBYMAIL, RECRUITMENTCANDIDATURE_MODIFY, ...
// Can also be a value defined by an external module like SENTBYSMS, COMPANY_SENTBYSMS, MEMBER_SENTBYSMS, ... // Can also be a value defined by an external module like SENTBYSMS, COMPANY_SENTBYSMS, MEMBER_SENTBYSMS, ...
// Note: We are here only if $conf->global->MAIN_AGENDA_ACTIONAUTO_action is on (tested at begining of this function). // Note: We are here only if $conf->global->MAIN_AGENDA_ACTIONAUTO_action is on (tested at begining of this function).
// Note that these key can be set in agenda setup, only if defined into llx_c_action_trigger // Note that these key can be set in agenda setup, only if defined into llx_c_action_trigger

View File

@ -303,6 +303,7 @@ ErrorValueForTooLow=Value for <b>%s</b> is too low
ErrorValueCantBeNull=Value for <b>%s</b> can't be null ErrorValueCantBeNull=Value for <b>%s</b> can't be null
ErrorDateOfMovementLowerThanDateOfFileTransmission=The date of the bank transaction can't be lower than the date of the file transmission ErrorDateOfMovementLowerThanDateOfFileTransmission=The date of the bank transaction can't be lower than the date of the file transmission
ErrorTooMuchFileInForm=Too much files in form, the maximum number is %s file(s) ErrorTooMuchFileInForm=Too much files in form, the maximum number is %s file(s)
ErrorSessionInvalidatedAfterPasswordChange=The session was invalidated after a password change. Please relogin.
# Warnings # Warnings
WarningParamUploadMaxFileSizeHigherThanPostMaxSize=Your PHP parameter upload_max_filesize (%s) is higher than PHP parameter post_max_size (%s). This is not a consistent setup. WarningParamUploadMaxFileSizeHigherThanPostMaxSize=Your PHP parameter upload_max_filesize (%s) is higher than PHP parameter post_max_size (%s). This is not a consistent setup.
@ -325,6 +326,7 @@ WarningPaymentDateLowerThanInvoiceDate=Payment date (%s) is earlier than invoice
WarningTooManyDataPleaseUseMoreFilters=Too many data (more than %s lines). Please use more filters or set the constant %s to a higher limit. WarningTooManyDataPleaseUseMoreFilters=Too many data (more than %s lines). Please use more filters or set the constant %s to a higher limit.
WarningSomeLinesWithNullHourlyRate=Some times were recorded by some users while their hourly rate was not defined. A value of 0 %s per hour was used but this may result in wrong valuation of time spent. WarningSomeLinesWithNullHourlyRate=Some times were recorded by some users while their hourly rate was not defined. A value of 0 %s per hour was used but this may result in wrong valuation of time spent.
WarningYourLoginWasModifiedPleaseLogin=Your login was modified. For security purpose you will have to login with your new login before next action. WarningYourLoginWasModifiedPleaseLogin=Your login was modified. For security purpose you will have to login with your new login before next action.
WarningYourPasswordWasModifiedPleaseLogin=Your password was modified. For security purpose you will have to login now with your new password.
WarningAnEntryAlreadyExistForTransKey=An entry already exists for the translation key for this language WarningAnEntryAlreadyExistForTransKey=An entry already exists for the translation key for this language
WarningNumberOfRecipientIsRestrictedInMassAction=Warning, number of different recipient is limited to <b>%s</b> when using the mass actions on lists WarningNumberOfRecipientIsRestrictedInMassAction=Warning, number of different recipient is limited to <b>%s</b> when using the mass actions on lists
WarningDateOfLineMustBeInExpenseReportRange=Warning, the date of line is not in the range of the expense report WarningDateOfLineMustBeInExpenseReportRange=Warning, the date of line is not in the range of the expense report

View File

@ -1219,4 +1219,5 @@ NoSpecificContactAddress=No specific contact or address
NoSpecificContactAddressBis=This tab is dedicated to force specific contacts or addresses for the current object. Use it only if you want to define one or several specific contacts or addresses for the object when the information on the thirdparty is not enough or not accurate. NoSpecificContactAddressBis=This tab is dedicated to force specific contacts or addresses for the current object. Use it only if you want to define one or several specific contacts or addresses for the object when the information on the thirdparty is not enough or not accurate.
HideOnVCard=Hide %s HideOnVCard=Hide %s
AddToContacts=Add address to my contacts AddToContacts=Add address to my contacts
LastAccess=Last access LastAccess=Last access
UploadAnImageToSeeAPhotoHere=Upload an image from the tab %s to see a photo here

View File

@ -66,7 +66,8 @@ LinkedToDolibarrUser=Link to user
LinkedToDolibarrThirdParty=Link to third party LinkedToDolibarrThirdParty=Link to third party
CreateDolibarrLogin=Create a user CreateDolibarrLogin=Create a user
CreateDolibarrThirdParty=Create a third party CreateDolibarrThirdParty=Create a third party
LoginAccountDisableInDolibarr=Account disabled in Dolibarr. LoginAccountDisableInDolibarr=Account disabled in Dolibarr
PASSWORDInDolibarr=Password modified in Dolibarr
UsePersonalValue=Use personal value UsePersonalValue=Use personal value
ExportDataset_user_1=Users and their properties ExportDataset_user_1=Users and their properties
DomainUser=Domain user %s DomainUser=Domain user %s

View File

@ -943,26 +943,35 @@ if (!defined('NOLOGIN')) {
dol_syslog("- This is an already logged session. _SESSION['dol_login']=".$login." _SESSION['dol_entity']=".$entity, LOG_DEBUG); dol_syslog("- This is an already logged session. _SESSION['dol_login']=".$login." _SESSION['dol_entity']=".$entity, LOG_DEBUG);
$resultFetchUser = $user->fetch('', $login, '', 1, ($entity > 0 ? $entity : -1)); $resultFetchUser = $user->fetch('', $login, '', 1, ($entity > 0 ? $entity : -1));
if ($resultFetchUser <= 0) { if ($resultFetchUser <= 0 || ($user->flagdelsessionsbefore && !empty($_SESSION["dol_logindate"]) && $user->flagdelsessionsbefore > $_SESSION["dol_logindate"])) {
// Account has been removed after login if ($resultFetchUser <= 0) {
dol_syslog("Can't load user even if session logged. _SESSION['dol_login']=".$login, LOG_WARNING); // Account has been removed after login
dol_syslog("Can't load user even if session logged. _SESSION['dol_login']=".$login, LOG_WARNING);
} else {
// Session is no more valid
dol_syslog("The user has a date for session invalidation = ".$user->flagdelsessionsbefore." and a session date = ".$_SESSION["dol_logindate"].". We must invalidate its sessions.");
}
session_destroy(); session_destroy();
session_set_cookie_params(0, '/', null, (empty($dolibarr_main_force_https) ? false : true), true); // Add tag secure and httponly on session cookie session_set_cookie_params(0, '/', null, (empty($dolibarr_main_force_https) ? false : true), true); // Add tag secure and httponly on session cookie
session_name($sessionname); session_name($sessionname);
session_start(); session_start();
if ($resultFetchUser == 0) { if ($resultFetchUser == 0) {
// Load translation files required by page
$langs->loadLangs(array('main', 'errors')); $langs->loadLangs(array('main', 'errors'));
$_SESSION["dol_loginmesg"] = $langs->transnoentitiesnoconv("ErrorCantLoadUserFromDolibarrDatabase", $login); $_SESSION["dol_loginmesg"] = $langs->transnoentitiesnoconv("ErrorCantLoadUserFromDolibarrDatabase", $login);
$user->trigger_mesg = 'ErrorCantLoadUserFromDolibarrDatabase - login='.$login; $user->trigger_mesg = 'ErrorCantLoadUserFromDolibarrDatabase - login='.$login;
} } elseif ($resultFetchUser < 0) {
if ($resultFetchUser < 0) {
$_SESSION["dol_loginmesg"] = $user->error; $_SESSION["dol_loginmesg"] = $user->error;
$user->trigger_mesg = $user->error; $user->trigger_mesg = $user->error;
} else {
$langs->loadLangs(array('main', 'errors'));
$_SESSION["dol_loginmesg"] = $langs->transnoentitiesnoconv("ErrorSessionInvalidatedAfterPasswordChange");
$user->trigger_mesg = 'ErrorUserSessionWasInvalidated - login='.$login;
} }
// Call trigger // Call trigger
@ -975,7 +984,7 @@ if (!defined('NOLOGIN')) {
// Hooks on failed login // Hooks on failed login
$action = ''; $action = '';
$hookmanager->initHooks(array('login')); $hookmanager->initHooks(array('login'));
$parameters = array('dol_authmode'=>$dol_authmode, 'dol_loginmesg'=>$_SESSION["dol_loginmesg"]); $parameters = array('dol_authmode' => (isset($dol_authmode) ? $dol_authmode : ''), 'dol_loginmesg' => $_SESSION["dol_loginmesg"]);
$reshook = $hookmanager->executeHooks('afterLoginFailed', $parameters, $user, $action); // Note that $action and $object may have been modified by some hooks $reshook = $hookmanager->executeHooks('afterLoginFailed', $parameters, $user, $action); // Note that $action and $object may have been modified by some hooks
if ($reshook < 0) { if ($reshook < 0) {
$error++; $error++;

View File

@ -257,13 +257,8 @@ if (empty($reshook)) {
if ($action == 'add') { if ($action == 'add') {
$error = 0; $error = 0;
if (!GETPOST('label', 'alpha') || !GETPOST('bank', 'alpha')) { if (!GETPOST('label', 'alpha')) {
if (!GETPOST('label', 'alpha')) { setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Label")), null, 'errors');
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Label")), null, 'errors');
}
if (!GETPOST('bank', 'alpha')) {
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("BankName")), null, 'errors');
}
$action = 'create'; $action = 'create';
$error++; $error++;
} }
@ -274,6 +269,8 @@ if (empty($reshook)) {
$companybankaccount->socid = $object->id; $companybankaccount->socid = $object->id;
$companybankaccount->fetch_thirdparty();
$companybankaccount->bank = GETPOST('bank', 'alpha'); $companybankaccount->bank = GETPOST('bank', 'alpha');
$companybankaccount->label = GETPOST('label', 'alpha'); $companybankaccount->label = GETPOST('label', 'alpha');
$companybankaccount->courant = GETPOST('courant', 'alpha'); $companybankaccount->courant = GETPOST('courant', 'alpha');
@ -293,6 +290,12 @@ if (empty($reshook)) {
$companybankaccount->datec = dol_now(); $companybankaccount->datec = dol_now();
$companybankaccount->status = 1; $companybankaccount->status = 1;
$companybankaccount->bank = trim($companybankaccount->bank);
if (empty($companybankaccount->bank) && !empty($companybankaccount->thirdparty)) {
$companybankaccount->bank = $langs->trans("Bank").' '.$companybankaccount->thirdparty->name;
}
$companybankaccount->bic = str_replace(' ', '', $companybankaccount->bic);
$db->begin(); $db->begin();
// This test can be done only once properties were set // This test can be done only once properties were set
@ -1980,7 +1983,7 @@ if ($socid && $action == 'create' && $permissiontoaddupdatepaymentinformation) {
print '<tr><td class="titlefieldcreate fieldrequired">'.$langs->trans("Label").'</td>'; print '<tr><td class="titlefieldcreate fieldrequired">'.$langs->trans("Label").'</td>';
print '<td><input class="minwidth200" type="text" id="label" name="label" value="'.(GETPOSTISSET('label') ? GETPOST('label') : $object->name).'"></td></tr>'; print '<td><input class="minwidth200" type="text" id="label" name="label" value="'.(GETPOSTISSET('label') ? GETPOST('label') : $object->name).'"></td></tr>';
print '<tr><td class="fieldrequired">'.$langs->trans("Bank").'</td>'; print '<tr><td>'.$langs->trans("Bank").'</td>';
print '<td><input class="minwidth200" type="text" id="bank" name="bank" value="'.GETPOST('bank').'"></td></tr>'; print '<td><input class="minwidth200" type="text" id="bank" name="bank" value="'.GETPOST('bank').'"></td></tr>';
// Show fields of bank account // Show fields of bank account

View File

@ -521,7 +521,14 @@ if (empty($reshook)) {
} }
if (!$error) { if (!$error) {
$ret = $object->update($user); $passwordismodified = 0;
if (!empty($object->pass)) {
if ($object->pass != $object->pass_indatabase && !dol_verifyHash($object->pass, $object->pass_indatabase_crypted)) {
$passwordismodified = 1;
}
}
$ret = $object->update($user); // This may include call to setPassword if password has changed
if ($ret < 0) { if ($ret < 0) {
$error++; $error++;
if ($db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') { if ($db->errno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
@ -615,6 +622,13 @@ if (empty($reshook)) {
$langs->load("errors"); $langs->load("errors");
setEventMessages($langs->transnoentitiesnoconv("WarningYourLoginWasModifiedPleaseLogin"), null, 'warnings'); setEventMessages($langs->transnoentitiesnoconv("WarningYourLoginWasModifiedPleaseLogin"), null, 'warnings');
} }
if ($passwordismodified && $object->login == $user->login) { // Current user has changed its password
$error++;
$langs->load("errors");
setEventMessages($langs->transnoentitiesnoconv("WarningYourPasswordWasModifiedPleaseLogin"), null, 'warnings');
header("Location: ".DOL_URL_ROOT.'/user/card.php?id='.$object->id);
exit;
}
} else { } else {
$db->rollback(); $db->rollback();
} }
@ -1023,7 +1037,10 @@ if ($action == 'create' || $action == 'adduserldap') {
$valuetoshow .= preg_replace('/./i', '*', $ldap_pass); $valuetoshow .= preg_replace('/./i', '*', $ldap_pass);
} else { } else {
// We do not use a field password but a field text to show new password to use. // We do not use a field password but a field text to show new password to use.
$valuetoshow .= ($valuetoshow ? ' + '.$langs->trans("DolibarrPassword") : '').'<input maxsize="32" type="text" name="password" value="'.dol_escape_htmltag($password).'" autocomplete="new-password">'; $valuetoshow .= ($valuetoshow ? ' + '.$langs->trans("DolibarrPassword") : '').'<input class="minwidth300 maxwidth400 widthcentpercentminusx" maxsize="32" type="text" id="password" name="password" value="'.dol_escape_htmltag($password).'" autocomplete="new-password">';
if (!empty($conf->use_javascript_ajax)) {
$valuetoshow .= '&nbsp;'.img_picto($langs->trans('Generate'), 'refresh', 'id="generate_password" class="linkobject"');
}
} }
} }
@ -1044,7 +1061,7 @@ if ($action == 'create' || $action == 'adduserldap') {
//$generated_password = getRandomPassword(false); //$generated_password = getRandomPassword(false);
print '<tr><td>'.$langs->trans("ApiKey").'</td>'; print '<tr><td>'.$langs->trans("ApiKey").'</td>';
print '<td>'; print '<td>';
print '<input class="minwidth300 widthcentpercentminusx" maxsize="32" type="text" id="api_key" name="api_key" value="'.GETPOST('api_key', 'alphanohtml').'" autocomplete="off">'; print '<input class="minwidth300 maxwidth400 widthcentpercentminusx" maxsize="32" type="text" id="api_key" name="api_key" value="'.GETPOST('api_key', 'alphanohtml').'" autocomplete="off">';
if (!empty($conf->use_javascript_ajax)) { if (!empty($conf->use_javascript_ajax)) {
print '&nbsp;'.img_picto($langs->trans('Generate'), 'refresh', 'id="generate_api_key" class="linkobject"'); print '&nbsp;'.img_picto($langs->trans('Generate'), 'refresh', 'id="generate_api_key" class="linkobject"');
} }
@ -2392,7 +2409,7 @@ if ($action == 'create' || $action == 'adduserldap') {
} }
if (preg_match('/dolibarr/', $dolibarr_main_authentication)) { if (preg_match('/dolibarr/', $dolibarr_main_authentication)) {
if ($caneditpassword) { if ($caneditpassword) {
$valuetoshow .= ($valuetoshow ? (' '.$langs->trans("or").' ') : '').'<input maxlength="128" type="password" class="flat" name="password" value="'.dol_escape_htmltag($object->pass).'" autocomplete="new-password">'; $valuetoshow .= ($valuetoshow ? (' '.$langs->trans("or").' ') : '').'<input maxlength="128" type="password" class="flat" id="password" name="password" value="'.dol_escape_htmltag($object->pass).'" autocomplete="new-password">';
} else { } else {
$valuetoshow .= ($valuetoshow ? (' '.$langs->trans("or").' ') : '').preg_replace('/./i', '*', $object->pass); $valuetoshow .= ($valuetoshow ? (' '.$langs->trans("or").' ') : '').preg_replace('/./i', '*', $object->pass);
} }
@ -2875,11 +2892,10 @@ if ($action == 'create' || $action == 'adduserldap') {
} }
if (!empty($conf->api->enabled)) { if (!empty($conf->api->enabled)) {
$constname = 'api_key';
// Add button to autosuggest a key // Add button to autosuggest a key
include_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php'; include_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
print dolJSToSetRandomPassword($constname, 'generate_api_key'); print dolJSToSetRandomPassword('password', 'generate_password', 0);
print dolJSToSetRandomPassword('api_key', 'generate_api_key', 1);
} }
// End of page // End of page

View File

@ -276,6 +276,7 @@ class User extends CommonObject
public $datelastlogin; public $datelastlogin;
public $datepreviouslogin; public $datepreviouslogin;
public $flagdelsessionsbefore;
public $iplastlogin; public $iplastlogin;
public $ippreviouslogin; public $ippreviouslogin;
public $datestartvalidity; public $datestartvalidity;
@ -441,6 +442,7 @@ class User extends CommonObject
$sql .= " u.tms as datem,"; $sql .= " u.tms as datem,";
$sql .= " u.datelastlogin as datel,"; $sql .= " u.datelastlogin as datel,";
$sql .= " u.datepreviouslogin as datep,"; $sql .= " u.datepreviouslogin as datep,";
$sql .= " u.flagdelsessionsbefore,";
$sql .= " u.iplastlogin,"; $sql .= " u.iplastlogin,";
$sql .= " u.ippreviouslogin,"; $sql .= " u.ippreviouslogin,";
$sql .= " u.datelastpassvalidation,"; $sql .= " u.datelastpassvalidation,";
@ -575,6 +577,7 @@ class User extends CommonObject
$this->datem = $this->db->jdate($obj->datem); $this->datem = $this->db->jdate($obj->datem);
$this->datelastlogin = $this->db->jdate($obj->datel); $this->datelastlogin = $this->db->jdate($obj->datel);
$this->datepreviouslogin = $this->db->jdate($obj->datep); $this->datepreviouslogin = $this->db->jdate($obj->datep);
$this->flagdelsessionsbefore = $this->db->jdate($obj->flagdelsessionsbefore, 'gmt');
$this->iplastlogin = $obj->iplastlogin; $this->iplastlogin = $obj->iplastlogin;
$this->ippreviouslogin = $obj->ippreviouslogin; $this->ippreviouslogin = $obj->ippreviouslogin;
$this->datestartvalidity = $this->db->jdate($obj->datestartvalidity); $this->datestartvalidity = $this->db->jdate($obj->datestartvalidity);
@ -2031,9 +2034,9 @@ class User extends CommonObject
// Update password // Update password
if (!empty($this->pass)) { if (!empty($this->pass)) {
if ($this->pass != $this->pass_indatabase && $this->pass != $this->pass_indatabase_crypted) { if ($this->pass != $this->pass_indatabase && !dol_verifyHash($this->pass, $this->pass_indatabase_crypted)) {
// If a new value for password is set and different than the one crypted into database // If a new value for password is set and different than the one crypted into database
$result = $this->setPassword($user, $this->pass, 0, $notrigger, $nosyncmemberpass); $result = $this->setPassword($user, $this->pass, 0, $notrigger, $nosyncmemberpass, 0, 1);
if ($result < 0) { if ($result < 0) {
return -5; return -5;
} }

View File

@ -204,7 +204,7 @@ class UserTest extends PHPUnit\Framework\TestCase
$newlocalobject=new User($this->savdb); $newlocalobject=new User($this->savdb);
$newlocalobject->initAsSpecimen(); $newlocalobject->initAsSpecimen();
$this->changeProperties($newlocalobject); $this->changeProperties($newlocalobject);
$this->assertEquals($this->objCompare($localobject, $newlocalobject, true, array('id','socid','societe_id','specimen','note','ref','pass','pass_indatabase','pass_indatabase_crypted','pass_temp','datec','datem','datelastlogin','datepreviouslogin','iplastlogin','ippreviouslogin','trackid')), array()); // Actual, Expected $this->assertEquals($this->objCompare($localobject, $newlocalobject, true, array('id','socid','societe_id','specimen','note','ref','pass','pass_indatabase','pass_indatabase_crypted','pass_temp','datec','datem','datelastlogin','datepreviouslogin','flagdelsessionsbefore','iplastlogin','ippreviouslogin','trackid')), array()); // Actual, Expected
return $localobject; return $localobject;
} }