"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Token = void 0; const Feature_1 = require("oak-frontend-base/es/types/Feature"); const Exception_1 = require("oak-domain/lib/types/Exception"); const Projection_1 = require("../types/Projection"); const Exception_2 = require("../types/Exception"); const constants_1 = require("../config/constants"); const lodash_1 = require("oak-domain/lib/utils/lodash"); class Token extends Feature_1.Feature { tokenValue; environment; cache; storage; application; ignoreExceptionList = [Exception_1.OakNetworkException, Exception_1.OakServerProxyException, Exception_1.OakRequestTimeoutException, Exception_1.OakClockDriftException]; async loadSavedToken() { this.tokenValue = await this.storage.load(constants_1.LOCAL_STORAGE_KEYS.token); await this.refreshTokenData(this.tokenValue); this.publish(); } constructor(cache, storage, environment, application) { super(); this.cache = cache; this.storage = storage; this.environment = environment; this.application = application; this.tokenValue = ''; // 置个空字符串代表还在load storage缓存的数据 // this.loadSavedToken(); application.subscribe(() => this.loadSavedToken()); if (process.env.OAK_PLATFORM === 'web' && (process.env.NODE_ENV !== 'development' || process.env.OAK_DEV_MODE === 'server')) { // 纯前台模式 多窗口时不监听storage // 在web下可能多窗口,一个窗口更新了token,其它窗口应跟着变 window.addEventListener('storage', async (e) => { if (e.key === constants_1.LOCAL_STORAGE_KEYS.token) { this.tokenValue = e.newValue ? JSON.parse(e.newValue) : undefined; await this.refreshTokenData(this.tokenValue); this.publish(); } }); } } checkNeedSetPassword() { const user = this.getUserInfo(); const { system } = this.application.getApplication(); const { Security } = system.config; if (Security?.level === 'strong' && user && !user.hasPassword) { return Promise.reject(new Exception_2.OakPasswordUnset()); } } async refreshTokenData(tokenValue) { if (!tokenValue) { this.tokenValue = undefined; return; } const env = await this.environment.getEnv(); try { const applicationId = this.application.getApplicationId(); const { result } = await this.cache.exec('refreshToken', { tokenValue, env, applicationId, }, undefined, true, true); if (tokenValue !== result) { // 如果返回空字符串,token被disabled,tokenValue置为undefined if (result) { this.tokenValue = result; await this.storage.save(constants_1.LOCAL_STORAGE_KEYS.token, result); this.checkNeedSetPassword(); } else { this.removeToken(true); } } else { this.checkNeedSetPassword(); } } catch (err) { // refresh出了任何错都无视(排除网络异常),直接放弃此token console.warn(err); // if ( // err instanceof OakNetworkException || // err instanceof OakServerProxyException || // err instanceof OakRequestTimeoutException || // err instanceof OakClockDriftException // ) { // return; // } if (this.ignoreExceptionList.some((clazz) => { return (0, Exception_1.isOakException)(err, clazz); })) { return; } this.removeToken(true); } } async loginByMobile(mobile, captcha, disableRegister) { const env = await this.environment.getEnv(); const { result } = await this.cache.exec('loginByMobile', { mobile, captcha, disableRegister, env, }, undefined, true); this.tokenValue = result; await this.storage.save(constants_1.LOCAL_STORAGE_KEYS.token, result); this.publish(); this.checkNeedSetPassword(); } async loginByEmail(email, captcha, disableRegister) { const env = await this.environment.getEnv(); const { result } = await this.cache.exec('loginByEmail', { email, captcha, disableRegister, env, }, undefined, true); this.tokenValue = result; await this.storage.save(constants_1.LOCAL_STORAGE_KEYS.token, result); this.publish(); this.checkNeedSetPassword(); } async loginByAccount(account, password) { const env = await this.environment.getEnv(); const { result } = await this.cache.exec('loginByAccount', { account, password, env, }, undefined, true); this.tokenValue = result; await this.storage.save(constants_1.LOCAL_STORAGE_KEYS.token, result); this.publish(); this.checkNeedSetPassword(); } async bindByMobile(mobile, captcha) { const env = await this.environment.getEnv(); await this.cache.exec('bindByMobile', { mobile, captcha, env, }, undefined, true); this.publish(); } async bindByEmail(email, captcha) { const env = await this.environment.getEnv(); await this.cache.exec('bindByEmail', { email, captcha, env, }, undefined, true); this.publish(); } async loginWebByMpToken(mpToken) { const env = await this.environment.getEnv(); const { result } = await this.cache.exec('loginWebByMpToken', { mpToken, env, }, undefined, true); this.tokenValue = result; await this.storage.save(constants_1.LOCAL_STORAGE_KEYS.token, result); this.publish(); this.checkNeedSetPassword(); } async loginByWechatInWebEnv(wechatLoginId) { const env = await this.environment.getEnv(); const { result } = await this.cache.exec('loginByWechat', { env: env, wechatLoginId, }); this.tokenValue = result; await this.storage.save(constants_1.LOCAL_STORAGE_KEYS.token, result); this.publish(); this.checkNeedSetPassword(); } async loginByOAuth(code, state) { const env = await this.environment.getEnv(); const { result } = await this.cache.exec('loginByOauth', { env: env, code, state, }); this.tokenValue = result; await this.storage.save(constants_1.LOCAL_STORAGE_KEYS.token, result); this.publish(); this.checkNeedSetPassword(); } async loginWechat(code, params) { const env = await this.environment.getEnv(); const { result } = await this.cache.exec('loginWechat', { code, env: env, wechatLoginId: params?.wechatLoginId, }); this.tokenValue = result; await this.storage.save(constants_1.LOCAL_STORAGE_KEYS.token, result); this.publish(); this.checkNeedSetPassword(); } async loginWechatMp() { const { code } = await wx.login(); const env = await this.environment.getEnv(); const { result } = await this.cache.exec('loginWechatMp', { code, env: env, }); this.tokenValue = result; await this.storage.save(constants_1.LOCAL_STORAGE_KEYS.token, result); this.publish(); this.checkNeedSetPassword(); } async loginWechatNative(code) { const env = await this.environment.getEnv(); const { result } = await this.cache.exec('loginWechatNative', { code, env: env, }); this.tokenValue = result; await this.storage.save(constants_1.LOCAL_STORAGE_KEYS.token, result); this.publish(); this.checkNeedSetPassword(); } async syncUserInfoWechatMp() { // 2.27.1及以上版本不再支持getUserProfile(返回头像为【灰色头像】,昵称为【微信用户】) const info = await wx.getUserProfile({ desc: '同步微信昵称和头像信息', }); const { userInfo: { nickName: nickname, avatarUrl }, encryptedData, signature, iv, } = info; await this.cache.exec('syncUserInfoWechatMp', { nickname, avatarUrl, encryptedData, signature, iv, }); this.publish(); } async logout(dontPublish) { await this.cache.exec('logout', { tokenValue: this.tokenValue, }, undefined, undefined, true); this.removeToken(dontPublish); } removeToken(dontPublish) { this.tokenValue = undefined; this.storage.remove(constants_1.LOCAL_STORAGE_KEYS.token); if (!dontPublish) { this.publish(); } } getTokenValue() { if (this.tokenValue === '') { throw new Exception_2.OakUserInfoLoadingException(); } return this.tokenValue; } getToken(allowUnloggedIn) { if (this.tokenValue === '') { throw new Exception_2.OakUserInfoLoadingException(); } if (this.tokenValue) { const token = this.cache.get('token', { data: (0, lodash_1.cloneDeep)(Projection_1.tokenProjection), filter: { value: this.tokenValue, }, })[0]; if (!token) { if (allowUnloggedIn) { return undefined; } throw new Exception_2.OakUserInfoLoadingException(); } return token; } if (allowUnloggedIn) { return undefined; } throw new Exception_1.OakUnloggedInException(); } getUserId(allowUnloggedIn) { const token = this.getToken(allowUnloggedIn); if (token?.userId) { return token.userId; } } // getUserInfo 不要求登录 getUserInfo() { const token = this.getToken(true); if (token?.user) { return token.user; } } isRoot() { const token = this.getToken(true); return !!token?.user?.isRoot; } /** * 这个是指token的player到底是不是root * @returns */ isReallyRoot() { const token = this.getToken(true); return !!token?.player?.isRoot; } isSelf() { const token = this.getToken(); return token?.playerId === token?.userId; } async sendCaptcha(origin, content, type) { const env = await this.environment.getEnv(); if (origin === 'mobile') { const { result } = await this.cache.exec('sendCaptchaByMobile', { mobile: content, env: env, type, }); return result; } else { const { result } = await this.cache.exec('sendCaptchaByEmail', { email: content, env: env, type, }); return result; } } async switchTo(userId) { const currentUserId = this.getUserId(); if (currentUserId === userId) { throw new Exception_1.OakPreConditionUnsetException('您已经是当前用户'); } await this.cache.exec('switchTo', { userId, }); this.publish(); } async refreshWechatPublicUserInfo() { await this.cache.exec('refreshWechatPublicUserInfo', {}); } async getWechatMpUserPhoneNumber(code) { const env = await this.environment.getEnv(); await this.cache.exec('getWechatMpUserPhoneNumber', { code, env: env, }); } async wakeupParasite(id) { const env = await this.environment.getEnv(); const { result } = await this.cache.exec('wakeupParasite', { id, env: env, }); this.tokenValue = result; await this.storage.save(constants_1.LOCAL_STORAGE_KEYS.token, result); this.publish(); } needVerifyPassword() { const user = this.getUserInfo(); const { system } = this.application.getApplication(); const { Security } = system.config; if (Security && ['strong', 'medium'].includes(Security.level)) { // 对于安全要求中高的系统,需要检查其验证密码时间 const stamp = Date.now() - Security.passwordVerifyGap; return user?.hasPassword && user.verifyPasswordAt < stamp; } } async verifyPassword(password) { const env = this.environment.getEnv(); await this.cache.exec('verifyPassword', { password, env, }); } addIgnoreException(clazz) { if (!this.ignoreExceptionList.includes(clazz)) { this.ignoreExceptionList.push(clazz); } } removeIgnoreException(clazz) { this.ignoreExceptionList = this.ignoreExceptionList.filter((c) => c !== clazz); } } exports.Token = Token;