WIP splitting into modules

This commit is contained in:
Ivan Gromov 2020-03-13 00:44:49 +05:00
parent 42650e2af7
commit 9ee5238a79
6 changed files with 772 additions and 427 deletions

View file

@ -1,208 +0,0 @@
new Vue({
el: '#users_app',
data: {
config: {},
loading: false,
new_user: '',
save_config_message: ''
},
created: function() {
this.load_config();
},
methods: {
add_user: function() {
this.config.users.push(this.new_user);
this.new_user = '';
},
remove_user: function(index) {
this.config.users.splice(index, 1);
},
save_config: function() {
if (this.loading) return;
this.loading = true;
fetch('/config', {
method: 'POST',
body: JSON.stringify(this.config),
headers: {
'Content-Type': 'application/json'
}
})
.then(r => r.json())
.then(result => {
if (result.ok) {
this.ok = true;
this.save_config_message = 'Saved!';
setTimeout(() => {
this.save_config_message = '';
}, 1000);
} else {
this.ok = false;
this.save_config_message = 'Not Saved!';
setTimeout(() => {
this.save_config_message = '';
}, 1000);
}
})
.finally(() => {
this.loading = false;
});
},
load_config: function() {
this.loading = true;
fetch('/config')
.then(r => r.json())
.then(config => {
this.config = config;
})
.finally(() => {
this.loading = false;
});
}
}
});
var vpn_options_extra_args = {
server_name: 'algo',
ondemand_cellular: false,
ondemand_wifi: false,
dns_adblocking: false,
ssh_tunneling: false,
store_pki: false,
ondemand_wifi_exclude: ''
};
new Vue({
el: '#options_app',
data: {
extra_args: vpn_options_extra_args
}
});
var provider_extra_args = {
provider: null
};
new Vue({
el: '#provider_app',
data: {
loading: false,
do_region_loading: false,
do_regions: [],
extra_args: provider_extra_args,
providers_map: [
{ name: 'DigitalOcean', alias: 'digitalocean' },
{ name: 'Amazon Lightsail', alias: 'lightsail' },
{ name: 'Amazon EC2', alias: 'ec2' },
{ name: 'Microsoft Azure', alias: 'azure' },
{ name: 'Google Compute Engine', alias: 'gce' },
{ name: 'Hetzner Cloud', alias: 'hetzner' },
{ name: 'Vultr', alias: 'vultr' },
{ name: 'Scaleway', alias: 'scaleway' },
{ name: 'OpenStack (DreamCompute optimised)', alias: 'openstack' },
{ name: 'CloudStack (Exoscale optimised)', alias: 'cloudstack' },
{
name: 'Install to existing Ubuntu 18.04 or 19.04 server (Advanced)',
alias: 'local'
}
]
},
methods: {
set_provider(provider) {
this.extra_args.provider = provider;
},
load_do_regions: function() {
if (
this.extra_args.provider === 'digitalocean' &&
this.extra_args.do_token
) {
this.loading = true;
this.do_region_loading = true;
fetch('/do/regions', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ token: this.extra_args.do_token })
})
.then(r => r.json())
.then(r => {
this.do_regions = r.regions;
})
.finally(() => {
this.loading = false;
this.do_region_loading = false;
});
}
}
}
});
new Vue({
el: '#status_app',
data: {
status: null,
program: null,
result: null,
error: null,
// shared data, do not write there
vpn_options_extra_args,
provider_extra_args,
},
created() {
this.loop = setInterval(this.get_status, 1000);
},
computed: {
extra_args() {
return Object.assign({}, this.vpn_options_extra_args, this.provider_extra_args);
},
cli_preview() {
var args = '';
for (arg in this.extra_args) {
args += `${arg}=${this.extra_args[arg]} `;
}
return `ansible-playbook main.yml --extra-vars ${args}`;
},
show_backdrop() {
return this.status === 'running';
},
is_success() {
return this.result === 0;
}
},
watch: {
status: function () {
if (this.status === 'done') {
clearInterval(this.loop);
}
}
},
methods: {
run() {
fetch('/playbook', {
method: 'POST',
body: JSON.stringify(this.extra_args),
headers: {
'Content-Type': 'application/json'
}
});
},
stop() {
fetch('/playbook', {
method: 'DELETE'
});
},
get_status() {
fetch('/playbook')
.then(r => r.json())
.then(status => {
this.status = status.status;
this.program = status.program;
this.result = status.result;
})
.catch(err => {
alert('Server error');
clearInterval(this.loop);
});
}
}
});

