app secrets

This commit is contained in:
Yuri Kuznetsov
2024-09-16 12:26:03 +03:00
parent 4ff8369180
commit 3c57b7e39e
19 changed files with 471 additions and 3 deletions

View File

@@ -0,0 +1,61 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Classes\Record\AppSecret;
use Espo\Core\Exceptions\BadRequest;
use Espo\Core\Record\Input\Data;
use Espo\Core\Record\Input\Filter;
use Espo\Core\Utils\Crypt;
/**
* @noinspection PhpUnused
*/
class ValueInputFilter implements Filter
{
private const ATTR_VALUE = 'value';
public function __construct(private Crypt $crypt) {}
/**
* @throws BadRequest
*/
public function filter(Data $data): void
{
$value = $data->get(self::ATTR_VALUE);
if ($value !== null) {
if (!is_string($value)) {
throw new BadRequest();
}
$data->set(self::ATTR_VALUE, $this->crypt->encrypt($value));
}
}
}

View File

@@ -0,0 +1,43 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Controllers;
use Espo\Core\Controllers\Record;
/**
* @noinspection PhpUnused
*/
class AppSecret extends Record
{
protected function checkAccess(): bool
{
return $this->user->isAdmin();
}
}

View File

@@ -0,0 +1,65 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Entities;
use Espo\Core\ORM\Entity;
class AppSecret extends Entity
{
public const ENTITY_TYPE = 'AppSecret';
public function getName(): string
{
return $this->get('name');
}
public function getValue(): string
{
return (string) $this->get('value');
}
public function setName(string $name): self
{
$this->set('name', $name);
return $this;
}
/**
* @internal Do not use.
* @todo Rename to setValue in v9.0.
*/
public function setSecretValue(string $value): self
{
$this->set('value', $value);
return $this;
}
}

View File

