UNPKG

copious-transitions

Version:
474 lines (427 loc) 24.4 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>JSDoc: Source: lib/general_auth.js</title> <script src="scripts/prettify/prettify.js"> </script> <script src="scripts/prettify/lang-css.js"> </script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> </head> <body> <div id="main"> <h1 class="page-title">Source: lib/general_auth.js</h1> <section> <article> <pre class="prettyprint source linenums"><code>// const {GeneralAuth,SessionManager_Lite} = require('./general_auth_session_lite') // Top level of session managers, effectively supplying an interface for intialization // Does some heavy lifting in controlling the flow of authorization and permission. // /** * @extends SessionManager_Lite from general_auth_session_lite * Provide the methods that will process login, registration, logout, and session initalization. * Also, there are methods dealing with the existene of the user and possible database storage of the user. * * NOTE: all the base classes in /lib return the class and do not return an instance. Explore the applications and * the reader will find that the descendant modules export instances. The classes provided by copious-transitions must * be extended by an application. * * @memberof base */ class SessionManager extends SessionManager_Lite { // constructor(exp_app,db_obj,business) { // reference to the DB and initializes the a middleware vector super(exp_app,db_obj,business) // // let conf = this.conf this.current_auth_strategy = "local" //this.foreign_authorizer_api_enpoint = conf.foreign_auth.api_enpoint this.login_amelioration = conf.login_amelioration this.password_fail_amelioration = conf.failed_password_amelioration this.registration_fail_amelioration = conf.failed_registration_duplicate this.second_login_amelioration = conf.second_login_amelioration } // foreign_authorizer -- add the endpoint to the authorizer field /* foreign_authorizer(primary_key,tobj,body) { tobj.foreign_authorizer_endpoint = this.foreign_authorizer_api_enpoint + '/start/' + body.strategy + '/' + body[primary_key] + '/' + tobj.token return(tobj) } */ /* async prep_foreign_auth(user,post_body,transtion_object) { let key_key = this.key_for_user() transtion_object._t_u_key = key_key transtion_object.user_key = user[key_key] this.loginTransitionFields(transtion_object,post_body,user) this.foreign_authorizer(primary_key,transtion_object,post_body) return(transtion_object) } */ /** * By default this method just checks to see if two strings are equal. * Applications will want to do something more sophisticated, e.g. checking a signature. * * @param {string} db_password * @param {string} client_password * @returns {boolean} - true if the comparison passes */ async password_check(db_password,client_password) { return(db_password === client_password) /// app should override this with a secure password check } // default behavior -- should override /** * By default, this method returns the parameter untouched. * Applications may hash the password or may encrypt or decrypt in order to find a string for comparison. * * @param {string} password * @returns {string} - the hash of the password */ hash_pass(password) { return(password) } /** * * @param {object} transtion_object * @param {object} post_body * @param {object} user */ loginTransitionFields(transtion_object,post_body,user) { // make tokens (first the transition token and then the session token) let sess_tok = this.generate_session_token(post_body) let token = this.generate_transition_token('user+',sess_tok) // put the session token into the transition object in its special field transtion_object.set_session('sess+' + sess_tok) transtion_object.set_token(token) // this token identifies this transition object // transtion_object.strategy = post_body.strategy // // Match the sessions's transition token later. transtion_object.elements = { "match" : transtion_object.token } this.stash_session_token(user,transtion_object) // stashing the token keeps the token with the server side transition object } /** * This method first checks the DB user password against password data obtained from the client. * Given the password check works, the transition object is flagged for a secondary action. * * The `loginTransitionFields` is called in order to create the session identifier and store it in local in-memory * hash tables. * * @param {object} user * @param {object} transtion_object * @param {object} post_body * @returns {boolean} - true if failed indicating that a corretive action must be done - false indicating no required action */ async login_transition(user,transtion_object,post_body) { if ( user.password &amp;&amp; post_body.password ) { let post_pass = await this.hash_pass(post_body.password) if ( await this.password_check(user.password,post_pass) ) { transtion_object.secondary_action = true let key_key = this.key_for_user() // a field name set by the application override of key_for_user. // transtion_object._t_u_key = key_key transtion_object.user_key = user[key_key] // this data is to be cached for the secondary action // await this.loginTransitionFields(transtion_object,post_body,user) return false } else { return this.password_fail_amelioration } } } /** * This method stores a user in the data base for the first time. * * In some applications this storing of the user is something perpetual. * In other applications, the user is stored newly each time with permanent identity storage happening elsewhere. * * The registration can also create a session by calling `generate_session_token` * This also creates an elements map with a `match` field for the session. * * @param {object} post_body * @param {object} transtion_object * @returns {boolean} The result is true if the user can be stored in the DB, false otherwise. */ async registration_transition(post_body,transtion_object) { if ( post_body.password ) { post_body.password = await this.hash_pass(post_body.password) if ( post_body.verify_password ) { delete post_body.verify_password } await this.db.store_user(post_body) /// CREATE USER ENTRY IN DB (store a relationship object) if ( this.business ) this.business.process('new-user',post_body) // let token = this.generate_transition_token('user+') // transaction token let registration_token = this.generate_session_token(post_body) transtion_object.set_token(token) transtion_object.set_session('sess+' + registration_token) // transtion_object.add_to_elements({ "match" : 'sess+' + registration_token }) return true; } return false } /** * This method is the target of user processing classes, that can be found in the contractual directory. * * The user processing classes help with the existence of users and the management of their sessions. * * There operations that this method handles are `login`, `logout` and `registration`. * * Handling `forgot`, for forgotten passwords is deprecated and may become be handled by transition processing at a later date. * * * The `logout` operation leads to a call to `destroySession`. * * The operations `login` and `register` lead to calls to their `transition` * * * @param {string} user_op * @param {object} post_body * @param {object} res * @param {string} primary_key * @returns {object} - the transition object made for continuing the requested operation */ async process_user(user_op,post_body,res,primary_key) { let use_ammelioration = false // let transtion_object = this.create_transition_record('user',user_op) // post_body = this.post_body_decode(post_body) switch ( user_op ) { case 'login' : { if ( this.db ) { let all = true let user = await this.db.fetch_user(post_body,all) if ( user ) { if ( user.logged_in ) { //transtion_object.amelioritive_action = this.second_login_amelioration //break; } // use_ammelioration = await this.login_transition(user,transtion_object,post_body) } else { use_ammelioration = this.login_amelioration } } break; // removed foreign auth 6/27/23 } case 'logout' : { if ( this.db ) { let key = this.token_to_key(post_body.token) // get an ownership key (e.g. ucwid) if ( key === undefined ) return; // Logout can be requested for dead sessions... let query = {} query[primary_key] = key let user = await this.db.fetch_user(query) if ( user ) { user.logged_in = false this.db.update_user(user) } // let token = post_body.token // going to take the transition token (state graph) and get the session from it for now transtion_object.clear_session() // going to whip out the session idenitifer in the rest of execution // if ( token &amp;&amp; this.sessionCurrent(token,key) ) { // there has to be a transition token associated with managing session state transisions this.destroySession(token) // still use the transition token to get the sesion and destroy the actual sesssion references. if ( res ) this.app_user_release_cookie(res) } } break; } case 'register' : { if ( this.db ) { let user = await this.db.fetch_user(post_body) if ( !(user) ) { let processed = await this.registration_transition(post_body,transtion_object) if ( processed ) break; } } use_ammelioration = this.registration_fail_amelioration break; } case 'forgot' : { if ( this.db ) { let user = await this.db.fetch_user(post_body) if ( user ) { if ( this.business &amp;&amp; this.business.process('forgot',post_body) ) { let update_password = await this.hash_pass(post_body.password) user.updates = { 'pass' : update_password } this.db.update_user(user) this.ok_forgetfulness(true,transtion_object) } else { this.ok_forgetfulness(false,transtion_object) } } else { use_ammelioration = this.login_amelioration } } break; } default : { break; } } // if ( use_ammelioration ) { transtion_object.amelioritive_action = use_ammelioration return(transtion_object.to_object(['amelioritive_action'])) } return(transtion_object.to_object()) } /** * This method responds to a client request by upd * * `finalize_transition` in some applications use this method. The invokation of `finalize_transition` is typically during a * secondary action and part of an active session. The token, from the stached transition object is expected in the client * request data. * * The token will map, via DB query on the key-value DB to a value to be used in the query for the user object * in the user table of the DB. If the keyed value and the user can be found, then the password introduced by the * client request's post body will be hashed and stored if the user object has the field `updates` set to an object * containing the desired password. The update password and the post body password must check. * * If the passwords check out, then the user password can be updated and stored in the DB for future transactions. * * The value this returns may be passed onto a business process, if the application is so condigured. * * @param {object} post_body * @returns {object} - the value `keyed_val` retrieved form the DB and that is mapped to the `token`. */ async update_user_password(post_body) { if ( this.db ) { try { if ( post_body.token ) { let keyed_val = await this.db.get_key_value(post_body.token) // information that links the user to the reset password if ( keyed_val ) { let query = {} query[post_body._t_u_key] = keyed_val let user = await this.db.fetch_user(query) if ( user ) { if ( user.password &amp;&amp; post_body.password ) { let post_pass = await this.hash_pass(post_body.password) let updates = user.updates if ( updates ) { if ( await this.password_check(updates.pass,post_pass) ) { user.password = updates.pass delete user.updates.pass if ( Object.keys(user.updates).length == 0 ) delete user.updates this.db.update_user(user) return(keyed_val) } } } } } } } catch(e) { console.log(e) } } return(false) } /** * Set the `forgetfulness_proceed` for the applications that handle forgotten passwords. * * @param {boolean} boolVal * @param {object} transtion_object */ ok_forgetfulness(boolVal,transtion_object) { transtion_object.forgetfulness_proceed = boolVal } /** * Applications will want to override this method in order to work with cookies used by the authorization process. * * @param {object} res - this is the HTTP request response object * @param {string} session_token */ app_set_user_cookie(res,session_token) { // application override } /** * Applications will want to override this method in order to work with cookies used by the authorization process. * * @param {object} res - this is the HTTP request response object */ app_user_release_cookie(res) {/* application only */} /** * * This method will start a user's session, enabling calls to asset delivery and to processess state transitions. * This method is called only after the session has been authorized and a session token has been created for it. * Also, this method only handles transition objects that have a `user_op` set to `login`. * * Given the user object is still in the DB, the user `logged_in` field will be set to true. * And, this state change will be stored in the DB for reference by this and other processes. * * Finally, the session for this user will be recorded in the session tables, and data created for the session will be released. * * * * Only available in the general_auth which should only be used in processes that are processing users. * This is not in the auth_session_lite, which is used by processes checking user ownership and permissions, * but those processes do not initiate user sessions or offer processing for new entries.... * * if the user session state can be initialized, this returns the elements map required by the cached transition object. * * @param {string} transition * @param {string} session_token * @param {object} transtionObj * @param {object} res * @returns {object|undefined} */ async initialize_session_state(transition,session_token,transtionObj,res) { if ( transition === 'user' ) { if ( transtionObj ) { if ( transtionObj.user_op === 'login' ) { // finalize login.... let user_key_val = transtionObj.user_key let key_key = transtionObj._t_u_key let query = {} query[key_key] = user_key_val // find the user from the application db let user = await this.db.fetch_user(query) if ( user ) { // if finding it, the log the user in (also the result of registration...) user.logged_in = true user.strategy = transtionObj.strategy // foreign login may be a strategy... so is local... // SEND USER TO DB as logged in... this.db.update_user(user) // update the user record with "logged_in" set to true.. // if ( transtionObj._db_session_key ) { // uuid --> and the sha255 hash -- e.g. the ucwid itself await this.addSession(transtionObj._db_session_key,session_token,transtionObj.token) // goes to shared memory, key-value, etc. } // if ( res ) this.app_set_user_cookie(res,session_token) // leave it to the app to manage this construct, perhaps express, perhaps not // let elements = {} let app_sess_data_access = this.sess_data_accessor() elements[app_sess_data_access] = this.release_session_data[session_token] // end of the transition... delete this.release_session_data[session_token] // return elements } } } } return undefined } } module.exports.GeneralAuth = GeneralAuth module.exports.SessionManager = SessionManager </code></pre> </article> </section> </div> <nav> <h2><a href="index.html">Home</a></h2><h3>Namespaces</h3><ul><li><a href="Contractual.html">Contractual</a></li><li><a href="CopiousTransitions.html">CopiousTransitions</a></li><li><a href="DefaultDB.html">DefaultDB</a></li><li><a href="base.html">base</a></li><li><a href="field_validators.html">field_validators</a></li></ul><h3>Classes</h3><ul><li><a href="Contractual.LocalTObjectCache.html">LocalTObjectCache</a></li><li><a href="Contractual.MimeHandling.html">MimeHandling</a></li><li><a href="Contractual.TransitionHandling.html">TransitionHandling</a></li><li><a href="Contractual.UserHandling.html">UserHandling</a></li><li><a href="CopiousTransitions.CopiousTransitions.html">CopiousTransitions</a></li><li><a href="DefaultDB.CustomizationMethodsByApplication.html">CustomizationMethodsByApplication</a></li><li><a href="DefaultDB.FauxInMemStore.html">FauxInMemStore</a></li><li><a href="DefaultDB.FileMapper.html">FileMapper</a></li><li><a href="DefaultDB.FilesAndRelays.html">FilesAndRelays</a></li><li><a href="DefaultDB.FilesAndRelays_base.html">FilesAndRelays_base</a></li><li><a href="DefaultDB.LocalStaticDB.html">LocalStaticDB</a></li><li><a href="DefaultDB.LocalStorageLifeCycle.html">LocalStorageLifeCycle</a></li><li><a href="DefaultDB.LocalStorageSerialization.html">LocalStorageSerialization</a></li><li><a href="DefaultDB.PageableMemStoreElement.html">PageableMemStoreElement</a></li><li><a href="DefaultDB.PersistenceContracts.html">PersistenceContracts</a></li><li><a href="DefaultDB.RemoteMessaging.html">RemoteMessaging</a></li><li><a href="DefaultDB.StaticDBDefault.html">StaticDBDefault</a></li><li><a href="GeneralUserDBWrapperImpl.html">GeneralUserDBWrapperImpl</a></li><li><a href="SessionTokenManager.html">SessionTokenManager</a></li><li><a href="base.DBClass.html">DBClass</a></li><li><a href="base.EndpointManager.html">EndpointManager</a></li><li><a href="base.GeneralAppLifeCycle.html">GeneralAppLifeCycle</a></li><li><a href="base.GeneralAuth.html">GeneralAuth</a></li><li><a href="base.GeneralBusiness.html">GeneralBusiness</a></li><li><a href="base.GeneralDynamic.html">GeneralDynamic</a></li><li><a href="base.GeneralMiddleWare.html">GeneralMiddleWare</a></li><li><a href="base.GeneralStatic.html">GeneralStatic</a></li><li><a href="base.GeneralTransitionEngImpl.html">GeneralTransitionEngImpl</a></li><li><a href="base.SessionManager.html">SessionManager</a></li><li><a href="base.SessionManager_Lite.html">SessionManager_Lite</a></li><li><a href="base.TaggedTransition.html">TaggedTransition</a></li><li><a href="base.TokenTables.html">TokenTables</a></li><li><a href="base.UserMessageEndpoint.html">UserMessageEndpoint</a></li><li><a href="base.WebSocketManager.html">WebSocketManager</a></li><li><a href="field_validators.DataLookupField.html">DataLookupField</a></li><li><a href="field_validators.EmailField.html">EmailField</a></li><li><a href="field_validators.EmailVerifyField.html">EmailVerifyField</a></li><li><a href="field_validators.FieldTest.html">FieldTest</a></li><li><a href="field_validators.FieldValidatorTools.html">FieldValidatorTools</a></li><li><a href="field_validators.ForeignAuth.html">ForeignAuth</a></li><li><a href="field_validators.GeneralValidator.html">GeneralValidator</a></li><li><a href="field_validators.LengthyAlphabetField.html">LengthyAlphabetField</a></li><li><a href="field_validators.LengthyDigitalField.html">LengthyDigitalField</a></li><li><a href="field_validators.LengthyField.html">LengthyField</a></li><li><a href="field_validators.LengthyStringField.html">LengthyStringField</a></li><li><a href="field_validators.PasswordField.html">PasswordField</a></li><li><a href="field_validators.PasswordVerifyField.html">PasswordVerifyField</a></li><li><a href="field_validators.TypeCheckField.html">TypeCheckField</a></li></ul><h3>Global</h3><ul><li><a href="global.html#generate_password_block">generate_password_block</a></li><li><a href="global.html#load_configuration">load_configuration</a></li><li><a href="global.html#load_parameters">load_parameters</a></li><li><a href="global.html#module_top">module_top</a></li></ul> </nav> <br class="clear"> <footer> Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a> on Tue Oct 31 2023 17:32:59 GMT-0700 (Pacific Daylight Time) </footer> <script> prettyPrint(); </script> <script src="scripts/linenumber.js"> </script> </body> </html>