From d2b6fa3d606812257f64a68dd522146ca5b3ed33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Tue, 11 Aug 2026 16:38:26 +0200 Subject: [PATCH] NEW: Unify extrafields admin pages into a single secured page (societe, socpeople pilot) --- .../extrafields.php} | 54 +++++---- htdocs/core/lib/admin_extrafields.lib.php | 63 +++++++++++ htdocs/core/lib/company.lib.php | 4 +- htdocs/societe/admin/contact_extrafields.php | 107 ------------------ 4 files changed, 95 insertions(+), 133 deletions(-) rename htdocs/{societe/admin/societe_extrafields.php => admin/extrafields.php} (62%) create mode 100644 htdocs/core/lib/admin_extrafields.lib.php delete mode 100644 htdocs/societe/admin/contact_extrafields.php diff --git a/htdocs/societe/admin/societe_extrafields.php b/htdocs/admin/extrafields.php similarity index 62% rename from htdocs/societe/admin/societe_extrafields.php rename to htdocs/admin/extrafields.php index 10a7df03e28..f81b17a83e9 100644 --- a/htdocs/societe/admin/societe_extrafields.php +++ b/htdocs/admin/extrafields.php @@ -1,9 +1,5 @@ - * Copyright (C) 2003 Jean-Louis Bergamo - * Copyright (C) 2004-2011 Laurent Destailleur - * Copyright (C) 2012 Regis Houssin - * Copyright (C) 2024 Frédéric France +/* Copyright (C) 2026 Frédéric France * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,15 +16,18 @@ */ /** - * \file htdocs/societe/admin/societe_extrafields.php - * \ingroup societe - * \brief Page to setup extra fields of third party + * \file htdocs/admin/extrafields.php + * \ingroup core + * \brief Single, secured admin page to create/edit/delete the + * extrafields of any registered object type. The set of + * accepted object types is a closed whitelist — see + * core/lib/admin_extrafields.lib.php. */ // Load Dolibarr environment -require '../../main.inc.php'; -require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require '../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/admin_extrafields.lib.php'; /** * @var Conf $conf @@ -38,7 +37,19 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; * @var User $user */ -$langs->loadLangs(array("companies", "admin", "members")); +if (!$user->admin) { + accessforbidden(); +} + +$elementtype = GETPOST('elementtype', 'aZ09'); + +$extrafieldsadminmap = getExtrafieldsAdminMap(); +if ($elementtype === '' || !array_key_exists($elementtype, $extrafieldsadminmap)) { + accessforbidden('Bad or missing value for parameter elementtype'); +} +$pagedef = $extrafieldsadminmap[$elementtype]; + +$langs->loadLangs($pagedef['langs']); $extrafields = new ExtraFields($db); $form = new Form($db); @@ -48,11 +59,6 @@ $type2label = ExtraFields::getListOfTypesLabels(); $action = GETPOST('action', 'aZ09'); $attrname = GETPOST('attrname', 'alpha'); -$elementtype = 'societe'; //Must be the $element of the class that manage extrafield - -if (!$user->admin) { - accessforbidden(); -} /* @@ -62,24 +68,24 @@ if (!$user->admin) { require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php'; - /* * View */ -$textobject = $langs->transnoentitiesnoconv("ThirdParty"); +$title = is_callable($pagedef['title']) ? $pagedef['title']() : $langs->trans($pagedef['title']); +$textobject = $langs->transnoentitiesnoconv($pagedef['headlabel']); -$help_url = 'EN:Module Third Parties setup|FR:Paramétrage_du_module_Tiers'; -llxHeader('', $langs->trans("CompanySetup"), $help_url); +$help_url = $pagedef['helpurl']; +llxHeader('', $title, $help_url); $linkback = ''.img_picto($langs->trans("BackToModuleList"), 'back', 'class="pictofixedwidth"').''.$langs->trans("BackToModuleList").''; -print load_fiche_titre($langs->trans("CompanySetup"), $linkback, 'title_setup'); +print load_fiche_titre($title, $linkback, 'title_setup'); +require_once DOL_DOCUMENT_ROOT.'/'.$pagedef['headfile']; +$head = call_user_func($pagedef['headfunction']); -$head = societe_admin_prepare_head(); - -print dol_get_fiche_head($head, 'attributes', $langs->trans("ThirdParties"), -1, 'company'); +print dol_get_fiche_head($head, $pagedef['tabid'], $textobject, -1, $pagedef['headpicto']); require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_view.tpl.php'; diff --git a/htdocs/core/lib/admin_extrafields.lib.php b/htdocs/core/lib/admin_extrafields.lib.php new file mode 100644 index 00000000000..576e94a97db --- /dev/null +++ b/htdocs/core/lib/admin_extrafields.lib.php @@ -0,0 +1,63 @@ + + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +/** + * \file htdocs/core/lib/admin_extrafields.lib.php + * \brief Whitelist of elementtype values accepted by the unified + * extrafields admin page (htdocs/admin/extrafields.php). + * + * This is a closed registry: only elementtype values explicitly listed + * here can ever be processed by the unified extrafields admin page. + * Do not make this dynamic or pattern-based — the whole point is that + * an attacker-controlled string can never reach ExtraFields::addExtraField(), + * ExtraFields::update()/delete(), or the raw SQL built in + * core/actions_extrafields.inc.php, without having first matched one of + * these hardcoded keys. + */ + +/** + * Return the whitelist of elementtype values accepted by + * htdocs/admin/extrafields.php, and the page metadata needed to render + * each one (which tab-bar function to call, which lang files to load, ...). + * + * @return array + */ +function getExtrafieldsAdminMap() +{ + return array( + 'societe' => array( + 'headfunction' => 'societe_admin_prepare_head', + 'headfile' => 'core/lib/company.lib.php', + 'tabid' => 'attributes', + 'headlabel' => 'ThirdParty', + 'headpicto' => 'company', + 'title' => 'CompanySetup', + 'helpurl' => 'EN:Module Third Parties setup|FR:Paramétrage_du_module_Tiers', + 'langs' => array('companies', 'admin', 'members'), + ), + 'socpeople' => array( + 'headfunction' => 'societe_admin_prepare_head', + 'headfile' => 'core/lib/company.lib.php', + 'tabid' => 'attributes_contacts', + 'headlabel' => 'ContactsAddresses', + 'headpicto' => 'company', + 'title' => 'CompanySetup', + 'helpurl' => 'EN:Module Third Parties setup|FR:Paramétrage_du_module_Tiers', + 'langs' => array('companies', 'admin'), + ), + ); +} diff --git a/htdocs/core/lib/company.lib.php b/htdocs/core/lib/company.lib.php index 4fec27a4c3c..32bec731e2e 100644 --- a/htdocs/core/lib/company.lib.php +++ b/htdocs/core/lib/company.lib.php @@ -611,7 +611,7 @@ function societe_admin_prepare_head() // $this->tabs = array('entity:-tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to remove a tab complete_head_from_modules($conf, $langs, null, $head, $h, 'company_admin'); - $head[$h][0] = dolBuildUrl(DOL_URL_ROOT . '/societe/admin/societe_extrafields.php'); + $head[$h][0] = dolBuildUrl(DOL_URL_ROOT . '/admin/extrafields.php', array('elementtype' => 'societe')); $head[$h][1] = $langs->trans("ExtraFieldsThirdParties"); $nbExtrafields = $extrafields->attributes['societe']['count']; if ($nbExtrafields > 0) { @@ -620,7 +620,7 @@ function societe_admin_prepare_head() $head[$h][2] = 'attributes'; $h++; - $head[$h][0] = dolBuildUrl(DOL_URL_ROOT . '/societe/admin/contact_extrafields.php'); + $head[$h][0] = dolBuildUrl(DOL_URL_ROOT . '/admin/extrafields.php', array('elementtype' => 'socpeople')); $head[$h][1] = $langs->trans("ExtraFieldsContacts"); $nbExtrafields = $extrafields->attributes['socpeople']['count']; if ($nbExtrafields > 0) { diff --git a/htdocs/societe/admin/contact_extrafields.php b/htdocs/societe/admin/contact_extrafields.php deleted file mode 100644 index 71f90c34eeb..00000000000 --- a/htdocs/societe/admin/contact_extrafields.php +++ /dev/null @@ -1,107 +0,0 @@ - - * Copyright (C) 2003 Jean-Louis Bergamo - * Copyright (C) 2004-2012 Laurent Destailleur - * Copyright (C) 2012 Regis Houssin - * Copyright (C) 2024 Frédéric France - * - * This program 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. - * - * This program 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 this program. If not, see . - */ - -/** - * \file htdocs/societe/admin/contact_extrafields.php - * \ingroup societe - * \brief Page to setup extra fields of contact - */ - -// Load Dolibarr environment -require '../../main.inc.php'; -require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; -require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; - -/** - * @var Conf $conf - * @var DoliDB $db - * @var HookManager $hookmanager - * @var Translate $langs - * @var User $user - */ - -$langs->loadLangs(array("companies", "admin")); - -$extrafields = new ExtraFields($db); -$form = new Form($db); - -// List of supported format -$type2label = ExtraFields::getListOfTypesLabels(); - -$action = GETPOST('action', 'aZ09'); -$attrname = GETPOST('attrname', 'alpha'); -$elementtype = 'socpeople'; //Must be the $element of the class that manage extrafield - -if (!$user->admin) { - accessforbidden(); -} - - -/* - * Actions - */ - -require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php'; - - - -/* - * View - */ - -$textobject = $langs->transnoentitiesnoconv("ContactsAddresses"); - -$help_url = 'EN:Module Third Parties setup|FR:Paramétrage_du_module_Tiers'; -llxHeader('', $langs->trans("CompanySetup"), $help_url); - -$linkback = ''.img_picto($langs->trans("BackToModuleList"), 'back', 'class="pictofixedwidth"').''.$langs->trans("BackToModuleList").''; - -print load_fiche_titre($langs->trans("CompanySetup"), $linkback, 'title_setup'); - - -$head = societe_admin_prepare_head(); - -print dol_get_fiche_head($head, 'attributes_contacts', $langs->trans("ThirdParties"), -1, 'company'); - -require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_view.tpl.php'; - -print dol_get_fiche_end(); - - -// Creation of an optional field -if ($action == 'create') { - print '
'; - print load_fiche_titre($langs->trans('NewAttribute')); - - require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_add.tpl.php'; -} - -// Edition of an optional field -if ($action == 'edit' && !empty($attrname)) { - print "
"; - print load_fiche_titre($langs->trans("FieldEdition", $attrname)); - - require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_edit.tpl.php'; -} - -// End of page -llxFooter(); -$db->close();