433
app/static/app.vue Normal file
View file

@ -0,0 +1,433 @@
<template>
<div style="overflow: auto">
<div class="container">
<h1 class="mb-5 text-center">Algo VPN Setup</h1>
<div class="row">
<div class="col-md-4 order-md-2 mb-4" id="users_app">
<h2>Users</h2>
<section class="my-3">
<h4>Set up user list</h4>
<ul class="list-group">
<li class="list-group-item" v-for="(user, index) in config.users" :key="user">
{{ user }}
<button
type="button"
class="btn btn-secondary btn-sm float-right"
@click="remove_user(index)"
>Remove</button>
</li>
</ul>
<div class="my-3 form-group">
<label for="id_new_user">Add new user</label>
<div class="input-group">
<input
type="text"
id="id_new_user"
class="form-control"
placeholder="username"
v-model="new_user"
/>
<div class="input-group-append">
<button
@click="add_user"
class="btn btn-outline-primary"
type="button"
id="button-addon2"
>Add</button>
</div>
</div>
</div>
</section>
<div>
<button
@click="save_config"
v-bind:disabled="loading"
class="btn btn-secondary"
type="button"
>Save</button>
<span
v-if="save_config_message"
v-bind:class="{ 'text-success': ok, 'text-danged': !ok }"
>{{save_config_message}}</span>
</div>
</div>
<div class="col-md-8 order-md-1" id="options_app">
<h2>VPN Options</h2>
<section class="my-3">
<div class="form-group">
<label>Name the vpn server</label>
<input
type="text"
class="form-control"
placeholder="server name"
v-model="extra_args.server_name"
/>
</div>
<label>MacOS/iOS IPsec clients to enable Connect On Demand:</label>
<div class="form-check">
<label
title="MacOS/iOS IPsec clients to enable Connect On Demand when connected to cellular
networks?"
>
<input
class="form-check-input"
type="checkbox"
name="ondemand_cellular"
v-model="extra_args.ondemand_cellular"
/>
when connected to cellular networks
</label>
</div>
<div class="form-check">
<label
title="MacOS/iOS IPsec clients to enable Connect On Demand when connected to Wi-Fi?"
>
<input
class="form-check-input"
type="checkbox"
name="ondemand_wifi"
v-model="extra_args.ondemand_wifi"
/>
when connected to WiFi
</label>
</div>
<div class="form-group">
<label for="id_ondemand_wifi_exclude">Trusted Wi-Fi networks</label>
<input
type="text"
class="form-control"
id="id_ondemand_wifi_exclude"
name="ondemand_wifi_exclude"
placeholder="HomeNet,OfficeWifi,AlgoWiFi"
v-model="extra_args.ondemand_wifi_exclude"
/>
<small class="form-text text-muted">
List the names of any trusted Wi-Fi networks where
macOS/iOS
IPsec clients should not use "Connect On Demand"
(e.g., your home network. Comma-separated value, e.g.,
HomeNet,OfficeWifi,AlgoWiFi)
</small>
</div>
<label>Retain the PKI</label>
<div class="form-check">
<label>
<input
class="form-check-input"
type="checkbox"
name="store_pki"
v-model="extra_args.store_pki"
/>
Do you want to retain the keys (PKI)?
<small
class="form-text text-muted"
>
required to add users in the future, but less
secure
</small>
</label>
</div>
<label>DNS adblocking</label>
<div class="form-check">
<label>
<input
class="form-check-input"
type="checkbox"
name="dns_adblocking"
v-model="extra_args.dns_adblocking"
/>
Enable DNS ad blocking on this VPN server
</label>
</div>
<label>SSH tunneling</label>
<div class="form-check">
<label>
<input
class="form-check-input"
type="checkbox"
name="ssh_tunneling"
v-model="extra_args.ssh_tunneling"
/>
Each user will have their own account for SSH tunneling
</label>
</div>
</section>
</div>
</div>
<hr class="my-3" />
<section class="my-3" id="provider_app">
<h2>Select cloud provider</h2>
<div class="row">
<div class="col-4">
<ul class="nav flex-column nav-pills">
<li class="nav-item" v-for="provider in providers_map">
<a
class="nav-link"
href="#"
v-bind:class="{ active: provider.alias === extra_args.provider }"
@click="set_provider(provider.alias)"
>{{provider.name}}</a>
</li>
</ul>
</div>
<div class="col-8">
<div class="my-3" v-if="extra_args.provider === 'digitalocean'">
<h4>Digital Ocean Options</h4>
<div class="form-group">
<label for="id_do_token">
Enter your API token. The token must have read and write permissions
(https://cloud.digitalocean.com/settings/api/tokens):
</label>
<input
type="text"
class="form-control"
id="id_do_token"
name="do_token"
v-model="extra_args.do_token"
@blur="load_do_regions"
/>
</div>
<div class="form-group">
<label
v-if="do_regions.length > 0"
for="id_region"
>What region should the server be located in?</label>
<label
v-if="do_regions.length === 0"
for="id_region"
>Please enter API key above to select region</label>
<label v-if="do_region_loading" for="id_region">Loading regions...</label>
<select
name="region"
id="id_region"
class="form-control"
v-model="extra_args.region"
v-bind:disabled="do_region_loading"
>
<option value disabled>Select region</option>
<option
v-for="(region, index) in do_regions"
v-bind:value="region.slug"
>{{region.name}}</option>
</select>
</div>
</div>
</div>
</div>
</section>
</div>
</div>
<footer class="footer mt-auto py-3" id="status_app">
<div
class="backdrop d-flex flex-column align-items-center justify-content-center"
v-if="show_backdrop"
>
<span class="spinner-border" role="status" aria-hidden="true"></span>
</div>
<div class="container">
<div v-if="!status || status === 'cancelled'">
<pre class="console">{{cli_preview}}</pre>
<button @click="run" class="btn btn-primary" type="button">Install</button>
</div>
<div v-if="status === 'running'">
<pre class="console">{{program.join(' ')}}</pre>
<button class="btn btn-danger" type="button" @click="stop">Stop</button>
<button class="btn btn-primary" type="button" disabled>
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
Running...
</button>
</div>
<div v-if="status === 'done'">
<pre class="console">{{program.join(' ')}}</pre>
<div v-if="is_success" class="text-success">Done!</div>
<div v-else class="text-danger">Failed!</div>
</div>
</div>
</footer>
</template>
<script>
var vpn_options_extra_args = {
server_name: "algo",
ondemand_cellular: false,
ondemand_wifi: false,
dns_adblocking: false,
ssh_tunneling: false,
store_pki: false,
ondemand_wifi_exclude: ""
};
new Vue({
el: "#options_app",
data: {
extra_args: vpn_options_extra_args
}
});
var provider_extra_args = {
provider: null
};
new Vue({
el: "#provider_app",
data: {
loading: false,
do_region_loading: false,
do_regions: [],
extra_args: provider_extra_args,
providers_map: [
{ name: "DigitalOcean", alias: "digitalocean" },
{ name: "Amazon Lightsail", alias: "lightsail" },
{ name: "Amazon EC2", alias: "ec2" },
{ name: "Microsoft Azure", alias: "azure" },
{ name: "Google Compute Engine", alias: "gce" },
{ name: "Hetzner Cloud", alias: "hetzner" },
{ name: "Vultr", alias: "vultr" },
{ name: "Scaleway", alias: "scaleway" },
{ name: "OpenStack (DreamCompute optimised)", alias: "openstack" },
{ name: "CloudStack (Exoscale optimised)", alias: "cloudstack" },
{
name: "Install to existing Ubuntu 18.04 or 19.04 server (Advanced)",
alias: "local"
}
]
},
methods: {
set_provider(provider) {
this.extra_args.provider = provider;
},
load_do_regions: function() {
if (
this.extra_args.provider === "digitalocean" &&
this.extra_args.do_token
) {
this.loading = true;
this.do_region_loading = true;
fetch("/do/regions", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({ token: this.extra_args.do_token })
})
.then(r => r.json())
.then(r => {
this.do_regions = r.regions;
})
.finally(() => {
this.loading = false;
this.do_region_loading = false;
});
}
}
}
});
new Vue({
el: "#status_app",
data: {
status: null,
program: null,
result: null,
error: null,
// shared data, do not write there
vpn_options_extra_args,
provider_extra_args
},
created() {
this.loop = setInterval(this.get_status, 1000);
},
computed: {
extra_args() {
return Object.assign(
{},
this.vpn_options_extra_args,
this.provider_extra_args
);
},
cli_preview() {
var args = "";
for (arg in this.extra_args) {
args += `${arg}=${this.extra_args[arg]} `;
}
return `ansible-playbook main.yml --extra-vars ${args}`;
},
show_backdrop() {
return this.status === "running";
},
is_success() {
return this.result === 0;
}
},
watch: {
status: function() {
if (this.status === "done") {
clearInterval(this.loop);
}
}
},
methods: {
run() {
fetch("/playbook", {
method: "POST",
body: JSON.stringify(this.extra_args),
headers: {
"Content-Type": "application/json"
}
});
},
stop() {
fetch("/playbook", {
method: "DELETE"
});
},
get_status() {
fetch("/playbook")
.then(r => r.json())
.then(status => {
this.status = status.status;
this.program = status.program;
this.result = status.result;
})
.catch(err => {
alert("Server error");
clearInterval(this.loop);
});
}
}
});
</script>
<style scoped>
.console {
background: black;
color: white;
padding: 4px;
border-radius: 2px;
white-space: pre-line;
padding-left: 2em;
position: relative;
}
.console::before {
content: "$";
position: absolute;
left: 1em;
}
.backdrop {
position: fixed;
background: white;
opacity: 0.6;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 100;
pointer-events: none;
}
.footer .container {
position: relative;
z-index: 101;
}
</style>

