-
Notifications
You must be signed in to change notification settings - Fork 14
/
index.html
438 lines (415 loc) · 28.4 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
<!--
*****************************************************************
*****************************************************************
**
**
** Hi!
**
** This is a tool, not an example.
** DO NOT copy this code into your application.
** DO NOT send your embed secret to users' browsers.
**
** Really.
**
** Don't.
**
** (For your own good)
**
** If you need something to copy, we have that too:
** https://github.com/looker/looker_embed_sso_examples
**
*****************************************************************
*****************************************************************
-->
<html>
<head>
<title>Signed Embed Constructor</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsSHA/2.2.0/sha1.js" async="true" integrity="sha256-+wcjkt38O0q7BEzMX2Ivt0V9AGhx2jhuMtcdp5zHnGM=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/json-editor/0.7.28/jsoneditor.min.js" integrity="sha256-51+oMmpgSgS4jV5/DcGKnDHIOL6Jeie2i7ka6sPQVro=" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha256-eZrrJcwDc/3uDhsdt61sL2oOBY362qM3lon1gyExkL0=" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.3/css/foundation.min.css" integrity="sha256-NTds7atVCDeolLUzbcl45lx4gJYO+hNXCaX1wC2HQHc=" crossorigin="anonymous" />
<script src="https://cdn.jsdelivr.net/gh/Nanonid/rison@e64af6c096fd30950ec32cfd48526ca6ee21649d/js/rison.js" integrity="sha256-4Zg2e0UX/I8JAIl4CQgnB/A15bw2jxjLCu/mjQRGoRI=" crossorigin="anonymous"></script>
<style>
textarea{font-size:10pt !important;}
#json-editor input+p{display:none}
#json-editor input:focus+p{display:block}
#json-editor textarea+p{display:none}
#json-editor textarea:focus+p{display:block}
#json-editor select+p{display:none}
#json-editor select:focus+p{display:block}
#json-editor select+p{display:none}
#json-editor select:focus+p{display:block}
</style>
<script>
// Set the JSONEditor CSS theme and icon library globally
JSONEditor.defaults.theme = 'foundation5';
JSONEditor.defaults.iconlib = 'fontawesome4';
</script>
</head>
<body>
<div id="msg" style="position:fixed;top:0px;display:none;width:100%;z-index:2;text-align:center;white-space:pre-line;color:#666;background-color:#EEC;font-size:12pt;"></div>
<div id="panel-toggle" style="height:2em;width:2em;position:fixed;left:-1px;bottom:-1px;z-index:20;text-align:center;background-color:#DDD;color:#333;border:1px solid #666;cursor:pointer;">
<i class="fa fa-eye-slash"></i>
</div>
<div style="display:flex; justify-content: space-around">
<div id="build-panel" style="flex-grow:1;min-width:480px;margin:0 25px">
<form id="build-form">
<div id="json-editor"></div>
<div style="text-align:right">
<div style="display:inline-block;vertical-align:top;">
<div><label for="embed-flag">Preview</label></div>
<div><input id="embed-flag" type="checkbox" checked="checked" /></div>
</div>
<div style="display:inline-block;vertical-align:top;margin: 0 2em;">
<input type="submit" style="margin-left:auto;margin-right:auto;border:solid 1px black" value="Go" class="button" />
</div>
</div>
</form>
</div>
<div style="flex-grow:1;min-width:480px;margin:0 25px">
<h5>Tips</h5>
<ul style="font-size:0.8em; font-family:serif; color:#333;">
<li> This is a static HTML file and can be used locally.
<span style="color:#C33;font-weight:bold;display:none" id="origin-warning">
If you use it from a shared domain (e.g. rawgit.com), other scripts on that domain may have access to data you enter here, including your embed secret :(
You can use the domain <a href="https://fabio-looker.github.io/looker_sso_tool/">fabio-looker.github.io</a> instead.<span></li>
<li> This is for demo/understanding only. You should <i>never</i> make your embed secret available to a user's browser!</li>
<li> Check the [Properties] button for additional parameters you can configure</li>
<li> If you want to use the Embed URI Validator in Looker, embedding here will consume the nonce and cause the URL to be invalid. Uncheck the "Preview" checkbox at the bottom to not embed after building the URL.</li>
<li> Links:
<nobr>[<a href="https://cloud.google.com/looker/docs/signed-embedding">Official Signed Embed docs</a>]</nobr>
<nobr>[<a href="https://github.com/looker/looker_embed_sso_examples">Examples in various server-side languages</a>]</nobr>
<nobr>[<a href="https://github.com/fabio-looker/looker_sso_tool/issues">Report an issue with this page</a>]</nobr>
<nobr>[<a href="signed-embed-troubleshooting.html">Troubleshooting guide (WIP)</a>]</nobr>
</li>
</ul>
<h5>Shareable form state</h5>
<input type="text" style="width:100%;" readonly="readonly" id="share-state" />
<h5>Built Embed URL</h5>
<textarea style="width:100%;height:12em" readonly="readonly" id="url-display"></textarea>
<h5>Embed Preview</h5>
<div style="position:relative;top:0;left:0;width:100%">
<img src="throbber.gif" id="throbber" style="position:absolute;left:-128px;margin-left:50%;top:120px;display:none" /></center>
<iframe id="embed-iframe" style="width:100%;height:560px;box-shadow: 0 0 10px rgba(0, 0, 0, 0.25);" frameBorder="0"></iframe>
</div>
</div>
</div>
</body>
<script>
if (
document.location.protocol !== "file:"
&& document.location.hostname !== "localhost"
&& document.location.hostname !== "127.0.0.1"
&& document.location.origin !== "https://fabio-looker.github.io"
){
$("#origin-warning").show()
}
// The hash sort order is significant. The UI and querystring sort order are just for aesthetics
var definitions=[
{sort:{ui:01,qs:00,hash:00}, id:"embed_secret", schema:{required:true}},
{sort:{ui:02,qs:00,hash:01}, id:"host", noJSON:true, schema:{required:true, description:"For example, 'customer.looker.com'"}},
{sort:{ui:03,qs:00,hash:02}, id:"embed_path", noJSON:true, schema:{required:true, description:"Should start with '/embed/'. Add any querystring parameters for filtering or embed_domain here."},
fn:(path=>"/login/embed/"+encodeURIComponent(path))
},
{sort:{ui:98,qs:11,hash:03}, id:"nonce",schema:{required:false, description:"Any unique value. Once used to embed, cannot be reused for another embed."},fn:(x=>x||nonce(16))},
{sort:{ui:99,qs:12,hash:04}, id:"time",schema:{required:false, description:"Epoch timestamp. The embed URL will contain this time incorporated into the signature. Looker will only accept the URL for 5 minutes after this timestamp (to prevent Signed Embed URLs being stored for later use)"},fn:(x=>parseInt(x)||parseInt(Date.now()/1000))}, //Left it as a string for now because I'm lazy and didn't want to confirm how JSONEditor would treat a blank input...
{sort:{ui:90,qs:13,hash:05}, id:"session_length", schema:{required:true,type:"number",minimum:1, description:"Session length in seconds"}},
{sort:{ui:04,qs:14,hash:06}, id:"external_user_id", schema:{required:true, description:"Any value that acts an identifier for this user. Subsequent Signed Embed requests pertaining to the same external_user_id will update the associated user"}},
{sort:{ui:05,qs:31,hash:00}, id:"first_name", schema:{required:true}},
{sort:{ui:06,qs:32,hash:00}, id:"last_name", schema:{required:true}},
{sort:{ui:07,qs:21,hash:07}, id:"permissions",
schema:{type:"array",required:true,uniqueItems:true,items:{type:"string",enum:[
"access_data",
"see_looks",
"see_user_dashboards",
"see_lookml_dashboards",
"explore",
"create_table_calculations",
"download_with_limit",
"download_without_limit",
"see_drill_overlay",
"save_content",
"embed_browse_spaces",
"schedule_look_emails",
"schedule_external_look_emails",
"send_to_sftp",
"send_to_s3",
"send_outgoing_webhook",
"see_sql", /* v4.10 */
"send_to_integration", /* v6.22 */
"create_alerts", /* v6.22 */
"embed_save_shared_space", /* v21.4 */
"clear_cache_refresh", /* v21.4 */
"create_custom_fields" /* v22.4 */
/* FYI - Signed Embed does not allow all permissions. If you add unsupported permissions, they will fail */
]}}
},
{sort:{ui:08,qs:22,hash:08}, id:"models",schema:{required:true,pattern:"^[-A-Za-z0-9_]+(,\\s*[-A-Za-z0-9_]+)*$"},fn:(s)=>s.split(/,\s*/),description:"The name of one more more models to give the user access to. (Comma-delimit multiple models)"},
{sort:{ui:09,qs:23,hash:09}, id:"group_ids",schema:{required:false,pattern:"^$|^[0-9]+(,\\s*[0-9]+)*$",description:"The ID of one or more existing user group within Looker (Comma-delimit multiple groups). Useful for several use cases; notably for granting access to a Shared space that is maintained by your non-embed users."},fn:(s)=>(s==""?[]:s.split(/,\s*/).map(s=>parseInt(s)))},
{sort:{ui:10,qs:24,hash:10}, id:"external_group_id",schema:{required:false, description: "Users with the same external_group_id will be able to share content with eachother (assuming they have the appropriate permissions). Use a human-readable string for this. For example 'Acme'"},fn:x=>x||""},
{sort:{ui:11,qs:25,hash:11}, id:"user_attributes",schema:{required:false,type:"array",format:"table",items:{type:"object",
description: "See https://discourse.looker.com/t/user-attributes/3979 for more info",
properties:{
field:{type:"string"},
value:{type:"string"}
}}
},
fn:(a=>(a||[]).reduce(objByOf(["field"],"value"),{}))},
{sort:{ui:12,qs:26,hash:12}, id:"access_filters",schema:{type:"array",required:false,format:"table",items:{type:"object",
description:"Stand-alone access filters are deprecated. Use 'user attributes' instead.",
properties:{
model:{type:"string"},
field:{type:"string"},
value:{type:"string"}
}}
},
fn:(a=>(a||[]).reduce(objByOf(["model","field"],"value"),{}))},
{sort:{ui:13,qs:27,hash:00}, id:"user_timezone",schema:{
type:"string",
required:false,
enum:["UTC","America/Los_Angeles","America/Denver","America/Chicago","America/New_York","America/Phoenix","Pacific/Honolulu","America/Juneau","Africa/Abidjan","Africa/Accra","Africa/Addis_Ababa","Africa/Algiers","Africa/Asmara","Africa/Asmera","Africa/Bamako","Africa/Bangui","Africa/Banjul","Africa/Bissau","Africa/Blantyre","Africa/Brazzaville","Africa/Bujumbura","Africa/Cairo","Africa/Casablanca","Africa/Ceuta","Africa/Conakry","Africa/Dakar","Africa/Dar_es_Salaam","Africa/Djibouti","Africa/Douala","Africa/El_Aaiun","Africa/Freetown","Africa/Gaborone","Africa/Harare","Africa/Johannesburg","Africa/Juba","Africa/Kampala","Africa/Khartoum","Africa/Kigali","Africa/Kinshasa","Africa/Lagos","Africa/Libreville","Africa/Lome","Africa/Luanda","Africa/Lubumbashi","Africa/Lusaka","Africa/Malabo","Africa/Maputo","Africa/Maseru","Africa/Mbabane","Africa/Mogadishu","Africa/Monrovia","Africa/Nairobi","Africa/Ndjamena","Africa/Niamey","Africa/Nouakchott","Africa/Ouagadougou","Africa/Porto-Novo","Africa/Sao_Tome","Africa/Timbuktu","Africa/Tripoli","Africa/Tunis","Africa/Windhoek","America/Adak","America/Anchorage","America/Anguilla","America/Antigua","America/Araguaina","America/Argentina/Buenos_Aires","America/Argentina/Catamarca","America/Argentina/ComodRivadavia","America/Argentina/Cordoba","America/Argentina/Jujuy","America/Argentina/La_Rioja","America/Argentina/Mendoza","America/Argentina/Rio_Gallegos","America/Argentina/Salta","America/Argentina/San_Juan","America/Argentina/San_Luis","America/Argentina/Tucuman","America/Argentina/Ushuaia","America/Aruba","America/Asuncion","America/Atikokan","America/Atka","America/Bahia","America/Bahia_Banderas","America/Barbados","America/Belem","America/Belize","America/Blanc-Sablon","America/Boa_Vista","America/Bogota","America/Boise","America/Buenos_Aires","America/Cambridge_Bay","America/Campo_Grande","America/Cancun","America/Caracas","America/Catamarca","America/Cayenne","America/Cayman","America/Chihuahua","America/Coral_Harbour","America/Cordoba","America/Costa_Rica","America/Creston","America/Cuiaba","America/Curacao","America/Danmarkshavn","America/Dawson","America/Dawson_Creek","America/Detroit","America/Dominica","America/Edmonton","America/Eirunepe","America/El_Salvador","America/Ensenada","America/Fort_Nelson","America/Fort_Wayne","America/Fortaleza","America/Glace_Bay","America/Godthab","America/Goose_Bay","America/Grand_Turk","America/Grenada","America/Guadeloupe","America/Guatemala","America/Guayaquil","America/Guyana","America/Halifax","America/Havana","America/Hermosillo","America/Indiana/Indianapolis","America/Indiana/Knox","America/Indiana/Marengo","America/Indiana/Petersburg","America/Indiana/Tell_City","America/Indiana/Vevay","America/Indiana/Vincennes","America/Indiana/Winamac","America/Indianapolis","America/Inuvik","America/Iqaluit","America/Jamaica","America/Jujuy","America/Kentucky/Louisville","America/Kentucky/Monticello","America/Knox_IN","America/Kralendijk","America/La_Paz","America/Lima","America/Louisville","America/Lower_Princes","America/Maceio","America/Managua","America/Manaus","America/Marigot","America/Martinique","America/Matamoros","America/Mazatlan","America/Mendoza","America/Menominee","America/Merida","America/Metlakatla","America/Mexico_City","America/Miquelon","America/Moncton","America/Monterrey","America/Montevideo","America/Montreal","America/Montserrat","America/Nassau","America/Nipigon","America/Nome","America/Noronha","America/North_Dakota/Beulah","America/North_Dakota/Center","America/North_Dakota/New_Salem","America/Ojinaga","America/Panama","America/Pangnirtung","America/Paramaribo","America/Port-au-Prince","America/Port_of_Spain","America/Porto_Acre","America/Porto_Velho","America/Puerto_Rico","America/Rainy_River","America/Rankin_Inlet","America/Recife","America/Regina","America/Resolute","America/Rio_Branco","America/Rosario","America/Santa_Isabel","America/Santarem","America/Santiago","America/Santo_Domingo","America/Sao_Paulo","America/Scoresbysund","America/Shiprock","America/Sitka","America/St_Barthelemy","America/St_Johns","America/St_Kitts","America/St_Lucia","America/St_Thomas","America/St_Vincent","America/Swift_Current","America/Tegucigalpa","America/Thule","America/Thunder_Bay","America/Tijuana","America/Toronto","America/Tortola","America/Vancouver","America/Virgin","America/Whitehorse","America/Winnipeg","America/Yakutat","America/Yellowknife","Antarctica/Casey","Antarctica/Davis","Antarctica/DumontDUrville","Antarctica/Macquarie","Antarctica/Mawson","Antarctica/McMurdo","Antarctica/Palmer","Antarctica/Rothera","Antarctica/South_Pole","Antarctica/Syowa","Antarctica/Troll","Antarctica/Vostok","Arctic/Longyearbyen","Asia/Aden","Asia/Almaty","Asia/Amman","Asia/Anadyr","Asia/Aqtau","Asia/Aqtobe","Asia/Ashgabat","Asia/Ashkhabad","Asia/Baghdad","Asia/Bahrain","Asia/Baku","Asia/Bangkok","Asia/Barnaul","Asia/Beirut","Asia/Bishkek","Asia/Brunei","Asia/Calcutta","Asia/Chita","Asia/Choibalsan","Asia/Chongqing","Asia/Chungking","Asia/Colombo","Asia/Dacca","Asia/Damascus","Asia/Dhaka","Asia/Dili","Asia/Dubai","Asia/Dushanbe","Asia/Gaza","Asia/Harbin","Asia/Hebron","Asia/Ho_Chi_Minh","Asia/Hong_Kong","Asia/Hovd","Asia/Irkutsk","Asia/Istanbul","Asia/Jakarta","Asia/Jayapura","Asia/Jerusalem","Asia/Kabul","Asia/Kamchatka","Asia/Karachi","Asia/Kashgar","Asia/Kathmandu","Asia/Katmandu","Asia/Khandyga","Asia/Kolkata","Asia/Krasnoyarsk","Asia/Kuala_Lumpur","Asia/Kuching","Asia/Kuwait","Asia/Macao","Asia/Macau","Asia/Magadan","Asia/Makassar","Asia/Manila","Asia/Muscat","Asia/Nicosia","Asia/Novokuznetsk","Asia/Novosibirsk","Asia/Omsk","Asia/Oral","Asia/Phnom_Penh","Asia/Pontianak","Asia/Pyongyang","Asia/Qatar","Asia/Qyzylorda","Asia/Rangoon","Asia/Riyadh","Asia/Saigon","Asia/Sakhalin","Asia/Samarkand","Asia/Seoul","Asia/Shanghai","Asia/Singapore","Asia/Srednekolymsk","Asia/Taipei","Asia/Tashkent","Asia/Tbilisi","Asia/Tehran","Asia/Tel_Aviv","Asia/Thimbu","Asia/Thimphu","Asia/Tokyo","Asia/Ujung_Pandang","Asia/Ulaanbaatar","Asia/Ulan_Bator","Asia/Urumqi","Asia/Ust-Nera","Asia/Vientiane","Asia/Vladivostok","Asia/Yakutsk","Asia/Yekaterinburg","Asia/Yerevan","Atlantic/Azores","Atlantic/Bermuda","Atlantic/Canary","Atlantic/Cape_Verde","Atlantic/Faeroe","Atlantic/Faroe","Atlantic/Jan_Mayen","Atlantic/Madeira","Atlantic/Reykjavik","Atlantic/South_Georgia","Atlantic/St_Helena","Atlantic/Stanley","Australia/ACT","Australia/Adelaide","Australia/Brisbane","Australia/Broken_Hill","Australia/Canberra","Australia/Currie","Australia/Darwin","Australia/Eucla","Australia/Hobart","Australia/LHI","Australia/Lindeman","Australia/Lord_Howe","Australia/Melbourne","Australia/NSW","Australia/North","Australia/Perth","Australia/Queensland","Australia/South","Australia/Sydney","Australia/Tasmania","Australia/Victoria","Australia/West","Australia/Yancowinna","Brazil/Acre","Brazil/DeNoronha","Brazil/East","Brazil/West","CET","CST6CDT","Canada/Atlantic","Canada/Central","Canada/East-Saskatchewan","Canada/Eastern","Canada/Mountain","Canada/Newfoundland","Canada/Pacific","Canada/Saskatchewan","Canada/Yukon","Chile/Continental","Chile/EasterIsland","Cuba","EET","EST","EST5EDT","Egypt","Eire","Etc/GMT","Etc/GMT+0","Etc/GMT+1","Etc/GMT+10","Etc/GMT+11","Etc/GMT+12","Etc/GMT+2","Etc/GMT+3","Etc/GMT+4","Etc/GMT+5","Etc/GMT+6","Etc/GMT+7","Etc/GMT+8","Etc/GMT+9","Etc/GMT-0","Etc/GMT-1","Etc/GMT-10","Etc/GMT-11","Etc/GMT-12","Etc/GMT-13","Etc/GMT-14","Etc/GMT-2","Etc/GMT-3","Etc/GMT-4","Etc/GMT-5","Etc/GMT-6","Etc/GMT-7","Etc/GMT-8","Etc/GMT-9","Etc/GMT0","Etc/Greenwich","Etc/UCT","Etc/UTC","Etc/Universal","Etc/Zulu","Europe/Amsterdam","Europe/Andorra","Europe/Astrakhan","Europe/Athens","Europe/Belfast","Europe/Belgrade","Europe/Berlin","Europe/Bratislava","Europe/Brussels","Europe/Bucharest","Europe/Budapest","Europe/Busingen","Europe/Chisinau","Europe/Copenhagen","Europe/Dublin","Europe/Gibraltar","Europe/Guernsey","Europe/Helsinki","Europe/Isle_of_Man","Europe/Istanbul","Europe/Jersey","Europe/Kaliningrad","Europe/Kiev","Europe/Lisbon","Europe/Ljubljana","Europe/London","Europe/Luxembourg","Europe/Madrid","Europe/Malta","Europe/Mariehamn","Europe/Minsk","Europe/Monaco","Europe/Moscow","Europe/Nicosia","Europe/Oslo","Europe/Paris","Europe/Podgorica","Europe/Prague","Europe/Riga","Europe/Rome","Europe/Samara","Europe/San_Marino","Europe/Sarajevo","Europe/Simferopol","Europe/Skopje","Europe/Sofia","Europe/Stockholm","Europe/Tallinn","Europe/Tirane","Europe/Tiraspol","Europe/Ulyanovsk","Europe/Uzhgorod","Europe/Vaduz","Europe/Vatican","Europe/Vienna","Europe/Vilnius","Europe/Volgograd","Europe/Warsaw","Europe/Zagreb","Europe/Zaporozhye","Europe/Zurich","GB","GB-Eire","GMT","GMT+0","GMT-0","GMT0","Greenwich","HST","Hongkong","Iceland","Indian/Antananarivo","Indian/Chagos","Indian/Christmas","Indian/Cocos","Indian/Comoro","Indian/Kerguelen","Indian/Mahe","Indian/Maldives","Indian/Mauritius","Indian/Mayotte","Indian/Reunion","Iran","Israel","Jamaica","Japan","Kwajalein","Libya","MET","MST","MST7MDT","Mexico/BajaNorte","Mexico/BajaSur","Mexico/General","NZ","NZ-CHAT","Navajo","PRC","PST8PDT","Pacific/Apia","Pacific/Auckland","Pacific/Bougainville","Pacific/Chatham","Pacific/Chuuk","Pacific/Easter","Pacific/Efate","Pacific/Enderbury","Pacific/Fakaofo","Pacific/Fiji","Pacific/Funafuti","Pacific/Galapagos","Pacific/Gambier","Pacific/Guadalcanal","Pacific/Guam","Pacific/Johnston","Pacific/Kiritimati","Pacific/Kosrae","Pacific/Kwajalein","Pacific/Majuro","Pacific/Marquesas","Pacific/Midway","Pacific/Nauru","Pacific/Niue","Pacific/Norfolk","Pacific/Noumea","Pacific/Pago_Pago","Pacific/Palau","Pacific/Pitcairn","Pacific/Pohnpei","Pacific/Ponape","Pacific/Port_Moresby","Pacific/Rarotonga","Pacific/Saipan","Pacific/Samoa","Pacific/Tahiti","Pacific/Tarawa","Pacific/Tongatapu","Pacific/Truk","Pacific/Wake","Pacific/Wallis","Pacific/Yap","Poland","Portugal","ROC","ROK","Singapore","SystemV/AST4","SystemV/AST4ADT","SystemV/CST6","SystemV/CST6CDT","SystemV/EST5","SystemV/EST5EDT","SystemV/HST10","SystemV/MST7","SystemV/MST7MDT","SystemV/PST8","SystemV/PST8PDT","SystemV/YST9","SystemV/YST9YDT","Turkey","UCT","US/Alaska","US/Aleutian","US/Arizona","US/Central","US/East-Indiana","US/Eastern","US/Hawaii","US/Indiana-Starke","US/Michigan","US/Mountain","US/Pacific","US/Pacific-New","US/Samoa","Universal","W-SU","WET","Zulu"]
},
fn:tz=>tz||undefined
},
{sort:{ui:91,qs:41,hash:00}, id:"force_logout_login",schema:{
type:"string",required:false,enum:["","true","false"],
description:"You basically always want to set this to true. If false, the embed will use an existing session if present in the browser, thereby ignoring all the above parameters",
},
fn:a=>(a!=="false")}
]
//.map(d=>set(d,"schema",get(d,"schema")||{}))
.map(d=>set(d,"schema.type",get(d,"schema.type")||(get(d,"schema.oneOf")?undefined:"string")))
.map(d=>set(d,"schema.propertyOrder",get(d,"sort.ui")))
.map(d=>set(d,"schema.title",autoLabel(d.id)))
var initialValue={
"embed_path":"/embed/looks/1",
"session_length":600,
"external_user_id":"test-id-123",
"first_name":"Testy",
"last_name":"McTestFace",
"permissions":["access_data","see_looks"]
}
var editorDef= {
schema: {
type:"object",
title:"Signed Embed Demo",
options:{"disable_edit_json":false,"disable_properties":false,"remove_empty_properties":true},
properties:definitions
.filter(d => d.sort.ui)
.reduce(objByOf("id","schema"),{})
},
startval:
tryRisonParse(qh("o"))
|| tryJSONParse(qh("o"))
|| tryJSONParse(localStorage.getItem("json-val"))
|| initialValue,
//"required_by_default":true,
"disable_collapse":true,
"disable_properties":true,
"display_required_only":true,
"keep_oneof_values":true,
"disable_edit_json":true
}
document.location.hash="" //Remove state from URL so it's not unintentionally copied/refreshed
var editor = new JSONEditor($("#json-editor")[0],editorDef);
editor.on('change',function() {
localStorage.setItem("json-val",JSON.stringify(editor.getValue()))
});
window.addEventListener("hashchange", function(evt){
var newVal= tryRisonParse(qh("o")) || tryJSONParse(qh("o"));
if(newVal){editor.setValue(newVal)}
document.location.hash="" //Remove state from URL so it's not unintentionally copied/refreshed
}, false);
//grrrrrrr...... Chrome is doing something annoying...
//$("input").on("invalid",function(evt){
// evt.preventDefault();//
// })
$("#panel-toggle").click(function(){$("#build-panel").toggle()})
$("#msg").click(function(){$("#msg").hide()})
$("#url-display").focus(function(){
// Highlight all on select
// Solution per http://stackoverflow.com/a/24589806
$(this).on("click.a keyup.a", function(e){
$(this).off("click.a keyup.a").select();
});
});
$("#share-state").focus(function(){
// Highlight all on select
// Solution per http://stackoverflow.com/a/24589806
$(this).on("click.a keyup.a", function(e){
$(this).off("click.a keyup.a").select();
});
});
$("#url-display").on("keypress",function(evt){
if(evt.keyCode==13){
$("#embed-iframe")[0].src=this.value
}
})
//
window.addEventListener("message",function(event){
//In order to receive events from Looker embed frame, you must add a whitelisted embed_domain parameter
//to the embed path querystring (not to the Signed querystring).
//Always validate the origin of messages before you trust their contents!
//if(event.origin!=="https://expected-origin/"){return;}
//https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#Security_concerns
//In our case, we will compare it to the host of the last embedded host which we are storing as a data attribute in our dom
if(event.origin!=="https://"+($("#embed-iframe")[0].dataset.lastHost||"")){return;}
var data = tryJSONParse(event.data)
console.log("Top-window message received from "+event.origin,data||event)
if(data.type=="page:changed"){$("#throbber").hide()}
if(data.type=="page:properties:changed" && data.height){
console.log("Top-window is updating iframe height based on received event");
$("#embed-iframe")[0].style.height = data.height+"px"
}
})
$("#build-form").on("submit",function(evt){
evt.preventDefault();
$("#msg").hide();
var errs=editor.validate();
var editorValue=editor.getValue()
var maskedEditorValue=Object.assign({},editorValue,{embed_secret:undefined})
$("#share-state").val("https://fabio-looker.github.io/looker_sso_tool/#o="+rison.encode_uri(maskedEditorValue))
if(errs.length){
$("#msg")
.text(errs.map(e=>e.path+": "+e.message).join("\n"))
.show()
return;
}
var definitionValues=
definitions
.map(d=>({d:d,val:d.default || ""}))
.map(({d,val})=>({d:d,val:
editorValue[d.id]!==undefined && editorValue[d.id]!==""
? editorValue[d.id]
: val
}))
.map(({d,val})=>({d:d,val:
d.fn?d.fn(val):val
}))
.map(({d,val})=>({d:d,val:
d.noJSON || val===undefined ? val:JSON.stringify(val)
}))
var valuesById=definitionValues.reduce(objByOf("d.id","val"),{})
if(valuesById.host.match(/:19999$/)){
let msg = "Looker port 19999 is normally used for API requests. In most cases, this is not the right host/port to use."
$("#msg")
.text(msg)
.show()
}
console.log("Values:",valuesById)
//App specific logic
var hashContent=definitionValues
.filter(dv=>dv.d.sort.hash)
.sort(sorter("d.sort.hash"))
.map(dv=>dv.val)
.join("\n")
;
console.log("String to sign:\n",hashContent)
var shaObj;
var signature=(
// Did you read the note at the top of the file???
// DO NOT DO THIS IN YOUR APPLICATION
shaObj=new jsSHA("SHA-1", "TEXT"),
shaObj.setHMACKey(editorValue.embed_secret,"TEXT"),
//Based on the format of the secret, you would think Hex...
shaObj.update(hashContent),
shaObj.getHMAC("B64")
);
console.log("Signature:",signature)
var url=("https://"
+ valuesById.host
+ valuesById.embed_path
+ "?"
+ definitionValues
.filter(dv=>dv.d.sort.qs && dv.val!==undefined)
.sort(sorter("d.sort.qs")) //Not required, but nice for consistency
.map(dv=>encodeURIComponent(dv.d.id)+"="+encodeURIComponent(dv.val))
.join("&")
+ "&signature=" + encodeURIComponent(signature)
);
//console.log("Url:",url)
$("#url-display").val(url)
if($("#embed-flag")[0].checked){
$("#embed-iframe")[0].src=url
$("#embed-iframe")[0].dataset.lastHost=valuesById.host
if(document.location.hostname
&& valuesById.embed_path.match(RegExp("%2[F6]embed_domain%3D(https%3A%2F%2F)?"+document.location.hostname.replace(/\./g,"\\.")))){
//The above conditional is just because I don't know if the Tool user will properly configure an embed domain
//so I don't want to show the throbber if there will be no events to hide it once the iframe does load
$("#throbber").show()
setTimeout(function(){$("#throbber").hide()},10*1000)//Failsafe
}
}
})
//Just functions below
function set(obj,path,val){
if(path.split){path=path.split('.')}
var head=path[0];
if(path.length==1){
obj[head]=val
}else{
obj[head]=obj[head]||{};
set(obj[head],path.slice(1),val)
}
return obj;
}
function get(obj,path){
if(path.split){path=path.split('.')}
var head=path[0];
if(path.length==1){
return obj && obj[head];
}else{
return get(obj[head],path.slice(1))
}
}
function objByOf(byKeys,ofKey){
byKeys=(byKeys instanceof Array ? byKeys : [byKeys])
return function(accum,x,i){
return set(accum,byKeys.map(k=>get(x,k)),ofKey?get(x,ofKey):x)
}
}
function sorter(path){
return function(a,b){
return get(a,path)-get(b,path)
}
}
function nonce(len) {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < len; i++){
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
function autoLabel(name){
return name.replace(/(^|_)([a-z])/g,s=>s.toUpperCase()).replace(/_/g," ")
}
function pathBuilderObjectToString(obj){
}
function tryJSONParse(s){
try{
return JSON.parse(s)
}catch(e){
return undefined
}
}
function tryRisonParse(s){
try{
return rison.decode(s.replace(/\+/g," "))
}catch(e){
return undefined
}
}
function qs(k){
return document.location.search.slice(1).split("&")
.filter(function(p){return p.indexOf(encodeURIComponent(k)+"=")===0})
.map(function(p){return decodeURIComponent(p.split("=").slice(1).join("="))})[0]
}
function qh(k){
return document.location.hash.slice(1).split("&")
.filter(function(p){return p.indexOf(encodeURIComponent(k)+"=")===0})
.map(function(p){return decodeURIComponent(p.split("=").slice(1).join("="))})[0]
}
</script>
</html>