copious-transitions
Version:
Framework for working with frameworks
267 lines (233 loc) • 9.84 kB
JavaScript
//
const AppLifeCycle = require("./general_lifecyle")
/// TokenTables
/**
* Top level abstraction defining the relationship between token users, and token storage which may refer to some DB.
*
* Provides access to token storage, making the semantics of token processing available to
* the authorization classes.
*
* This abstraction just fixes a handle to some DB interface and provides methods that wrap the token storage,
* which must be provided to the constructor.
*
* @memberof base
*/
class TokenTables extends AppLifeCycle {
constructor(db_obj,tokenStorage) {
super()
//
this.db = db_obj
// These are loosly written here. But, it may be good to keep
// a small number relative to session size id the backend is efficient
try {
this.tk_store = new tokenStorage(db_obj)
} catch (e) {
console.log(e)
}
}
/**
*
* @param {string} prefix
* @returns {string} - a token for a transition object
*/
generate_transition_token(prefix) {
return (this.tk_store.create_token(prefix))
}
/**
*
* @param {string} token
* @returns {any|Promise}
*/
token_to_key(token) {
let key = this.tk_store.from_token(token)
return key
}
/**
*
* @param {string} token
* @returns {boolean}
*/
async tokenCurrent(token) {
if ( token === undefined ) return(false)
let current = await this.tk_store.transition_token_is_active(token)
return ( current !== false )
}
}
/// SessionTokenManager
/**
*
* The Session Token Manager deals JSON objects arriving from some session oriented client.
* The JSON object is interned and stored as in the language's data object format.
* Certain fields may be expected in the data object. Methods for some default case are provided, but
* it is expected the application will override these methods and provide access for fields germain to the application.
*
* Provides basic methods for generating session tokens, stashing and unstashing.
*
* Manages a reference to a hashing method, called by `do_hash`.
*
* @extends TokenTables
*/
class SessionTokenManager extends TokenTables {
//
/**
*
* The configuration may bind the field `forhash` to a hashing function that will be used throughout the runtime.
*
* The db_obj is a reference to a class instance that knows how to talk to a database.
*
* The tokenStorage parameter is a required class reference that can generate a instance that manages tables of tokens.
*
* Initializes a table `release_session_data` for keeping data between client repsonses, where data comes from user objects,
* most likely obtained from the DB. In particular, the data will have a named field provided by `sess_data_accessor`. The data
* lasts until the user session is initialized by an authorization process, one that uses the general authorization (as opposed to
* light authorizatoin).
*
* @param {object} conf
* @param {object} db_obj
* @param {Class} tokenStorage
*/
constructor(conf,db_obj,tokenStorage) {
//
super(db_obj,tokenStorage) // token tables
//
this._sess_tok_hasher = (conf && (typeof conf.session_token_hasher === 'function')) ? conf.session_token_hasher : this.#produce_hasher()
//
if ( conf ) {
this.hashables = clonify(conf.forhash) // clone the field map from the configuration.
} else {
this.hashables = { "field1" : "ucwid", "field2" : "timestamp" } // if these were not configured use something failry arbitrary
}
//
this.release_session_data = {} // if a session provides information for release on finalization, temporarily keep it here
}
/**
* Return the field name of the user object that references data that should be accessed as part of the session
*/
sess_data_accessor() { // likely to be overridden e.g. "_tracking"
return "app_user_data"
}
/**
* Access to a default hash function set globally for the application
*/
#produce_hasher() {
try {
if ( global_hasher === undefined ) {
throw new Error("no hasher to return to the session manager in #produce_hasher")
} else {
return global_hasher
}
} catch (e) {
console.log(e)
}
}
/**
* Synonimic method to expose the hash function field, a configurable parameter
*
* @param {string} str
* @returns {string} - the hash of the string
*/
do_hash(str) { // default behavior --
return(this._sess_tok_hasher(str))
}
/**
* Makes a session token and returns it as a string
*
* >Uses access to a default hash function set globally for the application
*
* This method concatentates two informational parts and one nonce to make a parameter to a hash function
* in order to get a key that may be used as the session identifier.
*
* @param {object} post_body -- this is the JSON post body from the web application
*/
generate_session_token(post_body) {
let nonce = this.generate_transition_token();
//
let hash_part_1 = post_body[this.hashables.field1] // the field might no be supplied by the application
hash_part_1 = hash_part_1 ? hash_part_1 : "nothing1"
let hash_part_2 = post_body[this.hashables.field3] // the field might no be supplied by the application
hash_part_2 = hash_part_2 ? hash_part_2 : "nothing2"
//
let sess_tok = this.do_hash(hash_part_1 + hash_part_2 + nonce) // this is the session identifier just getting started.
return sess_tok
}
//
// stash_session_token
/**
* Stashes a session in the 'elements' map of the server-side transition object
*
* @param {object} user -- The user object is most likely extracted from the DB
* @param {object} transition_object -- a nascent transition object that has both server side and client side aspects, but must contain the newly generated session token
*/
stash_session_token(user,transition_object) { // sess_tok a made up token (app rule)
let sess_tok = transition_object.session_token
let app_sess_data_access_fld = this.sess_data_accessor() // get the application identified field name that should occur in a user object
if ( app_sess_data_access_fld ) {
this.release_session_data[sess_tok] = user[app_sess_data_access_fld] // app overrides so that it knows this field (ucwid)
// The elements field will provide access to the session token (in turn to the user data) for the life the authorization transition
transition_object.elements[app_sess_data_access_fld] = sess_tok // for secondary
}
}
// the stored transition object identified (mapped) by its token,
// will have the session token within the elements map object.
// see stash_session_token(user,transition_object,sess_tok) in general_auth which extends this module
//
/**
* given the server side transition object for an authorization transition retrieve the sesssion token
* from the transition object's elements fields
*/
unstash_session_token(transObject) {
let key = this.sess_data_accessor()
if ( key ) {
return(transObject.elements[key])
}
return false
}
/**
* Calls upon token storage to save the session and the relationship to its owner.
*
* @param {string} key -- a key, mostly likely a ucwid that identifies an owner of the session
* @param {string} session_token -- a session token (should be made by generate_session_token)
*/
async addSession(key,session_token) { // e.g. ucwid and server side hash
if ( (key !== undefined) && (session_token !== undefined) ) {
return (await this.tk_store.add_session(session_token,key,false,true)) // ucwid, stashed token -> stashed token, ucwid
}
}
/**
* Calls upon token storage to termiate a session and the tokens that expire with its termination.
* The parameter passed is the session's transition token, which had been created for authorization transitions.
* The parameter is used to obtain the session token.
*
* @param {string} token -- the session's authorization transition token.
*/
destroySession(token) {
this.tk_store.destroy_session(token)
}
/**
* Checks to see if a session is current.
* The source key may be supplied to check on the hash of owner related data.
*
* @param {string} session_token -- a session token (should be made by generate_session_token)
* @param {string} [src_key] -- data returned from storing the transition token
*/
async sessionCurrent(session_token,src_key) { // src_key is not in use in the general case
if ( src_key === undefined ) return(false)
let key = await this.tk_store.active_session(session_token,src_key) // src key might be a ucwid
return key
}
/**
* insert_session
*
* For apps that only check the session but have been informed how to construct a link hash.
*
* @param {string} session_token
* @param {string} link_hash
*/
insert_session(session_token,link_hash) {
this.tk_store.quick_insert_active_session(session_token,link_hash)
}
remove_session(session_token) {
this.tk_store.discard_quick_insert(session_token)
}
}
module.exports = SessionTokenManager