aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Crute <mike@crute.us>2021-11-22 07:54:18 -0800
committerMike Crute <mike@crute.us>2021-11-22 07:54:42 -0800
commit114dbb5ab7952ab66a041c814d5c6a028c8e3039 (patch)
treeaecdeeb2e79b233775eb893c2abc0277cfd707fb
parent20484058825f0137a89712f41ae8c50dcc7e697d (diff)
downloadcloud-identity-broker-114dbb5ab7952ab66a041c814d5c6a028c8e3039.tar.bz2
cloud-identity-broker-114dbb5ab7952ab66a041c814d5c6a028c8e3039.tar.xz
cloud-identity-broker-114dbb5ab7952ab66a041c814d5c6a028c8e3039.zip
Split assets from templates
-rw-r--r--cmd/web/server.go1
-rw-r--r--templates/assets/site.css62
-rw-r--r--templates/assets/site.js102
-rw-r--r--templates/index.tpl171
4 files changed, 168 insertions, 168 deletions
diff --git a/cmd/web/server.go b/cmd/web/server.go
index d2ea861..3797acd 100644
--- a/cmd/web/server.go
+++ b/cmd/web/server.go
@@ -154,6 +154,7 @@ func webMain(cfg app.Config, embeddedTemplates fs.FS, version string) {
154 } 154 }
155 s.GET("/favicon.ico", echo.NotFoundHandler) 155 s.GET("/favicon.ico", echo.NotFoundHandler)
156 s.GET("/logout", controllers.LogoutHandler) 156 s.GET("/logout", controllers.LogoutHandler)
157 s.CachedStaticRoute("/assets", "assets")
157 s.GET("/", controllers.IndexHandler, am.Middleware) 158 s.GET("/", controllers.IndexHandler, am.Middleware)
158 159
159 runner := service.NewAppRunner(ctx, s.Logger) 160 runner := service.NewAppRunner(ctx, s.Logger)
diff --git a/templates/assets/site.css b/templates/assets/site.css
new file mode 100644
index 0000000..65fb4ce
--- /dev/null
+++ b/templates/assets/site.css
@@ -0,0 +1,62 @@
1html {
2 display: grid;
3 grid-template-columns: [left] 10% [main] auto [right] 10%;
4 grid-template-rows: [main] auto;
5}
6body {
7 grid-column: main;
8 grid-row: main;
9}
10table {
11 width: 100%;
12 border: 1px solid black;
13 border-collapse: collapse;
14}
15td, th {
16 border: 1px solid black;
17 padding: 0.5em;
18}
19th {
20 background-color: #CCCCCC;
21}
22textarea {
23 height: 10em;
24 width: 100%;
25 resize: none;
26}
27a, a:visited {
28 color: blue;
29}
30h1 {
31 text-align: center;
32}
33tt {
34 background-color: #CCC;
35 border: 1px solid #999;
36 padding: 0.25em;
37}
38#api-key {
39 margin: auto;
40}
41#api-key textarea {
42 height: 100%;
43}
44#api-error {
45 border: 0.25em solid red;
46 color: white;
47 font-size: 2em;
48 background-color: #ff8080;
49 padding: 1em;
50 text-align: center;
51 display: none;
52}
53#account-table tr td:nth-child(2),
54#account-table tr td:nth-child(3) {
55 text-align: center;
56}
57.admin {
58 display: none;
59}
60body.isAdmin .admin {
61 display: initial;
62}
diff --git a/templates/assets/site.js b/templates/assets/site.js
new file mode 100644
index 0000000..485a4cd
--- /dev/null
+++ b/templates/assets/site.js
@@ -0,0 +1,102 @@
1function fillTemplate(templateId, values) {
2 var tpl = document.getElementById(templateId).text;
3
4 Object.keys(values).forEach(function(key) {
5 tpl = tpl.replace(new RegExp("\\[\\[ \\." + key + " \\]\\]", "g"), values[key]);
6 });
7
8 var out = [];
9 tpl.split("\n").forEach(function(line) {
10 line = line.replace(/^\s+/, "").replace(/\s+$/, "");
11 if (line !== "") {
12 out.push(line);
13 }
14 });
15
16 return out.join("\n");
17}
18
19function getJSON(response) {
20 if (!response.ok) {
21 document.getElementById("api-error").style.display = "block";
22 throw new Error("Error loading api");
23 }
24
25 return response.json();
26}
27
28function accountTableLinkClick(event) {
29 event.preventDefault();
30
31 var thisRow = event.target.parentElement.parentElement;
32 var template = event.target.getAttribute("data-template");
33 var account = thisRow.getAttribute("data-account-name");
34 var credentialEndpoint = thisRow.getAttribute("data-global-credential-endpoint");
35 var oldText = event.target.text;
36
37 var existingTr = document.getElementById("credentials-for-" + account);
38 if (existingTr) {
39 existingTr.remove();
40 }
41
42 event.target.text = "Loading...";
43
44 fetch(credentialEndpoint).then(getJSON).then(function(vals) {
45 vals["ShortName"] = account;
46
47 var newTr = fillTemplate("credential_row_template", {
48 "Account": account,
49 "Content": fillTemplate(template, vals)
50 });
51
52 event.target.text = oldText;
53 thisRow.insertAdjacentHTML("afterend", newTr);
54 thisRow.nextElementSibling.getElementsByTagName("button")[0].addEventListener("click", function(event) {
55 event.target.parentNode.parentNode.remove();
56 });
57 });
58
59 return false;
60}
61
62function populateAccountTable() {
63 fetch("/api/account").then(getJSON).then(function(response) {
64 response.forEach(populateAccountRow);
65 });
66}
67
68function populateAccountRow(row) {
69 var out = fillTemplate("account_row_template", row);
70 document.querySelector("#account-table tr").insertAdjacentHTML("afterend", out);
71
72 document.querySelectorAll("#account-row-" + row["short_name"] + " a[data-template]").forEach(function(element) {
73 element.addEventListener("click", accountTableLinkClick);
74 });
75}
76
77function getCookie(name) {
78 return document.cookie.match(new RegExp(name + "=\"?([^;\"]*)\"?;?"))[1];
79}
80
81function parseJWT(token) {
82 return JSON.parse(atob(token.split(".")[1]));
83}
84
85function parseJWTExpires(token) {
86 return new Date(parseJWT(token)["exp"] * 1000);
87}
88
89function isAdmin(token) {
90 return parseJWT(token)["admin"];
91}
92
93function populateAPIKey() {
94 document.querySelector("#api-key textarea").innerText = getCookie("github-token");
95 document.querySelector("#session-expires").innerText = parseJWTExpires(getCookie("github-token"));
96}
97
98function setAdminClass() {
99 if (isAdmin(getCookie("github-token"))) {
100 document.body.classList.add("isAdmin");
101 }
102}
diff --git a/templates/index.tpl b/templates/index.tpl
index 3a6acbf..da0b59e 100644
--- a/templates/index.tpl
+++ b/templates/index.tpl
@@ -3,70 +3,7 @@
3 <head> 3 <head>
4 <title>Select Account</title> 4 <title>Select Account</title>
5 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6 <style type="text/css"> 6 <link rel="stylesheet" type="text/css" href="/assets/site.css" />
7 html {
8 display: grid;
9 grid-template-columns: [left] 10% [main] auto [right] 10%;
10 grid-template-rows: [main] auto;
11 }
12 body {
13 grid-column: main;
14 grid-row: main;
15 }
16 table {
17 width: 100%;
18 border: 1px solid black;
19 border-collapse: collapse;
20 }
21 td, th {
22 border: 1px solid black;
23 padding: 0.5em;
24 }
25 th {
26 background-color: #CCCCCC;
27 }
28 textarea {
29 height: 10em;
30 width: 100%;
31 resize: none;
32 }
33 a, a:visited {
34 color: blue;
35 }
36 h1 {
37 text-align: center;
38 }
39 tt {
40 background-color: #CCC;
41 border: 1px solid #999;
42 padding: 0.25em;
43 }
44 #api-key {
45 margin: auto;
46 }
47 #api-key textarea {
48 height: 100%;
49 }
50 #api-error {
51 border: 0.25em solid red;
52 color: white;
53 font-size: 2em;
54 background-color: #ff8080;
55 padding: 1em;
56 text-align: center;
57 display: none;
58 }
59 #account-table tr td:nth-child(2),
60 #account-table tr td:nth-child(3) {
61 text-align: center;
62 }
63 .admin {
64 display: none;
65 }
66 body.isAdmin .admin {
67 display: initial;
68 }
69 </style>
70 <script id="shell_template" type="text/template"> 7 <script id="shell_template" type="text/template">
71 export AWS_CREDS_EXPIRATION="[[ .expiration ]]" 8 export AWS_CREDS_EXPIRATION="[[ .expiration ]]"
72 export AWS_ACCESS_KEY_ID="[[ .access_key ]]" 9 export AWS_ACCESS_KEY_ID="[[ .access_key ]]"
@@ -87,14 +24,12 @@
87 expiration=[[ .expiration ]] 24 expiration=[[ .expiration ]]
88 </script> 25 </script>
89 <script id="credential_row_template" type="text/template"> 26 <script id="credential_row_template" type="text/template">
90 <body>
91 <tr id="credentials-for-[[ .Account ]]"> 27 <tr id="credentials-for-[[ .Account ]]">
92 <td colspan="3"> 28 <td colspan="3">
93 <textarea>[[ .Content ]]</textarea> 29 <textarea>[[ .Content ]]</textarea>
94 <button>Close</button> 30 <button>Close</button>
95 </td> 31 </td>
96 </tr> 32 </tr>
97 </body>
98 </script> 33 </script>
99 <script id="account_row_template" type="text/template"> 34 <script id="account_row_template" type="text/template">
100 <tr id="account-row-[[ .short_name ]]" data-account-name="[[ .short_name ]]" data-global-credential-endpoint="[[ .global_credential_url ]]"> 35 <tr id="account-row-[[ .short_name ]]" data-account-name="[[ .short_name ]]" data-global-credential-endpoint="[[ .global_credential_url ]]">
@@ -109,111 +44,11 @@
109 </td> 44 </td>
110 </tr> 45 </tr>
111 </script> 46 </script>
47 <script type="text/javascript" src="/assets/site.js"></script>
112 <script type="text/javascript"> 48 <script type="text/javascript">
113 function fillTemplate(templateId, values) {
114 var tpl = document.getElementById(templateId).text;
115
116 Object.keys(values).forEach(function(key) {
117 tpl = tpl.replace(new RegExp("\\[\\[ \\." + key + " \\]\\]", "g"), values[key]);
118 });
119
120 var out = [];
121 tpl.split("\n").forEach(function(line) {
122 line = line.replace(/^\s+/, "").replace(/\s+$/, "");
123 if (line !== "") {
124 out.push(line);
125 }
126 });
127
128 return out.join("\n");
129 }
130
131 function getJSON(response) {
132 if (!response.ok) {
133 document.getElementById("api-error").style.display = "block";
134 throw new Error("Error loading api");
135 }
136
137 return response.json();
138 }
139
140 function accountTableLinkClick(event) {
141 event.preventDefault();
142
143 var thisRow = event.target.parentElement.parentElement;
144 var template = event.target.getAttribute("data-template");
145 var account = thisRow.getAttribute("data-account-name");
146 var credentialEndpoint = thisRow.getAttribute("data-global-credential-endpoint");
147 var oldText = event.target.text;
148
149 var existingTr = document.getElementById("credentials-for-" + account);
150 if (existingTr) {
151 existingTr.remove();
152 }
153
154 event.target.text = "Loading...";
155
156 fetch(credentialEndpoint).then(getJSON).then(function(vals) {
157 vals["ShortName"] = account;
158
159 var newTr = fillTemplate("credential_row_template", {
160 "Account": account,
161 "Content": fillTemplate(template, vals)
162 });
163
164 event.target.text = oldText;
165 thisRow.insertAdjacentHTML("afterend", newTr);
166 thisRow.nextElementSibling.getElementsByTagName("button")[0].addEventListener("click", function(event) {
167 event.target.parentNode.parentNode.remove();
168 });
169 });
170
171 return false;
172 }
173
174 function populateAccountTable() {
175 fetch("/api/account").then(getJSON).then(function(response) {
176 response.forEach(populateAccountRow);
177 });
178 }
179
180 function populateAccountRow(row) {
181 var out = fillTemplate("account_row_template", row);
182 document.querySelector("#account-table tr").insertAdjacentHTML("afterend", out);
183
184 document.querySelectorAll("#account-row-" + row["short_name"] + " a[data-template]").forEach(function(element) {
185 element.addEventListener("click", accountTableLinkClick);
186 });
187 }
188
189 function getCookie(name) {
190 return document.cookie.match(new RegExp(name + "=\"?([^;\"]*)\"?;?"))[1];
191 }
192
193 function parseJWT(token) {
194 return JSON.parse(atob(token.split(".")[1]));
195 }
196
197 function parseJWTExpires(token) {
198 return new Date(parseJWT(token)["exp"] * 1000);
199 }
200
201 function isAdmin(token) {
202 return parseJWT(token)["admin"];
203 }
204
205 function populateAPIKey() {
206 document.querySelector("#api-key textarea").innerText = getCookie("github-token");
207 document.querySelector("#session-expires").innerText = parseJWTExpires(getCookie("github-token"));
208 }
209
210 window.addEventListener('load', populateAPIKey); 49 window.addEventListener('load', populateAPIKey);
211 window.addEventListener('load', populateAccountTable); 50 window.addEventListener('load', populateAccountTable);
212 window.addEventListener('load', function() { 51 window.addEventListener('load', setAdminClass);
213 if (isAdmin(getCookie("github-token"))) {
214 document.body.classList.add("isAdmin");
215 }
216 });
217 </script> 52 </script>
218 </head> 53 </head>
219 <body> 54 <body>