The banner calls ip.dsv.su.se and uses the returned information to determine whether the client is using a VPN connection.
307 lines
12 KiB
JavaScript
307 lines
12 KiB
JavaScript
'use strict';
|
|
(function() {
|
|
window.addEventListener('DOMContentLoaded', (event) => {
|
|
setup_page();
|
|
vpn_status();
|
|
});
|
|
|
|
function vpn_status() {
|
|
const wrapper = document.querySelector('vpnstatus');
|
|
const output = wrapper.querySelector('.result');
|
|
fetch('https://ip.dsv.su.se',
|
|
{headers: {'Accept': 'application/json'}})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error("API request failed: " + response.status);
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
const hostname = window.location.hostname.split('.')[0];
|
|
if(data.vpn === hostname) {
|
|
output.textContent = "Using VPN";
|
|
wrapper.classList.add('active');
|
|
} else {
|
|
output.textContent = "Not using VPN";
|
|
wrapper.classList.add('inactive');
|
|
}
|
|
})
|
|
.catch(err => {
|
|
const out = "Error when checking VPN status: " + err.message;
|
|
output.textContent = out;
|
|
wrapper.classList.add('error');
|
|
});
|
|
}
|
|
|
|
function close_modal(node) {
|
|
let current = node;
|
|
while(current.nodeName != 'BACKDROP') {
|
|
current = current.parentNode;
|
|
if(current.nodeName === 'HTML') {
|
|
console.error("can't find modal parent");
|
|
return;
|
|
}
|
|
}
|
|
current.parentNode.removeChild(current);
|
|
}
|
|
|
|
function deny_access() {
|
|
const vpnstatus = document.querySelector('vpnstatus');
|
|
vpnstatus.replaceWith('');
|
|
const topbox = document.querySelector('topbox');
|
|
while(topbox.firstChild) {
|
|
topbox.removeChild(topbox.lastChild);
|
|
}
|
|
const placeholder = document.querySelector('placeholder');
|
|
placeholder.replaceWith('');
|
|
const template = document.querySelector('template#access-denied')
|
|
.content.cloneNode(true);
|
|
topbox.appendChild(template);
|
|
document.querySelector('body').removeAttribute('style');
|
|
}
|
|
|
|
function display_create_form() {
|
|
const template = document.querySelector('template#create-form')
|
|
.content.cloneNode(true);
|
|
const form = template.querySelector('form');
|
|
form.addEventListener('submit', (event) => {
|
|
event.preventDefault();
|
|
const id = crypto.randomUUID();
|
|
const name = form.name.value;
|
|
if(!name) {
|
|
return;
|
|
}
|
|
const description = form.description.value.trim();
|
|
make_api_request('POST',
|
|
'/configs/' + id + '/create',
|
|
{'name': name,
|
|
'description': description})
|
|
.then((response) => {
|
|
if(response.result == 'success') {
|
|
display_configs(id);
|
|
close_modal(form);
|
|
} else {
|
|
throw new Error(response.reason);
|
|
}
|
|
})
|
|
.catch((exception) => {
|
|
console.error('creation failed for: '+id, exception);
|
|
});
|
|
});
|
|
display_modal(template, form.name);
|
|
}
|
|
|
|
function display_configs(...config_ids) {
|
|
const configs_parent = document.querySelector('configs');
|
|
const dlprefix = 'data:text/plain;charset:utf-8,';
|
|
config_ids.forEach((config_id) => {
|
|
const old = configs_parent.querySelector('#config-'+config_id);
|
|
if(old) {
|
|
old.parentNode.removeChild(old);
|
|
}
|
|
const template = document.querySelector('template#display-config')
|
|
.content.cloneNode(true);
|
|
const config = template.querySelector('config');
|
|
make_api_request('GET', '/configs/' + config_id)
|
|
.then((data) => {
|
|
config.id = 'config-' + config_id;
|
|
config.querySelector('name').textContent = data.name;
|
|
config.querySelector('description').textContent =
|
|
data.description;
|
|
config.querySelector('data').textContent = data.data;
|
|
|
|
const qr = config.querySelector('.qr');
|
|
qr.innerHTML = data.qrcode;
|
|
const svg = qr.querySelector('svg');
|
|
svg.setAttribute('shape-rendering', 'crisp-edges');
|
|
svg.setAttribute('aria-label', 'QR code');
|
|
|
|
const expires = config.querySelector('expires');
|
|
if(data.expires) {
|
|
expires.textContent = data.expires;
|
|
} else {
|
|
config.removeChild(expires);
|
|
}
|
|
|
|
const link = config.querySelector('.conffile');
|
|
link.setAttribute('href',
|
|
dlprefix + encodeURIComponent(data.data));
|
|
link.setAttribute('download', data.name + '.conf');
|
|
config.querySelector('button.edit')
|
|
.addEventListener('click', (event) => {
|
|
display_edit_form(config_id, data);
|
|
});
|
|
config.querySelector('button.download')
|
|
.addEventListener('click', (event) => {
|
|
link.click();
|
|
});
|
|
|
|
const config_children = configs_parent.children;
|
|
for(let i = 0; i < config_children.length; i++) {
|
|
const child = config_children[i];
|
|
if(child.nodeName === 'PLACEHOLDER') {
|
|
configs_parent.insertBefore(template, child);
|
|
break;
|
|
}
|
|
const name = child.querySelector('name').textContent;
|
|
if(data.name.toLowerCase() < name.toLowerCase()) {
|
|
configs_parent.insertBefore(template, child);
|
|
}
|
|
}
|
|
update_create_button();
|
|
});
|
|
});
|
|
|
|
}
|
|
|
|
function display_edit_form(config_id, config) {
|
|
const template = document.querySelector('template#update-form')
|
|
.content.cloneNode(true);
|
|
const form = template.querySelector('form');
|
|
form.name.value = config.name;
|
|
form.description.value = config.description;
|
|
form.addEventListener('submit', (event) => {
|
|
event.preventDefault();
|
|
make_api_request('POST',
|
|
'/configs/' + config_id + '/update',
|
|
{'name': form.name.value,
|
|
'description': form.description.value.trim()})
|
|
.then((response) => {
|
|
if(response.result == 'success') {
|
|
display_configs(config_id);
|
|
close_modal(form);
|
|
} else {
|
|
throw new Error(response.reason);
|
|
}
|
|
})
|
|
.catch((exception) => {
|
|
console.error('update failed for: '+config_id,
|
|
exception);
|
|
});
|
|
});
|
|
const delete_button = form.querySelector('button.delete');
|
|
delete_button.addEventListener('click', (event) => {
|
|
if(!window.confirm('Are you sure you want to delete this client?')) {
|
|
return;
|
|
}
|
|
make_api_request('POST',
|
|
'/configs/' + config_id + '/delete')
|
|
.then((response) => {
|
|
document.querySelector('#config-'+config_id).remove();
|
|
update_create_button();
|
|
close_modal(form);
|
|
})
|
|
.catch((exception) => {
|
|
console.error('deletion failed for: '+config_id,
|
|
exception);
|
|
});
|
|
});
|
|
display_modal(template, form.name);
|
|
}
|
|
|
|
function display_modal(fragment, focus_element) {
|
|
const modal = document.querySelector('template#modal')
|
|
.content.cloneNode(true);
|
|
modal.querySelector('wrapper').appendChild(fragment);
|
|
|
|
const backdrop = modal.querySelector('backdrop');
|
|
const cancel = modal.querySelector('button.cancel');
|
|
backdrop.addEventListener('click', (event) => {
|
|
if(event.target === backdrop
|
|
|| event.target === cancel) {
|
|
close_modal(backdrop);
|
|
}
|
|
});
|
|
|
|
document.querySelector('body').appendChild(modal);
|
|
focus_element.focus();
|
|
}
|
|
|
|
function get_cookies() {
|
|
var out = new Object();
|
|
const cookies = document.cookie.split('; ');
|
|
cookies.forEach((cookie) => {
|
|
const temp = cookie.split('=');
|
|
const name = temp[0];
|
|
const value = temp.slice(1).join('=');
|
|
out[name] = value;
|
|
});
|
|
return out;
|
|
}
|
|
|
|
function login() {
|
|
const current_path = window.location.pathname;
|
|
return window.location.replace('/api/login?return='
|
|
+ current_path);
|
|
}
|
|
|
|
async function make_api_request(method, path, body) {
|
|
const data = {'method': method,
|
|
'headers': {'Content-Type': 'application/json'}};
|
|
if(method != 'GET') {
|
|
data['body'] = JSON.stringify(body);
|
|
}
|
|
const request = new Request('/api' + path, data);
|
|
const response = await fetch(request);
|
|
if(response.status === 403) {
|
|
const cookies = get_cookies();
|
|
const access = cookies['access'];
|
|
if(access === 'denied') {
|
|
throw new Error('access denied');
|
|
}
|
|
login();
|
|
}
|
|
return response.json();
|
|
}
|
|
|
|
function update_create_button() {
|
|
const visible_configs = document.querySelectorAll('configs > config');
|
|
const max_clients = sessionStorage.getItem('max_clients');
|
|
|
|
let button_disabled = false;
|
|
let button_message = 'Add a client';
|
|
if(max_clients > 0 && visible_configs.length >= max_clients) {
|
|
button_disabled = true;
|
|
button_message = 'Limit of '+max_clients+' clients reached';
|
|
}
|
|
const button = document.querySelector('button#create-config');
|
|
button.disabled = button_disabled;
|
|
button.innerHTML = button_message;
|
|
}
|
|
|
|
async function setup_page(route) {
|
|
try {
|
|
const configs = await make_api_request('GET', '/configs/');
|
|
document.querySelector('body').removeAttribute('style');
|
|
const cookies = get_cookies();
|
|
const settings = JSON.parse(atob(cookies['server_settings']));
|
|
sessionStorage.setItem('max_clients', settings['client_limit']);
|
|
document.querySelector('head > title')
|
|
.textContent = settings['site_name'];
|
|
if('topbox_content' in settings) {
|
|
fetch(settings['topbox_content'])
|
|
.then((response) => response.text())
|
|
.then((data) => {
|
|
const template = document.createElement('template');
|
|
template.innerHTML = data;
|
|
document.querySelector('topbox > details')
|
|
.replaceWith(template.content.cloneNode(true));
|
|
});
|
|
}
|
|
document.querySelector('user#banner-userid')
|
|
.textContent = cookies['username'];
|
|
document.querySelector('button#create-config')
|
|
.addEventListener('click', (event) => {
|
|
display_create_form();
|
|
});
|
|
await display_configs(...configs);
|
|
} catch(e) {
|
|
if(e.message === 'access denied') {
|
|
deny_access();
|
|
return;
|
|
}
|
|
throw e;
|
|
}
|
|
}
|
|
})();
|