add certificate metadata to db table
Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
This commit is contained in:
@@ -983,7 +983,9 @@ CREATE TABLE IF NOT EXISTS `domain_ssl_settings` (
|
|||||||
`ssl_cert_chainfile` mediumtext,
|
`ssl_cert_chainfile` mediumtext,
|
||||||
`ssl_csr_file` mediumtext,
|
`ssl_csr_file` mediumtext,
|
||||||
`ssl_fullchain_file` mediumtext,
|
`ssl_fullchain_file` mediumtext,
|
||||||
`expirationdate` datetime DEFAULT NULL,
|
`validfromdate` datetime DEFAULT NULL,
|
||||||
|
`validtodate` datetime DEFAULT NULL,
|
||||||
|
`issuer` varchar(255) NOT NULL default '',
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY (`domainid`)
|
UNIQUE KEY (`domainid`)
|
||||||
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
) ENGINE=InnoDB CHARSET=utf8 COLLATE=utf8_general_ci;
|
||||||
|
|||||||
@@ -429,5 +429,27 @@ if (Froxlor::isDatabaseVersion('202302030')) {
|
|||||||
}
|
}
|
||||||
Update::lastStepStatus(0);
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Enhancing ssl data table");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` RENAME COLUMN `expirationdate` TO `validtodate`;");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` ADD `validfromdate` datetime DEFAULT NULL AFTER `ssl_fullchain_file`;");
|
||||||
|
Database::query("ALTER TABLE `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` ADD `issuer` varchar(255) NOT NULL default '' AFTER `validtodate`;");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
|
Update::showUpdateStep("Filling new ssl data fields with existing certificate data");
|
||||||
|
$crt_upd_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "` SET `validfromdate` = :validfromdate, `issuer` = :issuer WHERE `id` = :id");
|
||||||
|
$crt_stmt = Database::prepare("SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`");
|
||||||
|
Database::pexecute($crt_stmt);
|
||||||
|
while ($cert = $crt_stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||||
|
$cert_content = openssl_x509_parse($cert['ssl_cert_file']);
|
||||||
|
if (is_array($cert_content)) {
|
||||||
|
$validfromdate = empty($cert_content['validFrom_time_t']) ? null : date("Y-m-d H:i:s", $cert_content['validFrom_time_t']);
|
||||||
|
$issuer = $cert_content['issuer']['O'] ?? "";
|
||||||
|
Database::pexecute($crt_upd_stmt, ['validfromdate' => $validfromdate, 'issuer' => $issuer, 'id' => $cert['id']]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// clear possible user customized columns
|
||||||
|
Database::query("DELETE FROM `" . TABLE_PANEL_USERCOLUMNS . "` WHERE `section` = 'sslcertificates_list'");
|
||||||
|
Update::lastStepStatus(0);
|
||||||
|
|
||||||
Froxlor::updateToDbVersion('202303150');
|
Froxlor::updateToDbVersion('202303150');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,7 +127,9 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
$do_verify = true;
|
$do_verify = true;
|
||||||
$expirationdate = null;
|
$validtodate = null;
|
||||||
|
$validtodate = null;
|
||||||
|
$issuer = "";
|
||||||
// no cert-file given -> forget everything
|
// no cert-file given -> forget everything
|
||||||
if ($ssl_cert_file == '') {
|
if ($ssl_cert_file == '') {
|
||||||
$ssl_key_file = '';
|
$ssl_key_file = '';
|
||||||
@@ -168,7 +170,10 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
} else {
|
} else {
|
||||||
Response::standardError('sslcertificateinvalidcert', '', true);
|
Response::standardError('sslcertificateinvalidcert', '', true);
|
||||||
}
|
}
|
||||||
$expirationdate = empty($cert_content['validTo_time_t']) ? null : date("Y-m-d H:i:s", $cert_content['validTo_time_t']);
|
// get data from certificate to store in the table
|
||||||
|
$validfromdate = empty($cert_content['validFrom_time_t']) ? null : date("Y-m-d H:i:s", $cert_content['validFrom_time_t']);
|
||||||
|
$validtodate = empty($cert_content['validTo_time_t']) ? null : date("Y-m-d H:i:s", $cert_content['validTo_time_t']);
|
||||||
|
$issuer = $cert_content['issuer']['O'] ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add/Update database entry
|
// Add/Update database entry
|
||||||
@@ -183,7 +188,9 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
`ssl_key_file` = :ssl_key_file,
|
`ssl_key_file` = :ssl_key_file,
|
||||||
`ssl_ca_file` = :ssl_ca_file,
|
`ssl_ca_file` = :ssl_ca_file,
|
||||||
`ssl_cert_chainfile` = :ssl_cert_chainfile,
|
`ssl_cert_chainfile` = :ssl_cert_chainfile,
|
||||||
`expirationdate` = :expirationdate
|
`validfromdate` = :validfromdate,
|
||||||
|
`validtodate` = :validtodate,
|
||||||
|
`issuer` = :issuer
|
||||||
" . $qrywhere . " `domainid`= :domainid
|
" . $qrywhere . " `domainid`= :domainid
|
||||||
");
|
");
|
||||||
$params = [
|
$params = [
|
||||||
@@ -191,7 +198,9 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
"ssl_key_file" => $ssl_key_file,
|
"ssl_key_file" => $ssl_key_file,
|
||||||
"ssl_ca_file" => $ssl_ca_file,
|
"ssl_ca_file" => $ssl_ca_file,
|
||||||
"ssl_cert_chainfile" => $ssl_cert_chainfile,
|
"ssl_cert_chainfile" => $ssl_cert_chainfile,
|
||||||
"expirationdate" => $expirationdate,
|
"validfromdate" => $validfromdate,
|
||||||
|
"validtodate" => $validtodate,
|
||||||
|
"issuer" => $issuer,
|
||||||
"domainid" => $domainid
|
"domainid" => $domainid
|
||||||
];
|
];
|
||||||
Database::pexecute($stmt, $params, true, true);
|
Database::pexecute($stmt, $params, true, true);
|
||||||
@@ -299,27 +308,23 @@ class Certificates extends ApiCommand implements ResourceEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set data from certificate
|
// Set data from certificate
|
||||||
|
$cert['isvalid'] = false;
|
||||||
|
$cert['san'] = null;
|
||||||
$cert_data = openssl_x509_parse($cert['ssl_cert_file']);
|
$cert_data = openssl_x509_parse($cert['ssl_cert_file']);
|
||||||
if ($cert_data) {
|
if ($cert_data) {
|
||||||
$cert['validfromdate'] = date('Y-m-d H:i:s', $cert_data['validFrom_time_t']);
|
|
||||||
$cert['validtodate'] = date('Y-m-d H:i:s', $cert_data['validTo_time_t']);
|
|
||||||
$cert['isvalid'] = (bool)$cert_data['validTo_time_t'] > time();
|
$cert['isvalid'] = (bool)$cert_data['validTo_time_t'] > time();
|
||||||
$cert['issuer'] = $cert_data['issuer']['O'] ?? null;
|
// Set subject alt names from certificate
|
||||||
}
|
if (isset($cert_data['extensions']['subjectAltName']) && !empty($cert_data['extensions']['subjectAltName'])) {
|
||||||
|
$SANs = explode(",", $cert_data['extensions']['subjectAltName']);
|
||||||
// Set subject alt names from certificate
|
$SANs = array_map('trim', $SANs);
|
||||||
$cert['san'] = null;
|
foreach ($SANs as $san) {
|
||||||
if (isset($cert_data['extensions']['subjectAltName']) && !empty($cert_data['extensions']['subjectAltName'])) {
|
$san = str_replace("DNS:", "", $san);
|
||||||
$SANs = explode(",", $cert_data['extensions']['subjectAltName']);
|
if ($san != $cert_data['subject']['CN'] && strpos($san, "othername:") === false) {
|
||||||
$SANs = array_map('trim', $SANs);
|
$cert['san'][] = $san;
|
||||||
foreach ($SANs as $san) {
|
}
|
||||||
$san = str_replace("DNS:", "", $san);
|
|
||||||
if ($san != $cert_data['subject']['CN'] && strpos($san, "othername:") === false) {
|
|
||||||
$cert['san'][] = $san;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$result[] = $cert;
|
$result[] = $cert;
|
||||||
}
|
}
|
||||||
return $this->response([
|
return $this->response([
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ final class ValidateAcmeWebroot extends CliCommand
|
|||||||
'domain' => Settings::Get('system.hostname')
|
'domain' => Settings::Get('system.hostname')
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
$upd_stmt = Database::prepare("UPDATE domain_ssl_settings SET expirationdate=NULL WHERE `domainid` = :did");
|
$upd_stmt = Database::prepare("UPDATE domain_ssl_settings SET `validtodate`=NULL WHERE `domainid` = :did");
|
||||||
$acmesh_dir = dirname(Settings::Get('system.acmeshpath'));
|
$acmesh_dir = dirname(Settings::Get('system.acmeshpath'));
|
||||||
$acmesh_challenge_dir = rtrim(FileDir::makeCorrectDir(Settings::Get('system.letsencryptchallengepath')), "/");
|
$acmesh_challenge_dir = rtrim(FileDir::makeCorrectDir(Settings::Get('system.letsencryptchallengepath')), "/");
|
||||||
$recommended = rtrim(FileDir::makeCorrectDir(Froxlor::getInstallDir()), "/");
|
$recommended = rtrim(FileDir::makeCorrectDir(Froxlor::getInstallDir()), "/");
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ class HttpConfigBase
|
|||||||
$froxlor_ssl_settings_stmt = Database::prepare("
|
$froxlor_ssl_settings_stmt = Database::prepare("
|
||||||
SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
|
SELECT * FROM `" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
|
||||||
WHERE `domainid` = '0' AND
|
WHERE `domainid` = '0' AND
|
||||||
(`expirationdate` < DATE_ADD(NOW(), INTERVAL 30 DAY) OR `expirationdate` IS NULL)
|
(`validtodate` < DATE_ADD(NOW(), INTERVAL 30 DAY) OR `validtodate` IS NULL)
|
||||||
");
|
");
|
||||||
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
|
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
|
||||||
if ($froxlor_ssl && !empty($froxlor_ssl['ssl_cert_file'])) {
|
if ($froxlor_ssl && !empty($froxlor_ssl['ssl_cert_file'])) {
|
||||||
|
|||||||
@@ -114,7 +114,9 @@ class AcmeSh extends FroxlorCron
|
|||||||
`ssl_cert_chainfile` = :chain,
|
`ssl_cert_chainfile` = :chain,
|
||||||
`ssl_csr_file` = :csr,
|
`ssl_csr_file` = :csr,
|
||||||
`ssl_fullchain_file` = :fullchain,
|
`ssl_fullchain_file` = :fullchain,
|
||||||
`expirationdate` = :expirationdate
|
`validfromdate` = :validfromdate,
|
||||||
|
`validtodate` = :validtodate,
|
||||||
|
`issuer` = :issuer
|
||||||
");
|
");
|
||||||
|
|
||||||
// prepare domain update sql
|
// prepare domain update sql
|
||||||
@@ -136,7 +138,9 @@ class AcmeSh extends FroxlorCron
|
|||||||
'lepublickey' => Settings::Get('system.lepublickey'),
|
'lepublickey' => Settings::Get('system.lepublickey'),
|
||||||
'leregistered' => Settings::Get('system.leregistered'),
|
'leregistered' => Settings::Get('system.leregistered'),
|
||||||
'ssl_redirect' => Settings::Get('system.le_froxlor_redirect'),
|
'ssl_redirect' => Settings::Get('system.le_froxlor_redirect'),
|
||||||
'expirationdate' => null,
|
'validfromdate' => null,
|
||||||
|
'validtodate' => null,
|
||||||
|
'issuer' => "",
|
||||||
'ssl_cert_file' => null,
|
'ssl_cert_file' => null,
|
||||||
'ssl_key_file' => null,
|
'ssl_key_file' => null,
|
||||||
'ssl_ca_file' => null,
|
'ssl_ca_file' => null,
|
||||||
@@ -171,7 +175,9 @@ class AcmeSh extends FroxlorCron
|
|||||||
'lepublickey' => Settings::Get('system.lepublickey'),
|
'lepublickey' => Settings::Get('system.lepublickey'),
|
||||||
'leregistered' => Settings::Get('system.leregistered'),
|
'leregistered' => Settings::Get('system.leregistered'),
|
||||||
'ssl_redirect' => Settings::Get('system.le_froxlor_redirect'),
|
'ssl_redirect' => Settings::Get('system.le_froxlor_redirect'),
|
||||||
'expirationdate' => is_array($renew_froxlor) ? $renew_froxlor['expirationdate'] : date('Y-m-d H:i:s', 0),
|
'validfromdate' => is_array($renew_froxlor) ? $renew_froxlor['validfromdate'] : date('Y-m-d H:i:s', 0),
|
||||||
|
'validtodate' => is_array($renew_froxlor) ? $renew_froxlor['validtodate'] : date('Y-m-d H:i:s', 0),
|
||||||
|
'issuer' => is_array($renew_froxlor) ? $renew_froxlor['issuer'] : "",
|
||||||
'ssl_cert_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_cert_file'] : null,
|
'ssl_cert_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_cert_file'] : null,
|
||||||
'ssl_key_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_key_file'] : null,
|
'ssl_key_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_key_file'] : null,
|
||||||
'ssl_ca_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_ca_file'] : null,
|
'ssl_ca_file' => is_array($renew_froxlor) ? $renew_froxlor['ssl_ca_file'] : null,
|
||||||
@@ -187,7 +193,7 @@ class AcmeSh extends FroxlorCron
|
|||||||
'loginname' => $domain['loginname'],
|
'loginname' => $domain['loginname'],
|
||||||
'adminsession' => 0
|
'adminsession' => 0
|
||||||
]);
|
]);
|
||||||
if (defined('CRON_IS_FORCED') || self::checkFsFilesAreNewer($domain['domain'], $domain['expirationdate'])) {
|
if (defined('CRON_IS_FORCED') || self::checkFsFilesAreNewer($domain['domain'], $domain['validtodate'])) {
|
||||||
self::certToDb($domain, $cronlog, []);
|
self::certToDb($domain, $cronlog, []);
|
||||||
$changedetected = 1;
|
$changedetected = 1;
|
||||||
}
|
}
|
||||||
@@ -279,7 +285,9 @@ EOC;
|
|||||||
SELECT
|
SELECT
|
||||||
domssl.`id`,
|
domssl.`id`,
|
||||||
domssl.`domainid`,
|
domssl.`domainid`,
|
||||||
domssl.`expirationdate`,
|
domssl.`validfromdate`,
|
||||||
|
domssl.`validtodate`,
|
||||||
|
domssl.`issuer`,
|
||||||
domssl.`ssl_cert_file`,
|
domssl.`ssl_cert_file`,
|
||||||
domssl.`ssl_key_file`,
|
domssl.`ssl_key_file`,
|
||||||
domssl.`ssl_ca_file`,
|
domssl.`ssl_ca_file`,
|
||||||
@@ -306,7 +314,7 @@ EOC;
|
|||||||
AND dom.`letsencrypt` = 1
|
AND dom.`letsencrypt` = 1
|
||||||
AND dom.`aliasdomain` IS NULL
|
AND dom.`aliasdomain` IS NULL
|
||||||
AND dom.`iswildcarddomain` = 0
|
AND dom.`iswildcarddomain` = 0
|
||||||
AND domssl.`expirationdate` IS NULL
|
AND domssl.`validtodate` IS NULL
|
||||||
");
|
");
|
||||||
$customer_ssl = $certificates_stmt->fetchAll(PDO::FETCH_ASSOC);
|
$customer_ssl = $certificates_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
if ($customer_ssl) {
|
if ($customer_ssl) {
|
||||||
@@ -330,7 +338,7 @@ EOC;
|
|||||||
");
|
");
|
||||||
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
|
$froxlor_ssl = Database::pexecute_first($froxlor_ssl_settings_stmt);
|
||||||
// also check for possible existing certificate
|
// also check for possible existing certificate
|
||||||
if ($froxlor_ssl && self::checkFsFilesAreNewer(Settings::Get('system.hostname'), $froxlor_ssl['expirationdate'])) {
|
if ($froxlor_ssl && self::checkFsFilesAreNewer(Settings::Get('system.hostname'), $froxlor_ssl['validtodate'])) {
|
||||||
return $froxlor_ssl;
|
return $froxlor_ssl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -346,7 +354,9 @@ EOC;
|
|||||||
SELECT
|
SELECT
|
||||||
domssl.`id`,
|
domssl.`id`,
|
||||||
domssl.`domainid`,
|
domssl.`domainid`,
|
||||||
domssl.`expirationdate`,
|
domssl.`validfromdate`,
|
||||||
|
domssl.`validtodate`,
|
||||||
|
domssl.`issuer`,
|
||||||
domssl.`ssl_cert_file`,
|
domssl.`ssl_cert_file`,
|
||||||
domssl.`ssl_key_file`,
|
domssl.`ssl_key_file`,
|
||||||
dom.`domain`,
|
dom.`domain`,
|
||||||
@@ -370,7 +380,7 @@ EOC;
|
|||||||
if ($renew_certs) {
|
if ($renew_certs) {
|
||||||
if ($check) {
|
if ($check) {
|
||||||
foreach ($renew_certs as $cert) {
|
foreach ($renew_certs as $cert) {
|
||||||
if (self::checkFsFilesAreNewer($cert['domain'], $cert['expirationdate'])) {
|
if (self::checkFsFilesAreNewer($cert['domain'], $cert['validtodate'])) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -453,7 +463,7 @@ EOC;
|
|||||||
// Only issue let's encrypt certificate if no broken ssl_redirect is enabled
|
// Only issue let's encrypt certificate if no broken ssl_redirect is enabled
|
||||||
if ($certrow['ssl_redirect'] != 2) {
|
if ($certrow['ssl_redirect'] != 2) {
|
||||||
$do_force = false;
|
$do_force = false;
|
||||||
if (!empty($certrow['ssl_cert_file']) && empty($certrow['expirationdate'])) {
|
if (!empty($certrow['ssl_cert_file']) && empty($certrow['validtodate'])) {
|
||||||
// domain changed (SAN or similar)
|
// domain changed (SAN or similar)
|
||||||
$do_force = true;
|
$do_force = true;
|
||||||
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Re-creating certificate for " . $certrow['domain']);
|
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, "Re-creating certificate for " . $certrow['domain']);
|
||||||
@@ -594,7 +604,9 @@ EOC;
|
|||||||
'chain' => $return['chain'],
|
'chain' => $return['chain'],
|
||||||
'csr' => $return['csr'],
|
'csr' => $return['csr'],
|
||||||
'fullchain' => $return['fullchain'],
|
'fullchain' => $return['fullchain'],
|
||||||
'expirationdate' => date('Y-m-d H:i:s', $newcert['validTo_time_t'])
|
'validfromdate' => date('Y-m-d H:i:s', $newcert['validFrom_time_t']),
|
||||||
|
'validtodate' => date('Y-m-d H:i:s', $newcert['validTo_time_t']),
|
||||||
|
'issuer' => $newcert['issuer']['O'] ?? ""
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if ($certrow['ssl_redirect'] == 3) {
|
if ($certrow['ssl_redirect'] == 3) {
|
||||||
|
|||||||
@@ -350,7 +350,7 @@ class Domain
|
|||||||
$upd_stmt = Database::prepare("UPDATE
|
$upd_stmt = Database::prepare("UPDATE
|
||||||
`" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
|
`" . TABLE_PANEL_DOMAIN_SSL_SETTINGS . "`
|
||||||
SET
|
SET
|
||||||
`expirationdate` = null
|
`validtodate` = null
|
||||||
WHERE
|
WHERE
|
||||||
domainid = :domainid
|
domainid = :domainid
|
||||||
");
|
");
|
||||||
|
|||||||
@@ -45,31 +45,27 @@ return [
|
|||||||
'callback' => [SSLCertificate::class, 'domainWithSan'],
|
'callback' => [SSLCertificate::class, 'domainWithSan'],
|
||||||
'searchable' => false,
|
'searchable' => false,
|
||||||
],
|
],
|
||||||
'c.issuer' => [
|
's.issuer' => [
|
||||||
'label' => lng('ssl_certificates.issuer'),
|
'label' => lng('ssl_certificates.issuer'),
|
||||||
'field' => 'issuer',
|
'field' => 'issuer',
|
||||||
'searchable' => false,
|
|
||||||
'sortable' => false,
|
|
||||||
],
|
],
|
||||||
'c.validfromdate' => [
|
's.validfromdate' => [
|
||||||
'label' => lng('ssl_certificates.valid_from'),
|
'label' => lng('ssl_certificates.valid_from'),
|
||||||
'field' => 'validfromdate',
|
'field' => 'validfromdate',
|
||||||
'searchable' => false,
|
'searchable' => false,
|
||||||
'sortable' => false,
|
|
||||||
],
|
],
|
||||||
'c.validtodate' => [
|
's.validtodate' => [
|
||||||
'label' => lng('ssl_certificates.valid_until'),
|
'label' => lng('ssl_certificates.valid_until'),
|
||||||
'field' => 'validtodate',
|
'field' => 'validtodate',
|
||||||
'searchable' => false,
|
'searchable' => false,
|
||||||
'sortable' => false,
|
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'visible_columns' => Listing::getVisibleColumnsForListing('sslcertificates_list', [
|
'visible_columns' => Listing::getVisibleColumnsForListing('sslcertificates_list', [
|
||||||
'd.domain',
|
'd.domain',
|
||||||
'c.domain',
|
'c.domain',
|
||||||
'c.issuer',
|
's.issuer',
|
||||||
'c.validfromdate',
|
's.validfromdate',
|
||||||
'c.validtodate',
|
's.validtodate',
|
||||||
]),
|
]),
|
||||||
'actions' => [
|
'actions' => [
|
||||||
'edit' => [
|
'edit' => [
|
||||||
|
|||||||
Reference in New Issue
Block a user