Add beforeLogin trigger with support for auth providers (#5445)

* Add beforeLogin trigger with support for auth providers

* adjust comment that boxed off beforeLogin to a negative use-case only

* add internal error to help future maintainers regarding use of beforeLogin

* let beforeLogin accept className or constructor like other hook types

* add assertions for beforeLogin trigger className validation
This commit is contained in:
Omair Vaiyani
2019-04-23 16:24:20 +01:00
committed by Arthur Cinader
parent 3e003ee9f4
commit a1e1cef6d2
6 changed files with 340 additions and 60 deletions

View File

@@ -93,7 +93,7 @@ RestWrite.prototype.execute = function() {
return this.validateAuthData();
})
.then(() => {
return this.runBeforeTrigger();
return this.runBeforeSaveTrigger();
})
.then(() => {
return this.deleteEmailResetTokenIfNeeded();
@@ -123,7 +123,7 @@ RestWrite.prototype.execute = function() {
return this.handleFollowup();
})
.then(() => {
return this.runAfterTrigger();
return this.runAfterSaveTrigger();
})
.then(() => {
return this.cleanUserAuthData();
@@ -190,7 +190,7 @@ RestWrite.prototype.validateSchema = function() {
// Runs any beforeSave triggers against this operation.
// Any change leads to our data being mutated.
RestWrite.prototype.runBeforeTrigger = function() {
RestWrite.prototype.runBeforeSaveTrigger = function() {
if (this.response) {
return;
}
@@ -251,6 +251,33 @@ RestWrite.prototype.runBeforeTrigger = function() {
});
};
RestWrite.prototype.runBeforeLoginTrigger = async function(userData) {
// Avoid doing any setup for triggers if there is no 'beforeLogin' trigger
if (
!triggers.triggerExists(
this.className,
triggers.Types.beforeLogin,
this.config.applicationId
)
) {
return;
}
// Cloud code gets a bit of extra data for its objects
const extraData = { className: this.className };
const user = triggers.inflate(extraData, userData);
// no need to return a response
await triggers.maybeRunTrigger(
triggers.Types.beforeLogin,
this.auth,
user,
null,
this.config,
this.context
);
};
RestWrite.prototype.setRequiredFieldsIfNeeded = function() {
if (this.data) {
// Add default fields
@@ -377,7 +404,7 @@ RestWrite.prototype.filteredObjectsByACL = function(objects) {
RestWrite.prototype.handleAuthData = function(authData) {
let results;
return this.findUsersWithAuthData(authData).then(r => {
return this.findUsersWithAuthData(authData).then(async r => {
results = this.filteredObjectsByACL(r);
if (results.length > 1) {
// More than 1 user with the passed id's
@@ -421,7 +448,12 @@ RestWrite.prototype.handleAuthData = function(authData) {
response: userResult,
location: this.location(),
};
// Run beforeLogin hook before storing any updates
// to authData on the db; changes to userResult
// will be ignored.
await this.runBeforeLoginTrigger(deepcopy(userResult));
}
// If we didn't change the auth data, just keep going
if (!hasMutatedAuthData) {
return;
@@ -430,7 +462,7 @@ RestWrite.prototype.handleAuthData = function(authData) {
// that can happen when token are refreshed,
// We should update the token and let the user in
// We should only check the mutated keys
return this.handleAuthDataValidation(mutatedAuthData).then(() => {
return this.handleAuthDataValidation(mutatedAuthData).then(async () => {
// IF we have a response, we'll skip the database operation / beforeSave / afterSave etc...
// we need to set it up there.
// We are supposed to have a response only on LOGIN with authData, so we skip those
@@ -441,6 +473,7 @@ RestWrite.prototype.handleAuthData = function(authData) {
this.response.response.authData[provider] =
mutatedAuthData[provider];
});
// Run the DB update directly, as 'master'
// Just update the authData part
// Then we're good for the user, early exit of sorts
@@ -1415,7 +1448,7 @@ RestWrite.prototype.runDatabaseOperation = function() {
};
// Returns nothing - doesn't wait for the trigger.
RestWrite.prototype.runAfterTrigger = function() {
RestWrite.prototype.runAfterSaveTrigger = function() {
if (!this.response || !this.response.response) {
return;
}