Skip to content

Commit 6059864

Browse files
cubapthehabes
andauthored
token localstorage hardening security review (#509)
* Gate 4.2: token/localStorage hardening (token-expiration UX, vault cache clear on logout, annotationsState scoping) * Remove vault cache clear on logout RERUM annotations are open data, clearing is unnecessary churn * Changes during review --------- Co-authored-by: Bryan Haberberger <bryan.j.haberberger@slu.edu>
1 parent abe24f2 commit 6059864

3 files changed

Lines changed: 19 additions & 6 deletions

File tree

api/TPEN.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@ class Tpen {
6161
eventDispatcher.on("tpen-user-loaded", ev => this.currentUser = ev.detail)
6262
eventDispatcher.on("tpen-project-loaded", ev => this.activeProject = ev.detail)
6363

64+
// Centralized token expiration UX: notify user and redirect to login
65+
let expirationTimeout = null
66+
eventDispatcher.on('token-expiration', () => {
67+
if (expirationTimeout) return
68+
eventDispatcher.dispatch('tpen-toast', { status: 'error', message: 'Your session has expired. Redirecting to login...' })
69+
expirationTimeout = setTimeout(() => this.login(), 4000)
70+
})
71+
6472
if (this.screen.projectInQuery) {
6573
try {
6674
import('./Project.js').then(module => {

components/new-action.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ class NewAction extends HTMLElement {
9494
}
9595

9696
TPEN2ImportHandler = async () => {
97-
const userToken = localStorage.getItem("userToken")
97+
const userToken = TPEN.getAuthorization()
98+
if (!userToken) return TPEN.login()
9899
let tokenDomain
99100
let isProdTPEN
100101

interfaces/manage-columns/index.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,11 @@ class TpenManageColumns extends HTMLElement {
305305

306306
connectedCallback() {
307307
TPEN.attachAuthentication(this)
308-
localStorage.removeItem('annotationsState')
308+
if (!TPEN.screen.projectInQuery) {
309+
this.showError("No project id provided")
310+
return
311+
}
312+
localStorage.removeItem(`annotationsState:${TPEN.screen.projectInQuery}`)
309313
if (!TPEN.screen.pageInQuery) {
310314
this.showError("No page id provided")
311315
return
@@ -403,7 +407,7 @@ class TpenManageColumns extends HTMLElement {
403407
}))
404408
})
405409
this.totalIds = annotations.filter(anno => !assignedAnnotationIds.some(a => a.lineId === anno.lineId)).map(a => a.lineId)
406-
localStorage.setItem('annotationsState', JSON.stringify({
410+
localStorage.setItem(`annotationsState:${TPEN.screen.projectInQuery}`, JSON.stringify({
407411
remainingIDs: this.totalIds,
408412
selectedIDs: []
409413
}))
@@ -526,7 +530,7 @@ class TpenManageColumns extends HTMLElement {
526530
this.totalIds = this.cachedAnnotations
527531
.filter(anno => !assignedAnnotationIds.some(a => a.lineId === anno.lineId))
528532
.map(a => a.lineId)
529-
localStorage.setItem('annotationsState', JSON.stringify({
533+
localStorage.setItem(`annotationsState:${TPEN.screen.projectInQuery}`, JSON.stringify({
530534
remainingIDs: this.totalIds,
531535
selectedIDs: []
532536
}))
@@ -927,7 +931,7 @@ class TpenManageColumns extends HTMLElement {
927931
}
928932

929933
restoreAnnotationState() {
930-
const saved = localStorage.getItem('annotationsState')
934+
const saved = localStorage.getItem(`annotationsState:${TPEN.screen.projectInQuery}`)
931935
if (!saved) return
932936
const { selectedIDs = [] } = JSON.parse(saved)
933937
const boxes = Array.from(this.shadowRoot.querySelectorAll('.overlayBox'))
@@ -1023,7 +1027,7 @@ class TpenManageColumns extends HTMLElement {
10231027
const selectedIDs = this.selectedBoxes.map(b => b.dataset.lineId)
10241028
const remainingIDs = this.totalIds.filter(id => !this.selectedBoxes.some(b => b.dataset.lineId === id))
10251029
try {
1026-
localStorage.setItem('annotationsState', JSON.stringify({ remainingIDs, selectedIDs }))
1030+
localStorage.setItem(`annotationsState:${TPEN.screen.projectInQuery}`, JSON.stringify({ remainingIDs, selectedIDs }))
10271031
} catch (e) {
10281032
// localStorage may be unavailable (e.g., private mode, quota exceeded)
10291033
// Silent fail as this is just a convenience feature

0 commit comments

Comments
 (0)