-
Notifications
You must be signed in to change notification settings - Fork 31
Expand file tree
/
Copy pathapi.ejs
More file actions
242 lines (221 loc) · 7.4 KB
/
api.ejs
File metadata and controls
242 lines (221 loc) · 7.4 KB
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
<%- include('header'); -%>
<!-- Template for /api route -->
<style>
/* Make this page wider */
.mainCard {
width: 1200px;
}
.demo > div {
height: 500px;
overflow: scroll;
font-size: 14px;
}
#log {
font-size: 14px;
}
.log-entry {
display: flex;
margin-bottom: 5px;
}
.log-message {
padding-left: 10px;
}
</style>
<!-- IMPORTANT: Any changes to these URLs need to be made in the CSP "script-src" header as well! -->
<!-- login-client -->
<script src="https://cdn.jsdelivr.net/npm/gbv-login-client@1/dist/gbv-login-client.js"></script>
<!-- node-jsonwebtoken -->
<script src="https://cdn.jsdelivr.net/gh/stefandesu/node-jsonwebtoken@master/build/jsonwebtoken.js"></script>
<h3>API Demo</h3>
<p>This page illustrates use of the <a href="https://github.com/gbv/login-server#http-api">HTTP API</a> and <a href="https://github.com/gbv/login-server#websocket">WebSocket API</a> (see also <a href="https://github.com/gbv/login-server/blob/master/views/api.ejs" target="_blank">demo sources</a>).</p>
<div class="container">
<div class="row demo">
<div class="col-4">
<div id="log"></div>
</div>
<div class="col-4">
<!-- Connection status -->
<p>
<strong>Status: </strong><span id="status"></span>
</p>
<!-- Current token -->
<p>
<strong>Token: </strong><span id="token"></span>
</p>
<!-- About -->
<p>
<strong>About the server:</strong>
<pre id="about"></pre>
</p>
<!-- Providers -->
<p>
<strong>Providers:</strong>
<pre id="providers"></pre>
</p>
</div>
<div class="col-4">
<!-- Login/logout buttons -->
<p id="loginButtons"></p>
<!-- User information -->
<p>
<strong>User:</strong>
<pre id="user"></pre>
</p>
</div>
</div>
</div>
<p>
<div class="form-group form-check">
<label class="form-check-label">
<input id="toggleShowReceivedTokenButton" class="form-check-input" type="checkbox"> Show "Received token" events
</label>
</div>
</p>
<script nonce="<%= nonceTemp %>">
const { LoginClient } = GLC
const logEl = document.getElementById("log")
const statusEl = document.getElementById("status")
const tokenEl = document.getElementById("token")
const aboutEl = document.getElementById("about")
const providersEl = document.getElementById("providers")
const loginButtonsEl = document.getElementById("loginButtons")
const userEl = document.getElementById("user")
// See: https://github.com/gbv/login-client
let client = new LoginClient("<%= config.cleanUrl %>", { ssl: "<%= config.ssl %>" === "true" })
let token = null
let publicKey = null
let showReceivedToken = false
function toggleShowReceivedToken(checkbox) {
showReceivedToken = checkbox.checked
// Adjust existing elements
for (let element of document.querySelectorAll("[data-event='token']")) {
element.style.display = showReceivedToken ? "flex" : "none"
}
}
// Add handler to button
const toggleShowReceivedTokenButton = document.getElementById("toggleShowReceivedTokenButton")
toggleShowReceivedTokenButton.onclick = () => toggleShowReceivedToken(toggleShowReceivedTokenButton)
function log(message, color = "black", event = "other") {
let displayNone = showReceivedToken || event != "token" ? "" : "display: none;"
logEl.innerHTML = `
<div class="log-entry" style="color: ${color}; ${displayNone}" data-event="${event}">
<div class="log-timestamp small">
<code>${(new Date()).toISOString()}</code>
</div>
<div class="log-message">
${message}
</div>
</div>
` + logEl.innerHTML
}
// Update tokenEl regularly
const verifyJwt = () => {
jwt.verify(token, publicKey, (error, decoded) => {
if (error) {
tokenEl.innerHTML = `<span style="color:red">${error.message}</span>`
} else {
let currentTime = Date.now() / 1000
let validSeconds = Math.round(decoded.exp - currentTime)
tokenEl.innerHTML = `<span style="color:green">verified!</span> (valid for <tt>${validSeconds}</tt> seconds) (${byteCount(token)} bytes)`
}
})
}
setTimeout(verifyJwt, 100)
setInterval(verifyJwt, 1000)
let windowManager = {
_window: null,
_eventType: null,
open(url, eventType) {
this._window = window.open(url)
this._eventType = eventType
},
event(eventType) {
if (eventType == this._eventType && this._window) {
// Close window with timeout so that success screen will be shown
// TODO: There must be a better way to do this.
setTimeout(() => {
this._window.close()
this._window = null
}, 100)
}
},
}
// Update loginButtonsEl
function updateLoginButtons() {
loginButtonsEl.innerHTML = ""
for (let provider of client.providers) {
if (client.user && client.user.identities[provider.id]) {
// Skip existing providers
loginButtonsEl.innerHTML += `<button class="btn btn-primary btn-block btn-sm" disabled>Already connected with ${provider.name}.</button>`
continue
}
loginButtonsEl.innerHTML += `<button class="btn btn-primary btn-block btn-sm" id="providerButton-${provider.id}">Login/Connect with ${provider.name}</button>`
setTimeout(() => {
let buttonEl = document.getElementById("providerButton-" + provider.id)
if (buttonEl) {
buttonEl.onclick = () => {
windowManager.open(provider.loginURL, LoginClient.events.login)
}
}
}, 200)
}
// Show logout button if user is logged in
if (client.user) {
let url = `<%= baseUrl %>logout`
loginButtonsEl.innerHTML += `<button class="btn btn-primary btn-block btn-sm" id="providerButton-logout">Logout (${client.user.name})</>`
document.getElementById("providerButton-logout").onclick = () => {
windowManager.open(url, LoginClient.events.logout)
}
}
}
client.addEventListener(null, event => {
switch (event.type) {
case LoginClient.events.connect:
log("Connected", "green")
statusEl.innerHTML = `<strong style="color: green;">Connected</strong> <small>(${(new Date()).toISOString()})</small>`
break
case LoginClient.events.disconnect:
log("Disconnected", "red")
statusEl.innerHTML = `<strong style="color: red;">Not Connected</strong> <small>(${(new Date()).toISOString()})</small>`
break
case LoginClient.events.login:
log("User logged in", "blue")
userEl.innerHTML = JSON.stringify(event.user, null, 2)
break
case LoginClient.events.logout:
log("User logged out", "orange")
userEl.innerHTML = "not logged in"
break
case LoginClient.events.update:
log("User updated", "blue")
userEl.innerHTML = JSON.stringify(event.user, null, 2)
break
case LoginClient.events.about:
log("Received about", "black")
publicKey = event.publicKey
event.type = undefined
aboutEl.innerHTML = JSON.stringify(event, null, 2)
break
case LoginClient.events.providers:
log("Received providers", "black")
providersEl.innerHTML = JSON.stringify(event.providers, null, 2)
break
case LoginClient.events.token:
log("Received token", "black", "token")
token = event.token
break
case LoginClient.events.error:
log("Error", "red")
break
}
windowManager.event(event.type)
updateLoginButtons()
})
client.connect()
// from: https://gist.github.com/mathiasbynens/1010324
// Returns the byte count for a string
function byteCount(s) {
return encodeURI(s).split(/%..|./).length - 1;
}
</script>
<%- include('footer'); -%>