SSH keys CRUD working

This commit is contained in:
forest 2020-05-11 11:57:39 -05:00
parent 18e6a1b141
commit 452f236c6b
11 changed files with 232 additions and 71 deletions

View File

@ -1,3 +1,4 @@
import re
from flask import Blueprint from flask import Blueprint
from flask import flash from flask import flash
from flask import current_app from flask import current_app
@ -24,7 +25,62 @@ def makeCapsulId():
@bp.route("/") @bp.route("/")
@account_required @account_required
def index(): def index():
return render_template("console.html", vms=get_model().list_vms_for_account(session["account"])) return render_template("capsuls.html", vms=get_model().list_vms_for_account(session["account"]))
@bp.route("/ssh", methods=("GET", "POST"))
@account_required
def ssh_public_keys():
db_model = get_model()
error = None
if request.method == "POST":
method = request.form["method"]
name = request.form["name"]
if not name or len(name.strip()) < 1:
error = "Name is required"
elif not re.match(r"^[0-9A-Za-z_ -]+$", name):
error = "Name must match \"^[0-9A-Za-z_ -]+$\""
if method == "POST":
content = request.form["content"]
if not content or len(content.strip()) < 1:
error = "Content is required"
else:
content = content.replace("\r", "").replace("\n", "")
if not re.match(r"^(ssh|ecdsa)-[0-9A-Za-z+/_=@ -]+$", content):
error = "Content must match \"^(ssh|ecdsa)-[0-9A-Za-z+/_=@ -]+$\""
if db_model.ssh_public_key_name_exists(session["account"], name):
error = "A key with that name already exists"
if error is None:
db_model.create_ssh_public_key(session["account"], name, content)
elif method == "DELETE":
if error is None:
db_model.delete_ssh_public_key(session["account"], name)
if error:
flash(error)
# keys_list=
# for key in keys_list:
# if len(key['content']) > 40:
# print(key['content'])
# print(f"{key['content'][:20]}...{key['content'][len(key['content'])-20:]}")
# key["content"] =
# return
return render_template(
"ssh-public-keys.html",
ssh_public_keys=map(
lambda x: dict(name=x['name'], content=f"{x['content'][:20]}...{x['content'][len(x['content'])-20:]}"),
db_model.list_ssh_public_keys_for_account(session["account"])
)
)
@bp.route("/create", methods=("GET", "POST")) @bp.route("/create", methods=("GET", "POST"))
@account_required @account_required
@ -64,8 +120,11 @@ def create():
memory=vm_sizes[size].memory memory=vm_sizes[size].memory
) )
if error:
flash(error)
return render_template( return render_template(
"create.html", "create-capsul.html",
ssh_public_keys=ssh_public_keys, ssh_public_keys=ssh_public_keys,
operating_systems=operating_systems, operating_systems=operating_systems,
vm_sizes=vm_sizes vm_sizes=vm_sizes

View File

@ -55,12 +55,29 @@ class DBModel:
return vmSizes return vmSizes
def list_ssh_public_keys_for_account(self, email): def list_ssh_public_keys_for_account(self, email):
self.cursor.execute("SELECT name, content FROM ssh_public_keys WHERE email = %s", (email, )) self.cursor.execute("SELECT name, content, created FROM ssh_public_keys WHERE email = %s", (email, ))
return map( return map(
lambda x: dict(name=x[0], content=x[1]), lambda x: dict(name=x[0], content=x[1], created=x[2]),
self.cursor.fetchall() self.cursor.fetchall()
) )
def ssh_public_key_name_exists(self, email, name):
self.cursor.execute( "SELECT name FROM ssh_public_keys where email = %s AND name = %s", (email, name) )
return len(self.cursor.fetchall()) > 0
def create_ssh_public_key(self, email, name, content):
self.cursor.execute("""
INSERT INTO ssh_public_keys (email, name, content)
VALUES (%s, %s, %s)
""",
(email, name, content)
)
self.connection.commit()
def delete_ssh_public_key(self, email, name):
self.cursor.execute( "DELETE FROM ssh_public_keys where email = %s AND name = %s", (email, name) )
self.connection.commit()
def list_vms_for_account(self, email): def list_vms_for_account(self, email):
self.cursor.execute(""" self.cursor.execute("""
SELECT vms.id, vms.last_seen_ipv4, vms.last_seen_ipv6, vms.size, os_images.description, vms.created, vms.deleted SELECT vms.id, vms.last_seen_ipv4, vms.last_seen_ipv6, vms.size, os_images.description, vms.created, vms.deleted

View File

@ -23,6 +23,7 @@ CREATE TABLE ssh_public_keys (
email TEXT REFERENCES accounts(email) ON DELETE RESTRICT, email TEXT REFERENCES accounts(email) ON DELETE RESTRICT,
name TEXT NOT NULL, name TEXT NOT NULL,
content TEXT NOT NULL, content TEXT NOT NULL,
created TIMESTAMP NOT NULL DEFAULT NOW(),
PRIMARY KEY (email, name) PRIMARY KEY (email, name)
); );
@ -42,8 +43,8 @@ CREATE TABLE vm_ssh_public_key (
ssh_public_key_name TEXT NOT NULL, ssh_public_key_name TEXT NOT NULL,
email TEXT NOT NULL, email TEXT NOT NULL,
vm_id TEXT NOT NULL, vm_id TEXT NOT NULL,
FOREIGN KEY (email, ssh_public_key_name) REFERENCES ssh_public_keys(email, name) ON DELETE RESTRICT, FOREIGN KEY (email, ssh_public_key_name) REFERENCES ssh_public_keys(email, name) ON DELETE CASCADE,
FOREIGN KEY (email, vm_id) REFERENCES vms(email, id) ON DELETE RESTRICT, FOREIGN KEY (email, vm_id) REFERENCES vms(email, id) ON DELETE CASCADE,
PRIMARY KEY (email, vm_id, ssh_public_key_name) PRIMARY KEY (email, vm_id, ssh_public_key_name)
); );
@ -78,4 +79,7 @@ VALUES ('f1-s', 5.33, 512, 1, 500),
('f1-xx', 29.66, 8192, 4, 8000), ('f1-xx', 29.66, 8192, 4, 8000),
('f1-xxx', 57.58, 16384, 8, 16000); ('f1-xxx', 57.58, 16384, 8, 16000);
INSERT INTO accounts (email)
VALUES ('forest.n.johnson@gmail.com');
UPDATE schemaversion SET version = 2; UPDATE schemaversion SET version = 2;

View File

@ -93,11 +93,11 @@ label.align {
min-width: 10em; min-width: 10em;
} }
input, select, label { input, textarea, select, label {
margin: 0.5em; margin: 0.5em;
} }
input, select { input, select, textarea {
outline: 0; outline: 0;
padding: 0.25em 0.5em; padding: 0.25em 0.5em;
border-radius: 0.5em; border-radius: 0.5em;
@ -118,7 +118,7 @@ select {
background-size: 0.5em; background-size: 0.5em;
} }
input { input, textarea {
background: none; background: none;
} }
@ -126,18 +126,31 @@ input[type=text] {
font: calc(0.40rem + 1vmin) monospace; font: calc(0.40rem + 1vmin) monospace;
border: 0; border: 0;
border-bottom: 1px solid #777e73; border-bottom: 1px solid #777e73;
min-width: 20em;
outline: 0; outline: 0;
} }
input[type=submit], select { input[type=text], textarea {
min-width: 20em;
}
input[type=text].expand, textarea.expand {
width: 100%;
}
textarea {
height: 6em;
}
input[type=submit], select, textarea {
font: calc(0.40rem + 1vmin) monospace; font: calc(0.40rem + 1vmin) monospace;
cursor: pointer;
border: 1px solid #777e73; border: 1px solid #777e73;
background-color: #bdc7b810; background-color: #bdc7b810;
} }
input[type=submit], select {
cursor: pointer;
}
h1, h2, h3, h4, h5 { h1, h2, h3, h4, h5 {
font-size:calc(0.40rem + 1vmin); font-size:calc(0.40rem + 1vmin);
margin: initial; margin: initial;
@ -156,6 +169,13 @@ ul li {
border: 1px solid #777e73; border: 1px solid #777e73;
background: #bdc7b810; background: #bdc7b810;
} }
.break-word {
word-break: break-word;
}
.dim {
color: #777e73bb;
}
footer, p { footer, p {
text-align: left; text-align: left;
@ -172,3 +192,7 @@ footer {
font-size: 1.8em; font-size: 1.8em;
} }
.smalltext {
font-size: 0.8em;
}

View File

@ -27,7 +27,6 @@
{% if session["account"] %} {% if session["account"] %}
<a href="/console/">Console</a> <a href="/console/">Console</a>
<a href="/console/billing">Billing</a>
{% endif %} {% endif %}
<a href="/support">Support</a> <a href="/support">Support</a>

View File

@ -0,0 +1,37 @@
{% extends 'console-base.html' %}
{% block title %}Console{% endblock %}
{% block consoletitle %}Console{% endblock %}
{% block consolecontent %}
{% if vms[0] is defined %}
<table>
<thead>
<tr>
<th>id</th>
<th>size</th>
<th>ipv4</th>
<th>os</th>
<th>created</th>
</tr>
</thead>
<tbody>
{% for vm in vms %}
<a href="/console/{{ vm['id'] }}">
<tr>
<td>{{ vm["id"] }}</td>
<td>{{ vm["size"] }}</td>
<td>{{ vm["ipv4"] }}</td>
<td>{{ vm["os"] }}</td>
<td>{{ vm["created"] }}</td>
</tr>
</a>
{% endfor %}
</tbody>
</table>
{% else %}
You don't have any Capsuls running. <a href="/console/create">Create one</a> today!
{% endif %}
{% endblock %}
{% block pagesource %}/templates/capsuls.html{% endblock %}

View File

@ -0,0 +1,17 @@
{% extends 'base.html' %}
{% block content %}
<div class="third-margin">
<h1>{% block consoletitle %}{% endblock %}</h1>
</div>
<div class="third-margin">
<div class="nav-row">
<a href="/console">Capsuls</a>
<a href="/console/ssh">SSH Public Keys</a>
<a href="/console/billing">Billing</a>
</div>
</div>
<div class="third-margin">
{% block consolecontent %}{% endblock %}
</div>
{% endblock %}

View File

@ -1,49 +0,0 @@
{% extends 'base.html' %}
{% block title %}Console{% endblock %}
{% block content %}
<div class="third-margin">
<h1>CONSOLE</h1>
</div>
<div class="third-margin">
<div class="nav-row">
<a href="/console">Capsuls</a>
<a href="/console/ssh">SSH Public Keys</a>
<a href="/console/billing">Billing</a>
</div>
</div>
<div class="third-margin">
{% if vms[0] is defined %}
<table>
<thead>
<tr>
<th>id</th>
<th>size</th>
<th>ipv4</th>
<th>os</th>
<th>created</th>
</tr>
</thead>
<tbody>
{% for vm in vms %}
<a href="/console/{{ vm['id'] }}">
<tr>
<td>{{ vm["id"] }}</td>
<td>{{ vm["size"] }}</td>
<td>{{ vm["ipv4"] }}</td>
<td>{{ vm["os"] }}</td>
<td>{{ vm["created"] }}</td>
</tr>
</a>
{% endfor %}
</tbody>
</table>
{% else %}
You don't have any Capsuls running. <a href="/console/create">Create one</a> today!
{% endif %}
</div>
{% endblock %}
{% block pagesource %}/templates/console.html{% endblock %}

View File

@ -1,12 +1,10 @@
{% extends 'base.html' %} {% extends 'console-base.html' %}
{% block title %}Create{% endblock %} {% block title %}Create{% endblock %}
{% block consoletitle %}Console - Create Capsul{% endblock %}
{% block consolecontent %}
{% block content %}
<div class="half-margin">
<h1>CONSOLE - CREATE CAPSUL</h1>
</div>
<div class="half-margin">
{% if ssh_public_keys[0] is defined %} {% if ssh_public_keys[0] is defined %}
<pre> <pre>
CAPSUL SIZES CAPSUL SIZES
@ -22,7 +20,7 @@ f1-xxx $57.58 8 16G 25G 16TB
* net is calculated as a per-month average * net is calculated as a per-month average
* all VMs come standard with one public IPv4 addr</pre> * all VMs come standard with one public IPv4 addr</pre>
</div>
<form method="post"> <form method="post">
<div class="row justify-start"> <div class="row justify-start">
<label class="align" for="size">Capsul Size</label> <label class="align" for="size">Capsul Size</label>
@ -65,4 +63,4 @@ f1-xxx $57.58 8 16G 25G 16TB
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% block pagesource %}/templates/console.html{% endblock %} {% block pagesource %}/templates/create-capsul.html{% endblock %}

View File

@ -141,5 +141,5 @@ $ doas su -</pre>
{% endblock %} {% endblock %}
{% block pagesource %}/templates/changelog.html{% endblock %} {% block pagesource %}/templates/faq.html{% endblock %}

View File

@ -0,0 +1,55 @@
{% extends 'console-base.html' %}
{% block title %}SSH Public Keys{% endblock %}
{% block consoletitle %}Console - SSH Public Keys{% endblock %}
{% block consolecontent %}
{% if ssh_public_keys[0] is defined %} <hr/> {% endif %}
{% for ssh_public_key in ssh_public_keys %}
<form method="post">
<input type="hidden" name="method" value="DELETE"></input>
<input type="hidden" name="name" value="{{ ssh_public_key['name'] }}"></input>
<div class="row">
<span class="code">{{ ssh_public_key['name'] }}</span>
<span class="dim">{{ ssh_public_key['content'] }}</span>
<input type="submit" value="Delete">
</div>
</form>
{% endfor %}
{% if ssh_public_keys[0] is defined %} <hr/> {% endif %}
<div class="third-margin">
<h1>UPLOAD A NEW SSH KEY</h1>
</div>
<form method="post">
<input type="hidden" name="method" value="POST"></input>
<div class="row justify-start">
<label class="align" for="name">Name</label>
<input type="text" id="name" name="name"></input>
</div>
<div class="row justify-start">
<label class="align" for="content">Content</label>
<textarea class="expand" id="content" name="content"></textarea>
</div>
<div class="smalltext">
<p>Paste the contents of your SSH public key file here.
( Something like <span class='code'>~/.ssh/id_rsa.pub</span> )
</p><p>
The contents of this file should look similar to
<span class='code'>ssh-rsa AAAAC3NzaC1l...Yqv== me@my-computer</span>
</p><p>
If you wish, you can <a href="https://git-scm.com/book/en/v2/Git-on-the-Server-Generating-Your-SSH-Public-Key">
generate a new SSH key pair using the ssh-keygen utility</a>.
</p>
</div>
<div class="row justify-end">
<input type="submit" value="Upload">
</div>
</form>
{% endblock %}
{% block pagesource %}/templates/ssh-public-keys.html{% endblock %}