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 | ||||||