| // Async METHOD to API |
| async function METHOD(method = 'POST', url = '', data) { |
| let payload = { |
| method: method, |
| mode: 'cors', |
| cache: 'no-cache', |
| credentials: 'same-origin', |
| headers: data ? { |
| 'Content-Type': 'application/json' |
| } : {}, |
| redirect: 'follow', |
| referrerPolicy: 'no-referrer' |
| } |
| if (data) { |
| payload.body = JSON.stringify(data); |
| } |
| try { |
| const response = await fetch(url, payload).catch( (e) => {throw e}); |
| if (response.ok !== true) throw `HTTP Error ${response.status}: ${response.statusText}` |
| let js = response.json(); |
| return js |
| } catch (e) { |
| alert(e); |
| } |
| } |
| |
| // HTTP methods |
| let DELETE = (url, data) => METHOD('DELETE', url, data); |
| let GET = (url, data) => METHOD('GET', url, data); |
| let PATCH = (url, data) => METHOD('PATCH', url, data); |
| let POST = (url, data) => METHOD('POST', url, data); |
| let PUT = (url, data) => METHOD('PUT', url, data); |
| |
| |
| // Prettifier for large numbers (adds commas) |
| Number.prototype.pretty = function(fix) { |
| if (fix) { |
| return String(this.toFixed(fix)).replace(/(\d)(?=(\d{3})+\.)/g, '$1,'); |
| } |
| return String(this.toFixed(0)).replace(/(\d)(?=(\d{3})+$)/g, '$1,'); |
| }; |
| |
| // HTML shortcuts |
| let htmlobj = (type, text) => { let obj = document.createElement(type); obj.innerText = text ? text : ""; return obj } |
| let _h1 = (title) => htmlobj('h1', title); |
| let _h2 = (title) => htmlobj('h2', title); |
| let _span = (title) => htmlobj('span', title); |
| let _p = (title) => htmlobj('p', title); |
| let _br = (title) => htmlobj('br'); |
| let _hr = (title) => htmlobj('hr'); |
| let _tr = () => htmlobj('tr'); |
| let _td = (title) => htmlobj('td', title); |
| let _th = (title, width) => { let obj = htmlobj('th', title); if (width) obj.style.width = width + "px"; return obj } |
| let _table = () => htmlobj('table'); |
| let _a = (txt) => htmlobj('a', txt); |
| |
| |
| async function unblock_ip(_entry, force = true) { |
| if (confirm(`This will unblock ${_entry.ip} and add it to the allow-list for 10 minutes. Continue?`)) { |
| result = await POST('allow', { |
| ip: _entry.ip, |
| reason: "Temporarily allow-listed for 10 minutes to unblock IP", |
| expires: parseInt(new Date().getTime()/1000) + 600, |
| force: force |
| }) |
| if (result.success === true) { |
| alert("IP Unblocked. Please allow for a few moments for it to apply across the servers."); |
| location.reload(); |
| } else { |
| alert(result.message); |
| } |
| } |
| return false; |
| } |
| |
| |
| async function remove_allow(_entry) { |
| if (confirm(`This will remove ${_entry.ip} from the allow list. Continue?`)) { |
| result = await DELETE('allow', { |
| ip: _entry.ip, |
| force: true |
| }) |
| if (result.success === true) { |
| alert("IP Removed from allow-list."); |
| location.reload(); |
| } else { |
| alert(result.message); |
| } |
| } |
| return false; |
| } |
| |
| |
| function unblock_link(entry, allowlist=false) { |
| let link = _a(allowlist ? 'Remove' : 'Unblock'); |
| let _entry = entry; |
| link.setAttribute("href", 'javascript:void(0);'); |
| if (allowlist === true) { link.addEventListener('click', () => remove_allow(_entry)); } |
| else {link.addEventListener('click', () => unblock_ip(_entry));} |
| return link; |
| } |
| |
| async function prime_frontpage() { |
| let all = await GET("all"); |
| let main = document.getElementById('main'); |
| main.innerHTML = ""; |
| let block_count = all.block.length.pretty(); |
| let h1 = _h1(`Recent activity (${block_count} blocks in total)`); |
| main.appendChild(h1); |
| all.block.sort((a,b) => b.timestamp - a.timestamp); // sort desc by timestamp |
| |
| |
| // Recent blocks |
| let activity_table = _table(); |
| activity_table.style.tableLayout = 'fixed'; |
| main.appendChild(activity_table); |
| |
| let theader = _tr(); |
| theader.appendChild(_th('Source IP', 300)); |
| theader.appendChild(_th('Added', 120)); |
| theader.appendChild(_th('Expires', 120)); |
| theader.appendChild(_th('Reason', 500)); |
| theader.appendChild(_th('Actions', 100)); |
| activity_table.appendChild(theader); |
| |
| let results_shown = 0; |
| for (const entry of all.block) { |
| let tr = _tr(); |
| let td_ip = _td(entry.ip); |
| td_ip.style.fontFamily = "monospace"; |
| if (entry.ip.length > 16) td_ip.style.fontSize = "0.8rem"; |
| let td_added = _td(moment(entry.timestamp*1000.0).fromNow()); |
| let td_expires = _td(entry.expires > 0 ? moment(entry.expires*1000.0).fromNow() : 'Never'); |
| let td_reason = _td(entry.reason); |
| let td_action = _td(); |
| td_action.appendChild(unblock_link(entry)); |
| tr.appendChild(td_ip); |
| tr.appendChild(td_added); |
| tr.appendChild(td_expires); |
| tr.appendChild(td_reason); |
| tr.appendChild(td_action); |
| activity_table.appendChild(tr); |
| results_shown++; |
| if (results_shown > 25 && all.block.length > 25) { |
| break |
| } |
| } |
| if (results_shown === 0) { |
| let tr = _tr(); |
| tr.innerText = "No activity found..."; |
| activity_table.appendChild(_tr); |
| } |
| |
| |
| } |
| |
| |
| async function prime_search(target, state) { |
| if (!state) { |
| window.history.pushState({}, '', `?search:${target}`); |
| } |
| let main = document.getElementById('main'); |
| main.innerHTML = ''; |
| if (target && target.length > 0) { |
| let title = _h1("Search results for " + target + ":"); |
| main.appendChild(title); |
| |
| let p = _p("Searching, please wait..."); |
| main.appendChild(p); |
| |
| let results = await POST('search', {source: target}); |
| |
| if (results.success === false) { |
| p.innerText = results.message; |
| return |
| } |
| |
| main.removeChild(p); |
| |
| // Allow list results |
| let h2 = _h2(`Allow list results (${results.allow.length})`); |
| main.appendChild(h2); |
| let allow_table = _table(); |
| allow_table.style.tableLayout = 'fixed'; |
| main.appendChild(allow_table); |
| |
| let theader = _tr(); |
| theader.appendChild(_th('Source IP', 300)); |
| theader.appendChild(_th('Added', 120)); |
| theader.appendChild(_th('Expires', 120)); |
| theader.appendChild(_th('Reason', 500)); |
| theader.appendChild(_th('Actions', 100)); |
| allow_table.appendChild(theader); |
| |
| let results_shown = 0; |
| results.allow.sort((a,b) => b.timestamp - a.timestamp); // sort desc by timestamp |
| for (const entry of results.allow) { |
| let tr = _tr(); |
| let td_ip = _td(entry.ip); |
| let td_added = _td(moment(entry.timestamp * 1000.0).fromNow()); |
| let td_expires = _td(entry.expires > 0 ? moment(entry.expires * 1000.0).fromNow() : 'Never'); |
| let td_reason = _td(entry.reason); |
| let td_action = _td(); |
| td_action.appendChild(unblock_link(entry, true)); |
| td_ip.style.fontFamily = "monospace"; |
| if (entry.ip.length > 16) td_ip.style.fontSize = "0.8rem"; |
| tr.appendChild(td_ip); |
| tr.appendChild(td_added); |
| tr.appendChild(td_expires); |
| tr.appendChild(td_reason); |
| tr.appendChild(td_action); |
| allow_table.appendChild(tr); |
| results_shown++; |
| if (results_shown > 25 && results.block.length > 25) { |
| break |
| } |
| } |
| if (results_shown === 0) { |
| let tr = _tr(); |
| tr.innerText = "No results found..."; |
| allow_table.appendChild(tr); |
| } |
| |
| // Block list results |
| let bh2 = _h2(`Block list results (${results.block.length})`); |
| main.appendChild(bh2); |
| let block_table = _table(); |
| block_table.style.tableLayout = 'fixed'; |
| main.appendChild(block_table); |
| |
| let btheader = _tr(); |
| btheader.appendChild(_th('Source IP', 300)); |
| btheader.appendChild(_th('Added', 120)); |
| btheader.appendChild(_th('Expires', 120)); |
| btheader.appendChild(_th('Reason', 500)); |
| btheader.appendChild(_th('Actions', 100)); |
| block_table.appendChild(btheader); |
| |
| results_shown = 0; |
| results.block.sort((a,b) => b.timestamp - a.timestamp); // sort desc by timestamp |
| for (const entry of results.block) { |
| let tr = _tr(); |
| let td_ip = _td(entry.ip); |
| let td_added = _td(moment(entry.timestamp * 1000.0).fromNow()); |
| let td_expires = _td(entry.expires > 0 ? moment(entry.expires * 1000.0).fromNow() : 'Never'); |
| let td_reason = _td(entry.reason); |
| let td_actions = _td(''); |
| td_actions.appendChild(unblock_link(entry)); |
| td_ip.style.fontFamily = "monospace"; |
| if (entry.ip.length > 16) td_ip.style.fontSize = "0.8rem"; |
| tr.appendChild(td_ip); |
| tr.appendChild(td_added); |
| tr.appendChild(td_expires); |
| tr.appendChild(td_reason); |
| tr.appendChild(td_actions); |
| |
| block_table.appendChild(tr); |
| results_shown++; |
| if (results_shown > 25 && results.block.length > 25) { |
| break |
| } |
| } |
| if (results_shown === 0) { |
| let tr = _tr(); |
| tr.innerText = "No results found..."; |
| block_table.appendChild(tr); |
| } |
| |
| // iptables results |
| let ih2 = _h2(`Local iptables results (${results.iptables.length})`); |
| main.appendChild(ih2); |
| let iptables_table = _table(); |
| iptables_table.style.tableLayout = 'fixed'; |
| main.appendChild(iptables_table); |
| |
| let itheader = _tr(); |
| itheader.appendChild(_th('Source IP', 300)); |
| itheader.appendChild(_th('Host', 200)); |
| itheader.appendChild(_th('Chain', 100)); |
| itheader.appendChild(_th('Reason', 450)); |
| itheader.appendChild(_th('Actions', 100)); |
| iptables_table.appendChild(itheader); |
| |
| results_shown = 0; |
| for (const entry of results.iptables) { |
| let tr = _tr(); |
| let td_ip = _td(entry.source); |
| let td_host = _td(entry.hostname); |
| let td_chain = _td(entry.chain); |
| let td_reason = _td(entry.extensions.replace(/\/\*\s*(.+)\s*\*\//, (b,a) => a)); |
| let td_actions = _td(); |
| td_actions.appendChild(unblock_iptables_link(entry)); |
| td_ip.style.fontFamily = "monospace"; |
| if (entry.source.length > 16) td_ip.style.fontSize = "0.8rem"; |
| tr.appendChild(td_ip); |
| tr.appendChild(td_host); |
| tr.appendChild(td_chain); |
| tr.appendChild(td_reason); |
| tr.appendChild(td_actions); |
| |
| iptables_table.appendChild(tr); |
| results_shown++; |
| if (results_shown > 25 && results.block.length > 25) { |
| break |
| } |
| } |
| if (results_shown === 0) { |
| let tr = _tr(); |
| tr.innerText = "No results found..."; |
| iptables_table.appendChild(tr); |
| } |
| |
| } else { |
| //let x = await sleep(10); |
| let p = _p("Use the search bar in the top left corner for now..."); |
| main.appendChild(p); |
| } |
| |
| } |
| |
| function unblock_iptables_link(entry) { |
| let link = _a('Soft Unblock'); |
| let _entry = entry; |
| _entry.ip = _entry.source; |
| link.setAttribute("href", 'javascript:void(0);'); |
| link.addEventListener('click', () => unblock_ip(_entry, false)); |
| return link; |
| } |
| |
| function rule_tr(rule) { |
| let tr = _tr(); |
| |
| // Description |
| let t_desc = _td(); |
| let x_desc = document.createElement('input'); |
| x_desc.setAttribute('type', 'text'); |
| x_desc.setAttribute('id', `desc_${rule.id}`); |
| x_desc.style.width = "95%"; |
| if (rule.description) { |
| x_desc.value = rule.description; |
| } else { |
| x_desc.placeholder = "Create a new rule here..."; |
| } |
| t_desc.appendChild(x_desc); |
| tr.appendChild(t_desc); |
| |
| |
| // AggType |
| let t_agg = _td(); |
| let x_agg = document.createElement('select'); |
| x_agg.setAttribute('id', `agg_${rule.id}`); |
| for (let opt of ['requests', 'bytes']) { |
| let x_opt = document.createElement('option'); |
| x_opt.value = opt; |
| x_opt.textContent = opt; |
| if (opt == rule.aggtype) x_opt.setAttribute('selected', 'selected'); |
| x_agg.appendChild(x_opt); |
| } |
| t_agg.appendChild(x_agg); |
| tr.appendChild(t_agg); |
| |
| // Limit |
| let t_limit = _td(); |
| let x_limit = document.createElement('input'); |
| x_limit.setAttribute('type', 'number'); |
| x_limit.value = rule.limit; |
| x_limit.setAttribute('id', `limit_${rule.id}`); |
| x_limit.style.width = "95%"; |
| t_limit.appendChild(x_limit); |
| tr.appendChild(t_limit); |
| |
| // Timespan |
| let t_time = _td(); |
| let x_time = document.createElement('input'); |
| x_time.setAttribute('type', 'text'); |
| x_time.setAttribute('id', `time_${rule.id}`); |
| x_time.style.width = "95%"; |
| x_time.value = rule.duration; |
| t_time.appendChild(x_time); |
| tr.appendChild(t_time); |
| |
| // Filters |
| let t_filters = _td(); |
| let x_filters = document.createElement('textarea'); |
| x_filters.setAttribute('id', `filters_${rule.id}`); |
| x_filters.style.width = "95%"; |
| x_filters.textContent = rule.filters; |
| t_filters.appendChild(x_filters) |
| tr.appendChild(t_filters); |
| |
| // Actions |
| let t_actions = _td(); |
| t_actions.style.textAlign = 'center'; |
| tr.appendChild(t_actions); |
| |
| |
| if (rule.description) { |
| let x_save = document.createElement('button'); |
| x_save.innerText = 'Save'; |
| x_save.addEventListener('click', () => patch_rule(rule)); |
| t_actions.appendChild(x_save); |
| |
| let x_delete = document.createElement('button'); |
| x_delete.style.marginLeft = '32px'; |
| x_delete.innerText = 'Delete'; |
| x_delete.addEventListener('click', () => delete_rule(rule)); |
| t_actions.appendChild(x_delete); |
| } else { |
| let x_save = document.createElement('button'); |
| x_save.innerText = 'Create Rule'; |
| x_save.addEventListener('click', () => create_rule(rule)); |
| t_actions.appendChild(x_save); |
| |
| } |
| |
| return tr |
| } |
| |
| function fetch_rule_data(rule) { |
| let desc = document.getElementById(`desc_${rule.id}`).value; |
| let agg = document.getElementById(`agg_${rule.id}`).value; |
| let limit = parseInt(document.getElementById(`limit_${rule.id}`).value); |
| let duration = document.getElementById(`time_${rule.id}`).value; |
| let filters = document.getElementById(`filters_${rule.id}`).value.trim(); |
| return { |
| description: desc, |
| aggtype: agg, |
| limit: limit, |
| duration: duration, |
| filter: filters |
| } |
| } |
| async function delete_rule(rule) { |
| if (confirm("Are you sure you wish to delete this rule?")) { |
| let result = await DELETE('rules', {rule: rule.id}); |
| alert(result.message); |
| if (result.success === true) location.reload(); |
| } |
| } |
| |
| async function patch_rule(rule) { |
| let new_rule = fetch_rule_data(rule); |
| new_rule.rule = rule.id; |
| let result = await PATCH('rules', new_rule); |
| alert(result.message); |
| if (result.success === true) location.reload(); |
| } |
| async function create_rule(rule) { |
| let new_rule = fetch_rule_data(rule); |
| let result = await PUT('rules', new_rule); |
| alert(result.message); |
| if (result.success === true) location.reload(); |
| } |
| |
| async function prime_rules(target, state) { |
| let main = document.getElementById('main'); |
| main.innerHTML = ''; |
| let title = _h1("Block rules"); |
| main.appendChild(title); |
| |
| let t = _table(); |
| t.style.tableLayout = 'fixed'; |
| main.appendChild(t); |
| |
| let btheader = _tr(); |
| btheader.appendChild(_th('Description', 500)); |
| btheader.appendChild(_th('Aggregation Type', 160)); |
| btheader.appendChild(_th('Limit', 140)); |
| btheader.appendChild(_th('Timespan', 80)); |
| btheader.appendChild(_th('Filters', 360)); |
| btheader.appendChild(_th('Actions', 150)); |
| t.appendChild(btheader); |
| |
| let rules = await GET('rules'); |
| |
| for (let rule of rules) { |
| let tr = rule_tr(rule); |
| t.appendChild(tr); |
| } |
| |
| let tr = _tr(); |
| let td = _td(); |
| td.appendChild(_hr()); |
| td.colSpan = 6; |
| tr.appendChild(td); |
| t.appendChild(tr); |
| |
| let new_rule = rule_tr({id: 9999, duration: "24h", limit: 100}); |
| t.appendChild(new_rule); |
| |
| let p = _p("Filters support regular Lucene match (foo = bar), exact terms match (foo == bar), regexp (foo ~= ba[rz]). All matches can be negated with !, such as !=, !==, !~= etc") |
| main.appendChild(p); |
| |
| } |
| |
| async function save_allow() { |
| let ip = document.getElementById('add_source').value; |
| let expiry = parseInt(document.getElementById('add_expiry').value); |
| let reason = document.getElementById('add_reason').value; |
| let host = document.getElementById('add_host').value; |
| let true_expiry = parseInt(new Date().getTime() / 1000) + expiry; |
| let force = document.getElementById('add_force').checked ? true : false; |
| if (expiry == -1) true_expiry = -1; |
| |
| let result = await PUT('allow', { |
| ip: ip, |
| host: host, |
| reason: reason, |
| expires: true_expiry, |
| force: force |
| }); |
| alert(result.message); |
| if (result.success === true) location.reload(); |
| } |
| |
| |
| |
| |
| async function prime_allow() { |
| let all = await GET("all"); |
| let main = document.getElementById('main'); |
| main.innerHTML = ""; |
| |
| let h2 = _h2("Add an allow rule:"); |
| main.appendChild(h2); |
| |
| |
| // Add an entry |
| let add_table = _table(); |
| add_table.style.tableLayout = 'fixed'; |
| main.appendChild(add_table); |
| let atheader = _tr(); |
| atheader.appendChild(_th('Source IP', 300)); |
| atheader.appendChild(_th('Expiry', 120)); |
| atheader.appendChild(_th('Reason', 500)); |
| atheader.appendChild(_th('Host', 100)); |
| atheader.appendChild(_th('Force', 60)); |
| atheader.appendChild(_th(' ', 100)); |
| add_table.appendChild(atheader); |
| |
| let add_tr = _tr(); |
| |
| // source ip |
| let add_source = _td(); |
| let add_source_input = document.createElement('input'); |
| add_source_input.placeholder = "CIDR, e.g. 127.0.0.1/32 or 2001:dead:beef::1" |
| add_source_input.style.width = "95%"; |
| add_source_input.id = "add_source" |
| add_source.appendChild(add_source_input); |
| add_tr.appendChild(add_source); |
| |
| // expiry |
| let add_expiry = _td(); |
| let add_expiry_input = document.createElement('select'); |
| add_expiry_input.id = "add_expiry"; |
| let options = { |
| "10 minutes": 600, |
| "1 hour": 3600, |
| "2 hours": 7200, |
| "12 hours": 43200, |
| "24 hours": 86400, |
| "7 days": 604800, |
| "never": -1 |
| } |
| for (let key in options) { |
| let x_opt = document.createElement('option'); |
| x_opt.value = options[key]; |
| x_opt.text = key; |
| add_expiry_input.appendChild(x_opt); |
| } |
| add_expiry.appendChild(add_expiry_input); |
| add_tr.appendChild(add_expiry); |
| |
| // Reason |
| let add_reason = _td(); |
| let add_reason_input = document.createElement('input'); |
| add_reason_input.placeholder = "Enter a reason for allowing this IP/block." |
| add_reason_input.style.width = "95%"; |
| add_reason_input.id = "add_reason"; |
| add_reason.appendChild(add_reason_input); |
| add_tr.appendChild(add_reason); |
| |
| // Host |
| let add_host = _td(); |
| let add_host_input = document.createElement('input'); |
| add_host_input.placeholder = "* or foo.apache.org"; |
| add_host_input.value = "*"; |
| add_host_input.style.width = "95%"; |
| add_host_input.id = "add_host"; |
| add_host.appendChild(add_host_input); |
| add_tr.appendChild(add_host); |
| |
| // Force |
| let add_force = _td(); |
| let add_force_input = document.createElement('input'); |
| add_force_input.setAttribute('type', 'checkbox'); |
| add_force_input.setAttribute('value', 'true'); |
| add_force_input.id = 'add_force'; |
| add_force.appendChild(add_force_input); |
| add_tr.appendChild(add_force); |
| |
| // Save button |
| let add_save = _td(); |
| let add_save_button = document.createElement('button'); |
| add_save_button.innerText = "Add allow rule"; |
| add_save_button.addEventListener('click', () => save_allow()); |
| add_save.appendChild(add_save_button); |
| add_tr.appendChild(add_save); |
| |
| |
| add_table.appendChild(add_tr); |
| main.appendChild(_hr()); |
| |
| |
| let allow_count = all.allow.length.pretty(); |
| let h1 = _h1(`Allowed IPs (${allow_count} entries in total)`); |
| main.appendChild(h1); |
| all.allow.sort((a,b) => b.timestamp - a.timestamp); // sort desc by timestamp |
| |
| |
| // Current entries in allow list |
| let activity_table = _table(); |
| activity_table.style.tableLayout = 'fixed'; |
| main.appendChild(activity_table); |
| |
| let theader = _tr(); |
| theader.appendChild(_th('Source IP', 300)); |
| theader.appendChild(_th('Added', 120)); |
| theader.appendChild(_th('Expires', 120)); |
| theader.appendChild(_th('Reason', 500)); |
| theader.appendChild(_th('Host', 100)); |
| theader.appendChild(_th('Actions', 100)); |
| activity_table.appendChild(theader); |
| |
| let results_shown = 0; |
| for (const entry of all.allow) { |
| let tr = _tr(); |
| let td_ip = _td(entry.ip); |
| td_ip.style.fontFamily = "monospace"; |
| if (entry.ip.length > 16) td_ip.style.fontSize = "0.8rem"; |
| let td_added = _td(moment(entry.timestamp*1000.0).fromNow()); |
| let td_expires = _td(entry.expires > 0 ? moment(entry.expires*1000.0).fromNow() : 'Never'); |
| let td_reason = _td(entry.reason); |
| let td_host = _td(entry.host); |
| let td_action = _td(); |
| td_action.appendChild(unblock_link(entry, true)); |
| tr.appendChild(td_ip); |
| tr.appendChild(td_added); |
| tr.appendChild(td_expires); |
| tr.appendChild(td_reason); |
| tr.appendChild(td_host); |
| tr.appendChild(td_action); |
| activity_table.appendChild(tr); |
| results_shown++; |
| } |
| if (results_shown === 0) { |
| let tr = _tr(); |
| tr.innerText = "No entries found..."; |
| activity_table.appendChild(_tr); |
| } |
| |
| |
| |
| } |
| |
| |
| |
| async function save_block() { |
| let ip = document.getElementById('add_source').value; |
| let expiry = parseInt(document.getElementById('add_expiry').value); |
| let reason = document.getElementById('add_reason').value; |
| let host = document.getElementById('add_host').value; |
| let true_expiry = parseInt(new Date().getTime() / 1000) + expiry; |
| if (expiry == -1) true_expiry = -1; |
| |
| let result = await PUT('block', { |
| ip: ip, |
| host: host, |
| reason: reason, |
| expires: true_expiry |
| }); |
| alert(result.message); |
| if (result.success === true) location.reload(); |
| } |
| |
| |
| |
| async function prime_block() { |
| let all = await GET("all"); |
| let main = document.getElementById('main'); |
| main.innerHTML = ""; |
| |
| let h2 = _h1("Add a block rule:"); |
| main.appendChild(h2); |
| |
| |
| // Add an entry |
| let add_table = _table(); |
| add_table.style.tableLayout = 'fixed'; |
| main.appendChild(add_table); |
| let atheader = _tr(); |
| atheader.appendChild(_th('Source IP', 300)); |
| atheader.appendChild(_th('Expiry', 120)); |
| atheader.appendChild(_th('Reason', 500)); |
| atheader.appendChild(_th('Host', 100)); |
| atheader.appendChild(_th(' ', 100)); |
| add_table.appendChild(atheader); |
| |
| let add_tr = _tr(); |
| |
| // source ip |
| let add_source = _td(); |
| let add_source_input = document.createElement('input'); |
| add_source_input.placeholder = "CIDR, e.g. 127.0.0.1/32 or 2001:dead:beef::1" |
| add_source_input.style.width = "95%"; |
| add_source_input.id = "add_source" |
| add_source.appendChild(add_source_input); |
| add_tr.appendChild(add_source); |
| |
| // expiry |
| let add_expiry = _td(); |
| let add_expiry_input = document.createElement('select'); |
| add_expiry_input.id = "add_expiry"; |
| let options = { |
| "1 hour": 3600, |
| "2 hours": 7200, |
| "12 hours": 43200, |
| "24 hours": 86400, |
| "7 days": 604800, |
| "never": -1 |
| } |
| for (let key in options) { |
| let x_opt = document.createElement('option'); |
| x_opt.value = options[key]; |
| x_opt.text = key; |
| add_expiry_input.appendChild(x_opt); |
| } |
| add_expiry.appendChild(add_expiry_input); |
| add_tr.appendChild(add_expiry); |
| |
| // Reason |
| let add_reason = _td(); |
| let add_reason_input = document.createElement('input'); |
| add_reason_input.placeholder = "Enter a reason for allowing this IP/block." |
| add_reason_input.style.width = "95%"; |
| add_reason_input.id = "add_reason"; |
| add_reason.appendChild(add_reason_input); |
| add_tr.appendChild(add_reason); |
| |
| // Host |
| let add_host = _td(); |
| let add_host_input = document.createElement('input'); |
| add_host_input.placeholder = "* or foo.apache.org"; |
| add_host_input.value = "*"; |
| add_host_input.style.width = "95%"; |
| add_host_input.id = "add_host"; |
| add_host.appendChild(add_host_input); |
| add_tr.appendChild(add_host); |
| |
| // Save button |
| let add_save = _td(); |
| let add_save_button = document.createElement('button'); |
| add_save_button.innerText = "Add block rule"; |
| add_save_button.addEventListener('click', () => save_block()); |
| add_save.appendChild(add_save_button); |
| add_tr.appendChild(add_save); |
| |
| |
| add_table.appendChild(add_tr); |
| main.appendChild(_hr()); |
| } |
| |
| |
| |
| let actions = { |
| frontpage: prime_frontpage, |
| allow: prime_allow, |
| add: prime_block, |
| search: prime_search, |
| rules: prime_rules |
| }; |
| |
| |
| async function prime(args) { |
| console.log(args); |
| let segs = location.search.substr(1).match(/^([a-z]*):?(.*)$/); |
| let action = segs[1]; |
| let params = segs[2]; |
| action_call = actions[action] ? actions[action] : actions['frontpage']; |
| await action_call(params, args ? args.state : null); |
| } |
| |
| window.onpopstate = prime; |