summaryrefslogtreecommitdiff
path: root/src/routers/vault/types/SessionStore.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/routers/vault/types/SessionStore.js')
-rw-r--r--src/routers/vault/types/SessionStore.js129
1 files changed, 129 insertions, 0 deletions
diff --git a/src/routers/vault/types/SessionStore.js b/src/routers/vault/types/SessionStore.js
new file mode 100644
index 0000000..daa71c3
--- /dev/null
+++ b/src/routers/vault/types/SessionStore.js
@@ -0,0 +1,129 @@
+"use strict";
+const Session = require("./Session.js");
+
+/**
+ * we store the timeout directly in Session instances
+ * @type Symbol("session timeout")
+ */
+const timeout_symbol = Symbol("session timeout");
+
+/**
+ * holds the Sessions and re-hydrates them when accessed
+ */
+class SessionStore {
+ /**
+ * a Map of all Session instances
+ * @type Map<string, Session>
+ */
+ sessions = new Map();
+ /** lifetime of an unauthenticated Session, in minutes */
+ base_lifetime = 30;
+ /** lifetime of a properly authenticated Session, in minutes */
+ authed_lifetime = 60 * 6; // 6 hours
+
+ /**
+ * creates a new SessionStore
+ * @param {number} base - the base Session lifetime, in minutes
+ * @param {number} authed - the lifetime of an authenticated Session
+ */
+ constructor (base = 0, authed = 0) {
+ this.base_lifetime = base || this.base_lifetime;
+ this.authed_lifetime = authed || this.authed_lifetime;
+ }
+
+ /**
+ * re-hydrates a Session by resetting the expiration
+ * @param {string} key - the Session key
+ * @param {Session} sess - the Session to hydrate
+ * @returns {Session} the same Session
+ */
+ hydrate (key, sess) {
+ /** the new expiration, in minutes */
+ let minutes = this.base_lifetime;
+
+ if (Reflect.has(sess, timeout_symbol)) {
+ /** clear any existing timeout */
+ clearTimeout(sess[timeout_symbol]);
+ }
+
+ if (sess.authenticated === true) {
+ /** Session is properly authenticated: set lifetime accordingly */
+ minutes = this.authed_lifetime;
+ }
+
+ /** the new expiry Date */
+ const expires = new Date();
+ expires.setUTCMinutes(expires.getUTCMinutes() + minutes); // update it
+ sess.expires = expires; // swap the old for the new expiry
+ sess[timeout_symbol] = setTimeout(() => this.delete(key), minutes * 60000);
+ return sess;
+ }
+
+ /**
+ * checks whether a Session with the given key exists
+ * @param {string} key - the Session key
+ */
+ has (key) {
+ return this.sessions.has(key);
+ }
+
+ /**
+ * returns a Session with the matching key
+ * @param {string} key - the Session key
+ * @returns {Session} the found Session
+ */
+ get (key) {
+ /** lookup the session by key */
+ const sess = this.sessions.get(key);
+
+ if (sess) {
+ /** the Session, re-hydrated */
+ return this.hydrate(key, sess);
+ }
+
+ /** session not found */
+ return null;
+ }
+
+ /**
+ * adds a Session to the store
+ * @param {string} key - the Session key
+ * @param {Session} sess - the Session
+ */
+ set (key, sess) {
+ this.sessions.set(key, this.hydrate(key, sess));
+ }
+
+ /**
+ * removes a Session with the matching key from the store
+ *
+ * NOTE: this does not actually delete the Session instance
+ * @param {string} key - the Session key
+ */
+ delete (key) {
+ /** lookup the session by key */
+ const sess = this.sessions.get(key);
+
+ if (sess) {
+ if (Reflect.has(sess, timeout_symbol)) {
+ /** clear any existing timeout */
+ clearTimeout(sess[timeout_symbol]);
+ }
+
+ return this.sessions.delete(key)
+ }
+
+ /** session not found */
+ return false;
+ }
+
+ /**
+ * iterator for use in for-of
+ * @returns {Iterator<[string, Session]>} the Map iterator of the SessionStore instance
+ */
+ [Symbol.iterator] () {
+ return this.sessions[Symbol.iterator]();
+ }
+}
+
+module.exports = SessionStore;