Skip to content

Commit f9674eb

Browse files
authored
Deal with session handling. (project-chip#1505)
1 parent 8e4ff10 commit f9674eb

File tree

5 files changed

+143
-25
lines changed

5 files changed

+143
-25
lines changed

src-electron/ui/browser-api.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,15 @@ const env = require('../util/env')
2929
* @returns session UUID
3030
*/
3131
async function getSessionUuidFromBrowserWindow(browserWindow) {
32-
let sessionUuid = await browserWindow.webContents.executeJavaScript(
32+
// Here, we're retrieving the map of all available sessions and return them.
33+
let sessionMapJson = await browserWindow.webContents.executeJavaScript(
3334
'window.sessionStorage.getItem("session_uuid")'
3435
)
35-
return sessionUuid
36+
if (sessionMapJson == null) {
37+
return new Map()
38+
} else {
39+
return new Map(JSON.parse(sessionMapJson))
40+
}
3641
}
3742

3843
/**

src-electron/ui/menu.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -216,11 +216,16 @@ const template = (httpPort) => [
216216
*/
217217
async function getUserSessionInfoMessage(browserWindow) {
218218
let userKey = await browserApi.getUserKeyFromBrowserWindow(browserWindow)
219-
let sessionUuid =
219+
let sessionUuidMap =
220220
await browserApi.getSessionUuidFromBrowserWindow(browserWindow)
221+
let sessionUuidText = ''
222+
for (const [key, value] of sessionUuidMap) {
223+
sessionUuidText += ` ${key} => ${value}\n`
224+
}
221225
return `
222-
Browser session UUID: ${sessionUuid}
223226
Browser user key: ${userKey}
227+
Browser session UUID:
228+
${sessionUuidText}
224229
`
225230
}
226231

src/boot/axios.js

+6-20
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,17 @@
1616
*/
1717

1818
import axios from 'axios'
19-
import { v4 as uuidv4 } from 'uuid'
2019
import restApi from '../../src-shared/rest-api.js'
2120
import * as Util from '../util/util.js'
22-
const querystring = require('querystring')
21+
import * as SessionId from '../util/session-id.js'
2322

2423
let zapUpdateExceptions = (payload, statusCode, message) => {}
2524

2625
// You can set this to false to not log all the roundtrips
2726
const log = false
2827

29-
let search = window.location.search
30-
31-
if (search[0] === '?') {
32-
search = search.substring(1)
33-
}
34-
let query = querystring.parse(search)
35-
if (window.sessionStorage.getItem('session_uuid') == null) {
36-
window.sessionStorage.setItem('session_uuid', uuidv4())
37-
}
38-
if (query[`stsApplicationId`]) {
39-
let currentSessionUuid = window.sessionStorage.getItem('session_uuid') || ''
40-
let updatedSessionUuid = query[`stsApplicationId`] + currentSessionUuid
41-
window.sessionStorage.setItem('session_uuid', updatedSessionUuid)
42-
}
28+
// Handle session initialization
29+
SessionId.initializeSessionIdInBrowser(window)
4330

4431
/**
4532
* URL rewriter that can come handy in development mode.
@@ -90,17 +77,16 @@ function processResponse(method, url, response) {
9077
* @returns config
9178
*/
9279
function fillConfig(config) {
80+
let sessionId = SessionId.sessionId(window)
9381
if (config == null) {
9482
config = { params: {} }
95-
config.params[restApi.param.sessionId] =
96-
window.sessionStorage.getItem('session_uuid')
83+
config.params[restApi.param.sessionId] = sessionId
9784
return config
9885
} else {
9986
if (!('params' in config)) {
10087
config.params = {}
10188
}
102-
config.params[restApi.param.sessionId] =
103-
window.sessionStorage.getItem('session_uuid')
89+
config.params[restApi.param.sessionId] = sessionId
10490
return config
10591
}
10692
}

src/boot/ws.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,15 @@ import restApi from '../../src-shared/rest-api.js'
2020
import rendApi from '../../src-shared/rend-api.js'
2121
import { Notify } from 'quasar'
2222
import * as Util from '../util/util.js'
23+
import * as SessionId from '../util/session-id.js'
2324

2425
const tickInterval = 15000 // 15 seconds tick interval for server watchdog.
2526

2627
let eventEmitter = new Events.EventEmitter()
2728
let restPort = Util.getServerRestPort()
2829
let wsUrl = `ws://${window.location.hostname}:${
2930
restPort == null ? window.location.port : restPort
30-
}?${restApi.param.sessionId}=${window.sessionStorage.getItem('session_uuid')}`
31+
}?${restApi.param.sessionId}=${SessionId.sessionId(window)}`
3132
const client = new WebSocket(wsUrl)
3233

3334
/**

src/util/session-id.js

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/**
2+
*
3+
* Copyright (c) 2025 Silicon Labs
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import { v4 as uuidv4 } from 'uuid'
19+
import { parse as querystringParse } from 'querystring'
20+
21+
// Session handling constants
22+
const SESSION_KEY = 'session_uuid'
23+
const APP_ID_KEY = 'stsApplicationId'
24+
const DEFAULT_APP_ID = 'defaultAppId'
25+
26+
/**
27+
* Loads a session map from the session storage.
28+
* Session map is a string=>string key/value map,
29+
* which contains "appId" as a key, and the generated UUID as a value.
30+
* If appId is not present (as in standalone), then a default value
31+
* is used.
32+
*
33+
* @param {*} window
34+
* @returns
35+
*/
36+
function loadSessionMap(window) {
37+
let json = window.sessionStorage.getItem(SESSION_KEY)
38+
if (json == null) {
39+
// Nothing there, let's just create an empty map.
40+
return new Map()
41+
} else {
42+
// Found it, so we deserialize it.
43+
const parsedArray = JSON.parse(json)
44+
return new Map(parsedArray)
45+
}
46+
}
47+
48+
/**
49+
* Saves a session map into the session storage.
50+
* @param {*} window
51+
* @param {*} map
52+
*/
53+
function saveSessionMap(window, map) {
54+
const mapArray = Array.from(map)
55+
const json = JSON.stringify(mapArray)
56+
window.sessionStorage.setItem(SESSION_KEY, json)
57+
}
58+
59+
/**
60+
* Determine application id. If there is actually an stsApplicationId passed
61+
* in, then what we get is that. Otherwise, it uses
62+
*
63+
* @param {*} window
64+
* @returns
65+
*/
66+
function retrieveApplicationId(window) {
67+
// Check if it has already been put on the dom.
68+
if (window.zapAppId) {
69+
return window.zapAppId
70+
}
71+
72+
// If it's not there, get it from the seach query....
73+
let search = window.location.search
74+
if (search[0] === '?') {
75+
search = search.substring(1)
76+
}
77+
let query = querystringParse(search)
78+
79+
let appId
80+
if (query[APP_ID_KEY]) {
81+
appId = query[APP_ID_KEY]
82+
} else {
83+
appId = DEFAULT_APP_ID
84+
}
85+
86+
// Store it onto the window object for quicker access.
87+
window.zapAppId = appId
88+
89+
return appId
90+
}
91+
92+
/**
93+
* Returns the session id after it's been created. This method WILL NOT
94+
* create one if it hasn't been created yet. Only the
95+
* initializeSessionIdInBrowser method will create a new session id.
96+
* @param {*} window
97+
* @returns
98+
*/
99+
export function sessionId(window) {
100+
let appId = retrieveApplicationId(window)
101+
let sessionMap = loadSessionMap(window)
102+
return sessionMap.get(appId)
103+
}
104+
105+
/**
106+
* This is the entry point for the boot file to handle the session object.
107+
* It mainly needs to figure out if it needs to create a new UUID or not.
108+
* @param {*} window
109+
*/
110+
export function initializeSessionIdInBrowser(window) {
111+
let sessionMap = loadSessionMap(window)
112+
let appId = retrieveApplicationId(window)
113+
114+
// Get the session object, that is keyed by the appId
115+
let sessionUuid = sessionMap.get(appId)
116+
if (sessionUuid == null) {
117+
// This is a whole new appId. Let's create a session object for it.
118+
sessionMap.set(appId, uuidv4())
119+
saveSessionMap(window, sessionMap)
120+
}
121+
}

0 commit comments

Comments
 (0)