Compare commits
8 Commits
32f5b0d5e9
...
upgrade-2.
| Author | SHA1 | Date | |
|---|---|---|---|
| d7a3568506 | |||
| 10c13bc5b1 | |||
| dcb3f6f568 | |||
| 7566def0d1 | |||
| 3630f82817 | |||
| 9ddd2e9154 | |||
| 53afe4ebd1 | |||
| 4f69e8ee0e |
@@ -299,6 +299,30 @@ if ($page == 'email_domain') {
|
||||
'action' => 'edit',
|
||||
'id' => $id,
|
||||
]);
|
||||
} elseif ($action == 'togglegreylist' && $id != 0) {
|
||||
try {
|
||||
$json_result = Emails::getLocal($userinfo, [
|
||||
'id' => $id
|
||||
])->get();
|
||||
} catch (Exception $e) {
|
||||
Response::dynamicError($e->getMessage());
|
||||
}
|
||||
$result = json_decode($json_result, true)['data'];
|
||||
|
||||
try {
|
||||
Emails::getLocal($userinfo, [
|
||||
'id' => $id,
|
||||
'disablegreylist' => ($result['disablegreylist'] == '1' ? 0 : 1)
|
||||
])->updateGreylist();
|
||||
} catch (Exception $e) {
|
||||
Response::dynamicError($e->getMessage());
|
||||
}
|
||||
Response::redirectTo($filename, [
|
||||
'page' => $page,
|
||||
'domainid' => $email_domainid,
|
||||
'action' => 'edit',
|
||||
'id' => $id,
|
||||
]);
|
||||
}
|
||||
} elseif ($page == 'accounts') {
|
||||
$email_domainid = Request::any('domainid', 0);
|
||||
|
||||
@@ -75,6 +75,7 @@ class Emails extends ApiCommand implements ResourceEntity
|
||||
|
||||
// parameters
|
||||
$iscatchall = $this->getBoolParam('iscatchall', true, 0);
|
||||
$disablegreylist = $this->getBoolParam('disablegreylist', true, 0);
|
||||
$description = $this->getParam('description', true, '');
|
||||
|
||||
// validation
|
||||
@@ -118,7 +119,7 @@ class Emails extends ApiCommand implements ResourceEntity
|
||||
|
||||
// duplicate check
|
||||
$stmt = Database::prepare("
|
||||
SELECT `id`, `email`, `email_full`, `iscatchall`, `destination`, `customerid` FROM `" . TABLE_MAIL_VIRTUAL . "`
|
||||
SELECT `id`, `email`, `email_full`, `iscatchall`, `destination`, `customerid`, `disablegreylist` FROM `" . TABLE_MAIL_VIRTUAL . "`
|
||||
WHERE (`email` = :email OR `email_full` = :emailfull )
|
||||
AND `customerid`= :cid
|
||||
");
|
||||
@@ -144,7 +145,8 @@ class Emails extends ApiCommand implements ResourceEntity
|
||||
`email_full` = :email_full,
|
||||
`iscatchall` = :iscatchall,
|
||||
`domainid` = :domainid,
|
||||
`description` = :description
|
||||
`description` = :description,
|
||||
`disablegreylist` = :disablegreylist
|
||||
");
|
||||
$params = [
|
||||
"cid" => $customer['customerid'],
|
||||
@@ -152,7 +154,8 @@ class Emails extends ApiCommand implements ResourceEntity
|
||||
"email_full" => $email_full,
|
||||
"iscatchall" => $iscatchall,
|
||||
"domainid" => $domain_check['id'],
|
||||
"description" => $description
|
||||
"description" => $description,
|
||||
"disablegreylist" => $disablegreylist
|
||||
];
|
||||
Database::pexecute($stmt, $params, true, true);
|
||||
|
||||
@@ -191,7 +194,7 @@ class Emails extends ApiCommand implements ResourceEntity
|
||||
$customer_ids = $this->getAllowedCustomerIds('email');
|
||||
$params['idea'] = ($id <= 0 ? $emailaddr : $id);
|
||||
|
||||
$result_stmt = Database::prepare("SELECT v.`id`, v.`email`, v.`email_full`, v.`iscatchall`, v.`destination`, v.`customerid`, v.`popaccountid`, v.`domainid`, v.`description`, u.`quota`, u.`imap`, u.`pop3`, u.`postfix`, u.`mboxsize`
|
||||
$result_stmt = Database::prepare("SELECT v.`id`, v.`email`, v.`email_full`, v.`iscatchall`, v.`disablegreylist`, v.`destination`, v.`customerid`, v.`popaccountid`, v.`domainid`, v.`description`, u.`quota`, u.`imap`, u.`pop3`, u.`postfix`, u.`mboxsize`
|
||||
FROM `" . TABLE_MAIL_VIRTUAL . "` v
|
||||
LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON v.`popaccountid` = u.`id`
|
||||
WHERE v.`customerid` IN (" . implode(", ", $customer_ids) . ")
|
||||
@@ -302,6 +305,81 @@ class Emails extends ApiCommand implements ResourceEntity
|
||||
return $this->response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* toggle greylist flag of given email address either by id or email-address
|
||||
*
|
||||
* @param int $id
|
||||
* optional, the email-address-id
|
||||
* @param string $emailaddr
|
||||
* optional, the email-address
|
||||
* @param int $customerid
|
||||
* optional, required when called as admin (if $loginname is not specified)
|
||||
* @param string $loginname
|
||||
* optional, required when called as admin (if $customerid is not specified)
|
||||
* @param boolean $greylist
|
||||
* optional
|
||||
* @param string $description
|
||||
* optional custom description (currently not used/shown in the frontend), default empty
|
||||
*
|
||||
* @access admin, customer
|
||||
* @return string json-encoded array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function updateGreylist()
|
||||
{
|
||||
if ($this->isAdmin() == false && Settings::IsInList('panel.customer_hide_options', 'email')) {
|
||||
throw new Exception("You cannot access this resource", 405);
|
||||
}
|
||||
|
||||
// if enabling catchall is not allowed by settings, we do not need
|
||||
// to run update()
|
||||
/** if (Settings::Get('catchall.catchall_enabled') != '1') {
|
||||
Response::standardError([
|
||||
'operationnotpermitted',
|
||||
'featureisdisabled'
|
||||
], 'catchall', true);
|
||||
} */
|
||||
|
||||
$id = $this->getParam('id', true, 0);
|
||||
$ea_optional = $id > 0;
|
||||
$emailaddr = $this->getParam('emailaddr', $ea_optional, '');
|
||||
|
||||
$result = $this->apiCall('Emails.get', [
|
||||
'id' => $id,
|
||||
'emailaddr' => $emailaddr
|
||||
]);
|
||||
$id = $result['id'];
|
||||
$email = $result['email'];
|
||||
|
||||
|
||||
// parameters
|
||||
$disablegreylist = $this->getBoolParam('disablegreylist', true, $result['disablegreylist']);
|
||||
$description = $this->getParam('description', true, $result['description']);
|
||||
|
||||
// get needed customer info to reduce the email-address-counter by one
|
||||
$customer = $this->getCustomerData();
|
||||
|
||||
// check for catchall-flag
|
||||
$stmt = Database::prepare("
|
||||
UPDATE `" . TABLE_MAIL_VIRTUAL . "`
|
||||
SET `email` = :email , `disablegreylist` = :grflag, `description` = :description
|
||||
WHERE `customerid`= :cid AND `id`= :id
|
||||
");
|
||||
$params = [
|
||||
"email" => $email,
|
||||
"grflag" => $disablegreylist,
|
||||
"description" => $description,
|
||||
"cid" => $customer['customerid'],
|
||||
"id" => $id
|
||||
];
|
||||
Database::pexecute($stmt, $params, true, true);
|
||||
$this->logger()->logAction($this->isAdmin() ? FroxlorLogger::ADM_ACTION : FroxlorLogger::USR_ACTION, LOG_NOTICE, "[API] toggled greylist-flag for email address '" . $result['email_full'] . "'");
|
||||
|
||||
$result = $this->apiCall('Emails.get', [
|
||||
'emailaddr' => $result['email_full']
|
||||
]);
|
||||
return $this->response($result);
|
||||
}
|
||||
/**
|
||||
* list all email addresses, if called from an admin, list all email addresses of all customers you are allowed to
|
||||
* view, or specify id or loginname for one specific customer
|
||||
@@ -331,7 +409,7 @@ class Emails extends ApiCommand implements ResourceEntity
|
||||
$result = [];
|
||||
$query_fields = [];
|
||||
$result_stmt = Database::prepare("
|
||||
SELECT m.`id`, m.`domainid`, m.`email`, m.`email_full`, m.`iscatchall`, m.`destination`, m.`popaccountid`, d.`domain`, u.`quota`, u.`imap`, u.`pop3`, u.`postfix`, u.`mboxsize`
|
||||
SELECT m.`id`, m.`domainid`, m.`email`, m.`email_full`, m.`iscatchall`, m.`disablegreylist`, m.`destination`, m.`popaccountid`, d.`domain`, u.`quota`, u.`imap`, u.`pop3`, u.`postfix`, u.`mboxsize`
|
||||
FROM `" . TABLE_MAIL_VIRTUAL . "` m
|
||||
LEFT JOIN `" . TABLE_PANEL_DOMAINS . "` d ON (m.`domainid` = d.`id`)
|
||||
LEFT JOIN `" . TABLE_MAIL_USERS . "` u ON (m.`popaccountid` = u.`id`)
|
||||
|
||||
@@ -132,18 +132,16 @@ abstract class DnsBase
|
||||
");
|
||||
|
||||
while ($domain = $result_domains_stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
$privkey_filename = FileDir::makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/dkim' . $domain['dkim_id'] . Settings::Get('dkim.privkeysuffix'));
|
||||
$pubkey_filename = FileDir::makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/dkim' . $domain['dkim_id'] . '.public');
|
||||
$privkey_filename = FileDir::makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/mx.' . $domain['domain'] . '.' . Settings::Get('dkim.privkeysuffix'));
|
||||
$pubkey_filename = FileDir::makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/mx.' . $domain['domain'] . '.public');
|
||||
|
||||
if ($domain['dkim_privkey'] == '' || $domain['dkim_pubkey'] == '') {
|
||||
$max_dkim_id_stmt = Database::query("SELECT MAX(`dkim_id`) as `max_dkim_id` FROM `" . TABLE_PANEL_DOMAINS . "`");
|
||||
$max_dkim_id = $max_dkim_id_stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$domain['dkim_id'] = (int)$max_dkim_id['max_dkim_id'] + 1;
|
||||
$privkey_filename = FileDir::makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/dkim' . $domain['dkim_id'] . Settings::Get('dkim.privkeysuffix'));
|
||||
FileDir::safe_exec('openssl genrsa -out ' . escapeshellarg($privkey_filename) . ' ' . Settings::Get('dkim.dkim_keylength'));
|
||||
$domain['dkim_privkey'] = file_get_contents($privkey_filename);
|
||||
FileDir::safe_exec("chmod 0640 " . escapeshellarg($privkey_filename));
|
||||
$pubkey_filename = FileDir::makeCorrectFile(Settings::Get('dkim.dkim_prefix') . '/dkim' . $domain['dkim_id'] . '.public');
|
||||
FileDir::safe_exec('openssl rsa -in ' . escapeshellarg($privkey_filename) . ' -pubout -outform pem -out ' . escapeshellarg($pubkey_filename));
|
||||
$domain['dkim_pubkey'] = file_get_contents($pubkey_filename);
|
||||
FileDir::safe_exec("chmod 0664 " . escapeshellarg($pubkey_filename));
|
||||
@@ -217,7 +215,7 @@ abstract class DnsBase
|
||||
`" . TABLE_PANEL_DOMAINS . "` `d`
|
||||
LEFT JOIN `" . TABLE_PANEL_CUSTOMERS . "` `c` USING(`customerid`)
|
||||
WHERE
|
||||
`d`.`isbinddomain` = '1'
|
||||
`d`.`isbinddomain` = '1' aND `d`.`deactivated` = '0'
|
||||
ORDER BY
|
||||
`d`.`domain` ASC
|
||||
");
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
* @author Froxlor team <team@froxlor.org>
|
||||
* @license https://files.froxlor.org/misc/COPYING.txt GPLv2
|
||||
*/
|
||||
|
||||
namespace Froxlor\Dns;
|
||||
|
||||
use Froxlor\Database\Database;
|
||||
@@ -183,7 +182,10 @@ class Dns
|
||||
}
|
||||
if (Settings::Get('dkim.use_dkim') == '1') {
|
||||
// check for DKIM content later
|
||||
self::addRequiredEntry('dkim' . $domain['dkim_id'] . '._domainkey.' . $sub_record, 'TXT', $required_entries);
|
||||
//self::addRequiredEntry('dkim' . $domain['dkim_id'] . '._domainkey.' . $sub_record, 'TXT', $required_entries);
|
||||
self::addRequiredEntry('mx._domainkey.' . $sub_record, 'TXT', $required_entries);
|
||||
//Also add dmarc
|
||||
self::addRequiredEntry('_dmarc' . $sub_record, 'TXT', $required_entries);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -220,7 +222,10 @@ class Dns
|
||||
}
|
||||
if (Settings::Get('dkim.use_dkim') == '1') {
|
||||
// check for DKIM content later
|
||||
self::addRequiredEntry('dkim' . $domain['dkim_id'] . '._domainkey', 'TXT', $required_entries);
|
||||
//self::addRequiredEntry('dkim' . $domain['dkim_id'] . '._domainkey', 'TXT', $required_entries);
|
||||
self::addRequiredEntry('mx._domainkey', 'TXT', $required_entries);
|
||||
//Also add dmarc
|
||||
self::addRequiredEntry('_dmarc', 'TXT', $required_entries);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,10 +383,13 @@ class Dns
|
||||
if (array_key_exists("TXT", $required_entries)) {
|
||||
if (Settings::Get('dkim.use_dkim') == '1') {
|
||||
$dkim_entries = self::generateDkimEntries($domain);
|
||||
$dmarc_entries = self::generateDmarcEntries($domain);
|
||||
}
|
||||
|
||||
foreach ($required_entries as $type => $records) {
|
||||
if ($type == 'TXT') {
|
||||
//$dkim_record = 'dkim' . $domain['dkim_id'] . '._domainkey';
|
||||
$dkim_record = 'mx._domainkey';
|
||||
foreach ($records as $record) {
|
||||
if ($record == '@SPF@') {
|
||||
// spf for main-domain
|
||||
@@ -392,9 +400,8 @@ class Dns
|
||||
$txt_content = Settings::Get('spf.spf_entry');
|
||||
$sub_record = substr($record, 6);
|
||||
$zonerecords[] = new DnsEntry($sub_record, 'TXT', self::encloseTXTContent($txt_content));
|
||||
} elseif (!empty($dkim_entries)) {
|
||||
} elseif (!empty($dkim_entries) && $record == $dkim_record ) {
|
||||
// DKIM entries
|
||||
$dkim_record = 'dkim' . $domain['dkim_id'] . '._domainkey';
|
||||
if ($record == $dkim_record) {
|
||||
// dkim for main-domain
|
||||
// check for multiline entry
|
||||
@@ -412,7 +419,10 @@ class Dns
|
||||
}
|
||||
$zonerecords[] = new DnsEntry($record, 'TXT', self::encloseTXTContent($dkim_entries[0], $multiline));
|
||||
}
|
||||
} elseif ($record == '_dmarc' && !empty($dmarc_entries) && $domain['isemaildomain'] == '1') {
|
||||
$zonerecords[] = new DnsEntry($record, 'TXT', self::encloseTXTContent($dmarc_entries[0]));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -523,7 +533,7 @@ class Dns
|
||||
* @param array $domain
|
||||
* @return array
|
||||
*/
|
||||
private static function generateDkimEntries(array $domain): array
|
||||
/** private static function generateDkimEntries(array $domain): array
|
||||
{
|
||||
$zone_dkim = [];
|
||||
|
||||
@@ -569,8 +579,26 @@ class Dns
|
||||
}
|
||||
|
||||
return $zone_dkim;
|
||||
} */
|
||||
private static function generateDkimEntries(array $domain): array
|
||||
{
|
||||
$zone_dkim = [];
|
||||
if (Settings::Get('dkim.use_dkim') == '1' && $domain['dkim'] == '1' && $domain['dkim_pubkey'] != '') {
|
||||
// start
|
||||
$dkim_txt = 'v=DKIM1;k=rsa;p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAosq0CmLqEzJJxIHkQwG1Xwk6CSyHHWSDXL9BHCKzY9lJXH7a23PogVlLvUBYaAgBtFOpsKuUCBl+/g6rOqgVXKg0OpYdpgTxZyz1i4NcubGFLifQGnF8ZKpIEDqIzmLI6SbH+9DKwYA319sXAR6feZI4g5bWqF07t/kzA5LN+2V5QnDQ3th++GPRl5rmWF6uoidIRD85UZVEX4s3J1hce0k6tRb2aEozCJaSXHUwyarmbbX/5rky467QQ+45Uy0q9CNaMMu1IX5eybhLRxYXK1k0TfIRJv4FH1UFLlq2QoGC7d+KvLrUabhzQ5wbdZkWuVgLFZ7CL2NegfzO6YeEcQIDAQAB';
|
||||
$zone_dkim[] = $dkim_txt;
|
||||
}
|
||||
return $zone_dkim;
|
||||
}
|
||||
private static function generateDmarcEntries(array $domain): array
|
||||
{
|
||||
$zone_dmarc = [];
|
||||
if (Settings::Get('dkim.use_dkim') == '1' && $domain['dkim'] == '1' ){
|
||||
$dmarc_txt = 'v=DMARC1; p=reject; ruf=mailto:dmarc@'. $domain['domain'] . '; rua=mailto:dmarc@'. $domain['domain'] . '; fo=1; adkim=r; aspf=r; pct=100; rf=afrf; ri=345600;';
|
||||
$zone_dmarc[] = $dmarc_txt;
|
||||
}
|
||||
return $zone_dmarc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $txt_content
|
||||
* @param bool $isMultiLine
|
||||
@@ -579,11 +607,11 @@ class Dns
|
||||
public static function encloseTXTContent(string $txt_content, bool $isMultiLine = false): string
|
||||
{
|
||||
// check that TXT content is enclosed in " "
|
||||
if (!$isMultiLine && Settings::Get('system.dns_server') != 'PowerDNS') {
|
||||
if (! $isMultiLine && Settings::Get('system.dns_server') != 'PowerDNS') {
|
||||
if (substr($txt_content, 0, 1) != '"') {
|
||||
$txt_content = '"' . $txt_content;
|
||||
}
|
||||
if (substr($txt_content, -1) != '"') {
|
||||
if (substr($txt_content, - 1) != '"') {
|
||||
$txt_content .= '"';
|
||||
}
|
||||
}
|
||||
@@ -592,8 +620,8 @@ class Dns
|
||||
if (substr($txt_content, 0, 1) == '"') {
|
||||
$txt_content = substr($txt_content, 1);
|
||||
}
|
||||
if (substr($txt_content, -1) == '"') {
|
||||
$txt_content = substr($txt_content, 0, -1);
|
||||
if (substr($txt_content, - 1) == '"') {
|
||||
$txt_content = substr($txt_content, 0, - 1);
|
||||
}
|
||||
}
|
||||
return $txt_content;
|
||||
|
||||
@@ -52,6 +52,12 @@ return [
|
||||
'type' => 'checkbox',
|
||||
'value' => '1',
|
||||
'checked' => false
|
||||
],
|
||||
'disablegreylist' => [
|
||||
'label' => lng('emails.disablegreylist'),
|
||||
'type' => 'checkbox',
|
||||
'value' => '1',
|
||||
'checked' => false
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
@@ -102,6 +102,19 @@ return [
|
||||
]
|
||||
]
|
||||
],
|
||||
'mail_disablegreylist' => [
|
||||
'label' => lng('emails.greylist'),
|
||||
'type' => 'label',
|
||||
'value' => ((int)$result['disablegreylist'] == 0 ? lng('panel.no') : lng('panel.yes')),
|
||||
'next_to' => [
|
||||
'add_link' => [
|
||||
'type' => 'link',
|
||||
'href' => $filename . '?page=' . $page . '&domainid=' . $result['domainid'] . '&action=togglegreylist&id=' . $result['id'],
|
||||
'label' => '<i class="fa-solid fa-arrow-right-arrow-left"></i> ' . lng('panel.toggle'),
|
||||
'classes' => 'btn btn-sm btn-secondary'
|
||||
]
|
||||
]
|
||||
],
|
||||
'mail_fwds' => [
|
||||
'label' => lng('emails.forwarders') . ' (' . $forwarders_count . ')',
|
||||
'type' => 'itemlist',
|
||||
|
||||
@@ -55,6 +55,12 @@ return [
|
||||
'callback' => [Text::class, 'boolean'],
|
||||
'visible' => Settings::Get('catchall.catchall_enabled') == '1'
|
||||
],
|
||||
'm.disablegreylist' => [
|
||||
'label' => lng('emails.greylist'),
|
||||
'field' => 'disablegreylist',
|
||||
'callback' => [Text::class, 'boolean'],
|
||||
'#visible' => Settings::Get('greylist.greylist_enabled') == '1'
|
||||
],
|
||||
'u.quota' => [
|
||||
'label' => lng('emails.quota'),
|
||||
'field' => 'quota',
|
||||
@@ -66,6 +72,7 @@ return [
|
||||
'm.destination',
|
||||
'm.popaccountid',
|
||||
'm.iscatchall',
|
||||
'm.disablegreylist',
|
||||
'u.quota'
|
||||
]),
|
||||
'actions' => [
|
||||
|
||||
@@ -724,6 +724,8 @@ return [
|
||||
'back_to_overview' => 'Zurück zur Domain-Übersicht',
|
||||
'accounts' => 'Konten',
|
||||
'emails' => 'Adressen',
|
||||
'disablegreylist' => 'Greylisting deaktivieren?',
|
||||
'greylist' => 'Greylisting aus?'
|
||||
],
|
||||
'error' => [
|
||||
'error' => 'Fehlermeldung',
|
||||
|
||||
55
notice.html
Normal file
55
notice.html
Normal file
@@ -0,0 +1,55 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>froxlor - Domain not configured</title>
|
||||
<style>
|
||||
:root{--primary:#1872a2;--fonts:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"}
|
||||
body{display:flex;flex-direction:column;background:#f8f9fa;color:#4b5563;align-items:center;justify-content:center;font-family:var(--fonts)}
|
||||
main{background:#fff;margin:10% auto 12px;max-width:540px;padding:2rem;box-shadow:4px 8px 16px 0 rgba(0,0,0,.07);border-radius:.375rem}
|
||||
main h2{margin:0}
|
||||
main p{margin-bottom:1.5rem}
|
||||
main p:last-child{margin-bottom:0}
|
||||
main ul{list-style:none;margin-left:-40px}
|
||||
main li{display:flex;align-items:center;margin-bottom:1rem}
|
||||
main .icon{min-width:24px;width:24px;stroke:var(--primary);margin-right:.75rem}
|
||||
code{background:#eee;padding:.1rem .25rem;border-radius:4px;color:rgba(0,0,0,.75)}
|
||||
hr{margin:2rem 0;border:none;border-bottom:solid 1px rgba(0,0,0,.1)}
|
||||
a,a:active,a:visited{color:var(--primary);text-decoration:none}
|
||||
a:hover{text-decoration:underline}
|
||||
footer{display:flex;align-items:center;margin-top:.5rem}
|
||||
footer .logo{margin-right:.35rem}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root{--primary:#29a2d6}
|
||||
body{background:#212529;color:#f8f9fa}
|
||||
main{background:#343a40}
|
||||
hr{border-color:rgba(0,0,0,.2)}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h2>Domain not configured</h2>
|
||||
<p>
|
||||
This domain requires configuration via the froxlor server management panel, as it is currently not assigned to any customer.
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="icon">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" />
|
||||
</svg>
|
||||
<span>Please ask your provider/hoster if you have any questions.</span>
|
||||
</li>
|
||||
</ul>
|
||||
</main>
|
||||
<footer>
|
||||
<img class="logo" src="data:image/png;base64,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" alt="froxlor"/>
|
||||
<small>© 2009-<span id="year"></span> by <a href="https://froxlor.org" rel="external">the froxlor team</a></small>
|
||||
</footer>
|
||||
<script>
|
||||
document.getElementById("year").innerHTML = new Date().getFullYear();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,5 +0,0 @@
|
||||
<?php
|
||||
chmod('/app//bin/froxlor-cli', 0755);
|
||||
// re-create cron.d configuration file
|
||||
exec('/app//bin/froxlor-cli froxlor:cron -r 99');
|
||||
exit;
|
||||
17
templates/Froxlor/assets/css/dark.css
Normal file
17
templates/Froxlor/assets/css/dark.css
Normal file
File diff suppressed because one or more lines are too long
17
templates/Froxlor/assets/css/main.css
Normal file
17
templates/Froxlor/assets/css/main.css
Normal file
File diff suppressed because one or more lines are too long
2
templates/Froxlor/assets/js/main.js
Normal file
2
templates/Froxlor/assets/js/main.js
Normal file
File diff suppressed because one or more lines are too long
45
templates/Froxlor/assets/js/main.js.LICENSE.txt
Normal file
45
templates/Froxlor/assets/js/main.js.LICENSE.txt
Normal file
@@ -0,0 +1,45 @@
|
||||
/*!
|
||||
* Bootstrap v5.3.2 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2023 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @kurkle/color v0.2.1
|
||||
* https://github.com/kurkle/color#readme
|
||||
* (c) 2022 Jukka Kurkela
|
||||
* Released under the MIT License
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Chart.js v3.9.1
|
||||
* https://www.chartjs.org
|
||||
* (c) 2022 Chart.js Contributors
|
||||
* Released under the MIT License
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2023 Fonticons, Inc.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* jQuery JavaScript Library v3.7.1
|
||||
* https://jquery.com/
|
||||
*
|
||||
* Copyright OpenJS Foundation and other contributors
|
||||
* Released under the MIT license
|
||||
* https://jquery.org/license
|
||||
*
|
||||
* Date: 2023-08-28T13:37Z
|
||||
*/
|
||||
|
||||
/*!
|
||||
* jQuery Validation Plugin v1.20.0
|
||||
*
|
||||
* https://jqueryvalidation.org/
|
||||
*
|
||||
* Copyright (c) 2023 Jörn Zaefferer
|
||||
* Released under the MIT license
|
||||
*/
|
||||
13
templates/Froxlor/assets/mix-manifest.json
Normal file
13
templates/Froxlor/assets/mix-manifest.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"/js/main.js": "/js/main.js?id=29451cc889431e973473738b93e6a626",
|
||||
"/css/dark.css": "/css/dark.css?id=f965da97d900604705c3762bb9cd645a",
|
||||
"/css/main.css": "/css/main.css?id=cbda89c88526530a66fe1e0d46a63a22",
|
||||
"/webfonts/fa-brands-400.ttf": "/webfonts/fa-brands-400.ttf?id=69e5d8e4e818f05fd882cceb758d1eba",
|
||||
"/webfonts/fa-brands-400.woff2": "/webfonts/fa-brands-400.woff2?id=189b85e9c72c6f75e464c3f58a6707cf",
|
||||
"/webfonts/fa-regular-400.ttf": "/webfonts/fa-regular-400.ttf?id=ed4c23399d1013809882e90bfe396d1b",
|
||||
"/webfonts/fa-regular-400.woff2": "/webfonts/fa-regular-400.woff2?id=be75b1958ae0da55e1eed562d9b7713d",
|
||||
"/webfonts/fa-solid-900.ttf": "/webfonts/fa-solid-900.ttf?id=dfdc7801582dd0d20ea75faa3b96c296",
|
||||
"/webfonts/fa-solid-900.woff2": "/webfonts/fa-solid-900.woff2?id=a0feb384c3c6071947a49708f2b0bc85",
|
||||
"/webfonts/fa-v4compatibility.ttf": "/webfonts/fa-v4compatibility.ttf?id=e24ec0b8661f7fa333b29444df39e399",
|
||||
"/webfonts/fa-v4compatibility.woff2": "/webfonts/fa-v4compatibility.woff2?id=e11465c0eff0549edd4e8ea6bbcf242f"
|
||||
}
|
||||
BIN
templates/Froxlor/assets/webfonts/fa-brands-400.ttf
Normal file
BIN
templates/Froxlor/assets/webfonts/fa-brands-400.ttf
Normal file
Binary file not shown.
BIN
templates/Froxlor/assets/webfonts/fa-brands-400.woff2
Normal file
BIN
templates/Froxlor/assets/webfonts/fa-brands-400.woff2
Normal file
Binary file not shown.
BIN
templates/Froxlor/assets/webfonts/fa-regular-400.ttf
Normal file
BIN
templates/Froxlor/assets/webfonts/fa-regular-400.ttf
Normal file
Binary file not shown.
BIN
templates/Froxlor/assets/webfonts/fa-regular-400.woff2
Normal file
BIN
templates/Froxlor/assets/webfonts/fa-regular-400.woff2
Normal file
Binary file not shown.
BIN
templates/Froxlor/assets/webfonts/fa-solid-900.ttf
Normal file
BIN
templates/Froxlor/assets/webfonts/fa-solid-900.ttf
Normal file
Binary file not shown.
BIN
templates/Froxlor/assets/webfonts/fa-solid-900.woff2
Normal file
BIN
templates/Froxlor/assets/webfonts/fa-solid-900.woff2
Normal file
Binary file not shown.
BIN
templates/Froxlor/assets/webfonts/fa-v4compatibility.ttf
Normal file
BIN
templates/Froxlor/assets/webfonts/fa-v4compatibility.ttf
Normal file
Binary file not shown.
BIN
templates/Froxlor/assets/webfonts/fa-v4compatibility.woff2
Normal file
BIN
templates/Froxlor/assets/webfonts/fa-v4compatibility.woff2
Normal file
Binary file not shown.
@@ -97,7 +97,7 @@
|
||||
--bs-highlight-bg: #fff3cd;
|
||||
--bs-border-width: 1px;
|
||||
--bs-border-style: solid;
|
||||
--bs-border-color: #dee2e6;
|
||||
--bs-border-color: #A08C78;
|
||||
--bs-border-color-translucent: rgba(0,0,0,.175);
|
||||
--bs-border-radius: 0.375rem;
|
||||
--bs-border-radius-sm: 0.25rem;
|
||||
@@ -119,8 +119,17 @@
|
||||
--bs-form-invalid-border-color: #be123c
|
||||
}
|
||||
|
||||
.navbar {
|
||||
background: rgb(var(--bs-primary-rgb));
|
||||
}
|
||||
|
||||
|
||||
.form-control:focus {
|
||||
background-color: #fff;
|
||||
border-color: rgb(var(--bs-primary-rgb));
|
||||
box-shadow: 0 0 0 .25rem rgba(24,114,162,.25);
|
||||
color: var(--bs-body-color);
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
|
||||
.navbar .navbar-brand {
|
||||
@@ -131,7 +140,7 @@
|
||||
}
|
||||
|
||||
.sidebar>.nav>.nav-item>.nav-link:not(.collapsed) {
|
||||
background: rgb(180,170,160);
|
||||
background: rgb(var(--bs-primaryu-rgb));
|
||||
border-left: 3px solid #1872a2;
|
||||
padding-left: calc(1rem - 3px);
|
||||
}
|
||||
@@ -189,4 +198,16 @@ img.header-logo {
|
||||
|
||||
|
||||
|
||||
.alert, .card, .shadow-sm, .sub-sidebar {
|
||||
box-shadow: var(--bs-box-shadow)!important;
|
||||
}
|
||||
|
||||
|
||||
body.d-flex {
|
||||
display: flex!important;
|
||||
background-color: rgb(var(--bs-secondary-rgb))!important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user