Added preliminary interfacing with updown scripts
@ -76,20 +76,20 @@ def validate_common_name(func):
|
|||||||
|
|
||||||
|
|
||||||
class MyEncoder(json.JSONEncoder):
|
class MyEncoder(json.JSONEncoder):
|
||||||
REQUEST_ATTRIBUTES = "signable", "subject", "changed", "common_name", \
|
REQUEST_ATTRIBUTES = "signable", "identity", "changed", "common_name", \
|
||||||
"organizational_unit", "given_name", "surname", "fqdn", "email_address", \
|
"organizational_unit", "given_name", "surname", "fqdn", "email_address", \
|
||||||
"key_type", "key_length", "md5sum", "sha1sum", "sha256sum", "key_usage"
|
"key_type", "key_length", "md5sum", "sha1sum", "sha256sum", "key_usage"
|
||||||
|
|
||||||
CERTIFICATE_ATTRIBUTES = "revokable", "subject", "changed", "common_name", \
|
CERTIFICATE_ATTRIBUTES = "revokable", "identity", "changed", "common_name", \
|
||||||
"organizational_unit", "given_name", "surname", "fqdn", "email_address", \
|
"organizational_unit", "given_name", "surname", "fqdn", "email_address", \
|
||||||
"key_type", "key_length", "sha256sum", "serial_number", "key_usage"
|
"key_type", "key_length", "sha256sum", "serial_number", "key_usage"
|
||||||
|
|
||||||
def default(self, obj):
|
def default(self, obj):
|
||||||
if isinstance(obj, crypto.X509Name):
|
if isinstance(obj, crypto.X509Name):
|
||||||
try:
|
try:
|
||||||
return "".join(["/%s=%s" % (k.decode("ascii"),v.decode("utf-8")) for k, v in obj.get_components()])
|
return ", ".join(["%s=%s" % (k.decode("ascii"),v.decode("utf-8")) for k, v in obj.get_components()])
|
||||||
except UnicodeDecodeError: # Work around old buggy pyopenssl
|
except UnicodeDecodeError: # Work around old buggy pyopenssl
|
||||||
return "".join(["/%s=%s" % (k.decode("ascii"),v.decode("iso8859")) for k, v in obj.get_components()])
|
return ", ".join(["%s=%s" % (k.decode("ascii"),v.decode("iso8859")) for k, v in obj.get_components()])
|
||||||
if isinstance(obj, ipaddress._IPAddressBase):
|
if isinstance(obj, ipaddress._IPAddressBase):
|
||||||
return str(obj)
|
return str(obj)
|
||||||
if isinstance(obj, set):
|
if isinstance(obj, set):
|
||||||
@ -110,6 +110,7 @@ class MyEncoder(json.JSONEncoder):
|
|||||||
if hasattr(obj, key) and getattr(obj, key)])
|
if hasattr(obj, key) and getattr(obj, key)])
|
||||||
if isinstance(obj, CertificateAuthority):
|
if isinstance(obj, CertificateAuthority):
|
||||||
return dict(
|
return dict(
|
||||||
|
event_channel = obj.push_server + "/ev/" + obj.uuid,
|
||||||
slug = obj.slug,
|
slug = obj.slug,
|
||||||
certificate = obj.certificate,
|
certificate = obj.certificate,
|
||||||
admin_users = obj.admin_users,
|
admin_users = obj.admin_users,
|
||||||
@ -225,11 +226,12 @@ class LeaseResource(CertificateAuthorityBase):
|
|||||||
if remainder:
|
if remainder:
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
# TODO: Check for duplicate entries?
|
# TODO: Check for duplicate entries?
|
||||||
|
def generate():
|
||||||
for chunk in chunks:
|
for chunk in chunks:
|
||||||
for chunkette in chunk:
|
for chunkette in chunk:
|
||||||
key, value = chunkette
|
key, value = chunkette
|
||||||
dn += "/" + OIDS[key] + "=" + value
|
yield str(OIDS[key] + "=" + value)
|
||||||
return str(dn)
|
return ", ".join(generate())
|
||||||
|
|
||||||
# BUGBUG
|
# BUGBUG
|
||||||
SQL_LEASES = """
|
SQL_LEASES = """
|
||||||
@ -237,7 +239,7 @@ class LeaseResource(CertificateAuthorityBase):
|
|||||||
acquired,
|
acquired,
|
||||||
released,
|
released,
|
||||||
address,
|
address,
|
||||||
identities.data as dn
|
identities.data as identity
|
||||||
FROM
|
FROM
|
||||||
addresses
|
addresses
|
||||||
RIGHT JOIN
|
RIGHT JOIN
|
||||||
@ -256,7 +258,7 @@ class LeaseResource(CertificateAuthorityBase):
|
|||||||
row["acquired"] = datetime.utcfromtimestamp(row["acquired"])
|
row["acquired"] = datetime.utcfromtimestamp(row["acquired"])
|
||||||
row["released"] = datetime.utcfromtimestamp(row["released"]) if row["released"] else None
|
row["released"] = datetime.utcfromtimestamp(row["released"]) if row["released"] else None
|
||||||
row["address"] = ip_address(bytes(row["address"]))
|
row["address"] = ip_address(bytes(row["address"]))
|
||||||
row["dn"] = parse_dn(bytes(row["dn"]))
|
row["identity"] = parse_dn(bytes(row["identity"]))
|
||||||
yield row
|
yield row
|
||||||
|
|
||||||
|
|
||||||
@ -270,7 +272,7 @@ class SignedCertificateListResource(CertificateAuthorityBase):
|
|||||||
yield omit(
|
yield omit(
|
||||||
key_type=j.key_type,
|
key_type=j.key_type,
|
||||||
key_length=j.key_length,
|
key_length=j.key_length,
|
||||||
subject=j.distinguished_name,
|
identity=j.identity,
|
||||||
cn=j.common_name,
|
cn=j.common_name,
|
||||||
c=j.country_code,
|
c=j.country_code,
|
||||||
st=j.state_or_county,
|
st=j.state_or_county,
|
||||||
@ -324,7 +326,7 @@ class RequestListResource(CertificateAuthorityBase):
|
|||||||
yield omit(
|
yield omit(
|
||||||
key_type=j.key_type,
|
key_type=j.key_type,
|
||||||
key_length=j.key_length,
|
key_length=j.key_length,
|
||||||
subject=j.distinguished_name,
|
identity=j.identity,
|
||||||
cn=j.common_name,
|
cn=j.common_name,
|
||||||
c=j.country_code,
|
c=j.country_code,
|
||||||
st=j.state_or_county,
|
st=j.state_or_county,
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<p>Authority administration is allowed from: {% if authority.admin_subnets %}{% for i in authority.admin_subnets %}{{ i }} {% endfor %}{% else %}anywhere{% endif %}
|
<p>Authority administration is allowed from: {% if authority.admin_subnets %}{% for i in authority.admin_subnets %}{{ i }} {% endfor %}{% else %}anywhere{% endif %}
|
||||||
<p>Authority administration allowed for: {% for i in authority.admin_users %}{{ i }} {% endfor %}</p>
|
<p>Authority administration allowed for: {% for i in authority.admin_users %}{{ i }} {% endfor %}</p>
|
||||||
|
|
||||||
{% set s = authority.certificate.subject %}
|
{% set s = authority.certificate.identity %}
|
||||||
|
|
||||||
<h1>Pending requests</h1>
|
<h1>Pending requests</h1>
|
||||||
|
|
||||||
@ -23,21 +23,21 @@
|
|||||||
|
|
||||||
<ul id="signed_certificates">
|
<ul id="signed_certificates">
|
||||||
{% for j in authority.signed | sort | reverse %}
|
{% for j in authority.signed | sort | reverse %}
|
||||||
<li id="certificate_{{ j.sha256sum }}" data-dn="{{ j.subject }}">
|
<li id="certificate_{{ j.sha256sum }}" data-dn="{{ j.identity }}">
|
||||||
<a class="button" href="/api/{{authority.slug}}/signed/{{j.subject}}/">Fetch</a>
|
<a class="button icon download" href="/api/ca/{{authority.slug}}/signed/{{j.common_name}}/">Fetch</a>
|
||||||
<button onClick="javascript:$.ajax({url:'/api/{{authority.slug}}/signed/{{j.subject.CN}}/',type:'delete'});">Revoke</button>
|
<button class="icon revoke" onClick="javascript:$(this).addClass('busy');$.ajax({url:'/api/ca/{{authority.slug}}/signed/{{j.common_name}}/',type:'delete'});">Revoke</button>
|
||||||
|
|
||||||
<div class="monospace">
|
<div class="monospace">
|
||||||
{% include 'iconmonstr-certificate-15-icon.svg' %}
|
{% include 'img/iconmonstr-certificate-15-icon.svg' %}
|
||||||
{{j.subject}}
|
{{j.identity}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if j.email_address %}
|
{% if j.email_address %}
|
||||||
<div class="email">{% include 'iconmonstr-email-2-icon.svg' %} {{ j.email_address }}</div>
|
<div class="email">{% include 'img/iconmonstr-email-2-icon.svg' %} {{ j.email_address }}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="monospace">
|
<div class="monospace">
|
||||||
{% include 'iconmonstr-key-2-icon.svg' %}
|
{% include 'img/iconmonstr-key-2-icon.svg' %}
|
||||||
<span title="SHA-256 of public key">
|
<span title="SHA-256 of public key">
|
||||||
{{ j.sha256sum }}
|
{{ j.sha256sum }}
|
||||||
</span>
|
</span>
|
||||||
@ -46,11 +46,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{% include 'iconmonstr-flag-3-icon.svg' %}
|
{% include 'img/iconmonstr-flag-3-icon.svg' %}
|
||||||
{{j.key_usage}}
|
{{j.key_usage}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="status">
|
<div class="status">
|
||||||
{% include 'status.html' %}
|
{% include 'status.html' %}
|
||||||
</div>
|
</div>
|
||||||
@ -76,7 +75,7 @@ openssl ocsp -issuer authority.pem -CAfile authority.pem -url {{request.url}}/oc
|
|||||||
{% for j in authority.revoked %}
|
{% for j in authority.revoked %}
|
||||||
<li id="certificate_{{ j.sha256sum }}">
|
<li id="certificate_{{ j.sha256sum }}">
|
||||||
{{j.changed}}
|
{{j.changed}}
|
||||||
{{j.serial_number}} <span class="monospace">{{j.distinguished_name}}</span>
|
{{j.serial_number}} <span class="monospace">{{j.identity}}</span>
|
||||||
</li>
|
</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li>Great job! No certificate signing requests to sign.</li>
|
<li>Great job! No certificate signing requests to sign.</li>
|
||||||
|
@ -42,7 +42,8 @@ button, .button {
|
|||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
margin: 2px;
|
margin: 2px;
|
||||||
padding: 4px 8px;
|
padding: 6px 12px;
|
||||||
|
background-position: 6px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,3 +141,20 @@ li {
|
|||||||
clear: both;
|
clear: both;
|
||||||
border-top: 1px dashed #ccc;
|
border-top: 1px dashed #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon{
|
||||||
|
background-size: 24px;
|
||||||
|
padding-left: 36px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
display: block;
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.icon.revoke { background-image: url("../img/iconmonstr-x-mark-5-icon.svg"); }
|
||||||
|
.icon.download { background-image: url("../img/iconmonstr-download-12-icon.svg"); }
|
||||||
|
.icon.sign { background-image: url("../img/iconmonstr-pen-10-icon.svg"); }
|
||||||
|
|
||||||
|
/* Make sure this is the last one */
|
||||||
|
.icon.busy{background-image:url("https://software.opensuse.org/assets/ajax-loader-ea46060b6c9f42822a3d58d075c83ea2.gif");}
|
||||||
|
BIN
certidude/static/img/ajax-loader.gif
Normal file
After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
29
certidude/static/img/iconmonstr-download-12-icon.svg
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- The icon can be used freely in both personal and commercial projects with no attribution required, but always appreciated.
|
||||||
|
You may NOT sub-license, resell, rent, redistribute or otherwise transfer the icon without express written permission from iconmonstr.com -->
|
||||||
|
|
||||||
|
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
|
||||||
|
width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
|
||||||
|
|
||||||
|
<path id="download-12-icon" d="M462,246.575c0,44.318-35.928,80.246-80.246,80.246H331.58v-38.119
|
||||||
|
|
||||||
|
c-0.998-43.379,40.92-44.379,59.67-46.379c-27.168-33.334-70.918-48.244-104.611-48.244c-66.546,0-108.17,39.104-108.17,104.808
|
||||||
|
|
||||||
|
v27.935h-48.223C85.928,326.821,50,290.894,50,246.575c0-40.982,30.729-74.766,70.396-79.623
|
||||||
|
|
||||||
|
c2.891-42.287,49.035-66.355,85.217-45.898c19.236-30.605,53.297-50.953,92.115-50.953c57.107,0,103.932,44.033,108.375,100
|
||||||
|
|
||||||
|
C438.516,180.413,462,210.747,462,246.575z M301.58,288.702c0-30.761,6.053-48.484,31.926-56.837
|
||||||
|
|
||||||
|
c-20.066-8.452-125.037-28.815-125.037,67.021c0,32.187,0,58.909,0,58.909h-37.408l83.963,84.104l83.965-84.104H301.58
|
||||||
|
|
||||||
|
C301.58,357.796,301.58,315.59,301.58,288.702z"/>
|
||||||
|
|
||||||
|
</svg>
|
||||||
|
|
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 982 B After Width: | Height: | Size: 982 B |
Before Width: | Height: | Size: 786 B After Width: | Height: | Size: 786 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
13
certidude/static/img/iconmonstr-pen-10-icon.svg
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<!-- License Agreement at http://iconmonstr.com/license/ -->
|
||||||
|
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
|
||||||
|
<path id="pen-10-icon" d="M244.558,199.493l67.827,67.826l-73.17,134.531c0,0-90.805,23.4-147.694,60.027l-14.185-14.182
|
||||||
|
l68.113-68.105c5.975-5.982,13.726-9.773,22.11-10.807c4.642-0.582,9.128-2.621,12.696-6.205c8.538-8.547,8.546-22.4-0.002-30.951
|
||||||
|
c-8.549-8.543-22.407-8.543-30.959-0.002c-3.573,3.572-5.623,8.061-6.199,12.693c-1.028,8.371-4.834,16.15-10.8,22.117
|
||||||
|
l-68.104,68.105L50,420.354c37.028-57.496,60.021-147.693,60.021-147.693L244.558,199.493z M315.896,50.122
|
||||||
|
c-22.784,44.143-53.014,100-53.014,100l98.872,98.869c0,0,55.909-30.086,100.246-52.766L315.896,50.122z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1016 B |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
21
certidude/static/img/iconmonstr-x-mark-5-icon.svg
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- The icon can be used freely in both personal and commercial projects with no attribution required, but always appreciated.
|
||||||
|
You may NOT sub-license, resell, rent, redistribute or otherwise transfer the icon without express written permission from iconmonstr.com -->
|
||||||
|
|
||||||
|
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
|
||||||
|
width="32px" height="32px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
|
||||||
|
|
||||||
|
<path id="x-mark-5-icon" d="M432.546,133.462L367.133,76.39L254.078,210.715L140.967,73.702l-61.513,65.068
|
||||||
|
|
||||||
|
c33.791,43.885,78.146,89.797,123.688,132.465L82.993,413.987l19.865,22.629c29.251-20.31,87.839-65.578,150.312-120.092
|
||||||
|
|
||||||
|
c63.662,55.812,122.861,101.336,151.301,121.773l21.438-19.443L303.804,270.95C352.439,225.709,399.308,177.442,432.546,133.462z"/>
|
||||||
|
|
||||||
|
</svg>
|
||||||
|
|
After Width: | Height: | Size: 1001 B |
@ -20,14 +20,40 @@ $(document).ready(function() {
|
|||||||
success: function(authority, status, xhr) {
|
success: function(authority, status, xhr) {
|
||||||
console.info("Got CA:", authority);
|
console.info("Got CA:", authority);
|
||||||
|
|
||||||
console.info("Opening EventSource from:", "/api/ca/" + authority.slug);
|
console.info("Opening EventSource from:", authority.event_channel);
|
||||||
|
|
||||||
var source = new EventSource("/api/" + authority.slug);
|
var source = new EventSource(authority.event_channel);
|
||||||
|
|
||||||
source.onmessage = function(event) {
|
source.onmessage = function(event) {
|
||||||
console.log("Received server-sent event:", event);
|
console.log("Received server-sent event:", event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
source.addEventListener("up-client", function(e) {
|
||||||
|
console.log("Adding security association:" + e.data);
|
||||||
|
var lease = JSON.parse(e.data);
|
||||||
|
var $status = $("#signed_certificates [data-dn='" + lease.identity + "'] .status");
|
||||||
|
$status.html(nunjucks.render('status.html', {
|
||||||
|
lease: {
|
||||||
|
address: lease.address,
|
||||||
|
identity: lease.identity,
|
||||||
|
acquired: new Date(),
|
||||||
|
released: null
|
||||||
|
}}));
|
||||||
|
});
|
||||||
|
|
||||||
|
source.addEventListener("down-client", function(e) {
|
||||||
|
console.log("Removing security association:" + e.data);
|
||||||
|
var lease = JSON.parse(e.data);
|
||||||
|
var $status = $("#signed_certificates [data-dn='" + lease.identity + "'] .status");
|
||||||
|
$status.html(nunjucks.render('status.html', {
|
||||||
|
lease: {
|
||||||
|
address: lease.address,
|
||||||
|
identity: lease.identity,
|
||||||
|
acquired: null,
|
||||||
|
released: new Date()
|
||||||
|
}}));
|
||||||
|
});
|
||||||
|
|
||||||
source.addEventListener("request_deleted", function(e) {
|
source.addEventListener("request_deleted", function(e) {
|
||||||
console.log("Removing deleted request #" + e.data);
|
console.log("Removing deleted request #" + e.data);
|
||||||
$("#request_" + e.data).remove();
|
$("#request_" + e.data).remove();
|
||||||
@ -39,13 +65,13 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
source.addEventListener("request_signed", function(e) {
|
source.addEventListener("request_signed", function(e) {
|
||||||
console.log("Request signed:", e.data);
|
console.log("Request signed:", e.data);
|
||||||
$("#request_" + e.data).remove();
|
$("#request_" + e.data).slideUp("normal", function() { $(this).remove(); });
|
||||||
// TODO: Insert <li> to signed certs list
|
// TODO: Insert <li> to signed certs list
|
||||||
});
|
});
|
||||||
|
|
||||||
source.addEventListener("certificate_revoked", function(e) {
|
source.addEventListener("certificate_revoked", function(e) {
|
||||||
console.log("Removing revoked certificate #" + e.data);
|
console.log("Removing revoked certificate #" + e.data);
|
||||||
$("#certificate_" + e.data).remove();
|
$("#certificate_" + e.data).slideUp("normal", function() { $(this).remove(); });
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#container").html(nunjucks.render('authority.html', { authority: authority, session: session }));
|
$("#container").html(nunjucks.render('authority.html', { authority: authority, session: session }));
|
||||||
@ -57,7 +83,7 @@ $(document).ready(function() {
|
|||||||
success: function(leases, status, xhr) {
|
success: function(leases, status, xhr) {
|
||||||
console.info("Got leases:", leases);
|
console.info("Got leases:", leases);
|
||||||
for (var j = 0; j < leases.length; j++) {
|
for (var j = 0; j < leases.length; j++) {
|
||||||
var $status = $("#signed_certificates [data-dn='" + leases[j].dn + "'] .status");
|
var $status = $("#signed_certificates [data-dn='" + leases[j].identity + "'] .status");
|
||||||
if (!$status.length) {
|
if (!$status.length) {
|
||||||
console.info("Detected rogue client:", leases[j]);
|
console.info("Detected rogue client:", leases[j]);
|
||||||
continue;
|
continue;
|
||||||
@ -65,7 +91,7 @@ $(document).ready(function() {
|
|||||||
$status.html(nunjucks.render('status.html', {
|
$status.html(nunjucks.render('status.html', {
|
||||||
lease: {
|
lease: {
|
||||||
address: leases[j].address,
|
address: leases[j].address,
|
||||||
dn: leases[j].dn,
|
identity: leases[j].identity,
|
||||||
acquired: new Date(leases[j].acquired).toLocaleString(),
|
acquired: new Date(leases[j].acquired).toLocaleString(),
|
||||||
released: leases[j].released ? new Date(leases[j].released).toLocaleString() : null
|
released: leases[j].released ? new Date(leases[j].released).toLocaleString() : null
|
||||||
}}));
|
}}));
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
<li id="request_{{ j.md5sum }}">
|
<li id="request_{{ j.md5sum }}">
|
||||||
|
|
||||||
<a class="button" href="/api/{{authority.slug}}/request/{{j.common_name}}/">Fetch</a>
|
<a class="button icon download" href="/api/ca/{{authority.slug}}/request/{{j.common_name}}/">Fetch</a>
|
||||||
{% if j.signable %}
|
{% if j.signable %}
|
||||||
<button onClick="javascript:$.ajax({url:'/api/{{authority.slug}}/request/{{j.common_name}}/',type:'patch'});">Sign</button>
|
<button class="icon sign" onClick="javascript:$(this).addClass('busy');$.ajax({url:'/api/ca/{{authority.slug}}/request/{{j.common_name}}/',type:'patch'});">Sign</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
<button title="Please use certidude command-line utility to sign unusual requests" disabled>Sign</button>
|
<button title="Please use certidude command-line utility to sign unusual requests" disabled>Sign</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<button onClick="javascript:$.ajax({url:'/api/{{authority.slug}}/request/{{j.common_name}}/',type:'delete'});">Delete</button>
|
<button class="icon revoke" onClick="javascript:$(this).addClass('busy');$.ajax({url:'/api/ca/{{authority.slug}}/request/{{j.common_name}}/',type:'delete'});">Delete</button>
|
||||||
|
|
||||||
|
|
||||||
<div class="monospace">
|
<div class="monospace">
|
||||||
{% include 'iconmonstr-certificate-15-icon.svg' %}
|
{% include 'img/iconmonstr-certificate-15-icon.svg' %}
|
||||||
{{j.subject}}
|
{{j.identity}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if j.email_address %}
|
{% if j.email_address %}
|
||||||
<div class="email">{% include 'iconmonstr-email-2-icon.svg' %} {{ j.email_address }}</div>
|
<div class="email">{% include 'img/iconmonstr-email-2-icon.svg' %} {{ j.email_address }}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div class="monospace">
|
<div class="monospace">
|
||||||
{% include 'iconmonstr-key-2-icon.svg' %}
|
{% include 'img/iconmonstr-key-2-icon.svg' %}
|
||||||
<span title="SHA-1 of public key">
|
<span title="SHA-1 of public key">
|
||||||
{{ j.sha256sum }}
|
{{ j.sha256sum }}
|
||||||
</span>
|
</span>
|
||||||
@ -30,7 +30,7 @@
|
|||||||
{% set key_usage = j.key_usage %}
|
{% set key_usage = j.key_usage %}
|
||||||
{% if key_usage %}
|
{% if key_usage %}
|
||||||
<div>
|
<div>
|
||||||
{% include 'iconmonstr-flag-3-icon.svg' %}
|
{% include 'img/iconmonstr-flag-3-icon.svg' %}
|
||||||
{{j.key_usage}}
|
{{j.key_usage}}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<svg height="32" width="32">
|
<svg height="32" width="32">
|
||||||
<circle cx="16" cy="16" r="13" stroke="black" stroke-width="3" fill="{% if lease %}{% if lease.released %}green{%else %}red{% endif %}{% else %}yellow{% endif %}" />
|
<circle cx="16" cy="16" r="13" stroke="black" stroke-width="3" fill="{% if lease %}{% if lease.released %}red{%else %}green{% endif %}{% else %}yellow{% endif %}" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<span>
|
<span>
|
||||||
|
Before Width: | Height: | Size: 428 B After Width: | Height: | Size: 428 B |
@ -59,8 +59,8 @@ def subject2dn(subject):
|
|||||||
bits = []
|
bits = []
|
||||||
for j in "CN", "GN", "SN", "C", "S", "L", "O", "OU":
|
for j in "CN", "GN", "SN", "C", "S", "L", "O", "OU":
|
||||||
if getattr(subject, j, None):
|
if getattr(subject, j, None):
|
||||||
bits.append("/%s=%s" % (j, getattr(subject, j)))
|
bits.append("%s=%s" % (j, getattr(subject, j)))
|
||||||
return "".join(bits)
|
return ", ".join(bits)
|
||||||
|
|
||||||
class CertificateAuthorityConfig(object):
|
class CertificateAuthorityConfig(object):
|
||||||
"""
|
"""
|
||||||
@ -225,7 +225,7 @@ class CertificateBase:
|
|||||||
return subject2dn(self.issuer)
|
return subject2dn(self.issuer)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def distinguished_name(self):
|
def identity(self):
|
||||||
return subject2dn(self.subject)
|
return subject2dn(self.subject)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
4
doc/strongswan-updown.sh
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
cat << EOF | curl -X POST -d @- -H "Event-Type: $PLUTO_VERB" http://ca.example.com/pub/?id=CA-channel-identifier-goes-here
|
||||||
|
{"address": "$PLUTO_PEER_SOURCEIP","peer": "$PLUTO_PEER","identity": "$PLUTO_PEER_ID","routed_subnet": "$PLUTO_MY_CLIENT"}
|
||||||
|
EOF
|