@zestlabs-io/react-native-zest-mobile
Version:
ZEST Labs Mobility Platform plugin for React Native
210 lines (209 loc) • 8.66 kB
JavaScript
"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;