@@ -38,6 +38,7 @@
"Auth Tokens": "Auth Tokens",
"Auth Log": "Auth Log",
"App Log": "App Log",
"App Secrets": "App Secrets",
"Authentication": "Authentication",
"Currency": "Currency",
"Integrations": "Integrations",
@@ -297,6 +298,7 @@
"templateManager": "Customize message templates.",
"authLog": "Login history.",
"appLog": "Application log.",
"appSecrets": "Store sensitive information like API keys, passwords, and other secrets.",
"leadCapture": "API entry points for Web-to-Lead.",
"attachments": "All file attachments stored in the system.",
"systemRequirements": "System Requirements for EspoCRM.",
@@ -325,7 +327,8 @@
"entityManager": "fields,relations,relationships",
"templateManager": "notifications",
"jobs": "cron",
"labelManager": "language,translation"
"labelManager": "language,translation",
"appSecrets": "key,keys,password"
},
"options": {
"previewSize": {

View File

@@ -0,0 +1,11 @@
{
"labels": {
"Create AppSecret": "Create Secret"
},
"fields": {
"value": "Value"
},
"tooltips": {
"name": "Allowed characters:\n* `[a-z]`\n* `[A-Z]`\n* `[0-9]`\n* `_`"
}
}

View File

@@ -63,7 +63,8 @@
"WorkingTimeRange": "Working Time Exception",
"AuthenticationProvider": "Authentication Provider",
"GlobalStream": "Global Stream",
"AddressCountry": "Address Country"
"AddressCountry": "Address Country",
"AppSecret": "App Secret"
},
"scopeNamesPlural": {
"Note": "Notes",
@@ -117,7 +118,8 @@
"WorkingTimeRange": "Working Time Exceptions",
"AuthenticationProvider": "Authentication Providers",
"GlobalStream": "Global Stream",
"AddressCountry": "Address Countries"
"AddressCountry": "Address Countries",
"AppSecret": "App Secrets"
},
"labels": {
"Previous Page": "Previous Page",

View File

@@ -0,0 +1,13 @@
[
{
"rows": [
[{"name": "name"}, false],
[{"name": "value"}]
]
},
{
"rows": [
[{"name": "description"}]
]
}
]

View File

@@ -0,0 +1,13 @@
[
{
"rows": [
[{"name": "name"}],
[{"name": "value"}]
]
},
{
"rows": [
[{"name": "description"}]
]
}
]

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,10 @@
[
{
"name": "name",
"link": true
},
{
"name": "description",
"width": 50
}
]

View File

@@ -338,6 +338,12 @@
"iconClass": "fas fa-phone",
"description": "phoneNumbers"
},
{
"url": "#Admin/appSecrets",
"label": "App Secrets",
"iconClass": "fas fa-key",
"description": "appSecrets"
},
{
"url": "#Admin/appLog",
"label": "App Log",

View File

@@ -0,0 +1,6 @@
{
"controller": "controllers/record",
"mergeDisabled": true,
"exportDisabled": true,
"massUpdateDisabled": true
}

View File

@@ -0,0 +1,7 @@
{
"fields": {
"value": {
"internal": true
}
}
}

View File

@@ -0,0 +1,61 @@
{
"fields": {
"name": {
"type": "varchar",
"maxLength": 100,
"required": true,
"pattern": "[a-zA-Z]{1}[a-zA-Z0-9_]+",
"index": true,
"tooltip": true
},
"value": {
"type": "text",
"required": true,
"view": "views/admin/app-secret/fields/value"
},
"description": {
"type": "text"
},
"createdAt": {
"type": "datetime",
"readOnly": true
},
"modifiedAt": {
"type": "datetime",
"readOnly": true
},
"createdBy": {
"type": "link",
"readOnly": true
},
"modifiedBy": {
"type": "link",
"readOnly": true
}
},
"links": {
"createdBy": {
"type": "belongsTo",
"entity": "User"
},
"modifiedBy": {
"type": "belongsTo",
"entity": "User"
}
},
"collection": {
"orderBy": "name",
"order": "asc",
"textFilterFields": ["name"]
},
"indexes": {
"nameDeleteId": {
"type": "unique",
"columns": [
"name",
"deleteId"
]
}
},
"deleteId": true
}

View File

@@ -0,0 +1,9 @@
{
"createInputFilterClassNameList": [
"Espo\\Classes\\Record\\AppSecret\\ValueInputFilter"
],
"updateInputFilterClassNameList": [
"Espo\\Classes\\Record\\AppSecret\\ValueInputFilter"
],
"duplicateWhereBuilderClassName": "Espo\\Classes\\DuplicateWhereBuilders\\General"
}

View File

@@ -0,0 +1,8 @@
{
"entity": true,
"layouts": false,
"tab": false,
"acl": false,
"customizable": false,
"duplicateCheckFieldList": ["name"]
}

View File

@@ -0,0 +1,64 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Tools\AppSecret;
use Espo\Core\Utils\Crypt;
use Espo\Entities\AppSecret;
use Espo\ORM\EntityManager;
/**
* @since 8.5.0
* @noinspection PhpUnused
*/
class SecretProvider
{
public function __construct(
private Crypt $crypt,
private EntityManager $entityManager,
) {}
/**
* Get an app secret value
* @param string $name A secret name.
*/
public function get(string $name): ?string
{
$secret = $this->entityManager
->getRDBRepositoryByClass(AppSecret::class)
->where(['name' => $name])
->findOne();
if (!$secret) {
return null;
}
return $this->crypt->decrypt($secret->getValue());
}
}

View File

@@ -394,6 +394,11 @@ class AdminController extends Controller {
});
}
// noinspection JSUnusedGlobalSymbols
actionAppSecrets() {
this.getRouter().dispatch('AppSecret', 'list', {fromAdmin: true});
}
// noinspection JSUnusedGlobalSymbols
actionJobs() {
this.collectionFactory.create('Job', collection => {

View File

@@ -0,0 +1,80 @@
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
import TextFieldView from 'views/fields/text';
export default class extends TextFieldView {
detailTemplateContent = `**********`
validations = ['required']
changingMode = false
data() {
return {
isNew: this.model.isNew(),
...super.data(),
};
}
afterRenderEdit() {
super.afterRenderEdit();
if (!this.model.isNew() && !this.changingMode) {
this.element.innerHTML = '';
const a = document.createElement('a');
a.role = 'button';
a.onclick = () => this.changePassword();
a.textContent = this.translate('change');
this.element.appendChild(a);
}
}
onDetailModeSet() {
this.changingMode = false;
return super.onDetailModeSet();
}
fetch() {
if (!this.model.isNew() && !this.changingMode) {
return {};
}
return super.fetch();
}
async changePassword() {
this.changingMode = true;
await this.reRender();
}
}