refactor(ui): inject the session server-side instead of fetching it client-side
The pages are rendered by the server, which already holds the session — so /fingerprint, /cropper and the landing now embed window.__SESSION__ (JSON, with '<' escaped) instead of each fetching /auth/session on load: - /fingerprint gets token, identity, agentUrl and the permitted domains (the same cached context the endpoint returned); /cropper gets identity - landing nav is now server-rendered (Sign in vs user chip + Sign out); its client fetch script is deleted - per-user HTML is sent with Cache-Control: no-store and Vary: Cookie - express.static runs with index:false so '/' can be session-aware while assets stay session-free - GET /auth/session remains as the documented JSON contract (and the canonical place the domain-filter caching is exercised in tests) Client code shrinks by a fetch + error path per page; 3 new tests (injection, escaping, landing header) — 43 total.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
Identity comes from the YOUreka session; the only operator credential is
|
||||
the save-time OTP (required by a2loft). Notifications are Carbon toasts. */
|
||||
/* global Vue, axios, Croppa, customElements */
|
||||
/* window.__SESSION__ is injected server-side by /cropper */
|
||||
Vue.config.ignoredElements = [/^cds-/];
|
||||
|
||||
(function () {
|
||||
@@ -69,17 +70,13 @@ Vue.config.ignoredElements = [/^cds-/];
|
||||
|
||||
created: function () {
|
||||
var self = this;
|
||||
axios.get('/auth/session').then(function (r) {
|
||||
self.session = r.data;
|
||||
self.loading = false;
|
||||
}).catch(function (err) {
|
||||
if (err.response && err.response.status === 401) {
|
||||
window.location.href = '/auth/login';
|
||||
return;
|
||||
}
|
||||
self.loading = false;
|
||||
self.toast('error', 'Session error', 'Could not load your session. Please refresh the page.');
|
||||
});
|
||||
// injected by the server when the page was rendered (no round-trip)
|
||||
this.session = window.__SESSION__ || null;
|
||||
if (!this.session) {
|
||||
window.location.href = '/auth/login';
|
||||
return;
|
||||
}
|
||||
this.loading = false;
|
||||
Promise.all(
|
||||
['cds-button', 'cds-toast', 'cds-toast-item', 'cds-tag'].map(function (n) {
|
||||
return customElements.whenDefined(n).catch(function () {});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/* Fingerprint Agent — enrollment wizard. Captures run through the local
|
||||
fpagent binary; artifacts are saved via the app's a2loft proxy. */
|
||||
/* global Vue, axios, io, customElements */
|
||||
/* window.__SESSION__ is injected server-side by /fingerprint */
|
||||
Vue.config.ignoredElements = [/^cds-/];
|
||||
|
||||
(function () {
|
||||
@@ -102,19 +103,17 @@ Vue.config.ignoredElements = [/^cds-/];
|
||||
},
|
||||
|
||||
loadSession: function () {
|
||||
var self = this;
|
||||
return axios.get('/auth/session').then(function (r) {
|
||||
self.session = r.data;
|
||||
if (self.session.domains.length) self.domain = self.session.domains[0].code;
|
||||
self.loading = false;
|
||||
}).catch(function (err) {
|
||||
if (err.response && err.response.status === 401) {
|
||||
window.location.href = '/auth/login';
|
||||
return;
|
||||
}
|
||||
self.loading = false;
|
||||
self.showNotif('error', 'Session error', 'Could not load your session. Please refresh the page.', true);
|
||||
});
|
||||
// injected by the server when the page was rendered (no round-trip)
|
||||
this.session = window.__SESSION__ || null;
|
||||
if (!this.session) {
|
||||
window.location.href = '/auth/login';
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (this.session.domains && this.session.domains.length) {
|
||||
this.domain = this.session.domains[0].code;
|
||||
}
|
||||
this.loading = false;
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
refreshDomains: function () {
|
||||
|
||||
+1
-28
@@ -22,9 +22,7 @@
|
||||
</span>
|
||||
YOUreka <small>Tools</small>
|
||||
</a>
|
||||
<div class="nav-right" id="nav-session">
|
||||
<a class="linklike" href="/auth/login">Sign in</a>
|
||||
</div>
|
||||
<div class="nav-right"><!--session-nav--></div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -69,30 +67,5 @@
|
||||
<span>Scan captures run locally via the fpagent agent — no scanner data leaves this machine except the enrolled artifacts you save.</span>
|
||||
</div>
|
||||
</footer>
|
||||
<script>
|
||||
// Reflect the current session in the header: Sign in vs user chip + Sign out.
|
||||
fetch('/auth/session')
|
||||
.then(function (r) { return r.ok ? r.json() : null; })
|
||||
.then(function (session) {
|
||||
var host = document.getElementById('nav-session');
|
||||
if (!session) return; // keep the Sign in link
|
||||
var name = (session.firstName || session.phone || '?').trim();
|
||||
host.textContent = '';
|
||||
var chip = document.createElement('span');
|
||||
chip.className = 'user-chip';
|
||||
var avatar = document.createElement('span');
|
||||
avatar.className = 'avatar';
|
||||
avatar.textContent = name.slice(0, 2).toUpperCase(); // textContent, never innerHTML
|
||||
var label = document.createElement('span');
|
||||
label.textContent = name;
|
||||
chip.append(avatar, label);
|
||||
var signOut = document.createElement('a');
|
||||
signOut.className = 'linklike';
|
||||
signOut.href = '/auth/logout';
|
||||
signOut.textContent = 'Sign out';
|
||||
host.append(chip, signOut);
|
||||
})
|
||||
.catch(function () { /* keep Sign in */ });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user