mirror of
https://github.com/trailofbits/algo.git
synced 2025-07-13 09:13:01 +02:00
More careful variable extraction, without regexp
This commit is contained in:
parent
547711d83e
commit
aa0fff068e
5 changed files with 84 additions and 49 deletions
|
@ -1,9 +1,9 @@
|
|||
import configparser
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from os.path import join, dirname, expanduser
|
||||
from functools import reduce
|
||||
|
||||
import ansible_runner
|
||||
import yaml
|
||||
|
@ -55,12 +55,27 @@ task_program = ''
|
|||
|
||||
class Status:
|
||||
RUNNING = 'running'
|
||||
ERROR = 'error'
|
||||
CANCELLED = 'cancelled'
|
||||
DONE = 'done'
|
||||
ERROR = 'failed'
|
||||
TIMEOUT = 'timeout'
|
||||
CANCELLED = 'canceled'
|
||||
DONE = 'successful'
|
||||
NEW = None
|
||||
|
||||
|
||||
def by_path(data: dict, path: str):
|
||||
def get(obj, attr):
|
||||
if type(obj) is dict:
|
||||
return obj.get(attr, None)
|
||||
elif type(obj) is list:
|
||||
try:
|
||||
return obj[int(attr)]
|
||||
except ValueError:
|
||||
return None
|
||||
else:
|
||||
return None
|
||||
|
||||
return reduce(get, path.split('.'), data)
|
||||
|
||||
class Playbook:
|
||||
|
||||
def __init__(self):
|
||||
|
@ -69,28 +84,40 @@ class Playbook:
|
|||
self.events = []
|
||||
self.config_vars = {}
|
||||
self._runner = None
|
||||
|
||||
def parse(self, event: dict):
|
||||
data = {}
|
||||
if by_path(event, 'event_data.task') == 'Set subjectAltName as a fact':
|
||||
ansible_ssh_host = by_path(event, 'event_data.res.ansible_facts.IP_subject_alt_name')
|
||||
if ansible_ssh_host:
|
||||
data['ansible_ssh_host'] = ansible_ssh_host
|
||||
|
||||
if by_path(event, 'event_data.play') == 'Configure the server and install required software':
|
||||
local_service_ip = by_path(event, 'event_data.res.ansible_facts.ansible_lo.ipv4_secondaries.0.address')
|
||||
ipv6 = by_path(event, 'event_data.res.ansible_facts.ansible_lo.ipv6.0.address')
|
||||
p12_export_password = by_path(event, 'event_data.res.ansible_facts.p12_export_password')
|
||||
if local_service_ip:
|
||||
data['local_service_ip'] = local_service_ip
|
||||
if ipv6:
|
||||
data['ipv6'] = ipv6
|
||||
if p12_export_password:
|
||||
data['p12_export_password'] = p12_export_password
|
||||
|
||||
if by_path(event, 'event_data.play') == 'Provision the server':
|
||||
host_name = by_path(event, 'event_data.res.add_host.host_name')
|
||||
if host_name:
|
||||
data['host_name'] = host_name
|
||||
|
||||
return data if data else None
|
||||
|
||||
def event_handler(self, data: dict) -> None:
|
||||
if data['event'] == 'runner_on_ok':
|
||||
# Looking for '-passout pass:"{{ CA_password }}"'
|
||||
if 'Build the CA pair' in data['event_data']['task']:
|
||||
m = re.match(r'-passout pass:\"(?P<password>.*)\"', data['event_data']['cmd'])
|
||||
if m:
|
||||
self.config_vars['CA_password'] = m.group('password')
|
||||
if self.parse(data):
|
||||
self.config_vars.update(self.parse(data))
|
||||
|
||||
# Looking for '-passout pass:"{{ p12_export_password }}"'
|
||||
if "Build the client's p12" in data['event_data']['task']:
|
||||
m = re.match(r'-passout pass:\"(?P<password>.*)\"', data['event_data']['cmd'])
|
||||
if m:
|
||||
self.config_vars['p12_export_password'] = m.group('password')
|
||||
self.events.append(data)
|
||||
|
||||
# Looking for 'DNS = {{ wireguard_dns_servers }}'
|
||||
if "Generate QR codes" in data['event_data']['task']:
|
||||
self.config_vars['host'] = data['event_data']['host']
|
||||
m = re.match(r'DNS = (?P<dns>.*)\n\n', data['event_data']['cmd'])
|
||||
if m:
|
||||
self.config_vars['local_service_ip'] = m.group('dns')
|
||||
self.events.append(data)
|
||||
def status_handler(self, status_data: dict, *args, **kwargs) -> None:
|
||||
self.status = status_data.get('status')
|
||||
|
||||
def cancel_handler(self) -> bool:
|
||||
if self.want_cancel:
|
||||
|
@ -103,11 +130,14 @@ class Playbook:
|
|||
def run(self, extra_vars: dict) -> None:
|
||||
self.want_cancel = False
|
||||
self.status = Status.RUNNING
|
||||
_, runner = ansible_runner.run_async(private_data_dir='.',
|
||||
playbook='main.yml',
|
||||
extravars=extra_vars,
|
||||
cancel_callback=self.cancel_handler,
|
||||
event_handler=self.event_handler)
|
||||
_, runner = ansible_runner.run_async(
|
||||
private_data_dir='.',
|
||||
playbook='main.yml',
|
||||
extravars=extra_vars,
|
||||
status_handler=self.status_handler,
|
||||
cancel_callback=self.cancel_handler,
|
||||
event_handler=self.event_handler
|
||||
)
|
||||
self._runner = runner
|
||||
|
||||
|
||||
|
@ -282,12 +312,14 @@ async def check_vultr_config(request):
|
|||
try:
|
||||
open(os.environ['VULTR_API_CONFIG'], 'r').read()
|
||||
response['has_secret'] = True
|
||||
response['saved_to'] = os.environ.get('VULTR_API_CONFIG')
|
||||
except IOError:
|
||||
pass
|
||||
try:
|
||||
default_path = expanduser(join('~', '.vultr.ini'))
|
||||
open(default_path, 'r').read()
|
||||
response['has_secret'] = True
|
||||
response['saved_to'] = default_path
|
||||
except IOError:
|
||||
pass
|
||||
return web.json_response(response)
|
||||
|
|
|
@ -71,10 +71,10 @@
|
|||
<h1 class="mb-5 text-center" v-if="step === 'status-running'">
|
||||
<span class="spin">🙂</span> Please be patient
|
||||
</h1>
|
||||
<h1 class="mb-5 text-center" v-if="step === 'status-error'">
|
||||
<h1 class="mb-5 text-center" v-if="step === 'status-failed'">
|
||||
😢 Set up failed
|
||||
</h1>
|
||||
<h1 class="mb-5 text-center" v-if="step === 'status-done'">
|
||||
<h1 class="mb-5 text-center" v-if="step === 'status-successful'">
|
||||
🥳 Congratulations, your Algo server is running!
|
||||
</h1>
|
||||
<h1 class="mb-5 text-center" v-if="step === 'status-exit'">
|
||||
|
@ -82,7 +82,7 @@
|
|||
</h1>
|
||||
</h1>
|
||||
<transition name="fade">
|
||||
<div class="row" v-if="step == 'setup'">
|
||||
<div class="row" v-if="step === 'setup'">
|
||||
<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"
|
||||
|
@ -90,35 +90,35 @@
|
|||
</div>
|
||||
</transition>
|
||||
<transition name="fade">
|
||||
<provider-setup v-if="step == 'provider'"
|
||||
<provider-setup v-if="step === 'provider'"
|
||||
v-bind:extra_args="extra_args"
|
||||
v-on:submit="step = 'command'">
|
||||
</provider-setup>
|
||||
</transition>
|
||||
<transition name="fade">
|
||||
<command-preview v-if="step == 'command'"
|
||||
<command-preview v-if="step === 'command'"
|
||||
v-bind:extra_args="extra_args"
|
||||
v-on:submit="start(); step = 'status-running';">
|
||||
</command-preview>
|
||||
</transition>
|
||||
<transition name="fade">
|
||||
<status-running v-if="step == 'status-running'"
|
||||
<status-running v-if="step === 'status-running'"
|
||||
v-on:submit="stop(); step = 'setup';"
|
||||
v-on:done="step = 'status-done'"
|
||||
v-on:error="step = 'status-error'"
|
||||
v-on:successful="step = 'status-successful'"
|
||||
v-on:error="step = 'status-failed'"
|
||||
v-on:cancelled="step = 'setup'">
|
||||
</status-running>
|
||||
</transition>
|
||||
<transition name="fade">
|
||||
<section v-if="step == 'status-error'" class="text-center">
|
||||
<section v-if="step === 'status-failed'" class="text-center">
|
||||
<p>Now it’s time to inspect console output</p>
|
||||
<p>Restart console process to try again</p>
|
||||
</section>
|
||||
</transition>
|
||||
<transition name="fade">
|
||||
<status-done v-if="step == 'status-done'"
|
||||
<status-successful v-if="step === 'status-successful'"
|
||||
v-on:submit="exit(); step = 'status-exit'" >
|
||||
</status-done>
|
||||
</status-successful>
|
||||
</transition>
|
||||
</div>
|
||||
|
||||
|
@ -144,13 +144,13 @@
|
|||
'provider-setup': window.httpVueLoader('/static/provider-setup.vue'),
|
||||
'command-preview': window.httpVueLoader('/static/command-preview.vue'),
|
||||
'status-running': window.httpVueLoader('/static/status-running.vue'),
|
||||
'status-done': window.httpVueLoader('/static/status-done.vue')
|
||||
'status-successful': window.httpVueLoader('/static/status-done.vue')
|
||||
},
|
||||
created() {
|
||||
fetch("/playbook")
|
||||
.then(r => r.json())
|
||||
.catch(() => {
|
||||
this.step = 'status-error';
|
||||
this.step = 'status-failed';
|
||||
})
|
||||
.then(data => {
|
||||
if (data.status && data.status !== 'cancelled'){
|
||||
|
|
|
@ -85,6 +85,7 @@ module.exports = {
|
|||
.then(response => {
|
||||
if (response.has_secret) {
|
||||
this.ui_token_from_env = true;
|
||||
this.vultr_config = response.saved_to;
|
||||
this.load_regions();
|
||||
} else if (response.error) {
|
||||
this.ui_config_error = response.error;
|
||||
|
@ -138,10 +139,8 @@ module.exports = {
|
|||
},
|
||||
submit() {
|
||||
let submit_value = {
|
||||
region: this.region
|
||||
}
|
||||
if (!this.ui_token_from_env) {
|
||||
submit_value['vultr_config'] = this.vultr_config;
|
||||
region: this.region,
|
||||
vultr_config: this.vultr_config
|
||||
}
|
||||
this.$emit("submit", submit_value);
|
||||
},
|
||||
|
@ -150,4 +149,4 @@ module.exports = {
|
|||
"region-select": window.httpVueLoader("/static/region-select.vue"),
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</script>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<p v-if="result.local_service_ip">Local DNS resolver {{result.local_service_ip}}</p>
|
||||
<p v-if="result.p12_export_password">The p12 and SSH keys password for new users is <code>{{result.p12_export_password}}</code></p>
|
||||
<p v-if="result.CA_password">The CA key password is <code>{{result.CA_password}}</code></p>
|
||||
<p v-if="result.ssh_access">Shell access: <code>ssh -F configs/{{result.ansible_ssh_host}}/ssh_config {{config.server_name}}</code></p>
|
||||
<p v-if="result.ansible_ssh_host">Shell access: <code>ssh -F configs/{{result.ansible_ssh_host}}/ssh_config {{config.server_name}}</code></p>
|
||||
<p>Read more on how to set up clients at the <a href="https://github.com/trailofbits/algo" target="_blank" rel="noopener noopener">Algo home page</a></p>
|
||||
</section>
|
||||
<section>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
</p>
|
||||
<p>Don’t close terminal!</p>
|
||||
<transition-group name="console" tag="div">
|
||||
<code class="console-item" v-for="(event, i) in last_n_events" v-bind:key="event.counter">[{{ event.counter }}]: {{ event.stdout }}</code>
|
||||
<code class="console-item" v-for="(event, i) in last_n_events" v-bind:key="event.counter">{{ event.stdout }}</code>
|
||||
</transition-group>
|
||||
</section>
|
||||
</template>
|
||||
|
@ -43,8 +43,12 @@ module.exports = {
|
|||
})
|
||||
.then(data => {
|
||||
this.events = data.events;
|
||||
if (data.status && data.status === 'done') {
|
||||
this.$emit('done');
|
||||
if (data.status && data.status === 'successful') {
|
||||
this.$emit('successful');
|
||||
throw new Error();
|
||||
}
|
||||
if (data.status && data.status === 'failed') {
|
||||
this.$emit('error');
|
||||
throw new Error();
|
||||
}
|
||||
if (!data.status || data.status === 'cancelled') {
|
||||
|
|
Loading…
Add table
Reference in a new issue