firewall/views/settings.html
<style>
{{custom_css}}
/* IMPORTED STYLES */
.card { max-width: 100%; }
.right { float: right; }
/*
.form-switch { width: 80px; margin-left: -80px; }
.form-switch .right { right: 0; }
.form-check-input { left: 85px; }
*/
.form-check .form-switch { width: 80px; margin-left: -80px; }
.spinner-border { margin-left: -110px; }
/*
.lnum { float: right; }
*/
.pointer { cursor: pointer; }
.card-body { padding: 0.5rem !important; }
.center { text-align: center; }
.left { float: left; }
.right { float: right; }
/*
.col { flex: 1 0 0%; }
.col-auto { flex: 0 0 auto; width: auto; }
.row { display: flex; }
.row>* {
flex-shrink: 0;
width: 100%;
max-width: 100%;
padding-right: calc(var(--bs-gutter-x)/2);
padding-left: calc(var(--bs-gutter-x)/2);
margin-top: var(--bs-gutter-y);
}
*/
.zn1 { z-index: -1;}
image.type { fill: #e63757; }
a.nav-link { color: #2c7be5 !important;}
a.nav-link:hover { text-decoration: underline; }
svg { fill: #977; }
.blue { fill: #30b7e5; color: #30b7e5; }
svg.green { fill: #21d97e; }
svg.yellow { fill: #f6c343; }
svg.red { fill: #e63757; }
img.red { filter: invert(27%) sepia(51%) saturate(2878%) hue-rotate(346deg) brightness(104%) contrast(97%); }
img.grey_blue { filter: invert(82%) sepia(15%) saturate(597%) hue-rotate(184deg) brightness(89%) contrast(86%); }
img.orange { filter: invert(83%) sepia(34%) saturate(523%) hue-rotate(336deg) brightness(98%) contrast(92%); }
img.white { filter: invert(99%) sepia(7%) saturate(889%) hue-rotate(165deg) brightness(114%) contrast(100%); }
h6 { text-transform: uppercase; line-height: 1.5;color: rgb(149, 170, 201); font-family: "Cerebri Sans", sans-serif; font-weight: 400; }
.header-body { padding: 24px 0; }
.oh { overflow: auto; }
.wrap { white-space: break-spaces; line-break: anywhere; }
.nowrap { white-space: nowrap; }
.hidden { display: none; }
.country { float: right; display: block; }
.btn-sm {
padding: 0.1rem .5rem !important;
font-size: .4rem !important;
font-weight: bold;
}
.btn-group-tiny>.btn {
padding: .075rem .25rem;
font-size: .4rem;
line-height: 1.0;
border-radius: .25rem;
}
.dropdown-toggle {
width: 65px;
}
.nav-sm .nav-link {
font-size: .6125rem;
}
.navbar-vertical.navbar-expand-md .navbar-nav .nav .nav-link {
padding-left: .5rem;
padding-right: 0rem;
}
.grow { flex-grow: 1; }
.success:checked { background-color: #00d97e; }
.warning:checked { background-color: #f6c343; }
.success, .success:checked { background-color: #00d97e; }
.form-switch { min-height: 1.5rem; padding-left: 1.5rem; }
.form-switch .form-check-input:checked { background-position: 100%; }
.form-switch .form-check-input:checked, .form-switch .form-check-input:focus {
}
.form-check-input { cursor: pointer; }
input { overflow: visible; }
input[type=checkbox] { box-sizing: border-box; padding: 0; }
.form-check-input { position: absolute; vertical-align: top; background-color: #e3ebf6; background-repeat: no-repeat; background-size: contain; border: transparent; appearance: none;}
.form-check-input:checked[type=checkbox] {
background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3 6-6'/%3E%3C/svg%3E");
background-position: 100%;
}
.form-check-input[type=checkbox] {
background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E");
background-position: 0%;
background-repeat: no-repeat;
width: 3rem;
margin: 0;
margin-left: -3.5rem;
border-radius: 3rem;
transition: background-position .15s ease-in-out;
height: 1.5rem;
}
input[type=checkbox]:checked::before { content: ''; }
input[type=checkbox], input[type=radio] {
box-sizing: border-box;
padding: 0;
}
.form-check-input { cursor: pointer; vertical-align: top; background-size: contain; border: transparent; appearance: none; position: absolute; }
.cover.system { background-image: url('{{public}}img/system-low.jpg'); }
.cover.shield { background-image: url('{{public}}img/shield1.jpg'); }
.cover.robot { background-image: url('{{public}}img/robot-low.jpg'); }
.cover.server { background-image: url('{{public}}img/server-low.jpg'); }
.cover.server-red { background-image: url('{{public}}img/server-red.jpg'); }
.cover {
width: 100%;
height: 100px;
border-top-left-radius: 0.5rem;
border-top-right-radius: 0.5rem;
background-size: 100%;
background-repeat: no-repeat;
background-position: center;
opacity: 0.9;
position: absolute;
top:0;
left:0;
right:0;
overflow: hidden;
}
.header-icon { position: absolute; left:16px; top:12px; font-size: 48px; }
.card-title { margin-top: -1rem; border-bottom: 1px solid #DDD; padding-bottom: 1rem; }
.alt1,h2,h4 { color: #3b506c; }
</style>
<script type="text/javascript">
window.CONFIG_LIST = {};
function rand_string(config_name, length = 32) {
let result = '';
let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for ( var i = 0; i < length; i++ ) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
GBI(config_name+"_text").value = result;
update_str(config_name);
}
function show_list(config_name) {
let html = "";
for (let i=0; i < domain_list.length; i++) {
let id = config_name + "-" + i;
html += '<div style="margin-bottom:5px;" id="item_'+id+'">';
html += '<input type="text" autocomplete="off" disabled id="list_'+id+'" class="form-control txtin" style="width:80%;float:left;margin-right:10px" value="'+domain_list[i]+'">';
html += '<div class="btn btn-danger" style="cursor:pointer;padding-top:10px;padding-left:10px;" title="remove list element" onclick="remove_list(\''+config_name+'\', \''+domain_list[i]+'\', '+i+')"><span class="fe fe-trash"></span></div>';
}
return html;
}
function remove_list(config_name, value, idx) {
console.log("config name delete", config_name, value, idx);
BitFire_api("remove_list_elm", {"config_name":config_name, "config_value":value, "index":idx})
.then(r => r.json())
.then(function(res) {
if (res.success) {
window.location.reload();
} else {
alert(res.note);
window.location.reload();
}
});
}
function add_list(config_name) {
let elm = GBI("new_"+config_name);
BitFire_api("add_list_elm", {"config_name":config_name, "config_value":elm.value})
.then(r => r.json())
.then(function(res) {
if (res.success) {
window.location.reload();
} else {
alert(res.note);
window.location.reload();
}
});
}
const VERSION = {{version}};
window.BITFIRE_NONCE = '{{api_code}}';
const VERSION_STR = "{{sym_version}}";
function set_config(id, value) {
console.log("set config", id, value);
}
function soption(config, value) {
GBI("drop_"+config).innerText = value;
return update_value(config, value);
}
function update_value(config, value) {
GBI(config+"_spin").classList.remove("hidden");
console.log("update value: ", config);
BitFire_api("toggle_config_value", {"param":config,"value":value})
.then(r => r.json())
.then(data => {
console.log("saved", config, data);
window.setTimeout(function(){ GBI(config+"_spin").classList.add("hidden"); }, 100);
});
}
function update_str(config) {
console.log("up", config);
let e = GBI(config+"_text");
if (e) {
let value = e.value;
console.log("update str", config, value);
return update_value(config, value);
} else {
alert("error, unable to update " + config + " please create support ticket");
}
}
function toggle_report(config, report) {
if (config == "enforce_ssl_1year" && window.location.protocol != "https:") {
alert("Please switch to SSL to enable this feature");
return false;
}
GBI(config+"_spin").classList.remove("hidden");
if (report && window.CONFIG_LIST[config] == "on") {
let g = GBI(config+"_block");
if (g) { g.checked = false; }
}
if (!report && window.CONFIG_LIST[config] == "report") {
let g = GBI(config+"_report");
if (g) { g.checked = false; }
}
let value = "false";
let r = GBI(config+"_report");
if (r && r.checked) { value = "report"; }
if (GBI(config+"_block").checked) { value = "on"; }
window.CONFIG_LIST[config] = value;
if (config == "auto_start") {
let action=(value == "on") ? "install" : "uninstall";
BitFire_api(action, {})
.then(r => r.json())
.then(response => {
console.log(response);
alert(response.note);
window.setTimeout(function(){ GBI(config+"_spin").classList.add("hidden"); }, 100);
});
}
else {
BitFire_api("toggle_config_value", {"param":config,"value":value})
.then(r => r.json())
.then(data => {
console.log("response...", data);
if (!data.success) { alert("error updating " + config + " : " + data.note + " : " + data.errors.join()); }
window.setTimeout(function(){ GBI(config+"_spin").classList.add("hidden"); }, 100);
});
}
}
// config name, block|on|true / report|alert / off|false
function toggle(elm, type) {
var e = GBI(elm);
console.log(e);
e.innerText = cap(type);
BitFire_api("toggle_config_value", {"param":elm,"value":type})
.then(r => r.json())
.then(data => { console.log("toggle", data); });
if (type == "block" || type == "on" || type == "true") {
e.classList.remove("btn-warning");
e.classList.remove("btn-secondary");
e.classList.add("btn-success");
} else if (type == "report" || type == "alert") {
e.classList.remove("btn-success");
e.classList.remove("btn-secondary");
e.classList.add("btn-warning");
} else {
e.classList.remove("btn-success");
e.classList.remove("btn-warning");
e.classList.add("btn-secondary");
}
}
</script>
<script type="text/template" id="alert_template">
<div class="alert alert-warning alert-dismissible fade show">
{{text}}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
</script>
<!-- NAVIGATION
================================================== -->
<div class="main-content">
{{header}}
<!-- CARDS -->
<div class="container-fluid" id="full_container">
<div class="row justify-content-center">
<div class="col-12 col-lg-10 col-xl-8">
<h2><small><a class="text-info" href="https://bitfire.co/support-core-settings" target="_blank">Settings Documentation <i class="fe fe-external-link"></i></a></small></h2>
<div class="card">
<div class="cover server"></div>
<div class="card-body" style="margin-top:1.5rem;">
<div class="avatar avatar-xl card-avatar card-avatar-top" style="margin-top:1rem;">
<img id="" src="{{public}}img/search.jpg" style="background-color:#FFF;" class="avatar-img rounded-circle border-card">
<span class="fe alt1 header-icon fe-settings"></span>
</div>
<h2 style="margin-top:-1rem;" class="card-title">
<strong>
<span class="tdc alt1">
BitFire Server Settings
</span>
</strong>
<span class="card-header-title text-secondary right">Enable</span>
<small class="text-muted"><i>(block automated scanners)</i></small>
</h2>
</div>
<!--
<div class="card-header">
<h4 class="card-header-title">
System Features
<small class="text-muted ml-4">
<a href="https://bitfire.co/web-blocking" target="_blank">Learn about web blocking <span class="fe fe-external-link"></span></a>
</small>
</h4>
<h4 class="card-header-title text-secondary">Enable</h4>
</div>
-->
<div class="card-body">
<div class="list-group list-group-flush my-n3">
<div class="list-group-item">
<div class="row align-items-center">
<div class="col">
<h4 class="font-weight-base mb-1">
Firewall Enable
</h4>
<small class="text-muted">
Enable/Disable all Firewall functionality
</small>
</div>
<div class="col-auto tog" id="bitfire_enabled_con" data-enabled="{{bitfire_enabled}}" data-title="Turn off to prevent all blocking" data-toggle="true">
</div>
</div> <!-- / .row -->
</div>
<div class="list-group-item">
<div class="row align-items-center">
<div class="col">
<h4 class="font-weight-base mb-1">
Always On Protection
</h4>
<small class="text-muted">
Run BitFire before WordPress. Prevent Firewall bypass and saves server resources. HIGHLY recommended.
</small>
</div>
<div class="col-auto tog" id="auto_start_con" data-enabled="{{auto_start}}" data-title="Enable BitFire to run before ALL requests" data-toggle="true">
</div>
</div> <!-- / .row -->
</div>
<div class="list-group-item">
<div class="row align-items-center">
<div class="col">
<h4 class="font-weight-base mb-1">
Allow IP Blocking
</h4>
<small class="text-muted">
Allow blocking IP Addresses when obvious attacks detected
</small>
</div>
<div class="col-auto tog" id="allow_ip_block_con" data-enabled="{{allow_ip_block}}" data-title="Block everything from bad IPS for an hour" data-toggle="true">
</div>
</div> <!-- / .row -->
</div>
<div class="list-group-item">
<div class="row align-items-center">
<div class="col">
<h4 class="font-weight-base mb-1">
Send HTTP Security Headers
</h4>
<small class="text-muted">
deny frames, disable content sniff, strict cross-origin
</small>
</div>
<div class="col-auto tog" id="security_headers_enabled_con" data-enabled="{{security_headers_enabled}}" data-title="Send HTTP security headers" data-toggle="true">
</div>
</div> <!-- / .row -->
</div>
<div class="list-group-item">
<div class="row align-items-center">
<div class="col">
<h4 class="font-weight-base mb-1">
Force SSL 1-year
</h4>
<small class="text-muted">
Force SSL and disable non-SSL for 1 year
</small>
</div>
<div class="col-auto tog" id="enforce_ssl_1year_con" data-enabled="{{enforce_ssl_1year}}" data-title="Prevent browsers from connecting without SSL" data-toggle="true">
</div>
</div> <!-- / .row -->
</div>
<div class="list-group-item">
<div class="row align-items-center">
<div class="col">
<h4 class="font-weight-base mb-1">
Block Profanity
</h4>
<small class="text-muted">
Replace profanity with !@#$!
</small>
</div>
<div class="col-auto tog" id="block_profanity_con" data-enabled="{{block_profanity}}" data-title="Profanity filter" data-toggle="true">
</div>
</div> <!-- / .row -->
</div>
</div>
</div>
</div>
<hr class="my-5">
<div class="card">
<div class="cover robot"></div>
<div class="card-body" style="margin-top:1.5rem;">
<div class="avatar avatar-xl card-avatar card-avatar-top" style="margin-top:1rem;">
<img id="" src="{{public}}img/robot.png" style="background-color:#FFF;" class="avatar-img rounded-circle border-card">
<!--
<span class="fe alt1 header-icon fe-server"></span>
-->
</div>
<h2 style="margin-top:-1rem;" class="card-title">
<strong>
<span class="tdc alt1">
BitFire Bot Blocking
</span>
</strong>
<span class="card-header-title text-secondary right">Alert / Block</span>
<small class="text-muted"><i>(block automated scanners)</i></small>
</h2>
</div>
<div class="card-body">
<div class="list-group list-group-flush my-n3">
<div class="list-group-item">
<div class="row align-items-center">
<div class="col">
<h4 class="font-weight-base mb-1">
Require Full Browser
</h4>
<small class="text-muted">
Verify browsers are not bots with a transparent JavaScript challenge
</small>
</div>
<div class="col-auto tog" id="require_full_browser_con" data-enabled="{{require_full_browser}}" data-title="JavaScript Challenge">
</div>
</div> <!-- / .row -->
</div>
<div class="list-group-item">
<div class="row align-items-center">
<div class="col">
<h4 class="font-weight-base mb-1">
Block Bots not on Whitelist
</h4>
<small class="text-muted">
Over 100 Search Engines and SEO tools included.
</small>
</div>
<div class="col-auto tog" id="whitelist_enable_con" data-enabled="{{whitelist_enable}}" data-title="Enable the Bot Allowlist">
</div>
</div> <!-- / .row -->
</div>
<div class="list-group-item">
<div class="row align-items-center">
<div class="col">
<h4 class="font-weight-base mb-1">
Quick Block Blacklist Bots
</h4>
<small class="text-muted">
Send immediate deny and IP block to any blacklisted user-agent
</small>
</div>
<div class="col-auto tog" id="blacklist_enable_con" data-enabled="{{blacklist_enable}}" data-title="Enable the Bot Blocklist">
</div>
</div> <!-- / .row -->
</div>
<div class="list-group-item">
<div class="row align-items-center">
<div class="col">
<h4 class="font-weight-base mb-1">
Rate Limit Action
</h4>
<small class="text-muted">
Block / Alert on rate limit hit. (Excludes search engines)
</small>
</div>
<div class="col-auto tog" id="rate_limit_con" data-enabled="{{rate_limit}}" data-title="Enable Rate Limit Enforcement">
</div>
</div> <!-- / .row -->
</div>
<div class="list-group-item">
<div class="row align-items-center">
<div class="col">
<div class="">
<h4 class="font-weight-base mb-1">
5 Minute Rate Limit
</h4>
<small class="form-text text-muted">5 Minute rate limit (excludes whitelisted bots)</small>
<div id="rr_5m_spin" class="spinner-border text-success spinner-border-sm left mt-1 mr-2 hidden" role="status">
<span class="xvisually-hidden">Saving...</span>
</div>
<input type="number" class="form-control txtin" id="rr_5m_text" autocomplete="off" onchange="update_str('rr_5m')" value="{{rr_5m}}" style="width:100px;">
</div>
</div>
</div> <!-- / .row -->
</div>
<div class="list-group-item">
<div class="row align-items-center">
<div class="col">
<h4 class="font-weight-base mb-1">
Block Direct IP Access
</h4>
<small class="text-muted">
Block spamming direct IP requests. Only allow access to domains on the domain list.
</small>
</div>
<div class="col-auto tog" id="check_domain_con" data-enabled="{{check_domain}}" data-title="Block Direct IP Access">
</div>
</div> <!-- / .row -->
</div>
<div class="list-group-item">
<div class="row align-items-center">
<div class="col">
<div class="">
<label class="form-label">
Allowed Domain List
</label>
<small class="form-text text-muted">
Only allow these domains to access the website (enabled via Block Direct IP Access)
</small>
{{valid_domains_html}}
</div>
</div>
</div>
</div>
<div class="list-group-item">
<div class="row align-items-center">
<div class="col">
<div class="">
<h4 class="font-weight-base mb-1">
Honeypot URL
</h4>
<small class="form-text text-muted">Add no-visit to robots.txt, block any IP that visits URL. (leave blank to disable)</small>
<div id="honeypot_url_spin" class="spinner-border text-success spinner-border-sm left mt-1 mr-2 hidden" role="status">
<span class="xvisually-hidden">Saving...</span>
</div>
<input type="text" class="form-control txtin" id="honeypot_url_text" autocomplete="off" onchange="update_str('honeypot_url')" value="{{honeypot_url}}">
</div>
</div>
</div> <!-- / .row -->
</div>
</div>
</div>
</div>
</div>
<hr class="my-5">
<div class="card">
<div class="cover shield"></div>
<div class="card-body" style="margin-top:1.5rem;">
<div class="avatar avatar-xl card-avatar card-avatar-top" style="margin-top:1rem;">
<img id="" src="{{public}}img/search.jpg" style="background-color:#FFF;" class="avatar-img rounded-circle border-card">
<span class="fe alt1 header-icon fe-shield"></span>
</div>
<h2 style="margin-top:-1rem;" class="card-title">
<strong>
<span class="tdc alt1">
Web Application Firewall Features
</span>
</strong>
<span class="card-header-title text-secondary right">Alert / Block</span>
<small class="text-muted"><i>(block automated scanners)</i></small>
</h2>
</div>
<div class="card-body">
<div class="list-group list-group-flush my-n3">
<div class="list-group-item">
<div class="row align-items-center">
<div class="col">
<h4 class="font-weight-base mb-1">
Generic Web Blocking
</h4>
<small class="text-muted">
Block generic attakcs, XXE, SSI, etc, (recommended)
</small>
</div>
<div class="col-auto tog" id="web_filter_enabled_con" data-enabled="{{web_filter_enabled}}" data-title="Generic Web Attack Protection">
</div>
</div> <!-- / .row -->
</div>
<div class="list-group-item">
<div class="row align-items-center">
<div class="col">
<h4 class="font-weight-base mb-1">
Block XSS
</h4>
<small class="text-muted">
Block Cross Site Scripting Attacks
</small>
</div>
<div class="col-auto tog" id="xss_block_con" data-enabled="{{xss_block}}" data-title="Cross Site Scripting Protection">
</div>
</div> <!-- / .row -->
</div>
<div class="list-group-item">
<div class="row align-items-center">
<div class="col">
<h4 class="font-weight-base mb-1">
Block SQLi
</h4>
<small class="text-muted">
Block SQL injection attacks
</small>
</div>
<div class="col-auto tog" id="sql_block_con" data-enabled="{{sql_block}}" data-title="SQL Injection Protection">
</div>
</div> <!-- / .row -->
</div>
<div class="list-group-item">
<div class="row align-items-center">
<div class="col">
<h4 class="font-weight-base mb-1">
Block Malicious Files
</h4>
<small class="text-muted">
Inspect all file uploads for malicious code
</small>
</div>
<div class="col-auto tog" id="file_block_con" data-enabled="{{file_block}}" data-title="Uploaded File Protection">
</div>
</div> <!-- / .row -->
</div>
</div>
</div>
</div>
<hr class="my-5">
<div class="card">
<div class="cover system"></div>
<div class="card-body" style="margin-top:1.5rem;">
<div class="avatar avatar-xl card-avatar card-avatar-top" style="margin-top:1rem;">
<img id="" src="{{public}}img/search.jpg" style="background-color:#FFF;" class="avatar-img rounded-circle border-card">
<span class="fe alt1 header-icon fe-database"></span>
</div>
<h2 style="margin-top:-1rem;" class="card-title">
<strong>
<span class="tdc alt1">
Server Configuration
</span>
</strong>
<small class="text-muted"><i>(PHP hosting environment. Auto Configured For You)</i></small>
</h2>
</div>
<div class="card-body">
<div class="row">
<div class="col-12 col-md-6 mb-2">
<div class="form-group">
<label class="form-label">
Cache Type
</label>
<small class="form-text text-muted">Server Side Cache (must have cache or cookies enabled)</small>
<div class="btn-group left">
<button type="button" class="btn btn-primary" id="drop_cache_type">{{cache_type}}</button>
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" style="width:auto" data-bs-toggle="dropdown" aria-expanded="false">
<span class="visually-hidden">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu">
<li class="hide_shmop"><span class="dropdown-item pointer" onclick="soption('cache_type', 'shmop')" href="#">SHMOP</span></li>
<li class="hide_apcu"><span class="dropdown-item pointer" onclick="soption('cache_type', 'apcu')" href="#">APCU</span></li>
<li><span class="dropdown-item pointer" onclick="soption('cache_type', 'nop')" href="#">none</span></li>
</ul>
</div>
<div id="cache_type_spin" class="spinner-border text-success spinner-border-sm mt-1 ml-2 hidden" role="status"></div>
</div>
</div>
<div class="col-12 col-md-6 mb-2">
<div class="form-group">
<label class="form-label">
DNS Services
</label>
<small class="form-text text-muted">CloudFlair (1.1.1.1) or localhost</small>
<div class="btn-group left">
<button type="button" class="btn btn-primary" id="drop_dns_service">{{dns_service}}</button>
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" style="width:auto" data-bs-toggle="dropdown" aria-expanded="false">
<span class="visually-hidden">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu">
<li><span class="dropdown-item pointer" onclick="soption('dns_service', '1.1.1.1')" href="#">1.1.1.1</span></li>
<li><span class="dropdown-item pointer" onclick="soption('dns_service', 'localhost')" href="#">localhost</span></li>
</ul>
</div>
<div id="dns_service_spin" class="spinner-border text-success spinner-border-sm mt-1 ml-2 hidden" role="status"></div>
</div>
</div>
<div class="col-12 col-md-6 mb-2">
<div class="form-group">
<label class="form-label">
Block HTTP Response Code
</label>
<small class="form-text text-muted">HTTP response code for block page</small>
<div class="btn-group left">
<button type="button" class="btn btn-primary" id="drop_response_code">{{response_code}}</button>
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" style="width:auto" data-bs-toggle="dropdown" aria-expanded="false">
<span class="visually-hidden">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu">
<li><span class="dropdown-item pointer" onclick="soption('response_code', '200')" href="#">200 OK</span></li>
<li><span class="dropdown-item pointer" onclick="soption('response_code', '203')" href="#">203 NON AUTHORITATIVE</span></li>
<li><span class="dropdown-item pointer" onclick="soption('response_code', '204')" href="#">204 NO CONTENT</span></li>
<li><span class="dropdown-item pointer" onclick="soption('response_code', '400')" href="#">400 BAD REQUEST</span></li>
<li><span class="dropdown-item pointer" onclick="soption('response_code', '401')" href="#">401 NOT AUTHORIZED</span></li>
<li><span class="dropdown-item pointer" onclick="soption('response_code', '403')" href="#">403 FORBIDDEN</span></li>
<li><span class="dropdown-item pointer" onclick="soption('response_code', '406')" href="#">406 NOT ACCEPTABLE</span></li>
<li><span class="dropdown-item pointer" onclick="soption('response_code', '500')" href="#">500 SERVER ERROR</span></li>
<li><span class="dropdown-item pointer" onclick="soption('response_code', '503')" href="#">503 UNAVAILABLE</span></li>
</ul>
</div>
<div id="response_code_spin" class="spinner-border text-success spinner-border-sm mt-1 ml-2 hidden" role="status"></div>
</div>
</div>
<div class="col-12 col-md-6 mb-2">
<div class="form-group">
<label class="form-label">
Remote IP Source
</label>
<small class="form-text text-muted">IP Address, X-Forwarded, Forward</small>
<div class="btn-group left">
<button type="button" class="btn btn-primary" id="drop_ip_header">{{ip_header}}</button>
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" style="width:auto" data-bs-toggle="dropdown" aria-expanded="false">
<span class="visually-hidden">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu">
<li><span class="dropdown-item pointer" onclick="soption('ip_header', 'REMOTE_ADDR')" href="#">REMOTE_ADDR</span></li>
<li><span class="dropdown-item pointer" onclick="soption('ip_header', 'X-FORWARDED-FOR')" href="#">X-FORWARDED</span></li>
<li><span class="dropdown-item pointer" onclick="soption('ip_header', 'FORWARD')" href="#">FORWARD</span></li>
</ul>
</div>
<div id="ip_header_spin" class="spinner-border text-success spinner-border-sm mt-1 ml-2 hidden" role="status"></div>
</div>
</div>
</div>
<div class="row mt-3">
<div class="col-12 col-md-6 ">
<div class="form-group">
<label class="form-label">
Cookie Support
</label>
<small class="form-text text-muted">Disable if server does not support cookies</small>
<div class="auto_col tog" id="cookies_enabled_con" data-enabled="{{cookies_enabled}}" data-title="Enable if your server supports cookies" data-toggle="true">
</div>
</div>
</div>
<div class="col-12 col-md-6 ">
<div class="form-group">
<label class="form-label">
Report Errors
</label>
<small class="form-text text-muted">Log BitFire PHP errors and send to developers </small>
<div class="auto_col tog" id="send_errors_con" data-enabled="{{send_errors}}" data-title="Disable to keep developers un-informed on potential issues" data-toggle="true">
</div>
</div>
</div>
</div>
</div>
</div>
<hr class="my-5">
<!--
<div class="card">
<div class="card-header">
<h4 class="card-header-title">
Optional Settings
<small class="text-muted ml-4">
<a href="https://bitfire.co/system_settings" target="_blank">Learn about BitFire System Settings<span class="fe fe-external-link"></span></a>
</small>
</h4>
</div>
<div class="card-body">
<div class="row">
<div class="form-group">
<label class="form-label">
BitFire Cookie Name
</label>
<small class="form-text text-muted">Cookie name for browser meta-data, unique random name</small>
<div id="browser_cookie_spin" class="spinner-border text-success spinner-border-sm left mt-1 mr-2 hidden" role="status">
<span class="xvisually-hidden">Saving...</span>
</div>
<input type="text" class="form-control txtin" id="browser_cookie_text" autocomplete="off" onchange="update_str('browser_cookie')" value="{{browser_cookie}}">
</div>
<div class="{{show_wp_class}}">
<div class="form-group">
<label class="form-label">
Dashboard Path
</label>
<small class="form-text text-muted">Path to serve BitFire dashboard from</small>
<div id="dashboard_path_spin" class="spinner-border text-success spinner-border-sm left mt-1 mr-2 hidden" role="status">
<span class="xvisually-hidden">Saving...</span>
</div>
<input type="text" class="form-control txtin" id="dashboard_path_text" autocomplete="off" onchange="update_str('dashboard_path')" value="{{dashboard_path}}">
</div>
<div class="form-group">
<label class="form-label">
WordPress Path
</label>
<small class="form-text text-muted">Leave blank if not WordPress</small>
<div id="cms_root_spin" class="spinner-border text-success spinner-border-sm left mt-1 mr-2 hidden" role="status">
<span class="xvisually-hidden">Saving...</span>
</div>
<input type="text" class="form-control txtin" id="dashboard_path_text" autocomplete="off" onchange="update_str('cms_root')" value="{{cms_root}}">
</div>
</div>
</div>
<div class="row">
<div class="form-group">
<label class="form-label">
BitFire Encryption Key
</label>
<small class="form-text text-muted">BitFire cookie encryption key, > 32bytes random</small>
<div id="encryption_key_spin" class="spinner-border text-success spinner-border-sm left mt-1 mr-2 hidden" role="status">
<span class="xvisually-hidden">Saving...</span>
</div>
<input type="text" class="form-control txtin" id="encryption_key_text" autocomplete="off" onchange="update_str('encryption_key')" value="{{encryption_key}}" style="width:88%;float:left;margin-right:10px;">
<div class="fe fe-refresh-cw pointer text-success" style="margin-top:15px;" onclick="rand_string('encryption_key')"></div>
</div>
<div class="form-group">
<label class="form-label">
BitFire Secret Key
</label>
<small class="form-text text-muted">BitFire secret key, > 32bytes random</small>
<div id="secret_spin" class="spinner-border text-success spinner-border-sm left mt-1 mr-2 hidden" role="status">
<span class="xvisually-hidden">Saving...</span>
</div>
<input type="text" class="form-control txtin" id="secret_text" autocomplete="off" onchange="update_str('secret')" value="{{secret}}" style="width:88%;float:left;margin-right:10px;">
<div class="fe fe-refresh-cw pointer text-success" style="margin-top:15px;" onclick="rand_string('secret')"></div>
</div>
</div>
</div>
</div>
-->
<div class="card">
<div class="cover server-red"></div>
<div class="card-body" style="margin-top:1.5rem;">
<div class="avatar avatar-xl card-avatar card-avatar-top" style="margin-top:1rem;">
<img id="" src="{{public}}img/search.jpg" style="background-color:#FFF;" class="avatar-img rounded-circle border-card">
<span class="fe alt1 header-icon fe-cpu"></span>
</div>
<h2 style="margin-top:-1rem;" class="card-title">
<strong>
<span class="tdc alt1">
BitFire PRO / PREMIUM Licensing
</span>
</strong>
</h2>
</div>
<div class="card-body">
<div class="row">
<div class="col-12 col-md-6">
<div class="form-group">
<label class="form-label">
BitFire PRO License
</label>
<small class="form-text text-muted">Check your email for license code after purchase</small>
<div id="pro_key_spin" class="spinner-border text-success spinner-border-sm left mt-1 mr-2 hidden" role="status">
<span class="xvisually-hidden">Saving...</span>
</div>
<input type="text" class="form-control txtin" id="pro_key_text" autocomplete="off" value="{{license}}">
</div>
</div>
<div class="col-12 col-md-6">
<button style="margin-top:4rem" class="btn btn-primary" id="gopro">Go PRO!</button>
</div>
</div>
</div>
</div>
<hr class="my-5 mt-4 mb-4">
<!--
<div class="card">
<div class="card-header">
<h4 class="card-header-title">
Allow editing config.ini
<small class="text-muted ml-4">
This will unlock config.ini for manual editing for a short while
</small>
</h4>
</div>
<div class="card-body">
<div class="row">
<div class="col-12">
<small class="text-secondary">Only unlock if you need to manually edit the config.ini file</small>
<button class="btn btn-secondary right" id="unlock_config">Unlock config.ini</button>
<div id="unlock_config_spin" class="spinner-border text-success spinner-border-sm right mt-1 mr-2 hidden" role="status">
</div>
</div>
</div>
</div>
</div>
-->
<div class="card">
<div class="card-header">
<h4 class="card-header-title">
Uninstall BitFire
<small class="text-muted ml-4">
This will uninstall BitFire from the startup script and remove all files.
</small>
</h4>
</div>
<div class="card-body">
<div class="row">
<div class="col-12">
<small class="text-secondary">The script files can be removed after the php cache expires in 5 minutes</small>
<button class="btn btn-secondary right" id="uninstall">Uninstall</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="hidden" id="uninstall_content">
<div class="row justify-content-center">
<div class="col-12 col-lg-10 col-xl-8">
<div class="card">
<div class="card-header">
<h4 class="card-header-title">
BitFire Uninstalled
<small class="text-muted ml-4">
BitFire has been removed from the startup script.
</small>
</h4>
</div>
<div class="card-body">
<div class="row">
<div class="col-12">
<p class="text-secondary mb-4">In 5 minutes the php ini cache will expire
and the new settings will take effect. After that you can remove
the script files from your server.
</p>
<h2 class="text-center text-secondary" data-time="300" id="countdown_timer">5:00</h2>
<button style="display:block;margin-left:auto;margin-right:auto;" id="remove_files" class="mb-4 btn btn-primary" disabled="disabled">Remove Files</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div><!-- / .main-content -->
<script type="text/javascript">
function save_pass() {
let p1 = GBI("pass1").value;
let p2 = GBI("pass2").value;
if (p1 != p2) { alert("password does not match"); return; }
if (p1.length < 8) { alert("password must be at least 8 characters"); return; }
console.log(p1);
BitFire_api("set_pass", {"pass1":encodeURIComponent(p1)})
.then(r => r.json())
.then(response => {
console.log(response);
if (response.success) {
alert("password updated successfully");
$("#password_set").modal("hide");
} else {
alert(response.note);
}
});
}
/*
// fetch("https://www."+"bitfire.co"+"/ver.php?ts="+Date.now()) // not used on WordPress
.then(response => response.json())
.then(response => {
console.log(response);
var behind = 0;
var latest_str = VERSION_STR;
var latest = VERSION;
for (const r in response) {
//console.log("version!", r);
if(response[r][0] > VERSION) {
if (response[r][0] > latest) {
latest = response[r][0];
latest_str = r;
behind++;
}
}
}
window.LATEST = latest_str;
/*
if (GBI("upgrade_link")) {
if (behind == 0) {
GBI("upgrade_link").innerText = "Software Up To Date";
GBI("upgrade_link").setAttribute("disabled", "disabled");
GBI("upgrade_link").classList.remove("lift");
} else {
GBI("upgrade_link").innerText = "Upgrade to " + latest_str;
GBI("upgrade_link").classList.remove("btn-secondary");
GBI("upgrade_link").classList.add("btn-warning");
GBI("upgrade_link").addEventListener("click", upgrade);
}
}
}
);
*/
function upgrade() {
console.log("upgrade!");
BitFire_api("upgrade", {"ver":window.LATEST})
.then(r => r.json())
.then(response => {
alert(response.note);
});
}
function toggle_features() {
var elms = document.getElementsByClassName("feature");
console.log("toggle features", elms);
Array.prototype.forEach.call(elms, function (element) {
console.log("element", element.innerText);
if (element.innerText.trim() == "report" || element.innerText.trim() == "alert") {
console.log("warn");
element.classList.remove("btn-success");
element.classList.remove("btn-secondary");
element.classList.add("btn-warning");
} else if (element.innerText.trim() == "block" || element.innerText.trim() == "true" || element.innerText.trim() == "on") {
console.log("success");
element.classList.remove("btn-warning");
element.classList.remove("btn-secondary");
element.classList.add("btn-success");
} else {
element.classList.remove("btn-success");
element.classList.remove("btn-warning");
element.classList.add("btn-secondary");
console.log("second");
}
});
}
</script>
<div class="modal fade" id="password_set" role="dialog" data-backdrop="static" data-keyboard="false" tabindex="-1">
<div class="modal-dialog" role="document" id="password_set2">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="pass_title">Set BitFire Initial Password</h5>
<!--
<button type="button" class="btn-close" data-dismiss="modal" aria-label="Close"></button>
-->
</div>
<div class="modal-body">
<p>BitFire password is required to access the dashboard. If you forget the password, change the "password" configuration item in config.ini to "default" to relaunch this modal or set it to the SHA1 value of your password</p>
<label style="width:150px;">Password:</label>
<input id="pass1" type="password" name="pass1" /><br />
<label style="width:150px;">Repeat Password:</label>
<input id="pass2" type="password" name="pass1" />
</div>
<div class="modal-footer">
<button id="password_close" type="button" class="btn btn-secondary " data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" id="save_pass">Save Password</button>
</div>
</div>
</div>
</div>
<script type="text/javascript">
function alert_or_block(config) {
// console.log("alert_or_block", config);
if (config === 'report' || config === 'alert') { return 'report'; }
if (!config) { return 'off'; }
return 'on';
}
if (GBI("password_btn")) {
GBI("password_btn").addEventListener("click", function() {
GBI('password_close').classList.remove("hidden");
});
}
let toggles = document.getElementsByClassName("tog");
for (let i = 0; i < toggles.length; i++) {
let id = toggles[i].getAttribute("id");
let name = id.replace("_con", "");
let title = toggles[i].getAttribute("data-title");
let tog = toggles[i].hasAttribute("data-toggle");
let de = toggles[i].getAttribute("data-enabled");
let alert = alert_or_block(de);
let check1 = (alert == "report") ? "checked" : "";
let check2 = (alert == "on") ? "checked" : "";
let tail1 = (tog) ? "" : " in alert mode only";
let tail2 = (tog) ? "" : " in full blocking";
let tool1 = 'data-bs-toggle="tooltip" data-bs-placement="top" title="'+title+tail1+'"';
let tool2 = 'data-bs-toggle="tooltip" data-bs-placement="top" title="'+title+tail2+'"';
let html = '<div id="'+name+'_spin" class="spinner-border text-success spinner-border-sm left mt-1 mr-2 hidden" role="status"></div>';
if (!tog) {
html += '<div class="form-check form-switch left" style="margin-left:-60px"> <input class="form-check-input warning" id="'+name+'_report" autocomplete="off" type="checkbox" onclick="return toggle_report(\''+name+'\', true)" '+check1+' '+ tool1 +'> </div>';
}
html += '\
<div class="form-switch right">\
<input class="form-check-input success" autocomplete="off" id="'+name+'_block" type="checkbox" onclick="return toggle_report(\''+name+'\', false)" '+check2+' '+tool2+'>\
</div>';
window.CONFIG_LIST[name] = alert;
toggles[i].innerHTML = html;
}
function gopro() {
update_str('pro_key');
window.setTimeout(function() {
alert("BitFire Pro license installed. Click OK to edit advanced-settings.");
window.location = "{{self}}?page=bitfire_advanced";
}, 1000);
}
function unlock_config() {
update_value("unlock_config", "true");
}
function uninstall() {
let doit = confirm("Are you sure you want to uninstall BitFire? This will remove all configuration and logs and cannot be undone.");
if (!doit) { return; }
BitFire_api("uninstall", {})
.then(r => r.json())
.then(data => {
let e = GBI("uninstall_content");
GBI("full_container").innerHTML = e.innerHTML;
window.BITF_INT = window.setInterval(function() {
let e = GBI("countdown_timer");
let sec = parseInt(e.getAttribute("data-time")) - 1;
if (sec == 0) {
window.clearInterval(window.BITF_INT);
GBI("remove_files").removeAttribute("disabled");
} else {
let min = Math.floor(sec / 60);
let rem = sec - (min * 60);
e.setAttribute("data-time", sec);
e.innerText = min + ":" + rem;
}
}, 1000);
});
}
// MAIN
document.addEventListener("DOMContentLoaded", function () {
let e2 = GBI("gopro");
e2.addEventListener("click", gopro);
/*
e2 = GBI("unlock_config");
e2.addEventListener("click", unlock_config);
e2 = GBI("uninstall");
e2.addEventListener("click", uninstall);
*/
});
</script>
{{gtag}}