UNPKG

@zestlabs-io/react-native-zest-mobile

Version:

ZEST Labs Mobility Platform plugin for React Native

210 lines (209 loc) 8.66 kB
"use strict"; 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.AuthBridge = exports.AuthUserChanged = exports.AuthLoggedOut = exports.AuthLoggedIn = void 0; /// <reference types="react-native-app-auth" /> //@ts-check const react_native_app_auth_1 = require("react-native-app-auth"); const jwt_decode_1 = __importDefault(require("jwt-decode")); const events_1 = require("events"); const zdb_1 = __importDefault(require("./zdb")); exports.AuthLoggedIn = 'logged_in'; exports.AuthLoggedOut = 'logged_out'; exports.AuthUserChanged = 'user_changed'; const EmptyState = { loggedIn: false, user: { idToken: {}, idTokenRAW: '' }, }; const TokenRefreshIntervalMs = 60000; class AuthBridge { constructor(config) { this.state = EmptyState; // ********************************* // Add on('event', listener) this.on = (eventName, listener) => { this._eventEmitter.on(eventName, listener); return this; }; this.removeListener = (eventName, listener) => { this._eventEmitter.removeListener(eventName, listener); }; // ********************************* // Status methods // ********************************* this.isUserLoggedIn = () => { return this.state.loggedIn && this.state.user != null && this.state.user.idToken != null && this.state.user.idToken.exp != null && new Date(this.state.user.idToken.exp * 1000).getTime() > new Date().getTime(); }; this.getAuthToken = () => { const token = 'Bearer ' + this.state.user.idTokenRAW; return token; }; this.getUserData = () => { if (this.isUserLoggedIn()) { return this.state.user; } return EmptyState.user; }; // ********************************* // Subscribe to login/logout events // ********************************* this._emit = (event, payload, error = false) => { try { this._eventEmitter.emit(event, payload, error); } catch (err) { console.log('emit error', err, event); } }; // ********************************* // Local load authentication // ********************************* this.loadAuthFromDB = () => __awaiter(this, void 0, void 0, function* () { console.log('Load auth from db'); try { const doc = yield this._authDB.get('login-data'); this._onAuthData(doc); } catch (err) { console.log(err); this.triggerAuthorization(); } }); // ********************************* // Trigger auth flow actions // ********************************* this.triggerAuthorization = () => { // console.log("Trigger Auth"); const result = react_native_app_auth_1.authorize(this._config) .then((result) => { this._onAuthSuccess(result); }) .then(() => { this._emit(exports.AuthLoggedIn, this.state.user); }) .catch((err) => this._onAuthError(err)); }; this.triggerRefresh = () => { // console.log("Trigger refresh " + JSON.stringify(this.state)); if (this.state.user && this.state.user.refreshToken) { const bridge = this; const result = react_native_app_auth_1.refresh(this._config, { refreshToken: this.state.user.refreshToken, }) .then((result) => { this._onAuthSuccess(result); }) .catch((err) => this._onRefreshError(err)); } }; this.triggerLogout = () => __awaiter(this, void 0, void 0, function* () { try { const result = yield react_native_app_auth_1.revoke(this._config, { tokenToRevoke: this.state.accessToken, sendClientId: true, }); } catch (err) { // console.log(err); } this._logoutUser(); }); // ********************************* // Helper data handling methods // ********************************* this._onAuthData = (data) => { if (data !== undefined && data.accessTokenExpirationDate !== undefined && new Date(data.accessTokenExpirationDate) > new Date()) { const bridge = this; this.state = { user: data, loggedIn: true }; this._emit(exports.AuthLoggedIn, data); return; } throw Error('Invalid or expired token'); // console.log("No data loaded " + JSON.stringify(data) + " " + new Date(data.accessTokenExpirationDate)); }; this._onAuthSuccess = (data) => { // console.log("Decode", data); const idToken = jwt_decode_1.default(data.idToken); const profile = idToken; const usr = { hasLoggedInOnce: true, accessToken: data.accessToken, accessTokenExpirationDate: data.accessTokenExpirationDate, refreshToken: data.refreshToken, idToken: idToken, idTokenRAW: data.idToken, }; const bridge = this; this._authDB .get('login-data') .then(function (doc) { return bridge._authDB.put(Object.assign({ _id: 'login-data', _rev: doc._rev }, usr)); }) .then(function (response) { // // console.log("Saved " + response); }) .catch(function (err) { // console.log("Error saving login data", err); return bridge._authDB.put(Object.assign({ _id: 'login-data' }, usr)); }); // // console.log("Dispatch loggedIn event"); this.state = { user: usr, loggedIn: true }; this._emit(exports.AuthUserChanged, this.state.user); }; this._onAuthError = (err) => { console.log('Error in authentication: ' + err); this._emit(exports.AuthLoggedOut, {}); }; this._onRefreshError = (err) => { // console.log("Error in refresh: " + err); if (!this.isUserLoggedIn()) { // Reset the state if the token is expired // console.log(this.state.loggedIn, new Date(this.state.user.idToken.exp * 1000).getTime(), new Date().getTime()); this._logoutUser(); } }; this._logoutUser = () => __awaiter(this, void 0, void 0, function* () { this.state = EmptyState; try { const logData = yield this._authDB.get('login-data'); this._authDB.remove(logData); } catch (err) { } this._emit(exports.AuthLoggedOut, {}); }); this._runRefresh = () => { if (this.isUserLoggedIn()) { this.triggerRefresh(); } const bridge = this; setTimeout(() => { bridge._runRefresh(); }, TokenRefreshIntervalMs); }; this._authDB = new zdb_1.default('_auth', { adapter: 'react-native-sqlite' }); this._config = config; this._eventEmitter = new events_1.EventEmitter(); this._runRefresh(); } } exports.AuthBridge = AuthBridge;