mongodb-stitch
Version:
[](https://gitter.im/mongodb/stitch?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
373 lines • 15.6 kB
JavaScript
import { EJSON } from "bson";
import { wrapDecodingError } from "../../internal/common/StitchErrorUtils";
import Headers from "../../internal/net/Headers";
import Method from "../../internal/net/Method";
import Stream from "../../internal/net/Stream";
import { StitchAuthDocRequest } from "../../internal/net/StitchAuthDocRequest";
import { StitchAuthRequest } from "../../internal/net/StitchAuthRequest";
import { StitchDocRequest } from "../../internal/net/StitchDocRequest";
import StitchClientError from "../../StitchClientError";
import { StitchClientErrorCode } from "../../StitchClientErrorCode";
import StitchError from "../../StitchError";
import StitchRequestError from "../../StitchRequestError";
import { StitchRequestErrorCode } from "../../StitchRequestErrorCode";
import StitchServiceError from "../../StitchServiceError";
import { StitchServiceErrorCode } from "../../StitchServiceErrorCode";
import StitchAuthResponseCredential from "../providers/internal/StitchAuthResponseCredential";
import AccessTokenRefresher from "./AccessTokenRefresher";
import AuthInfo from "./AuthInfo";
import JWT from "./JWT";
import ApiAuthInfo from "./models/ApiAuthInfo";
import ApiCoreUserProfile from "./models/ApiCoreUserProfile";
import { readFromStorage, writeToStorage } from "./models/StoreAuthInfo";
var OPTIONS = "options";
var DEVICE = "device";
var CoreStitchAuth = (function () {
function CoreStitchAuth(requestClient, authRoutes, storage, useTokenRefresher) {
if (useTokenRefresher === void 0) { useTokenRefresher = true; }
this.requestClient = requestClient;
this.authRoutes = authRoutes;
this.storage = storage;
var info;
try {
info = readFromStorage(storage);
}
catch (e) {
throw new StitchClientError(StitchClientErrorCode.CouldNotLoadPersistedAuthInfo);
}
if (info === undefined) {
this.authInfo = AuthInfo.empty();
}
else {
this.authInfo = info;
}
this.prepUser();
if (useTokenRefresher) {
this.accessTokenRefresher = new AccessTokenRefresher(this);
this.accessTokenRefresher.run();
}
}
Object.defineProperty(CoreStitchAuth.prototype, "isLoggedIn", {
get: function () {
return this.currentUser !== undefined;
},
enumerable: true,
configurable: true
});
Object.defineProperty(CoreStitchAuth.prototype, "user", {
get: function () {
return this.currentUser;
},
enumerable: true,
configurable: true
});
CoreStitchAuth.prototype.doAuthenticatedRequest = function (stitchReq) {
var _this = this;
return this.requestClient
.doRequest(this.prepareAuthRequest(stitchReq))
.catch(function (err) {
return _this.handleAuthFailure(err, stitchReq);
});
};
CoreStitchAuth.prototype.doAuthenticatedRequestWithDecoder = function (stitchReq, decoder) {
return this.doAuthenticatedRequest(stitchReq)
.then(function (response) {
var obj = EJSON.parse(response.body, { strict: false });
if (decoder) {
return decoder.decode(obj);
}
return obj;
})
.catch(function (err) {
throw wrapDecodingError(err);
});
};
CoreStitchAuth.prototype.openAuthenticatedEventStream = function (stitchReq, open) {
var _this = this;
if (open === void 0) { open = true; }
if (!this.isLoggedIn) {
throw new StitchClientError(StitchClientErrorCode.MustAuthenticateFirst);
}
var authToken;
if (stitchReq.useRefreshToken) {
authToken = this.authInfo.refreshToken;
}
else {
authToken = this.authInfo.accessToken;
}
return this.requestClient.doStreamRequest(stitchReq.builder
.withPath(stitchReq.path + "&stitch_at=" + authToken)
.build(), open, function () { return _this.openAuthenticatedEventStream(stitchReq, false); })
.catch(function (err) {
return _this.handleAuthFailureForEventStream(err, stitchReq, open);
});
};
CoreStitchAuth.prototype.openAuthenticatedStreamWithDecoder = function (stitchReq, decoder) {
return this.openAuthenticatedEventStream(stitchReq)
.then(function (eventStream) {
return new Stream(eventStream, decoder);
});
};
CoreStitchAuth.prototype.refreshAccessToken = function () {
var _this = this;
var reqBuilder = new StitchAuthRequest.Builder()
.withRefreshToken()
.withPath(this.authRoutes.sessionRoute)
.withMethod(Method.POST);
return this.doAuthenticatedRequest(reqBuilder.build()).then(function (response) {
try {
var partialInfo = ApiAuthInfo.fromJSON(JSON.parse(response.body));
_this.authInfo = _this.authInfo.merge(partialInfo);
}
catch (err) {
throw new StitchRequestError(err, StitchRequestErrorCode.DECODING_ERROR);
}
try {
writeToStorage(_this.authInfo, _this.storage);
}
catch (err) {
throw new StitchClientError(StitchClientErrorCode.CouldNotPersistAuthInfo);
}
});
};
CoreStitchAuth.prototype.loginWithCredentialInternal = function (credential) {
if (credential instanceof StitchAuthResponseCredential) {
return this.processLogin(credential, credential.authInfo, credential.asLink);
}
if (!this.isLoggedIn) {
return this.doLogin(credential, false);
}
if (credential.providerCapabilities.reusesExistingSession) {
if (credential.providerType === this.currentUser.loggedInProviderType) {
return Promise.resolve(this.currentUser);
}
}
this.logoutInternal();
return this.doLogin(credential, false);
};
CoreStitchAuth.prototype.linkUserWithCredentialInternal = function (user, credential) {
if (this.currentUser !== undefined && user.id !== this.currentUser.id) {
return Promise.reject(new StitchClientError(StitchClientErrorCode.UserNoLongerValid));
}
return this.doLogin(credential, true);
};
CoreStitchAuth.prototype.logoutInternal = function () {
var _this = this;
if (!this.isLoggedIn) {
return Promise.resolve();
}
return this.doLogout()
.then(function () {
_this.clearAuth();
})
.catch(function () {
_this.clearAuth();
});
};
Object.defineProperty(CoreStitchAuth.prototype, "hasDeviceId", {
get: function () {
return (this.authInfo.deviceId !== undefined &&
this.authInfo.deviceId !== "" &&
this.authInfo.deviceId !== "000000000000000000000000");
},
enumerable: true,
configurable: true
});
Object.defineProperty(CoreStitchAuth.prototype, "deviceId", {
get: function () {
if (!this.hasDeviceId) {
return undefined;
}
return this.authInfo.deviceId;
},
enumerable: true,
configurable: true
});
CoreStitchAuth.prototype.prepareAuthRequest = function (stitchReq) {
if (!this.isLoggedIn) {
throw new StitchClientError(StitchClientErrorCode.MustAuthenticateFirst);
}
var newReq = stitchReq.builder;
var newHeaders = newReq.headers || {};
if (stitchReq.useRefreshToken) {
newHeaders[Headers.AUTHORIZATION] = Headers.getAuthorizationBearer(this.authInfo.refreshToken);
}
else {
newHeaders[Headers.AUTHORIZATION] = Headers.getAuthorizationBearer(this.authInfo.accessToken);
}
newReq.withHeaders(newHeaders);
return newReq.build();
};
CoreStitchAuth.prototype.handleAuthFailureForEventStream = function (ex, req, open) {
var _this = this;
if (open === void 0) { open = true; }
if (!(ex instanceof StitchServiceError) ||
ex.errorCode !== StitchServiceErrorCode.InvalidSession) {
throw ex;
}
if (req.useRefreshToken || !req.shouldRefreshOnFailure) {
this.clearAuth();
throw ex;
}
return this.tryRefreshAccessToken(req.startedAt).then(function () {
return _this.openAuthenticatedEventStream(req.builder.withShouldRefreshOnFailure(false).build(), open);
});
};
CoreStitchAuth.prototype.handleAuthFailure = function (ex, req) {
var _this = this;
if (!(ex instanceof StitchServiceError) ||
ex.errorCode !== StitchServiceErrorCode.InvalidSession) {
throw ex;
}
if (req.useRefreshToken || !req.shouldRefreshOnFailure) {
this.clearAuth();
throw ex;
}
return this.tryRefreshAccessToken(req.startedAt).then(function () {
return _this.doAuthenticatedRequest(req.builder.withShouldRefreshOnFailure(false).build());
});
};
CoreStitchAuth.prototype.tryRefreshAccessToken = function (reqStartedAt) {
if (!this.isLoggedIn) {
throw new StitchClientError(StitchClientErrorCode.LoggedOutDuringRequest);
}
try {
var jwt = JWT.fromEncoded(this.authInfo.accessToken);
if (jwt.issuedAt >= reqStartedAt) {
return Promise.resolve();
}
}
catch (e) {
}
return this.refreshAccessToken();
};
CoreStitchAuth.prototype.prepUser = function () {
if (this.authInfo.userId !== undefined) {
this.currentUser = this.userFactory.makeUser(this.authInfo.userId, this.authInfo.loggedInProviderType, this.authInfo.loggedInProviderName, this.authInfo.userProfile);
}
};
CoreStitchAuth.prototype.attachAuthOptions = function (authBody) {
var options = {};
options[DEVICE] = this.deviceInfo;
authBody[OPTIONS] = options;
};
CoreStitchAuth.prototype.doLogin = function (credential, asLinkRequest) {
var _this = this;
return this.doLoginRequest(credential, asLinkRequest)
.then(function (response) { return _this.processLoginResponse(credential, response, asLinkRequest); })
.then(function (user) {
_this.onAuthEvent();
return user;
});
};
CoreStitchAuth.prototype.doLoginRequest = function (credential, asLinkRequest) {
var reqBuilder = new StitchDocRequest.Builder();
reqBuilder.withMethod(Method.POST);
if (asLinkRequest) {
reqBuilder.withPath(this.authRoutes.getAuthProviderLinkRoute(credential.providerName));
}
else {
reqBuilder.withPath(this.authRoutes.getAuthProviderLoginRoute(credential.providerName));
}
var material = credential.material;
this.attachAuthOptions(material);
reqBuilder.withDocument(material);
if (!asLinkRequest) {
return this.requestClient.doRequest(reqBuilder.build());
}
var linkRequest = new StitchAuthDocRequest(reqBuilder.build(), reqBuilder.document);
return this.doAuthenticatedRequest(linkRequest);
};
CoreStitchAuth.prototype.processLogin = function (credential, newAuthInfo, asLinkRequest) {
var _this = this;
var oldInfo = this.authInfo;
var oldUser = this.currentUser;
newAuthInfo = this.authInfo.merge(new AuthInfo(newAuthInfo.userId, newAuthInfo.deviceId, newAuthInfo.accessToken, newAuthInfo.refreshToken, credential.providerType, credential.providerName, undefined));
this.authInfo = newAuthInfo;
this.currentUser = this.userFactory.makeUser(this.authInfo.userId, credential.providerType, credential.providerName, undefined);
return this.doGetUserProfile()
.then(function (profile) {
newAuthInfo = newAuthInfo.merge(new AuthInfo(newAuthInfo.userId, newAuthInfo.deviceId, newAuthInfo.accessToken, newAuthInfo.refreshToken, credential.providerType, credential.providerName, profile));
try {
writeToStorage(newAuthInfo, _this.storage);
}
catch (err) {
throw new StitchClientError(StitchClientErrorCode.CouldNotPersistAuthInfo);
}
_this.authInfo = newAuthInfo;
_this.currentUser = _this.userFactory.makeUser(_this.authInfo.userId, credential.providerType, credential.providerName, profile);
return _this.currentUser;
})
.catch(function (err) {
if (asLinkRequest) {
_this.authInfo = oldInfo;
_this.currentUser = oldUser;
}
else {
_this.clearAuth();
}
throw err;
});
};
CoreStitchAuth.prototype.processLoginResponse = function (credential, response, asLinkRequest) {
try {
if (!response) {
throw new StitchServiceError("the login response could not be processed for credential: " + credential + ";" +
"response was undefined");
}
if (!response.body) {
throw new StitchServiceError("response with status code " + response.statusCode + " has empty body");
}
return this.processLogin(credential, ApiAuthInfo.fromJSON(JSON.parse(response.body)), asLinkRequest);
}
catch (err) {
throw new StitchRequestError(err, StitchRequestErrorCode.DECODING_ERROR);
}
};
CoreStitchAuth.prototype.doGetUserProfile = function () {
var reqBuilder = new StitchAuthRequest.Builder();
reqBuilder.withMethod(Method.GET).withPath(this.authRoutes.profileRoute);
return this.doAuthenticatedRequest(reqBuilder.build())
.then(function (response) { return ApiCoreUserProfile.fromJSON(JSON.parse(response.body)); })
.catch(function (err) {
if (err instanceof StitchError) {
throw err;
}
else {
throw new StitchRequestError(err, StitchRequestErrorCode.DECODING_ERROR);
}
});
};
CoreStitchAuth.prototype.doLogout = function () {
var reqBuilder = new StitchAuthRequest.Builder();
reqBuilder
.withRefreshToken()
.withPath(this.authRoutes.sessionRoute)
.withMethod(Method.DELETE);
return this.doAuthenticatedRequest(reqBuilder.build()).then(function () {
return;
});
};
CoreStitchAuth.prototype.clearAuth = function () {
if (!this.isLoggedIn) {
return;
}
this.authInfo = this.authInfo.loggedOut();
try {
writeToStorage(this.authInfo, this.storage);
}
catch (e) {
throw new StitchClientError(StitchClientErrorCode.CouldNotPersistAuthInfo);
}
this.currentUser = undefined;
this.onAuthEvent();
};
CoreStitchAuth.prototype.close = function () {
if (this.accessTokenRefresher) {
this.accessTokenRefresher.stop();
}
};
return CoreStitchAuth;
}());
export default CoreStitchAuth;
//# sourceMappingURL=CoreStitchAuth.js.map