mirror of
				https://github.com/laurivosandi/certidude
				synced 2025-10-30 17:09:19 +00:00 
			
		
		
		
	api: Added signed certificate tagging mechanism
This commit is contained in:
		| @@ -1,19 +1,19 @@ | ||||
|  | ||||
| <section id="about"> | ||||
| <p>Hi {{session.username}},</p> | ||||
|  | ||||
| <p>Request submission is allowed from: {% if session.request_subnets %}{% for i in session.request_subnets %}{{ i }} {% endfor %}{% else %}anywhere{% endif %}</p> | ||||
| <p>Autosign is allowed from: {% if session.autosign_subnets %}{% for i in session.autosign_subnets %}{{ i }} {% endfor %}{% else %}nowhere{% endif %}</p> | ||||
| <p>Authority administration is allowed from: {% if session.admin_subnets %}{% for i in session.admin_subnets %}{{ i }} {% endfor %}{% else %}anywhere{% endif %} | ||||
| <p>Authority administration allowed for: {% for i in session.admin_users %}{{ i }} {% endfor %}</p> | ||||
|  | ||||
| </section> | ||||
| {% set s = session.certificate.identity %} | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| <div id="requests"> | ||||
| <section id="requests"> | ||||
|     <h1>Pending requests</h1> | ||||
|  | ||||
|  | ||||
|     <ul id="pending_requests"> | ||||
|         {% for request in session.requests %} | ||||
|              {% include "request.html" %} | ||||
| @@ -23,19 +23,20 @@ | ||||
|             <pre>certidude setup client {{session.common_name}}</pre> | ||||
|         </li> | ||||
|     </ul> | ||||
| </div> | ||||
| </section> | ||||
|  | ||||
|  | ||||
| <div id="signed"> | ||||
| <section id="signed"> | ||||
|     <h1>Signed certificates</h1> | ||||
|     <input id="search" type="search" class="icon search"> | ||||
|     <ul id="signed_certificates"> | ||||
|         {% for certificate in session.signed | sort | reverse %} | ||||
|             {% include "signed.html" %} | ||||
| 	    {% endfor %} | ||||
|     </ul> | ||||
| </div> | ||||
| </section> | ||||
|  | ||||
| <div id="log"> | ||||
| <section id="log"> | ||||
|     <h1>Log</h1> | ||||
|     <p> | ||||
|         <input id="log_level_critical" type="checkbox" checked/> <label for="log_level_critical">Critical</label> | ||||
| @@ -46,9 +47,9 @@ | ||||
|     </p> | ||||
|     <ul id="log_entries"> | ||||
|     </ul> | ||||
| </div> | ||||
| </section> | ||||
|  | ||||
| <div id="revoked"> | ||||
| <section id="revoked"> | ||||
|     <h1>Revoked certificates</h1> | ||||
|     <p>To fetch certificate revocation list:</p> | ||||
|     <pre> | ||||
| @@ -72,4 +73,4 @@ | ||||
|             <li>Great job! No certificate signing requests to sign.</li> | ||||
| 	    {% endfor %} | ||||
|     </ul> | ||||
| </div> | ||||
| </section> | ||||
|   | ||||
| @@ -119,7 +119,7 @@ h2 svg { | ||||
|     top: 16px; | ||||
| } | ||||
|  | ||||
| p, td, footer, li, button, input { | ||||
| p, td, footer, li, button, input, select { | ||||
|     font-family: 'PT Sans Narrow'; | ||||
|     font-size: 14pt; | ||||
| } | ||||
| @@ -159,6 +159,7 @@ pre { | ||||
|     display: inline; | ||||
|     margin: 1mm 5mm 1mm 0; | ||||
|     line-height: 200%; | ||||
|     cursor: pointer; | ||||
| } | ||||
|  | ||||
| .icon{ | ||||
| @@ -170,24 +171,49 @@ pre { | ||||
|     text-decoration: none; | ||||
| } | ||||
|  | ||||
| li span.icon { | ||||
| #log_entries li span.icon { | ||||
|     background-size: 32px; | ||||
|     padding-left: 42px; | ||||
|     padding-top: 2px; | ||||
|     padding-bottom: 2px; | ||||
| } | ||||
|  | ||||
| .tags .tag { | ||||
|     display: inline; | ||||
|     background-size: 32px; | ||||
|     padding-top: 4px; | ||||
|     padding-bottom: 4px; | ||||
|     padding-right: 1em; | ||||
|     line-height: 200%; | ||||
|     cursor: pointer; | ||||
|     white-space: nowrap; | ||||
| } | ||||
|  | ||||
| select { | ||||
|    -webkit-appearance: none; | ||||
|    -moz-appearance: none; | ||||
|    appearance: none; | ||||
|    background: none; | ||||
|    border: none; | ||||
|    box-sizing: border-box; | ||||
|  | ||||
| } | ||||
|  | ||||
| .icon.tag { background-image: url("../img/iconmonstr-tag-2-icon.svg"); } | ||||
|  | ||||
| .icon.critical { background-image: url("../img/iconmonstr-error-4-icon.svg"); } | ||||
| .icon.error { background-image: url("../img/iconmonstr-error-4-icon.svg"); } | ||||
| .icon.warning { background-image: url("../img/iconmonstr-warning-6-icon.svg"); } | ||||
| .icon.info { background-image: url("../img/iconmonstr-info-6-icon.svg"); } | ||||
|  | ||||
|  | ||||
| .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"); } | ||||
| .icon.search { background-image: url("../img/iconmonstr-magnifier-4-icon.svg"); } | ||||
|  | ||||
| .icon.phone { background-image: url("../img/iconmonstr-mobile-phone-6-icon.svg"); } | ||||
| .icon.location { background-image: url("../img/iconmonstr-compass-7-icon.svg"); } | ||||
| .icon.room { background-image: url("../img/iconmonstr-home-4-icon.svg"); } | ||||
|  | ||||
| /* Make sure this is the last one */ | ||||
| .icon.busy{background-image:url("https://software.opensuse.org/assets/ajax-loader-ea46060b6c9f42822a3d58d075c83ea2.gif");} | ||||
|   | ||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 38 KiB | 
							
								
								
									
										19
									
								
								certidude/static/img/iconmonstr-compass-7-icon.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								certidude/static/img/iconmonstr-compass-7-icon.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| <?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="compass-7-icon" d="M256,90c91.74,0,166,74.243,166,166c0,91.741-74.245,166-166,166c-91.741,0-166-74.245-166-166 | ||||
| 	C90,164.259,164.244,90,256,90 M256,50C142.229,50,50,142.229,50,256s92.229,206,206,206s206-92.229,206-206S369.771,50,256,50z | ||||
| 	 M197.686,216.466l-28.355-47.135l47.225,28.408C209.145,202.733,202.736,209.099,197.686,216.466z M296.709,198.612 | ||||
| 	c6.459,4.562,12.119,10.179,16.729,16.602l29.232-45.883L296.709,198.612z M198.312,297.179l-28.982,45.492l45.416-28.936 | ||||
| 	C208.398,309.163,202.838,303.563,198.312,297.179z M296.018,314.604l46.652,28.066l-28.117-46.74 | ||||
| 	C309.596,303.253,303.299,309.593,296.018,314.604z M400.199,256.001l-99.238,21.998c-4.369,8.913-11.312,16.328-19.859,21.295 | ||||
| 	L256,400.2l-25.104-100.908c-8.545-4.965-15.488-12.381-19.857-21.293l-99.238-21.998l99.238-21.999 | ||||
| 	c4.369-8.913,11.312-16.328,19.857-21.294L256,111.8l25.104,100.908c8.545,4.966,15.488,12.381,19.857,21.294L400.199,256.001z | ||||
| 	 M278.406,256c0-12.374-10.031-22.407-22.406-22.407S233.592,243.626,233.592,256c0,12.376,10.033,22.408,22.408,22.408 | ||||
| 	S278.406,268.376,278.406,256z"/> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.7 KiB | 
							
								
								
									
										19
									
								
								certidude/static/img/iconmonstr-home-4-icon.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								certidude/static/img/iconmonstr-home-4-icon.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| <?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="home-4-icon" d="M419.492,275.815v166.213H300.725v-90.33h-89.451v90.33H92.507V275.815H50L256,69.972l206,205.844H419.492 | ||||
|  | ||||
| 	z M394.072,88.472h-47.917v38.311l47.917,48.023V88.472z"/> | ||||
|  | ||||
| </svg> | ||||
|  | ||||
| After Width: | Height: | Size: 836 B | 
							
								
								
									
										17
									
								
								certidude/static/img/iconmonstr-mobile-phone-6-icon.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								certidude/static/img/iconmonstr-mobile-phone-6-icon.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| <?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="mobile-phone-6-icon" d="M139.59,131.775c-13.807,0-25,11.197-25,25.01V436.99c0,13.812,11.193,25.01,25,25.01h150.49 | ||||
| 	c13.807,0,25-11.198,25-25.01V156.766c0-13.802-11.186-24.99-24.98-24.99H139.59z M179.832,416.514h-30.996v-24.51h30.996V416.514z | ||||
| 	 M179.832,372.203h-30.996v-24.51h30.996V372.203z M230.334,416.514h-30.996v-24.51h30.996V416.514z M230.334,372.203h-30.996 | ||||
| 	v-24.51h30.996V372.203z M280.836,416.514H249.84v-24.51h30.996V416.514z M280.836,372.203H249.84v-24.51h30.996V372.203z | ||||
| 	 M280.836,312.887h-132V183.226h132V312.887z M283.451,111.408c13.445-0.01,26.9,5.113,37.164,15.369s15.4,23.699,15.41,37.147 | ||||
| 	h22.121c-0.012-19.113-7.312-38.231-21.898-52.805c-14.588-14.573-33.691-21.854-52.797-21.842V111.408z M283.451,72.682 | ||||
| 	c23.354-0.015,46.691,8.882,64.52,26.696c17.828,17.812,26.75,41.187,26.766,64.547h22.674c-0.02-29.166-11.16-58.358-33.418-80.597 | ||||
| 	C341.734,61.089,312.605,49.982,283.451,50V72.682z"/> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.5 KiB | 
							
								
								
									
										25
									
								
								certidude/static/img/iconmonstr-tag-2-icon.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								certidude/static/img/iconmonstr-tag-2-icon.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| <?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="tag-2-icon" d="M234.508,50L50.068,50.262l-0.004,184.311L277.365,462l184.57-184.57L234.508,50z M114.877,167.365 | ||||
|  | ||||
| 	c-15.027-15.027-15.027-39.395,0-54.424c15.029-15.029,39.396-15.029,54.426,0s15.029,39.396,0,54.424 | ||||
|  | ||||
| 	C154.273,182.395,129.906,182.395,114.877,167.365z M242.316,327.94l-76.225-76.226l17.678-17.678l76.225,76.226L242.316,327.94z | ||||
|  | ||||
| 	 M317.609,335.887L199.764,218.041l17.678-17.678l117.846,117.846L317.609,335.887z M351.818,301.678L233.973,183.832l17.678-17.678 | ||||
|  | ||||
| 	L369.496,284L351.818,301.678z"/> | ||||
|  | ||||
| </svg> | ||||
|  | ||||
| After Width: | Height: | Size: 1.1 KiB | 
| @@ -11,14 +11,14 @@ | ||||
|     <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon"> | ||||
| </head> | ||||
| <body> | ||||
|     <div id="menu"> | ||||
|     <nav id="menu"> | ||||
|         <ul class="container"> | ||||
|           <li>Requests</li> | ||||
|           <li>Signed</li> | ||||
|           <li>Revoked</li> | ||||
|           <li>Log</li> | ||||
|           <li data-section="requests">Requests</li> | ||||
|           <li data-section="signed">Signed</li> | ||||
|           <li data-section="revoked">Revoked</li> | ||||
|           <li data-section="log">Log</li> | ||||
|         </ul> | ||||
|     </div> | ||||
|     </nav> | ||||
|     <div id="container" class="container"> | ||||
|         Loading certificate authority... | ||||
|     </div> | ||||
|   | ||||
| @@ -1,3 +1,159 @@ | ||||
|  | ||||
| function onTagClicked() { | ||||
|     var value = $(this).html(); | ||||
|     var updated = prompt("Enter new tag or clear to remove the tag", value); | ||||
|     if (updated == "") { | ||||
|         $(this).addClass("busy"); | ||||
|         $.ajax({ | ||||
|             method: "DELETE", | ||||
|             url: "/api/tag/" + $(this).attr("data-id") | ||||
|         }); | ||||
|  | ||||
|     } else if (updated && updated != value) { | ||||
|         $.ajax({ | ||||
|             method: "PUT", | ||||
|             url: "/api/tag/" + $(this).attr("data-id"), | ||||
|             dataType: "json", | ||||
|             data: { | ||||
|                 value: updated | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| function onNewTagClicked() { | ||||
|     var cn = $(event.target).attr("data-cn"); | ||||
|     var key = $(event.target).val(); | ||||
|     $(event.target).val(""); | ||||
|     var value = prompt("Enter new " + key + " tag for " + cn); | ||||
|     if (!value) return; | ||||
|     if (value.length == 0) return; | ||||
|     $.ajax({ | ||||
|         method: "POST", | ||||
|         url: "/api/tag/", | ||||
|         dataType: "json", | ||||
|         data: { | ||||
|             cn: cn, | ||||
|             value: value, | ||||
|             key: key | ||||
|         } | ||||
|     }); | ||||
| } | ||||
|  | ||||
| function onLogEntry (e) { | ||||
|     var entry = JSON.parse(e.data); | ||||
|     if ($("#log_level_" + entry.severity).prop("checked")) { | ||||
|         console.info("Received log entry:", entry); | ||||
|         $("#log_entries").prepend(nunjucks.render("logentry.html", { | ||||
|             entry: { | ||||
|                 created: new Date(entry.created).toLocaleString(), | ||||
|                 message: entry.message, | ||||
|                 severity: entry.severity | ||||
|             } | ||||
|         })); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| function onRequestSubmitted(e) { | ||||
|     console.log("Request submitted:", e.data); | ||||
|     $.ajax({ | ||||
|         method: "GET", | ||||
|         url: "/api/request/" + e.data + "/", | ||||
|         dataType: "json", | ||||
|         success: function(request, status, xhr) { | ||||
|             console.info(request); | ||||
|             $("#pending_requests").prepend( | ||||
|                 nunjucks.render('request.html', { request: request })); | ||||
|         } | ||||
|     }); | ||||
| } | ||||
|  | ||||
| function onRequestDeleted(e) { | ||||
|     console.log("Removing deleted request #" + e.data); | ||||
|     $("#request_" + e.data).remove(); | ||||
| } | ||||
|  | ||||
| function onClientUp(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 | ||||
|         }})); | ||||
| } | ||||
|  | ||||
| function onClientDown(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() | ||||
|         }})); | ||||
| } | ||||
|  | ||||
| function onRequestSigned(e) { | ||||
|     console.log("Request signed:", e.data); | ||||
|     $("#request_" + e.data).slideUp("normal", function() { $(this).remove(); }); | ||||
|  | ||||
|     $.ajax({ | ||||
|         method: "GET", | ||||
|         url: "/api/signed/" + e.data + "/", | ||||
|         dataType: "json", | ||||
|         success: function(certificate, status, xhr) { | ||||
|             console.info(certificate); | ||||
|             $("#signed_certificates").prepend( | ||||
|                 nunjucks.render('signed.html', { certificate: certificate })); | ||||
|         } | ||||
|     }); | ||||
| } | ||||
|  | ||||
| function onCertificateRevoked(e) { | ||||
|     console.log("Removing revoked certificate #" + e.data); | ||||
|     $("#certificate_" + e.data).slideUp("normal", function() { $(this).remove(); }); | ||||
| } | ||||
|  | ||||
| function onTagAdded(e) { | ||||
|     console.log("Tag added #" + e.data); | ||||
|     $.ajax({ | ||||
|         method: "GET", | ||||
|         url: "/api/tag/" + e.data + "/", | ||||
|         dataType: "json", | ||||
|         success: function(tag, status, xhr) { | ||||
|             // TODO: Deduplicate | ||||
|             $tag = $("<span id=\"tag_" + tag.id + "\" class=\"" + tag.key + " icon tag\" data-id=\""+tag.id+"\">" + tag.value + "</span>"); | ||||
|             $tags = $("#signed_certificates [data-cn='" + tag.cn + "'] .tags").prepend(" "); | ||||
|             $tags = $("#signed_certificates [data-cn='" + tag.cn + "'] .tags").prepend($tag); | ||||
|             $tag.click(onTagClicked); | ||||
|         } | ||||
|     }) | ||||
| } | ||||
|  | ||||
| function onTagRemoved(e) { | ||||
|     console.log("Tag removed #" + e.data); | ||||
|     $("#tag_" + e.data).remove(); | ||||
| } | ||||
|  | ||||
| function onTagUpdated(e) { | ||||
|     console.log("Tag updated #" + e.data); | ||||
|     $.ajax({ | ||||
|         method: "GET", | ||||
|         url: "/api/tag/" + e.data + "/", | ||||
|         dataType: "json", | ||||
|         success:function(tag, status, xhr) { | ||||
|             console.info("Updated tag", tag); | ||||
|             $("#tag_" + tag.id).html(tag.value); | ||||
|         } | ||||
|     }) | ||||
| } | ||||
|  | ||||
| $(document).ready(function() { | ||||
|     console.info("Loading CA, to debug: curl " + window.location.href + " --negotiate -u : -H 'Accept: application/json'"); | ||||
|     $.ajax({ | ||||
| @@ -13,8 +169,6 @@ $(document).ready(function() { | ||||
|             $("#container").html(nunjucks.render('error.html', { message: msg })); | ||||
|         }, | ||||
|         success: function(session, status, xhr) { | ||||
|             console.info("Got:", session); | ||||
|  | ||||
|             console.info("Opening EventSource from:", session.event_channel); | ||||
|  | ||||
|             var source = new EventSource(session.event_channel); | ||||
| @@ -23,90 +177,33 @@ $(document).ready(function() { | ||||
|                 console.log("Received server-sent event:", event); | ||||
|             } | ||||
|  | ||||
|             source.addEventListener("log-entry", function(e) { | ||||
|                 var entry = JSON.parse(e.data); | ||||
|                 console.info("Received log entry:", entry, "gonna prepend:", $("#log_level_" + entry.severity).prop("checked")); | ||||
|                 if ($("#log_level_" + entry.severity).prop("checked")) { | ||||
|                     $("#log_entries").prepend(nunjucks.render("logentry.html", { | ||||
|                         entry: { | ||||
|                             created: new Date(entry.created).toLocaleString(), | ||||
|                             message: entry.message, | ||||
|                             severity: entry.severity | ||||
|                         } | ||||
|                     })); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|             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) { | ||||
|                 console.log("Removing deleted request #" + e.data); | ||||
|                 $("#request_" + e.data).remove(); | ||||
|             }); | ||||
|  | ||||
|             source.addEventListener("request_submitted", function(e) { | ||||
|                 console.log("Request submitted:", e.data); | ||||
|                 $.ajax({ | ||||
|                     method: "GET", | ||||
|                     url: "/api/request/" + e.data + "/", | ||||
|                     dataType: "json", | ||||
|                     success: function(request, status, xhr) { | ||||
|                         console.info(request); | ||||
|                         $("#pending_requests").prepend( | ||||
|                             nunjucks.render('request.html', { request: request })); | ||||
|                     } | ||||
|                 }); | ||||
|  | ||||
|             }); | ||||
|  | ||||
|             source.addEventListener("request_signed", function(e) { | ||||
|                 console.log("Request signed:", e.data); | ||||
|                 $("#request_" + e.data).slideUp("normal", function() { $(this).remove(); }); | ||||
|  | ||||
|                 $.ajax({ | ||||
|                     method: "GET", | ||||
|                     url: "/api/signed/" + e.data + "/", | ||||
|                     dataType: "json", | ||||
|                     success: function(certificate, status, xhr) { | ||||
|                         console.info(certificate); | ||||
|                         $("#signed_certificates").prepend( | ||||
|                             nunjucks.render('signed.html', { certificate: certificate })); | ||||
|                     } | ||||
|                 }); | ||||
|             }); | ||||
|  | ||||
|             source.addEventListener("certificate_revoked", function(e) { | ||||
|                 console.log("Removing revoked certificate #" + e.data); | ||||
|                 $("#certificate_" + e.data).slideUp("normal", function() { $(this).remove(); }); | ||||
|             }); | ||||
|             source.addEventListener("log-entry", onLogEntry); | ||||
|             source.addEventListener("up-client", onClientUp); | ||||
|             source.addEventListener("down-client", onClientDown); | ||||
|             source.addEventListener("request-deleted", onRequestDeleted); | ||||
|             source.addEventListener("request-submitted", onRequestSubmitted); | ||||
|             source.addEventListener("request-signed", onRequestSigned); | ||||
|             source.addEventListener("certificate-revoked", onCertificateRevoked); | ||||
|             source.addEventListener("tag-added", onTagAdded); | ||||
|             source.addEventListener("tag-removed", onTagRemoved); | ||||
|             source.addEventListener("tag-updated", onTagUpdated); | ||||
|  | ||||
|             /** | ||||
|              * Render authority views | ||||
|              **/ | ||||
|             $("#container").html(nunjucks.render('authority.html', { session: session, window: window })); | ||||
|             console.info("Swtiching to requests section"); | ||||
|             $("section").hide(); | ||||
|             $("section#requests").show(); | ||||
|  | ||||
|             $("nav#menu li").click(function(e) { | ||||
|                 $("section").hide(); | ||||
|                 $("section#" + $(e.target).attr("data-section")).show(); | ||||
|             }); | ||||
|  | ||||
|             /** | ||||
|              * Fetch log entries | ||||
|              */ | ||||
|             $.ajax({ | ||||
|                 method: "GET", | ||||
|                 url: "/api/log/", | ||||
| @@ -127,6 +224,52 @@ $(document).ready(function() { | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|             /** | ||||
|              * Set up search bar | ||||
|               */ | ||||
|             $(window).on("search", function() { | ||||
|                 var q = $("#search").val(); | ||||
|                 $(".filterable").each(function(i, e) { | ||||
|                     if ($(e).attr("data-dn").toLowerCase().indexOf(q) >= 0) { | ||||
|                         $(e).show(); | ||||
|                     } else { | ||||
|                         $(e).hide(); | ||||
|                     } | ||||
|                 }); | ||||
|             }); | ||||
|  | ||||
|             /** | ||||
|              * Bind key up event of search bar | ||||
|              */ | ||||
|             $("#search").on("keyup", function() { | ||||
|                 if (window.searchTimeout) { clearTimeout(window.searchTimeout); } | ||||
|                 window.searchTimeout = setTimeout(function() { $(window).trigger("search"); }, 500); | ||||
|                 console.info("Setting timeout", window.searchTimeout); | ||||
|  | ||||
|             }); | ||||
|  | ||||
|             /** | ||||
|              * Fetch tags for certificates | ||||
|              */ | ||||
|             $.ajax({ | ||||
|                 method: "GET", | ||||
|                 url: "/api/tag/", | ||||
|                 dataType: "json", | ||||
|                 success:function(tags, status, xhr) { | ||||
|                     console.info("Got", tags.length, "tags"); | ||||
|                     for (var j = 0; j < tags.length; j++) { | ||||
|                         // TODO: Deduplicate | ||||
|                         $tag = $("<span id=\"tag_" + tags[j].id + "\" class=\"" + tags[j].key + " icon tag\" data-id=\""+tags[j].id+"\">" + tags[j].value + "</span>"); | ||||
|                         $tags = $("#signed_certificates [data-cn='" + tags[j].cn + "'] .tags").prepend(" "); | ||||
|                         $tags = $("#signed_certificates [data-cn='" + tags[j].cn + "'] .tags").prepend($tag); | ||||
|                         $tag.click(onTagClicked); | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|             /** | ||||
|              * Fetch leases associated with certificates | ||||
|              */ | ||||
|             $.ajax({ | ||||
|                 method: "GET", | ||||
|                 url: "/api/lease/", | ||||
| @@ -148,17 +291,6 @@ $(document).ready(function() { | ||||
|                             }})); | ||||
|                     } | ||||
|  | ||||
|                     /* Set up search box */ | ||||
|                     $("#search").on("keyup", function() { | ||||
|                         var q = $("#search").val().toLowerCase(); | ||||
|                         $(".filterable").each(function(i, e) { | ||||
|                             if ($(e).attr("data-dn").toLowerCase().indexOf(q) >= 0) { | ||||
|                                 $(e).show(); | ||||
|                             } else { | ||||
|                                 $(e).hide(); | ||||
|                             } | ||||
|                         }); | ||||
|                     }); | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| <li id="certificate_{{ certificate.sha256sum }}" data-dn="{{ certificate.identity }}" class="filterable"> | ||||
| <li id="certificate_{{ certificate.sha256sum }}" data-dn="{{ certificate.identity }}" data-cn="{{ certificate.common_name }}" class="filterable"> | ||||
|     <a class="button icon download" href="/api/signed/{{certificate.common_name}}/">Fetch</a> | ||||
|     <button class="icon revoke" onClick="javascript:$(this).addClass('busy');$.ajax({url:'/api/signed/{{certificate.common_name}}/',type:'delete'});">Revoke</button> | ||||
|  | ||||
| @@ -25,6 +25,15 @@ | ||||
|     {{certificate.key_usage}} | ||||
|     </div> | ||||
|  | ||||
|     <div class="tags"> | ||||
|       <select class="icon tag" data-cn="{{ certificate.common_name }}" onChange="onNewTagClicked();"> | ||||
|         <option value="">Add tag...</option> | ||||
|         <option value="location">Location</option> | ||||
|         <option value="phone">Phone</option> | ||||
|         <option value="room">Room</option> | ||||
|       </select> | ||||
|     </div> | ||||
|  | ||||
|     <div class="status"> | ||||
|     {% include 'status.html' %} | ||||
|     </div> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user