Skip to content

Commit d4eb8da

Browse files
improve logging and scoping of session
1 parent 1af5b7b commit d4eb8da

File tree

2 files changed

+31
-51
lines changed

2 files changed

+31
-51
lines changed

server/app.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ function testRoute(fastify, opts) {
3737
// we use the encrypted session api with get/set like the normal session api
3838
const previousValue = request.encryptedSession.get("testFromClient");
3939

40-
console.log("value stored before request is processed:", request.encryptedSession.data());
40+
console.log("value stored before request is processed:", request.encryptedSession.stringify());
4141

4242
if (query.test) {
4343
request.encryptedSession.set("testFromClient", query.test);

server/encrypted-session.js

Lines changed: 30 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,14 @@ async function encryptedSession(fastify) {
5252
fastify.addHook('onRequest', (request, _reply, next) => {
5353
//we use secure-session cookie to get the encryption key and decrypt the store
5454
if (!request[SECURE_SESSION_NAME].get(SECURE_COOKIE_KEY_ENCRYPTION_KEY)) {
55-
console.log("encryption key not found, creating new one");
55+
request.log.info({ "plugin": "encrypted-session" }, "user-side encryption key not found, creating new one");
5656

5757
let newEncryptionKey = generateSecureEncryptionKey();
5858
request[SECURE_SESSION_NAME].set(SECURE_COOKIE_KEY_ENCRYPTION_KEY, newEncryptionKey.toString('base64'));
59-
request[REQUEST_DECORATOR] = new Session()
59+
request[REQUEST_DECORATOR] = createStore()
6060
newEncryptionKey = undefined
6161
} else {
62-
console.log("encryption key found, using existing one");
62+
request.log.info({ "plugin": "encrypted-session" }, "user-side encryption key found, using existing one");
6363

6464
const loadedEncryptionKey = Buffer.from(request[SECURE_SESSION_NAME].get(SECURE_COOKIE_KEY_ENCRYPTION_KEY), "base64");
6565

@@ -70,15 +70,15 @@ async function encryptedSession(fastify) {
7070

7171
const decryptedCypherText = decryptSymetric(cipherText, iv, tag, loadedEncryptionKey);
7272
const decryptedStore = JSON.parse(decryptedCypherText);
73-
request[REQUEST_DECORATOR] = new Session(decryptedStore);
73+
request[REQUEST_DECORATOR] = createStore(decryptedStore);
7474
} catch (error) {
75-
console.error("Failed to parse encrypted store:", error);
76-
request[REQUEST_DECORATOR] = new Session();
75+
request.log.error({ "plugin": "encrypted-session" }, "Failed to parse encrypted session store", error);
76+
request[REQUEST_DECORATOR] = createStore();
7777
}
7878
} else {
7979
// we could not parse the encrypted store, so we create a new one and it would overwrite the previously stored store.
80-
console.log("No encrypted store found, creating new session");
81-
request[REQUEST_DECORATOR] = new Session();
80+
request.log.info({ "plugin": "encrypted-session" }, "No encrypted store found, creating new empty store");
81+
request[REQUEST_DECORATOR] = createStore();
8282
}
8383
}
8484

@@ -89,28 +89,33 @@ async function encryptedSession(fastify) {
8989
// onSend is called before the response is send. Here we take encrypt the Session object and store it in the fastify-session.
9090
// Then we also want to make sure the unencrypted object is removed from memory
9191
fastify.addHook('onSend', (request, reply, _payload, next) => {
92-
console.log("onSend hook called", request[REQUEST_DECORATOR].data());
92+
console.log("onSend hook called", request[REQUEST_DECORATOR].stringify());
9393

9494
//on send we will encrypt the store and set it in the backend-side session store
95-
console.log("Encrypted store that will be set in session:", JSON.stringify(request[REQUEST_DECORATOR].data()));
95+
console.log("Encrypted store that will be set in session:", request[REQUEST_DECORATOR].stringify());
9696

9797
const encyrptionKey = Buffer.from(request[SECURE_SESSION_NAME].get(SECURE_COOKIE_KEY_ENCRYPTION_KEY), "base64");
98-
98+
if (!encyrptionKey) {
99+
// if no encryption key is found in the secure session, we cannot encrypt the store. This should not happen since an encrption key is generated when the request arrived
100+
request.log.error({ "plugin": "encrypted-session" }, "No encryption key found in secure session, cannot encrypt store");
101+
throw new Error("No encryption key found in secure session, cannot encrypt store");
102+
}
99103

100104
//we store everything in one value in the session, that might be problematic for future redis with expiration times per key. we might want to split this
101-
const stringifiedData = JSON.stringify(request[REQUEST_DECORATOR].data())
105+
const stringifiedData = request[REQUEST_DECORATOR].stringify();
102106
const { cipherText, iv, tag } = encryptSymetric(stringifiedData, encyrptionKey);
103107

104108
//remove unencrypted data from memory
105109
delete request[REQUEST_DECORATOR];
106110
request[REQUEST_DECORATOR] = null;
107111

108-
request.session.encryptedStore = {
112+
request.session.set("encryptedStore", {
109113
cipherText,
110114
iv,
111115
tag,
112-
};
116+
});
113117
console.log("Encrypted store set in session:", request.session.encryptedStore);
118+
request.log.info("store encrypted and set into request.session.encryptedStore");
114119
next()
115120
})
116121

@@ -119,56 +124,31 @@ async function encryptedSession(fastify) {
119124

120125
export default fp(encryptedSession);
121126

122-
// maybe use a closure to encapsulate the session data so noone can reference it and we are the only ones keeping a reference
123-
function createEncryptedSession(previousValue) {
124-
let encryptedStore = {}; // Private variable
127+
// use a closure to encapsulate the session data so noone can reference it and we are the only ones keeping a reference
128+
function createStore(previousValue) {
129+
let unencryptedStore = {}; // Private variable
125130
if (previousValue) {
126-
encryptedStore = previousValue;
131+
unencryptedStore = previousValue;
127132
}
128133
return {
129134
set(key, value) {
130-
encryptedStore[key] = value;
135+
unencryptedStore[key] = value;
131136
},
132137
get(key) {
133-
return encryptedStore[key];
138+
return unencryptedStore[key];
134139
},
135140
delete(key) {
136-
delete encryptedStore[key];
141+
delete unencryptedStore[key];
142+
},
143+
stringify() {
144+
return JSON.stringify(unencryptedStore);
137145
},
138146
clear() {
139-
encryptedStore = {}; // Clear all data
147+
unencryptedStore = {}; // Clear all data
140148
},
141149
};
142150
}
143151

144-
class Session {
145-
#data;
146-
147-
constructor(obj) {
148-
this.#data = obj || {}
149-
}
150-
151-
get(key) {
152-
return this.#data[key]
153-
}
154-
155-
set(key, value) {
156-
this.#data[key] = value
157-
}
158-
159-
delete(key) {
160-
this.#data[key] = undefined
161-
}
162-
163-
data() {
164-
const copy = {
165-
...this.#data
166-
}
167-
168-
return copy
169-
}
170-
}
171-
172152
// generates a secure encryption key for aes-256-gcm.
173153
// Returns a buffer of 32 bytes (256 bits).
174154
function generateSecureEncryptionKey() {

0 commit comments

Comments
 (0)