View file

@ -1,227 +1,67 @@
<!DOCTYPE html>
<html class="h-100">
<head>
<title>Algo VPN</title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"
integrity="sha256-chlNFSVx3TdcQ2Xlw7SvnbLAavAQLO0Y/LBiWX04viY=" crossorigin="anonymous"></script>
<style>
.console {
background: black;
color: white;
padding: 4px;
border-radius: 2px;
white-space: pre-line;
padding-left: 2em;
position: relative;
}
.console::before {
content: "$";
position: absolute;
left: 1em;
}
.backdrop {
position: fixed;
background: white;
opacity: 0.6;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 100;
pointer-events: none;
}
.footer .container {
position: relative;
z-index: 101;
}
</style>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<script src="https://cdn.jsdelivr.net/npm/http-vue-loader@1.4.2/src/httpVueLoader.js"
integrity="sha256-aOeVxnlZDaiJOHsqNWVOMNsKdiGxgT8kbLp1p1Rv2sc=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11/dist/vue.js"
integrity="sha256-NSuqgY2hCZJUN6hDMFfdxvkexI7+iLxXQbL540RQ/c4=" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css"
integrity="sha256-L/W5Wfqfa0sdBNIKN9cG6QA5F2qx4qICmU2VgLruv9Y=" crossorigin="anonymous">
</head>
<body class="d-flex flex-column h-100">
<div style="overflow: auto">
<div class="container">
<h1 class="mb-5 text-center">Algo VPN Setup</h1>
<div class="row">
<div class="col-md-4 order-md-2 mb-4" id="users_app">
<h2>Users</h2>
<section class="my-3">
<h4>Set up user list</h4>
<ul class="list-group">
<li class="list-group-item"
v-for="(user, index) in config.users"
:key="user"
>
{{ user }}
<button type="button" class="btn btn-secondary btn-sm float-right"
@click="remove_user(index)">
Remove
</button>
</li>
</ul>
<div class="my-3 form-group">
<label for="id_new_user">Add new user</label>
<div class="input-group">
<input type="text" id="id_new_user" class="form-control" placeholder="username"
v-model="new_user">
<div class="input-group-append">
<button @click="add_user" class="btn btn-outline-primary" type="button"
id="button-addon2">
Add
</button>
</div>
</div>
</div>
</section>
<div>
<button @click="save_config" v-bind:disabled="loading" class="btn btn-secondary" type="button">Save
</button>
<span v-if="save_config_message"
v-bind:class="{ 'text-success': ok, 'text-danged': !ok }">{{save_config_message}}</span>
</div>
</div>
<div class="col-md-8 order-md-1" id="options_app">
<h2>VPN Options</h2>
<section class="my-3">
<div class="form-group">
<label>Name the vpn server</label>
<input type="text" class="form-control" placeholder="server name"
v-model="extra_args.server_name"/>
</div>
<label>MacOS/iOS IPsec clients to enable Connect On Demand:</label>
<div class="form-check">
<label title="MacOS/iOS IPsec clients to enable Connect On Demand when connected to cellular
networks?">
<input class="form-check-input" type="checkbox" name="ondemand_cellular"
v-model="extra_args.ondemand_cellular">
when connected to cellular networks
</label>
</div>
<div class="form-check">
<label title="MacOS/iOS IPsec clients to enable Connect On Demand when connected to Wi-Fi?">
<input class="form-check-input" type="checkbox" name="ondemand_wifi"
v-model="extra_args.ondemand_wifi">
when connected to WiFi
</label>
</div>
<div class="form-group">
<label for="id_ondemand_wifi_exclude">Trusted Wi-Fi networks</label>
<input type="text" class="form-control" id="id_ondemand_wifi_exclude"
name="ondemand_wifi_exclude"
placeholder="HomeNet,OfficeWifi,AlgoWiFi"
v-model="extra_args.ondemand_wifi_exclude"/>
<small class="form-text text-muted">
List the names of any trusted Wi-Fi networks where
macOS/iOS
IPsec clients should not use "Connect On Demand"
(e.g., your home network. Comma-separated value, e.g.,
HomeNet,OfficeWifi,AlgoWiFi)
</small>
</div>
<label>Retain the PKI</label>
<div class="form-check">
<label>
<input class="form-check-input" type="checkbox" name="store_pki"
v-model="extra_args.store_pki">
Do you want to retain the keys (PKI)?
<small class="form-text text-muted">required to add users in the future, but less
secure</small>
</label>
</div>
<label>DNS adblocking</label>
<div class="form-check">
<label>
<input class="form-check-input" type="checkbox" name="dns_adblocking"
v-model="extra_args.dns_adblocking">
Enable DNS ad blocking on this VPN server
</label>
</div>
<label>SSH tunneling</label>
<div class="form-check">
<label>
<input class="form-check-input" type="checkbox" name="ssh_tunneling"
v-model="extra_args.ssh_tunneling">
Each user will have their own account for SSH tunneling
</label>
</div>
</section>
</div>
</div>
<hr class="my-3">
<section class="my-3" id="provider_app">
<h2>Select cloud provider</h2>
<div class="row">
<div class="col-4">
<ul class="nav flex-column nav-pills">
<li class="nav-item"
v-for="provider in providers_map">
<a class="nav-link" href="#"
v-bind:class="{ active: provider.alias === extra_args.provider }"
@click="set_provider(provider.alias)">{{provider.name}}</a>
</li>
</ul>
</div>
<div class="col-8">
<div class="my-3" v-if="extra_args.provider === 'digitalocean'">
<h4>Digital Ocean Options</h4>
<div class="form-group">
<label for="id_do_token">Enter your API token. The token must have read and write permissions
(https://cloud.digitalocean.com/settings/api/tokens):</label>
<input type="text" class="form-control" id="id_do_token" name="do_token"
v-model="extra_args.do_token"
@blur="load_do_regions"/>
</div>
<div class="form-group">
<label v-if="do_regions.length > 0" for="id_region">What region should the server be located in?</label>
<label v-if="do_regions.length === 0" for="id_region">Please enter API key above to select region</label>
<label v-if="do_region_loading" for="id_region">Loading regions...</label>
<select name="region"
id="id_region"
class="form-control"
v-model="extra_args.region"
v-bind:disabled="do_region_loading">
<option value="" disabled>Select region</option>
<option
v-for="(region, index) in do_regions"
v-bind:value="region.slug">
{{region.name}}
</option>
</select>
</div>
</div>
</div>
</div>
</section>
<div class="container" id="algo">
<h1 class="mb-5 text-center">{{ title }}</h1>
<div class="row">
<user-config class="col-md-4 order-md-2 mb-4"></user-config>
<vpn-setup class="col-md-8 order-md-1"
v-bind:extra_args="extra_args"
v-on:submit="on_setup_submit"></vpn-setup>
</div>
</div>
<footer class="footer mt-auto py-3" id="status_app">
<div class="backdrop d-flex flex-column align-items-center justify-content-center" v-if="show_backdrop">
<span class="spinner-border" role="status" aria-hidden="true"></span>
</div>
<div class="container">
<div v-if="!status || status === 'cancelled'">
<pre class="console">{{cli_preview}}</pre>
<button @click="run" class="btn btn-primary" type="button">Install</button>
</div>
<div v-if="status === 'running'">
<pre class="console">{{program.join(' ')}}</pre>
<button class="btn btn-danger" type="button" @click="stop">Stop</button>
<button class="btn btn-primary" type="button" disabled>
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
Running...
</button>
</div>
<div v-if="status === 'done'">
<pre class="console">{{program.join(' ')}}</pre>
<div v-if="is_success" class="text-success">Done!</div>
<div v-else class="text-danger">Failed!</div>
</div>
</div>
</footer>
<script src="./static/app.js"></script>
<provider-setup v-bind:extra_args="extra_args" v-on:submit="on_provider_submit">
</provider-setup>
</div>
<script>
new window.Vue({
el: '#algo',
data: {
playbook: {},
extra_args: {
server_name: "algo",
ondemand_cellular: false,
ondemand_wifi: false,
dns_adblocking: false,
ssh_tunneling: false,
store_pki: false,
ondemand_wifi_exclude: []
}
},
computed: {
title() {
return 'Algo VPN Setup';
}
},
components: {
'user-config': window.httpVueLoader('/static/user-config.vue'),
'vpn-setup': window.httpVueLoader('/static/vpn-setup.vue'),
'provider-setup': window.httpVueLoader('/static/provider-setup.vue'),
},
methods: {
on_setup_submit: function(extra_args) {
Object.assign(this.extra_args, extra_args);
debugger;
},
on_provider_submit: function(extra_args) {
Object.assign(this.extra_args, extra_args);
debugger;
}
}
})
</script>
</body>
</html>
</html>

View file

@ -0,0 +1,57 @@
<template>
<div class="row" id="prodiver_id">
<h2 class="col-12">
<span v-if="provider">{{ provider.name }} Setup</span>
<span v-else>Select cloud provider</span>
</h2>
<div class="col-4">
<ul class="nav flex-column nav-pills">
<li class="nav-item"
v-for="item in providers_map"
v-bind:key="item.alias">
<a
class="nav-link"
href="#prodiver_id"
v-bind:class="{ active: item.alias === provider && provider.alias }"
@click="set_provider(item)"
>{{item.name}}</a>
</li>
</ul>
</div>
<div class="col-8">
{{ provider && provider.alias }}
</div>
</div>
</template>
<script>
module.exports = {
data: function() {
return {
loading: false,
provider: null,
providers_map: [
{ name: "DigitalOcean", alias: "digitalocean" },
{ name: "Amazon Lightsail", alias: "lightsail" },
{ name: "Amazon EC2", alias: "ec2" },
{ name: "Microsoft Azure", alias: "azure" },
{ name: "Google Compute Engine", alias: "gce" },
{ name: "Hetzner Cloud", alias: "hetzner" },
{ name: "Vultr", alias: "vultr" },
{ name: "Scaleway", alias: "scaleway" },
{ name: "OpenStack (DreamCompute optimised)", alias: "openstack" },
{ name: "CloudStack (Exoscale optimised)", alias: "cloudstack" },
{
name: "Install to existing Ubuntu 18.04 or 19.04 server (Advanced)",
alias: "local"
}
]
}
},
methods: {
set_provider(provider) {
this.provider = provider;
}
}
};
</script>

112
app/static/user-config.vue Normal file
View file

@ -0,0 +1,112 @@
<template>
<div>
<h2>Users</h2>
<section class="my-3">
<h4>Set up user list</h4>
<ul class="list-group">
<li class="list-group-item" v-for="(user, index) in config.users" :key="user">
{{ user }}
<button
type="button"
class="btn btn-secondary btn-sm float-right"
@click="remove_user(index)"
>Remove</button>
</li>
</ul>
<div class="my-3 form-group">
<label for="id_new_user">Add new user</label>
<div class="input-group">
<input
type="text"
id="id_new_user"
class="form-control"
placeholder="username"
v-model="new_user"
/>
<div class="input-group-append">
<button
@click="add_user"
class="btn btn-outline-primary"
type="button"
id="button-addon2"
>Add</button>
</div>
</div>
</div>
</section>
<div>
<span
v-if="save_config_message"
v-bind:class="{ 'text-success': ok, 'text-danged': !ok }"
>{{save_config_message}}</span>
</div>
</div>
</template>
<script>
module.exports = {
data: function() {
return {
config: {},
loading: false,
new_user: "",
save_config_message: ""
};
},
created: function() {
this.load_config();
},
methods: {
add_user: function() {
this.config.users.push(this.new_user);
this.new_user = "";
this.save_config();
},
remove_user: function(index) {
this.config.users.splice(index, 1);
this.save_config();
},
save_config: function() {
if (this.loading) return;
this.loading = true;
fetch("/config", {
method: "POST",
body: JSON.stringify(this.config),
headers: {
"Content-Type": "application/json"
}
})
.then(r => r.json())
.then(result => {
if (result.ok) {
this.ok = true;
this.save_config_message = "Saved!";
setTimeout(() => {
this.save_config_message = "";
}, 1000);
} else {
this.ok = false;
this.save_config_message = "Not Saved!";
setTimeout(() => {
this.save_config_message = "";
}, 1000);
}
})
.finally(() => {
this.loading = false;
});
},
load_config: function() {
this.loading = true;
fetch("/config")
.then(r => r.json())
.then(config => {
this.config = config;
})
.finally(() => {
this.loading = false;
});
}
}
};
</script>

111
app/static/vpn-setup.vue Normal file
View file

@ -0,0 +1,111 @@
<template>
<div>
<h2>VPN Options</h2>
<section class="my-3">
<div class="form-group">
<label>Name the vpn server</label>
<input
type="text"
class="form-control"
placeholder="server name"
v-model="extra_args.server_name"
/>
</div>
<label>MacOS/iOS IPsec clients to enable Connect On Demand:</label>
<div class="form-check">
<label
title="MacOS/iOS IPsec clients to enable Connect On Demand when connected to cellular
networks?"
>
<input
class="form-check-input"
type="checkbox"
name="ondemand_cellular"
v-model="extra_args.ondemand_cellular"
/>
when connected to cellular networks
</label>
</div>
<div class="form-check">
<label title="MacOS/iOS IPsec clients to enable Connect On Demand when connected to Wi-Fi?">
<input
class="form-check-input"
type="checkbox"
name="ondemand_wifi"
v-model="extra_args.ondemand_wifi"
/>
when connected to WiFi
</label>
</div>
<div class="form-group">
<label for="id_ondemand_wifi_exclude">Trusted Wi-Fi networks</label>
<input
type="text"
class="form-control"
id="id_ondemand_wifi_exclude"
name="ondemand_wifi_exclude"
placeholder="HomeNet,OfficeWifi,AlgoWiFi"
v-model="extra_args.ondemand_wifi_exclude"
/>
<small class="form-text text-muted">
List the names of any trusted Wi-Fi networks where
macOS/iOS
IPsec clients should not use "Connect On Demand"
(e.g., your home network. Comma-separated value, e.g.,
HomeNet,OfficeWifi,AlgoWiFi)
</small>
</div>
<label>Retain the PKI</label>
<div class="form-check">
<label>
<input
class="form-check-input"
type="checkbox"
name="store_pki"
v-model="extra_args.store_pki"
/>
Do you want to retain the keys (PKI)?
<small class="form-text text-muted">
required to add users in the future, but less
secure
</small>
</label>
</div>
<label>DNS adblocking</label>
<div class="form-check">
<label>
<input
class="form-check-input"
type="checkbox"
name="dns_adblocking"
v-model="extra_args.dns_adblocking"
/>
Enable DNS ad blocking on this VPN server
</label>
</div>
<label>SSH tunneling</label>
<div class="form-check">
<label>
<input
class="form-check-input"
type="checkbox"
name="ssh_tunneling"
v-model="extra_args.ssh_tunneling"
/>
Each user will have their own account for SSH tunneling
</label>
</div>
<button @click="$emit('submit')" class="btn btn-primary" type="button">Select Cloud Provider</button>
</section>
</div>
</template>
<script>
module.exports = {
props: {
// Warning: Mutable Object to edit partent props
extra_args: Object
}
}
</script>