UNPKG

@soundsright/user

Version:

soundsright user sdk

357 lines (356 loc) 14.1 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.UserEvent = void 0; const events_1 = require("events"); const js_cookie_1 = __importDefault(require("js-cookie")); const jwt_decode_1 = __importDefault(require("jwt-decode")); const connector_1 = __importStar(require("@soundsright/connector")); const utils_1 = require("@soundsright/utils"); const invite_1 = __importDefault(require("@soundsright/invite")); const types_1 = require("./types"); __exportStar(require("./types"), exports); const COOKIE_KEY_ACCESS_TOKEN = 'ACCESS_TOKEN'; const COOKIE_KEY_REFRESH_TOKEN = 'REFRESH_TOKEN'; const COOKIE_KEY_REMEMBER_USER = 'REMEMBER_USER'; const COOKIE_EXPIRES_DEFAULT = 7; const ERROR_CODE_REFRESH_TOKEN_EXPIRED = 400001007; const ERROR_CODE_ACCESS_TOKEN_EXPIRED = 400001006; const ERROR_CODE_ACCESS_TOKEN_EMPTY = 400001008; exports.UserEvent = { TokenExpired: 'tokenExpired', LoginSuccess: 'loginSuccess', Logout: 'logout', UserUpdate: 'userUpdate', }; class User extends events_1.EventEmitter { constructor(auth, service) { super(); this.auth = auth; this.service = service; this.refreshing = null; service.onBeforeRequest((options) => { const headers = Object.assign(Object.assign({}, options.headers), { Authorization: this.accessToken || '' }); if (headers.refreshToken) { headers.Authorization = ''; } return Object.assign(Object.assign({}, options), { headers }); }); service.onBeforeResponse((req, res) => __awaiter(this, void 0, void 0, function* () { if (res.code === ERROR_CODE_ACCESS_TOKEN_EXPIRED || res.code === ERROR_CODE_ACCESS_TOKEN_EMPTY) { yield this.refresh().catch((e) => { if (e instanceof types_1.UnauthorizedError) { this.removeToken(); this.emit(exports.UserEvent.TokenExpired); } throw e; }); const data = yield this.service.request(req); return this.service.wrapSuccessResponse(data); } if (res.code === ERROR_CODE_REFRESH_TOKEN_EXPIRED) { this.removeToken(); this.emit(exports.UserEvent.TokenExpired); throw new types_1.UnauthorizedError(); } return res; })); } authLogin(authResult) { return __awaiter(this, void 0, void 0, function* () { const inviter = invite_1.default.getInviter(); const res = yield this.service.request({ url: '/ucenter/user/login', method: 'post', data: Object.assign(Object.assign({}, authResult), { inviter }), }); this.updateToken(res); const user = this.getCurrentUser(); this.emit(exports.UserEvent.LoginSuccess, user); return user; }); } /** * 通过第三方平台登录 * @param type - 第三方登录类型:'Google' | 'Facebook' | 'Twitter' * @returns 用户信息 */ loginByThirdPlatform(type) { return __awaiter(this, void 0, void 0, function* () { const res = yield this.auth.authByThirdPlatform(type); return this.authLogin(res); }); } /** * 通过钱包连接和签名登录 * @param options - 钱包授权的选项 * ```ts * { * connectType?: ConnectType枚举或"MetaMask"|"WalletConnect", * signMessage?: 签名消息 * } * @returns 用户信息 * ``` */ loginByWallet(options) { return __awaiter(this, void 0, void 0, function* () { const res = yield this.auth.authByWallet(options); return this.authLogin(res); }); } /** * 通过cookie记录的token进行登录 * @returns 用户信息 */ loginByCookie() { return __awaiter(this, void 0, void 0, function* () { this.accessToken = js_cookie_1.default.get(COOKIE_KEY_ACCESS_TOKEN); this.refreshToken = js_cookie_1.default.get(COOKIE_KEY_REFRESH_TOKEN); if (!this.accessToken) { yield this.refresh(); } const user = this.getCurrentUser(); this.emit(exports.UserEvent.LoginSuccess, user); return user; }); } updateToken(res) { this.accessToken = res.accessToken; this.refreshToken = res.refreshToken; const baseCookieOptions = (0, utils_1.getBaseCookieOptions)(); js_cookie_1.default.set(COOKIE_KEY_ACCESS_TOKEN, this.accessToken, baseCookieOptions); js_cookie_1.default.set(COOKIE_KEY_REFRESH_TOKEN, this.refreshToken, Object.assign(Object.assign({}, baseCookieOptions), { expires: this.getRememberDays() || undefined })); } removeToken() { this.refreshToken = undefined; this.accessToken = undefined; const baseCookieOptions = (0, utils_1.getBaseCookieOptions)(); js_cookie_1.default.remove(COOKIE_KEY_REFRESH_TOKEN, baseCookieOptions); js_cookie_1.default.remove(COOKIE_KEY_ACCESS_TOKEN, baseCookieOptions); } /** * 设置是否记住用户登录状态 * @param remember - 是否记住用户登录状态 * @param days - 记住的天数,默认为7天 */ setRememberState(remember, days = COOKIE_EXPIRES_DEFAULT) { var _a; const domain = (_a = window.location.hostname.match(/[^.]+\.([a-zA-Z]+(:\d+)*)$/)) === null || _a === void 0 ? void 0 : _a[0]; if (remember && days > 0) { js_cookie_1.default.set(COOKIE_KEY_REMEMBER_USER, days.toString(), { path: '/', domain, expires: 3650 }); } else { // cookie.remove(COOKIE_KEY_REMEMBER_USER); // alter:如果不需要默认记住登录态 js_cookie_1.default.set(COOKIE_KEY_REMEMBER_USER, '0', { path: '/', domain, expires: 3650 }); // alter:如果需要默认记住状态 } } /** * 查询记住用户状态的天数 * @returns number,返回记住的天数。如果为0,则仅在Session期有效。 */ getRememberDays() { const remember = js_cookie_1.default.get(COOKIE_KEY_REMEMBER_USER); // if (!remember) return 0; // alter:如果不需要默认记住登录态 if (!remember) return COOKIE_EXPIRES_DEFAULT; // alter:如果需要默认记住状态 return +remember; } /** * 查询是否记住用户的状态 * @returns boolean */ getRememberState() { return !!this.getRememberDays(); } _refresh() { return __awaiter(this, void 0, void 0, function* () { if (!this.refreshToken) { throw new types_1.UnauthorizedError(); } const res = yield this.service.request({ url: '/ucenter/user/refreshToken', method: 'post', headers: { Authorization: '', refreshToken: this.refreshToken, }, }); this.updateToken(res); return res; }); } /** * 刷新用户Token * @returns * ```ts * { accessToken: string, refreshToken: string } * ``` */ refresh() { return __awaiter(this, void 0, void 0, function* () { if (this.refreshing) return this.refreshing; this.refreshing = this._refresh(); const res = yield this.refreshing; this.refreshing = null; return res; }); } /** * 获取当前登录的用户基本信息 * @returns 包括 { UserCode, NickName, Picture, Email, Phone, WalletAddr, NewUser } */ getCurrentUser() { if (!this.accessToken) { return null; } try { return (0, jwt_decode_1.default)(this.accessToken).userInfo; } catch (e) { return null; } } /** * 用户退出 */ logout() { return __awaiter(this, void 0, void 0, function* () { const refreshToken = this.refreshToken; this.removeToken(); this.emit(exports.UserEvent.Logout); if (refreshToken) { yield this.service.post('/ucenter/user/logout', {}, { refreshToken, }); } }); } /** * 查询用户是否登录 * @returns boolean */ isLogin() { return !!this.accessToken; } /** * 查询用户是否已经绑定钱包 * @returns boolean */ isWalletBound() { if (!this.isLogin()) return false; return !!this.getCurrentUser().WalletAddr; } authBind(authResult) { return __awaiter(this, void 0, void 0, function* () { const res = yield this.service.post('/ucenter/user/bindAccount', authResult); this.updateToken(res); const user = this.getCurrentUser(); this.emit(exports.UserEvent.UserUpdate, user); return user; }); } /** * 绑定第三方平台账号 * @param type - 第三方登录类型:'Google' | 'Facebook' | 'Twitter' * @returns 用户信息 */ bindThirdPlatform(type) { return __awaiter(this, void 0, void 0, function* () { const res = yield this.auth.authByThirdPlatform(type); return this.authBind(res); }); } /** * 通过钱包连接和签名绑定钱包 * @param options - 钱包授权的选项 * ```ts * { * connectType?: ConnectType枚举或"MetaMask"|"WalletConnect", * signMessage?: 签名消息 * } * @returns 用户信息 * ``` */ bindWallet(options) { return __awaiter(this, void 0, void 0, function* () { const res = yield this.auth.authByWallet(options); return this.authBind(res); }); } /** * 检查用户是否具备执行合约的条件。若不符合条件,则抛出相应的异常 - 该方法应作为执行合约的前置检测方法(模板方法) * Error类型有: * - UnauthorizedError,用户未登录,需要弹出登录窗口 * - WalletNotBoundError,用户未绑定钱包,需要弹出绑定钱包 * - WalletNotConnectedError,用户未连接钱包,需要弹出钱包连接 * - WalletNotMatchError,用户已连接的钱包地址与绑定的钱包地址不匹配 * 可以使用try catch 来处理相应的错误,可以通过error.name 来方便的判定类型。 * 在项目中结合界面操作逻辑,对该方法做进一步封装 * ```ts * try { * sdk.user.checkUserWeb3Condition(); * } catch (e) { * if(e.name === 'UnauthorizedError') { * // do something * } * ... * } * ``` */ checkUserWeb3Condition() { if (!this.isLogin()) { throw new types_1.UnauthorizedError(); } const user = this.getCurrentUser(); if (!user.WalletAddr) { throw new types_1.WalletNotBoundError(); } const connector = connector_1.default.getInstance(); if (!connector.state.connected) { throw new connector_1.WalletNotConnectedError(); } if (connector.state.account.toLowerCase() !== user.WalletAddr.toLowerCase()) { throw new types_1.WalletNotMatchError(); } } } exports.default = User;