UNPKG

will-core

Version:
662 lines (661 loc) 34.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SigninHandler = void 0; const uuid_1 = require("uuid"); const will_lib_1 = require("will-lib"); const will_api_1 = require("will-api"); const will_sql_1 = require("will-sql"); const will_util_1 = require("will-util"); const will_lib_2 = require("will-lib"); const EnvironmentVariable_1 = require("../utils/EnvironmentVariable"); const UserToken_1 = require("../models/UserToken"); const VerifyError_1 = require("../models/VerifyError"); const Responser_1 = require("../utils/Responser"); const DiffieHandler_1 = require("./DiffieHandler"); const SchemeHandler_1 = require("./SchemeHandler"); const TwoFactorHandler_1 = require("./TwoFactorHandler"); const bcrypt = require('bcrypt'); class SigninHandler extends SchemeHandler_1.SchemeHandler { constructor() { super(...arguments); this.model = { name: "tuser", alias: { privateAlias: this.section } }; //declared addon actions name this.handlers = [{ name: "signin" }, { name: "accesstoken" }, { name: "fetchtoken" }, { name: "validatetoken" }, { name: "signout" }, { name: "account" }]; } getSigninInfo(context) { return { username: context.params.username, password: context.params.password, site: context.params.site }; } async signin(context) { return this.callFunctional(context, { operate: "signin", raw: false }, this.doSignin); } async doSignin(context, model) { let signinfo = this.getSigninInfo(context); this.logger.debug(this.constructor.name + ".doSignin : username=" + signinfo.username); let db = this.getPrivateConnector(model); try { let authinfo = this.getAuthorizationInfo(context); this.logger.debug(this.constructor.name + ".doSignin: auth info", authinfo); if (authinfo && authinfo.authorization.trim().length > 0) { //if authen by basic, then decrypt let blib = new will_lib_1.BasicLibrary(); let basicinfo = await blib.decrypt(authinfo.authorization, authinfo.client, db); if (basicinfo) { this.logger.debug(this.constructor.name + ".doSignin: basic info: username=" + basicinfo.username); signinfo = { ...signinfo, ...basicinfo }; } this.logger.debug(this.constructor.name + ".doSignin: sign info: username=" + signinfo.username); } if ((!signinfo.username || signinfo.username.trim().length == 0) || (!signinfo.password || signinfo.password.trim().length == 0)) { return Promise.reject(new VerifyError_1.VerifyError("Invalid user or password", will_api_1.HTTP.BAD_REQUEST, -16081)); } if (EnvironmentVariable_1.AUTHEN_BY_VERIFY_DOMAIN) { return await this.doSigninByDomain(context, model, signinfo, db); } else { return await this.doSigninByConfigure(context, model, signinfo, db); } } catch (ex) { this.logger.error(this.constructor.name, ex); return Promise.reject(this.getDBError(ex)); } finally { if (db) db.close(); } } async doSigninByDomain(context, model, signinfo, db) { try { let loginfo = await this.loginWow(signinfo.username, signinfo.password); let account = will_lib_2.ActiveAuthen.getAccountDomain(signinfo.username); let adconfig = await will_lib_2.ActiveLibrary.getActiveConfig(db, account.domainName); this.logger.debug(this.constructor.name + ".doSigninByDomain: ad config = " + (adconfig ? adconfig.hasConfigure() : false)); if (adconfig && adconfig.hasConfigure()) { return await this.processSigninActiveDirectory(context, model, signinfo, db, adconfig, loginfo); } else { return await this.processSigninInternalSystem(context, model, signinfo, db, loginfo); } } catch (ex) { this.logger.error(this.constructor.name, ex); return Promise.reject(ex); } } async doSigninByConfigure(context, model, signinfo, db) { let loginfo = undefined; let errmsg = undefined; let authlist = will_util_1.Configure.getConfig("authentications"); if (authlist && authlist.length > 0) { for (let i = 0, isz = authlist.length; i < isz; i++) { let aut = authlist[i]; if (aut.enabled) { if ("SYSTEM" == aut.authtype) { let response = await this.processSigninInternalSystem(context, model, signinfo, db, loginfo); if (response.head.errorflag == "N") { return Promise.resolve(response); } else { errmsg = response.head.errordesc; } } else if ("AD" == aut.authtype) { let adconfig = will_lib_2.ActiveLibrary.createConfigure(aut); this.logger.debug(this.constructor.name + ".doSigninByConfigure: ad config = " + (adconfig ? adconfig.hasConfigure() : false)); if (adconfig && adconfig.hasConfigure()) { let response = await this.processSigninActiveDirectory(context, model, signinfo, db, adconfig, loginfo); if (response.head.errorflag == "N") { return Promise.resolve(response); } else { errmsg = response.head.errordesc; } } } else { let response = await this.processSigninPromptSystem(context, model, signinfo, db, loginfo); if (response.head.errorflag == "N") { return Promise.resolve(response); } else { errmsg = response.head.errordesc; } } } } } return Promise.reject(new will_lib_1.AuthenError(errmsg ? errmsg : "Authentication fail", will_api_1.HTTP.UNAUTHORIZED)); } async processTwoFactor(context, db, row) { let handler = new TwoFactorHandler_1.TwoFactorHandler(); let factorInfo = await handler.getFactorInfo(db, row.userid, true); if (factorInfo.factorverify && !factorInfo.factorfound && factorInfo.factorid.trim().length == 0) { factorInfo.userid = row.userid; factorInfo.email = row.email; factorInfo = await handler.performCreateFactor(context, db, factorInfo); } return factorInfo; } async processSigninInternalSystem(context, model, signinfo, db, loginfo) { let pname = signinfo.username; let ppass = signinfo.password; let pcode = context.params.code; let pstate = context.params.state; let pnonce = context.params.nonce; let response = new will_api_1.JSONReply(); response.head.modeling("signin", "signin"); response.head.composeNoError(); let body = new Map(); let sql = new will_sql_1.KnSQL("select tuser.userid,tuser.username,tuser.userpassword,tuser.passwordexpiredate,tuser.site,"); sql.append("tuser.accessdate,tuser.accesstime,tuser.changeflag,tuser.newflag,tuser.loginfailtimes,tuser.failtime,tuser.lockflag,"); sql.append("tuserinfo.userename,tuserinfo.useresurname,tuserinfo.email,tuserinfo.displayname,tuserinfo.activeflag,tuserinfo.langcode,tuserinfo.usercontents "); sql.append("from tuser,tuserinfo "); sql.append("where tuser.username = ?username "); sql.append("and tuser.userid = tuserinfo.userid "); sql.set("username", pname); this.logger.info(this.constructor.name + ".processSigninInternalSystem", sql); let rs = await sql.executeQuery(db, context); let rows = rs.rows; this.logger.debug(this.constructor.name + ".processSigninInternalSystem: effected " + rows.length + " rows."); let passed = true; if (rows && rows.length > 0) { let row = rows[0]; let userid = row.userid; let site = row.site; this.logger.debug(this.constructor.name + ".processSigninInternalSystem: MAX_FAILURE=" + EnvironmentVariable_1.MAX_FAILURE + ", loginfailtimes=" + row.loginfailtimes); let failtimes = row.loginfailtimes; if (failtimes >= EnvironmentVariable_1.MAX_FAILURE) { let now = new Date(); let failtime = row.failtime; let difftime = now.getTime() - failtime; this.logger.debug(this.constructor.name + ".processSigninInternalSystem: MAX_WAITTIME=" + EnvironmentVariable_1.MAX_WAITTIME + ", failtime=" + failtime + ", difftime=" + difftime); if (difftime <= EnvironmentVariable_1.MAX_WAITTIME) { passed = false; response.head.composeError("-5012", "Signin failure over " + EnvironmentVariable_1.MAX_FAILURE + " times. Please contact administrator or wait and retry again after 3 minute"); } } if (passed) { let ismatch = false; let tempmatch = false; let usrpass = row.userpassword; let plib = new will_lib_2.PasswordLibrary(); let tmppwd = await plib.getUserTemporaryPassword(db, userid); if (tmppwd && tmppwd.trxid) { tempmatch = bcrypt.compareSync(ppass, tmppwd.userpassword); ismatch = tempmatch; } if (!ismatch) { ismatch = bcrypt.compareSync(ppass, usrpass); } this.logger.debug(this.constructor.name + ".processSigninInternalSystem: temporary match=" + tempmatch + ", is match=" + ismatch); if (!ismatch) { passed = false; response.head.composeError("-3002", "Invalid user or password"); } else { try { let factorInfo = await this.processTwoFactor(context, db, row); await db.beginWork(); try { if (tempmatch) { await plib.updatePasswordFromTemporary(db, tmppwd.trxid, userid); } let usrinfo = { userid: userid, site: site, code: pcode, state: pstate, nonce: pnonce, loginfo: loginfo }; let token = await this.createUserAccess(db, usrinfo, context); let dhinfo = await this.createDiffie(context, db, token); this.composeResponseBody(body, token, pname, { ...row, ...factorInfo, accesscontents: loginfo }, tempmatch, dhinfo); await db.commitWork(); } catch (er) { this.logger.error(this.constructor.name, er); db.rollbackWork(); this.logger.debug(this.constructor.name + ".processSigninInternalSystem: roll back work"); response = Responser_1.Responser.createDbError("ensure", "signin", er); } } catch (ex) { this.logger.error(this.constructor.name, ex); response = Responser_1.Responser.createDbError("ensure", "signin", ex); } } } } else { passed = false; response.head.composeError("-3003", "Invalid user or password"); } try { if (passed) { this.updateUserAccessing(context, model, { userid: body.get("userid"), username: pname, lockflag: "0" }); } else { this.updateUserAccessing(context, model, { username: pname, lockflag: "1" }); } } catch (ex) { this.logger.error(this.constructor.name, ex); } response.body = Object.fromEntries(body); return Promise.resolve(response); } async processSigninActiveDirectory(context, model, signinfo, db, config, loginfo) { let pname = signinfo.username; let ppass = signinfo.password; let pcode = context.params.code; let pstate = context.params.state; let pnonce = context.params.nonce; let response = new will_api_1.JSONReply(); response.head.modeling("signin", "signin"); response.head.composeNoError(); let body = new Map(); let alib = new will_lib_2.ActiveLibrary(); try { let au = await alib.authenticate(pname, ppass, config, db); try { let row = { accessdate: new Date(), accesstime: will_util_1.Utilities.currentTime(), userid: au.accountName, userename: au.firstName, useresurname: au.lastName, email: au.principalName, displayname: au.displayName, activeflag: "1", usercontents: null, changeflag: "0", site: undefined }; let sql = new will_sql_1.KnSQL("select site,accessdate,accesstime,userid,userename,useresurname,email,displayname,activeflag,usercontents,'0' as changeflag,'0' as newflag "); sql.append("from tuserinfo where userid = ?userid "); sql.set("userid", au.accountName); let rs = await sql.executeQuery(db); if (rs.rows && rs.rows.length > 0) { row = rs.rows[0]; } let factorInfo = await this.processTwoFactor(context, db, row); await db.beginWork(); try { await alib.saveUserInfo(db, au); let usrinfo = { userid: au.accountName, site: row.site, code: pcode, state: pstate, nonce: pnonce, loginfo: loginfo }; let token = await this.createUserAccess(db, usrinfo, context); let dhinfo = await this.createDiffie(context, db, token); this.composeResponseBody(body, token, pname, { ...row, ...factorInfo, accesscontents: loginfo }, false, dhinfo); await db.commitWork(); this.updateUserAccessing(context, model, { userid: au.accountName }); } catch (er) { this.logger.error(this.constructor.name, er); db.rollbackWork(); this.logger.debug(this.constructor.name + ".processSigninActiveDirectory: roll back work"); response = Responser_1.Responser.createError("ensure", "signin", er); } } catch (ex) { this.logger.error(this.constructor.name, ex); response = Responser_1.Responser.createError("ensure", "signin", ex); } response.body = Object.fromEntries(body); } catch (ex) { this.logger.error(this.constructor.name, ex); response = Responser_1.Responser.createError("ensure", "signin", ex); } return Promise.resolve(response); } async processSigninPromptSystem(context, model, signinfo, db, config, loginfo) { let pname = signinfo.username; let ppass = signinfo.password; let pcode = context.params.code; let pstate = context.params.state; let pnonce = context.params.nonce; let response = new will_api_1.JSONReply(); response.head.modeling("signin", "signin"); response.head.composeNoError(); let body = new Map(); let alib = new will_lib_2.AuthenLibrary(); try { let pu = await alib.authenticate(pname, ppass, config, db); try { let row = { accessdate: new Date(), accesstime: will_util_1.Utilities.currentTime(), userid: pu.userid, userename: pu.username, useresurname: pu.usersurname, email: pu.email, displayname: pu.displayname, activeflag: "1", usercontents: null, changeflag: "0", site: undefined }; let sql = new will_sql_1.KnSQL("select site,accessdate,accesstime,userid,userename,useresurname,email,displayname,activeflag,usercontents,'0' as changeflag,'0' as newflag "); sql.append("from tuserinfo where userid = ?userid "); sql.set("userid", pu.userid); this.logger.info(this.constructor.name + ".processSigninPromptSystem", sql); let rs = await sql.executeQuery(db); if (rs.rows && rs.rows.length > 0) { row = rs.rows[0]; } let factorInfo = await this.processTwoFactor(context, db, row); await db.beginWork(); try { await alib.saveUserInfo(db, pu); let usrinfo = { userid: pu.userid, site: row.site, code: pcode, state: pstate, nonce: pnonce, loginfo: pu }; let token = await this.createUserAccess(db, usrinfo, context); let dhinfo = await this.createDiffie(context, db, token); this.composeResponseBody(body, token, pname, { ...row, ...factorInfo, accesscontents: pu }, false, dhinfo); await db.commitWork(); this.updateUserAccessing(context, model, { userid: pu.userid }); } catch (er) { this.logger.error(this.constructor.name, er); db.rollbackWork(); this.logger.debug(this.constructor.name + ".processSigninPromptSystem: roll back work"); response = Responser_1.Responser.createError("ensure", "signin", er); } } catch (ex) { this.logger.error(this.constructor.name, ex); response = Responser_1.Responser.createError("ensure", "signin", ex); } response.body = Object.fromEntries(body); } catch (ex) { this.logger.error(this.constructor.name, ex); response = Responser_1.Responser.createError("ensure", "signin", ex); } return Promise.resolve(response); } composeResponseBody(body, token, username, row, tempmatch = false, dhinfo) { let expdate = new Date(token.expiretimes); let expireflag = "0"; if (row.passwordexpiredate) { let expired = will_util_1.Utilities.compareDate(row.passwordexpiredate, will_util_1.Utilities.now()); if (expired < 0) { expireflag = "1"; } } body.set("useruuid", token.useruuid); body.set("expiretimes", token.expiretimes); body.set("expireddate", will_util_1.Utilities.currentDate(expdate) + " " + will_util_1.Utilities.currentTime(expdate)); body.set("code", token.code); body.set("state", token.state); body.set("nonce", token.nonce); body.set("authtoken", token.authtoken); body.set("username", username); body.set("userid", row.userid); body.set("name", row.userename); body.set("surname", row.useresurname); body.set("displayname", row.displayname); body.set("email", row.email); body.set("site", row.site); body.set("accessdate", will_util_1.Utilities.getDMY(row.accessdate)); body.set("accesstime", will_util_1.Utilities.getHMS(row.accesstime)); body.set("activeflag", row.activeflag); body.set("changeflag", row.changeflag); body.set("expireflag", expireflag); body.set("newflag", row.newflag); body.set("langcode", row.langcode); body.set("factorverify", row?.factorverify); body.set("factorflag", row?.factorflag); body.set("factorid", row?.factorid); body.set("factorcode", row?.factorcode); body.set("usercontents", row.usercontents); let accessinfo = row.accesscontents; if (will_util_1.Utilities.isString(row.accesscontents) && row.accesscontents.trim().length > 0) { accessinfo = JSON.parse(row.accesscontents); } body.set("accesscontents", accessinfo); if (tempmatch) body.set("changeflag", "1"); if (dhinfo) body.set("info", dhinfo); } async createUserAccess(db, usrinfo, context) { let useruuid = (0, uuid_1.v4)(); let authdata = { identifier: useruuid, site: usrinfo.site, accessor: usrinfo.userid }; let authtoken = will_lib_2.AuthenToken.createAuthenToken(authdata); return this.createUserToken(db, usrinfo, useruuid, authtoken, "S", EnvironmentVariable_1.EXPIRE_TIMES, context); } async createUserToken(db, usrinfo, useruuid, authtoken, tokentype = "S", expireins = EnvironmentVariable_1.EXPIRE_TIMES, context) { let now = new Date(); let expiretimes = now.getTime() + expireins; let expdate = new Date(expiretimes); let code = usrinfo.code ? usrinfo.code : (0, uuid_1.v4)(); let state = usrinfo.state ? usrinfo.state : (0, uuid_1.v4)(); let nonce = usrinfo.nonce ? usrinfo.nonce : (0, uuid_1.v4)(); let accesscontents = usrinfo.loginfo ? JSON.stringify(usrinfo.loginfo) : null; let sql = new will_sql_1.KnSQL("insert into tusertoken(useruuid,userid,createdate,createtime,createmillis,"); sql.append("expiredate,expiretime,expiretimes,site,code,state,nonce,authtoken,tokentype,accesscontents) "); sql.append("values(?useruuid,?userid,?createdate,?createtime,?createmillis,"); sql.append("?expiredate,?expiretime,?expiretimes,?site,?code,?state,?nonce,?authtoken,?tokentype,?accesscontents) "); sql.set("useruuid", useruuid); sql.set("userid", usrinfo.userid); sql.set("createdate", now, "DATE"); sql.set("createtime", now, "TIME"); sql.set("createmillis", now.getTime()); sql.set("expiredate", expdate, "DATE"); sql.set("expiretime", expdate, "TIME"); sql.set("expiretimes", expiretimes); sql.set("site", usrinfo.site); sql.set("code", code); sql.set("state", state); sql.set("nonce", nonce); sql.set("authtoken", authtoken); sql.set("tokentype", tokentype); sql.set("accesscontents", accesscontents); let rs = await sql.executeQuery(db, context); this.logger.debug(this.constructor.name + ".createUserToken: affected " + rs.rows.affectedRows + " rows."); return Promise.resolve(new UserToken_1.UserToken(useruuid, expiretimes, code, state, nonce, authtoken)); } async createDiffie(context, db, token) { let handler = new DiffieHandler_1.DiffieHandler(); let dh = await handler.createDiffie(context); console.log(this.constructor.name + ".createDiffie", dh); await handler.saveDiffie(db, { useruuid: token.useruuid }, dh, context); let info = handler.createDiffieInfo(dh); return Promise.resolve(info); } async updateUserAccessing(context, model, info) { let db = this.getPrivateConnector(model); try { if (info.userid) { await this.updateUserAccess(db, info.userid, context); } if (info.username) { await this.updateUserLock(db, info.username, info.lockflag, context); } } catch (ex) { this.logger.error(this.constructor.name, ex); } finally { if (db) db.close(); } } async updateUserAccess(db, userid, context) { let now = new Date(); let sql = new will_sql_1.KnSQL("update tuser set accessdate=?accessdate, accesstime=?accesstime, "); sql.append("accesshits = accesshits + ?accesshits, mistakens = 0, mistakentime = 0 "); sql.append("where userid=?userid "); sql.set("accessdate", now, "DATE"); sql.set("accesstime", now, "TIME"); sql.set("accesshits", 1); sql.set("userid", userid); this.logger.info(this.constructor.name + ".updateUserAccess", sql); let rs = await sql.executeUpdate(db, context); this.logger.debug(this.constructor.name + ".updateUserAccess: affected " + rs.rows.affectedRows + " rows."); sql.clear(); sql.append("update tuserinfo set accessdate=?accessdate, accesstime=?accesstime where userid=?userid "); sql.set("accessdate", now, "DATE"); sql.set("accesstime", now, "TIME"); sql.set("userid", userid); this.logger.info(this.constructor.name + ".updateUserAccess", sql); rs = await sql.executeUpdate(db, context); this.logger.debug(this.constructor.name + ".updateUserAccess: affected " + rs.rows.affectedRows + " rows."); return Promise.resolve(); } async updateUserLock(db, username, lockflag, context) { let loginfailtimes = 0; let now = new Date(); let failtime = now.getTime(); let sql = new will_sql_1.KnSQL(); let locked = "1" == lockflag; if (locked) { loginfailtimes = 1; sql.append("update tuser set loginfailtimes = loginfailtimes + ?loginfailtimes, failtime=?failtime "); } else { sql.append("update tuser set loginfailtimes=?loginfailtimes, failtime=?failtime "); failtime = 0; } sql.append("where username = ?username "); sql.set("loginfailtimes", loginfailtimes); sql.set("failtime", failtime); sql.set("username", username); this.logger.info(this.constructor.name + ".updateUserLock", sql); let rs = await sql.executeUpdate(db, context); this.logger.debug(this.constructor.name + ".updateUserLock: affected " + rs.rows.affectedRows + " rows."); return Promise.resolve(); } async accesstoken(context) { return this.callFunctional(context, { operate: "accesstoken", raw: false }, this.doAccessToken); } async account(context) { return this.callFunctional(context, { operate: "account", raw: false }, this.doAccessToken); } async doAccessToken(context, model) { let token = this.getTokenKey(context); this.logger.debug(this.constructor.name + ".doAccessToken: token = " + token); if (!token || token == "") { return Promise.reject(new VerifyError_1.VerifyError("Invalid access token", will_api_1.HTTP.NOT_ACCEPTABLE, -3010)); } await this.verifyAuthenToken(token); let db = this.getPrivateConnector(model); try { let body = await this.processAccessToken(db, token, false, context); this.updateUserAccessing(context, model, { userid: body.get("userid") }); return body; } catch (ex) { this.logger.error(this.constructor.name, ex); return Promise.reject(this.getDBError(ex)); } finally { if (db) db.close(); } } async processAccessToken(db, useruuid, fetching = true, context) { let body = new Map(); let now = new Date(); let sql = new will_sql_1.KnSQL("select tuser.userid,tuser.username,tuser.userpassword,tuser.passwordexpiredate,tuser.site,"); sql.append("tuser.accessdate,tuser.accesstime,tuser.changeflag,tuser.newflag,tuser.loginfailtimes,tuser.failtime,tuser.lockflag,"); sql.append("tuserinfo.userename,tuserinfo.useresurname,tuserinfo.email,tuserinfo.displayname,tuserinfo.langcode,tuserinfo.activeflag,tuserinfo.usercontents,"); sql.append("tusertoken.expiretimes,tusertoken.code,tusertoken.state,tusertoken.nonce,tusertoken.authtoken,tusertoken.accesscontents,"); sql.append("tusertoken.prime,tusertoken.generator,tusertoken.publickey,tusertoken.useruuid,tusertoken.factorcode "); sql.append("from tusertoken,tuser,tuserinfo "); if (fetching) { sql.append("where tusertoken.useruuid = ?useruuid "); sql.set("useruuid", useruuid); } else { sql.append("where tusertoken.authtoken = ?authtoken "); sql.set("authtoken", useruuid); } sql.append("and tusertoken.expiretimes >= ?expiretimes "); sql.append("and tusertoken.outdate is null and tusertoken.outtime is null "); sql.append("and tusertoken.userid = tuser.userid "); sql.append("and tuser.userid = tuserinfo.userid "); sql.set("expiretimes", now.getTime()); let rs = await sql.executeQuery(db, context); this.logger.debug(this.constructor.name + ".processAccessToken: effected " + rs.rows.length + " rows."); if (rs.rows && rs.rows.length > 0) { let row = rs.rows[0]; let handler = new TwoFactorHandler_1.TwoFactorHandler(); let factorInfo = await handler.getFactorInfo(db, row.userid, true); let token = new UserToken_1.UserToken(row.useruuid, row.expiretimes, row.code, row.state, row.nonce, row.authtoken); let dh = { prime: row.prime, generator: row.generator, publickey: row.publickey }; this.composeResponseBody(body, token, row.username, { ...row, ...factorInfo }, false, dh); } else { return Promise.reject(new VerifyError_1.VerifyError("Invalid access token", will_api_1.HTTP.NOT_ACCEPTABLE, -3011)); } return Promise.resolve(body); } async fetchtoken(context) { return this.callFunctional(context, { operate: "fetchtoken", raw: false }, this.doFetchToken); } async doFetchToken(context, model) { let puuid = context.params.useruuid; this.logger.debug(this.constructor.name + ".doFetchToken: useruuid = " + puuid); if (!puuid || puuid == "") { return Promise.reject(new VerifyError_1.VerifyError("Invalid access user", will_api_1.HTTP.NOT_ACCEPTABLE, -3010)); } let db = this.getPrivateConnector(model); try { let body = await this.processAccessToken(db, puuid, true); this.updateUserAccessing(context, model, { userid: body.get("userid") }); return body; } catch (ex) { this.logger.error(this.constructor.name, ex); return Promise.reject(this.getDBError(ex)); } finally { if (db) db.close(); } } async signout(context) { return this.callFunctional(context, { operate: "signout", raw: false }, this.doSignout); } async doSignout(context, model) { let puuid = context.params.useruuid; this.logger.debug(this.constructor.name + ".doSignout: useruuid = " + puuid); if (!puuid || puuid == "") { let token = await this.getAuthenToken(context, false, false); if (token) { puuid = token.identifier; } } if (!puuid || puuid == "") { return Promise.reject(new VerifyError_1.VerifyError("Invalid access token", will_api_1.HTTP.NOT_ACCEPTABLE, -3010)); } try { let session = context.meta?.session; if (session) { delete session.dh; delete session.user; } delete context.meta.user; } catch (ex) { } let db = this.getPrivateConnector(model); try { return await this.processSignout(db, puuid, context); } catch (ex) { this.logger.error(this.constructor.name, ex); return Promise.reject(this.getDBError(ex)); } finally { if (db) db.close(); } } async processSignout(db, useruuid, context) { let body = new Map(); let sql = new will_sql_1.KnSQL("delete from tusertoken where useruuid = ?useruuid "); sql.set("useruuid", useruuid); this.logger.info(this.constructor.name + ".processSignout", sql); let rs = await sql.executeUpdate(db, context); this.logger.debug(this.constructor.name + ".processSignout: affected " + rs.rows.affectedRows + " rows."); if (rs.rows.affectedRows > 0) { body.set("affected", rs.rows.affectedRows); } else { return Promise.reject(new VerifyError_1.VerifyError("Invalid access token", will_api_1.HTTP.BAD_REQUEST, -3011)); } return Promise.resolve(body); } async loginWow(userid, pwd, site) { let result = {}; if (EnvironmentVariable_1.NEWS_URL_ALWAYS_OPEN) result = will_lib_2.AuthenLibrary.getDefaultResponse(); try { let cfg = will_lib_2.AuthenLibrary.getDefaultConfigure(site); this.logger.debug(this.constructor.name + ".loginWow: login config", cfg); let alib = new will_lib_2.AuthenLibrary(); let res = await alib.authenticate(userid, pwd, cfg); return Promise.resolve(res); } catch (ex) { this.logger.error(this.constructor.name, ex); } return Promise.resolve(result); } async validatetoken(context) { await this.exposeFunctional(context, this.model, { operate: "validatetoken" }); return this.getAuthenToken(context, true, true); } } exports.SigninHandler = SigninHandler;