123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608 |
- "use strict";
- var _util = require("util");
- var _triggers = require("./triggers");
- var _logger = require("./logger");
- var _RestQuery = _interopRequireDefault(require("./RestQuery"));
- var _RestWrite = _interopRequireDefault(require("./RestWrite"));
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
- function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
- function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
- function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
- function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
- function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
- const Parse = require('parse/node');
- function Auth({
- config,
- cacheController = undefined,
- isMaster = false,
- isMaintenance = false,
- isReadOnly = false,
- user,
- installationId
- }) {
- this.config = config;
- this.cacheController = cacheController || config && config.cacheController;
- this.installationId = installationId;
- this.isMaster = isMaster;
- this.isMaintenance = isMaintenance;
- this.user = user;
- this.isReadOnly = isReadOnly;
-
-
- this.userRoles = [];
- this.fetchedRoles = false;
- this.rolePromise = null;
- }
- Auth.prototype.isUnauthenticated = function () {
- if (this.isMaster) {
- return false;
- }
- if (this.isMaintenance) {
- return false;
- }
- if (this.user) {
- return false;
- }
- return true;
- };
- function master(config) {
- return new Auth({
- config,
- isMaster: true
- });
- }
- function maintenance(config) {
- return new Auth({
- config,
- isMaintenance: true
- });
- }
- function readOnly(config) {
- return new Auth({
- config,
- isMaster: true,
- isReadOnly: true
- });
- }
- function nobody(config) {
- return new Auth({
- config,
- isMaster: false
- });
- }
- function shouldUpdateSessionExpiry(config, session) {
- const resetAfter = config.sessionLength / 2;
- const lastUpdated = new Date(session === null || session === void 0 ? void 0 : session.updatedAt);
- const skipRange = new Date();
- skipRange.setTime(skipRange.getTime() - resetAfter * 1000);
- return lastUpdated <= skipRange;
- }
- const throttle = {};
- const renewSessionIfNeeded = async ({
- config,
- session,
- sessionToken
- }) => {
- if (!(config !== null && config !== void 0 && config.extendSessionOnUse)) {
- return;
- }
- clearTimeout(throttle[sessionToken]);
- throttle[sessionToken] = setTimeout(async () => {
- try {
- if (!session) {
- const query = await (0, _RestQuery.default)({
- method: _RestQuery.default.Method.get,
- config,
- auth: master(config),
- runBeforeFind: false,
- className: '_Session',
- restWhere: {
- sessionToken
- },
- restOptions: {
- limit: 1
- }
- });
- const {
- results
- } = await query.execute();
- session = results[0];
- }
- if (!shouldUpdateSessionExpiry(config, session) || !session) {
- return;
- }
- const expiresAt = config.generateSessionExpiresAt();
- await new _RestWrite.default(config, master(config), '_Session', {
- objectId: session.objectId
- }, {
- expiresAt: Parse._encode(expiresAt)
- }).execute();
- } catch (e) {
- if ((e === null || e === void 0 ? void 0 : e.code) !== Parse.Error.OBJECT_NOT_FOUND) {
- _logger.logger.error('Could not update session expiry: ', e);
- }
- }
- }, 500);
- };
- const getAuthForSessionToken = async function ({
- config,
- cacheController,
- sessionToken,
- installationId
- }) {
- cacheController = cacheController || config && config.cacheController;
- if (cacheController) {
- const userJSON = await cacheController.user.get(sessionToken);
- if (userJSON) {
- const cachedUser = Parse.Object.fromJSON(userJSON);
- renewSessionIfNeeded({
- config,
- sessionToken
- });
- return Promise.resolve(new Auth({
- config,
- cacheController,
- isMaster: false,
- installationId,
- user: cachedUser
- }));
- }
- }
- let results;
- if (config) {
- const restOptions = {
- limit: 1,
- include: 'user'
- };
- const RestQuery = require('./RestQuery');
- const query = await RestQuery({
- method: RestQuery.Method.get,
- config,
- runBeforeFind: false,
- auth: master(config),
- className: '_Session',
- restWhere: {
- sessionToken
- },
- restOptions
- });
- results = (await query.execute()).results;
- } else {
- results = (await new Parse.Query(Parse.Session).limit(1).include('user').equalTo('sessionToken', sessionToken).find({
- useMasterKey: true
- })).map(obj => obj.toJSON());
- }
- if (results.length !== 1 || !results[0]['user']) {
- throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Invalid session token');
- }
- const session = results[0];
- const now = new Date(),
- expiresAt = session.expiresAt ? new Date(session.expiresAt.iso) : undefined;
- if (expiresAt < now) {
- throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'Session token is expired.');
- }
- const obj = session.user;
- if (typeof obj['objectId'] === 'string' && obj['objectId'].startsWith('role:')) {
- throw new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'Invalid object ID.');
- }
- delete obj.password;
- obj['className'] = '_User';
- obj['sessionToken'] = sessionToken;
- if (cacheController) {
- cacheController.user.put(sessionToken, obj);
- }
- renewSessionIfNeeded({
- config,
- session,
- sessionToken
- });
- const userObject = Parse.Object.fromJSON(obj);
- return new Auth({
- config,
- cacheController,
- isMaster: false,
- installationId,
- user: userObject
- });
- };
- var getAuthForLegacySessionToken = async function ({
- config,
- sessionToken,
- installationId
- }) {
- var restOptions = {
- limit: 1
- };
- const RestQuery = require('./RestQuery');
- var query = await RestQuery({
- method: RestQuery.Method.get,
- config,
- runBeforeFind: false,
- auth: master(config),
- className: '_User',
- restWhere: {
- _session_token: sessionToken
- },
- restOptions
- });
- return query.execute().then(response => {
- var results = response.results;
- if (results.length !== 1) {
- throw new Parse.Error(Parse.Error.INVALID_SESSION_TOKEN, 'invalid legacy session token');
- }
- const obj = results[0];
- obj.className = '_User';
- const userObject = Parse.Object.fromJSON(obj);
- return new Auth({
- config,
- isMaster: false,
- installationId,
- user: userObject
- });
- });
- };
- Auth.prototype.getUserRoles = function () {
- if (this.isMaster || this.isMaintenance || !this.user) {
- return Promise.resolve([]);
- }
- if (this.fetchedRoles) {
- return Promise.resolve(this.userRoles);
- }
- if (this.rolePromise) {
- return this.rolePromise;
- }
- this.rolePromise = this._loadRoles();
- return this.rolePromise;
- };
- Auth.prototype.getRolesForUser = async function () {
-
- const results = [];
- if (this.config) {
- const restWhere = {
- users: {
- __type: 'Pointer',
- className: '_User',
- objectId: this.user.id
- }
- };
- const RestQuery = require('./RestQuery');
- const query = await RestQuery({
- method: RestQuery.Method.find,
- runBeforeFind: false,
- config: this.config,
- auth: master(this.config),
- className: '_Role',
- restWhere
- });
- await query.each(result => results.push(result));
- } else {
- await new Parse.Query(Parse.Role).equalTo('users', this.user).each(result => results.push(result.toJSON()), {
- useMasterKey: true
- });
- }
- return results;
- };
- Auth.prototype._loadRoles = async function () {
- if (this.cacheController) {
- const cachedRoles = await this.cacheController.role.get(this.user.id);
- if (cachedRoles != null) {
- this.fetchedRoles = true;
- this.userRoles = cachedRoles;
- return cachedRoles;
- }
- }
-
- const results = await this.getRolesForUser();
- if (!results.length) {
- this.userRoles = [];
- this.fetchedRoles = true;
- this.rolePromise = null;
- this.cacheRoles();
- return this.userRoles;
- }
- const rolesMap = results.reduce((m, r) => {
- m.names.push(r.name);
- m.ids.push(r.objectId);
- return m;
- }, {
- ids: [],
- names: []
- });
-
- const roleNames = await this._getAllRolesNamesForRoleIds(rolesMap.ids, rolesMap.names);
- this.userRoles = roleNames.map(r => {
- return 'role:' + r;
- });
- this.fetchedRoles = true;
- this.rolePromise = null;
- this.cacheRoles();
- return this.userRoles;
- };
- Auth.prototype.cacheRoles = function () {
- if (!this.cacheController) {
- return false;
- }
- this.cacheController.role.put(this.user.id, Array(...this.userRoles));
- return true;
- };
- Auth.prototype.clearRoleCache = function (sessionToken) {
- if (!this.cacheController) {
- return false;
- }
- this.cacheController.role.del(this.user.id);
- this.cacheController.user.del(sessionToken);
- return true;
- };
- Auth.prototype.getRolesByIds = async function (ins) {
- const results = [];
-
- if (!this.config) {
- await new Parse.Query(Parse.Role).containedIn('roles', ins.map(id => {
- const role = new Parse.Object(Parse.Role);
- role.id = id;
- return role;
- })).each(result => results.push(result.toJSON()), {
- useMasterKey: true
- });
- } else {
- const roles = ins.map(id => {
- return {
- __type: 'Pointer',
- className: '_Role',
- objectId: id
- };
- });
- const restWhere = {
- roles: {
- $in: roles
- }
- };
- const RestQuery = require('./RestQuery');
- const query = await RestQuery({
- method: RestQuery.Method.find,
- config: this.config,
- runBeforeFind: false,
- auth: master(this.config),
- className: '_Role',
- restWhere
- });
- await query.each(result => results.push(result));
- }
- return results;
- };
- Auth.prototype._getAllRolesNamesForRoleIds = function (roleIDs, names = [], queriedRoles = {}) {
- const ins = roleIDs.filter(roleID => {
- const wasQueried = queriedRoles[roleID] !== true;
- queriedRoles[roleID] = true;
- return wasQueried;
- });
-
- if (ins.length == 0) {
- return Promise.resolve([...new Set(names)]);
- }
- return this.getRolesByIds(ins).then(results => {
-
- if (!results.length) {
- return Promise.resolve(names);
- }
-
- const resultMap = results.reduce((memo, role) => {
- memo.names.push(role.name);
- memo.ids.push(role.objectId);
- return memo;
- }, {
- ids: [],
- names: []
- });
-
- names = names.concat(resultMap.names);
-
- return this._getAllRolesNamesForRoleIds(resultMap.ids, names, queriedRoles);
- }).then(names => {
- return Promise.resolve([...new Set(names)]);
- });
- };
- const findUsersWithAuthData = (config, authData) => {
- const providers = Object.keys(authData);
- const query = providers.reduce((memo, provider) => {
- if (!authData[provider] || authData && !authData[provider].id) {
- return memo;
- }
- const queryKey = `authData.${provider}.id`;
- const query = {};
- query[queryKey] = authData[provider].id;
- memo.push(query);
- return memo;
- }, []).filter(q => {
- return typeof q !== 'undefined';
- });
- return query.length > 0 ? config.database.find('_User', {
- $or: query
- }, {
- limit: 2
- }) : Promise.resolve([]);
- };
- const hasMutatedAuthData = (authData, userAuthData) => {
- if (!userAuthData) return {
- hasMutatedAuthData: true,
- mutatedAuthData: authData
- };
- const mutatedAuthData = {};
- Object.keys(authData).forEach(provider => {
-
- if (provider === 'anonymous') return;
- const providerData = authData[provider];
- const userProviderAuthData = userAuthData[provider];
- if (!(0, _util.isDeepStrictEqual)(providerData, userProviderAuthData)) {
- mutatedAuthData[provider] = providerData;
- }
- });
- const hasMutatedAuthData = Object.keys(mutatedAuthData).length !== 0;
- return {
- hasMutatedAuthData,
- mutatedAuthData
- };
- };
- const checkIfUserHasProvidedConfiguredProvidersForLogin = (req = {}, authData = {}, userAuthData = {}, config) => {
- const savedUserProviders = Object.keys(userAuthData).map(provider => ({
- name: provider,
- adapter: config.authDataManager.getValidatorForProvider(provider).adapter
- }));
- const hasProvidedASoloProvider = savedUserProviders.some(provider => provider && provider.adapter && provider.adapter.policy === 'solo' && authData[provider.name]);
-
-
-
- if (hasProvidedASoloProvider) {
- return;
- }
- const additionProvidersNotFound = [];
- const hasProvidedAtLeastOneAdditionalProvider = savedUserProviders.some(provider => {
- let policy = provider.adapter.policy;
- if (typeof policy === 'function') {
- const requestObject = {
- ip: req.config.ip,
- user: req.auth.user,
- master: req.auth.isMaster
- };
- policy = policy.call(provider.adapter, requestObject, userAuthData[provider.name]);
- }
- if (policy === 'additional') {
- if (authData[provider.name]) {
- return true;
- } else {
-
- additionProvidersNotFound.push(provider.name);
- }
- }
- });
- if (hasProvidedAtLeastOneAdditionalProvider || !additionProvidersNotFound.length) {
- return;
- }
- throw new Parse.Error(Parse.Error.OTHER_CAUSE, `Missing additional authData ${additionProvidersNotFound.join(',')}`);
- };
- const handleAuthDataValidation = async (authData, req, foundUser) => {
- let user;
- if (foundUser) {
- user = Parse.User.fromJSON(_objectSpread({
- className: '_User'
- }, foundUser));
-
- } else if (req.auth && req.auth.user && typeof req.getUserId === 'function' && req.getUserId() === req.auth.user.id || req.auth && req.auth.isMaster && typeof req.getUserId === 'function' && req.getUserId()) {
- user = new Parse.User();
- user.id = req.auth.isMaster ? req.getUserId() : req.auth.user.id;
- await user.fetch({
- useMasterKey: true
- });
- }
- const {
- updatedObject
- } = req.buildParseObjects();
- const requestObject = (0, _triggers.getRequestObject)(undefined, req.auth, updatedObject, user, req.config);
-
-
- const acc = {
- authData: {},
- authDataResponse: {}
- };
- const authKeys = Object.keys(authData).sort();
- for (const provider of authKeys) {
- let method = '';
- try {
- if (authData[provider] === null) {
- acc.authData[provider] = null;
- continue;
- }
- const {
- validator
- } = req.config.authDataManager.getValidatorForProvider(provider);
- const authProvider = (req.config.auth || {})[provider] || {};
- if (!validator || authProvider.enabled === false) {
- throw new Parse.Error(Parse.Error.UNSUPPORTED_SERVICE, 'This authentication method is unsupported.');
- }
- let validationResult = await validator(authData[provider], req, user, requestObject);
- method = validationResult && validationResult.method;
- requestObject.triggerName = method;
- if (validationResult && validationResult.validator) {
- validationResult = await validationResult.validator();
- }
- if (!validationResult) {
- acc.authData[provider] = authData[provider];
- continue;
- }
- if (!Object.keys(validationResult).length) {
- acc.authData[provider] = authData[provider];
- continue;
- }
- if (validationResult.response) {
- acc.authDataResponse[provider] = validationResult.response;
- }
-
- if (!validationResult.doNotSave) {
- acc.authData[provider] = validationResult.save || authData[provider];
- }
- } catch (err) {
- const e = (0, _triggers.resolveError)(err, {
- code: Parse.Error.SCRIPT_FAILED,
- message: 'Auth failed. Unknown error.'
- });
- const userString = req.auth && req.auth.user ? req.auth.user.id : req.data.objectId || undefined;
- _logger.logger.error(`Failed running auth step ${method} for ${provider} for user ${userString} with Error: ` + JSON.stringify(e), {
- authenticationStep: method,
- error: e,
- user: userString,
- provider
- });
- throw e;
- }
- }
- return acc;
- };
- module.exports = {
- Auth,
- master,
- maintenance,
- nobody,
- readOnly,
- shouldUpdateSessionExpiry,
- getAuthForSessionToken,
- getAuthForLegacySessionToken,
- findUsersWithAuthData,
- hasMutatedAuthData,
- checkIfUserHasProvidedConfiguredProvidersForLogin,
- handleAuthDataValidation
- };
|