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 flash
from flask import current_app
@ -24,7 +25,62 @@ def makeCapsulId():
@bp.route("/")
@account_required
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"))
@account_required
@ -64,8 +120,11 @@ def create():
memory=vm_sizes[size].memory
)
if error:
flash(error)
return render_template(
"create.html",
"create-capsul.html",
ssh_public_keys=ssh_public_keys,
operating_systems=operating_systems,
vm_sizes=vm_sizes

View File

@ -55,12 +55,29 @@ class DBModel:
return vmSizes
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(
lambda x: dict(name=x[0], content=x[1]),
lambda x: dict(name=x[0], content=x[1], created=x[2]),
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):
self.cursor.execute("""
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,
name TEXT NOT NULL,
content TEXT NOT NULL,
created TIMESTAMP NOT NULL DEFAULT NOW(),
PRIMARY KEY (email, name)
);
@ -42,8 +43,8 @@ CREATE TABLE vm_ssh_public_key (
ssh_public_key_name TEXT NOT NULL,
email 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, vm_id) REFERENCES vms(email, id) 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 CASCADE,
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-xxx', 57.58, 16384, 8, 16000);
INSERT INTO accounts (email)
VALUES ('forest.n.johnson@gmail.com');
UPDATE schemaversion SET version = 2;

View File

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

View File

@ -27,7 +27,6 @@
{% if session["account"] %}
<a href="/console/">Console</a>
<a href="/console/billing">Billing</a>
{% endif %}
<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 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 %}
<pre>
CAPSUL SIZES
@ -22,7 +20,7 @@ f1-xxx $57.58 8 16G 25G 16TB
* net is calculated as a per-month average
* all VMs come standard with one public IPv4 addr</pre>
</div>
<form method="post">
<div class="row justify-start">
<label class="align" for="size">Capsul Size</label>
@ -65,4 +63,4 @@ f1-xxx $57.58 8 16G 25G 16TB
{% endif %}
{% endblock %}
{% block pagesource %}/templates/console.html{% endblock %}
{% block pagesource %}/templates/create-capsul.html{% endblock %}

View File

@ -141,5 +141,5 @@ $ doas su -</pre>
{% 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 %}