Skip to content

Commit a6d3ff1

Browse files
Merge pull request #7 from vizmo-vms/fix-dont-allow-nonmaster-to-update-authdata
2 parents c73874c + 8ad0f70 commit a6d3ff1

File tree

2 files changed

+63
-30
lines changed

2 files changed

+63
-30
lines changed

src/Adapters/Auth/mfa.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ class MFAAdapter extends AuthAdapter {
108108
});
109109
} else if (opts.period && typeof opts.period === 'object') {
110110
Object.keys(opts.period).forEach(method => {
111-
if (opts.period.hasOwnProperty(method) && typeof opts.period[method] === 'number') {
111+
if (typeof opts.period[method] === 'number') {
112112
this.period[method] = opts.period[method] ?? defaultPeriods[method] ?? 30;
113113
}
114114
});

src/RestWrite.js

Lines changed: 62 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,9 @@ RestWrite.prototype.ensureUniqueAuthDataId = async function () {
504504
key => this.data.authData[key] && this.data.authData[key].id
505505
);
506506

507-
if (!hasAuthDataId) { return; }
507+
if (!hasAuthDataId) {
508+
return;
509+
}
508510

509511
const r = await Auth.findUsersWithAuthData(this.config, this.data.authData);
510512
const results = this.filteredObjectsByACL(r);
@@ -547,7 +549,6 @@ RestWrite.prototype.handleAuthData = async function (authData) {
547549

548550
// User found with provided authData
549551
if (results.length === 1) {
550-
551552
this.storage.authProvider = Object.keys(authData).join(',');
552553

553554
const { hasMutatedAuthData, mutatedAuthData } = Auth.hasMutatedAuthData(
@@ -809,7 +810,9 @@ RestWrite.prototype._validateEmail = function () {
809810
};
810811

811812
RestWrite.prototype._validatePasswordPolicy = function () {
812-
if (!this.config.passwordPolicy) { return Promise.resolve(); }
813+
if (!this.config.passwordPolicy) {
814+
return Promise.resolve();
815+
}
813816
return this._validatePasswordRequirements().then(() => {
814817
return this._validatePasswordHistory();
815818
});
@@ -843,18 +846,20 @@ RestWrite.prototype._validatePasswordRequirements = function () {
843846
if (this.config.passwordPolicy.doNotAllowUsername === true) {
844847
if (this.data.username) {
845848
// username is not passed during password reset
846-
if (this.data.password.indexOf(this.data.username) >= 0)
847-
{ return Promise.reject(new Parse.Error(Parse.Error.VALIDATION_ERROR, containsUsernameError)); }
849+
if (this.data.password.indexOf(this.data.username) >= 0) {
850+
return Promise.reject(new Parse.Error(Parse.Error.VALIDATION_ERROR, containsUsernameError));
851+
}
848852
} else {
849853
// retrieve the User object using objectId during password reset
850854
return this.config.database.find('_User', { objectId: this.objectId() }).then(results => {
851855
if (results.length != 1) {
852856
throw undefined;
853857
}
854-
if (this.data.password.indexOf(results[0].username) >= 0)
855-
{ return Promise.reject(
856-
new Parse.Error(Parse.Error.VALIDATION_ERROR, containsUsernameError)
857-
); }
858+
if (this.data.password.indexOf(results[0].username) >= 0) {
859+
return Promise.reject(
860+
new Parse.Error(Parse.Error.VALIDATION_ERROR, containsUsernameError)
861+
);
862+
}
858863
return Promise.resolve();
859864
});
860865
}
@@ -878,19 +883,21 @@ RestWrite.prototype._validatePasswordHistory = function () {
878883
}
879884
const user = results[0];
880885
let oldPasswords = [];
881-
if (user._password_history)
882-
{ oldPasswords = _.take(
883-
user._password_history,
884-
this.config.passwordPolicy.maxPasswordHistory - 1
885-
); }
886+
if (user._password_history) {
887+
oldPasswords = _.take(
888+
user._password_history,
889+
this.config.passwordPolicy.maxPasswordHistory - 1
890+
);
891+
}
886892
oldPasswords.push(user.password);
887893
const newPassword = this.data.password;
888894
// compare the new password hash with all old password hashes
889895
const promises = oldPasswords.map(function (hash) {
890896
return passwordCrypto.compare(newPassword, hash).then(result => {
891-
if (result)
892-
// reject if there is a match
893-
{ return Promise.reject('REPEAT_PASSWORD'); }
897+
if (result) {
898+
// reject if there is a match
899+
return Promise.reject('REPEAT_PASSWORD');
900+
}
894901
return Promise.resolve();
895902
});
896903
});
@@ -900,14 +907,15 @@ RestWrite.prototype._validatePasswordHistory = function () {
900907
return Promise.resolve();
901908
})
902909
.catch(err => {
903-
if (err === 'REPEAT_PASSWORD')
904-
// a match was found
905-
{ return Promise.reject(
906-
new Parse.Error(
907-
Parse.Error.VALIDATION_ERROR,
908-
`New password should not be the same as last ${this.config.passwordPolicy.maxPasswordHistory} passwords.`
909-
)
910-
); }
910+
if (err === 'REPEAT_PASSWORD') {
911+
// a match was found
912+
return Promise.reject(
913+
new Parse.Error(
914+
Parse.Error.VALIDATION_ERROR,
915+
`New password should not be the same as last ${this.config.passwordPolicy.maxPasswordHistory} passwords.`
916+
)
917+
);
918+
}
911919
throw err;
912920
});
913921
});
@@ -941,10 +949,16 @@ RestWrite.prototype.createSessionTokenIfNeeded = async function () {
941949
// Get verification conditions which can be booleans or functions; the purpose of this async/await
942950
// structure is to avoid unnecessarily executing subsequent functions if previous ones fail in the
943951
// conditional statement below, as a developer may decide to execute expensive operations in them
944-
const verifyUserEmails = async () => this.config.verifyUserEmails === true || (typeof this.config.verifyUserEmails === 'function' && await Promise.resolve(this.config.verifyUserEmails(request)) === true);
945-
const preventLoginWithUnverifiedEmail = async () => this.config.preventLoginWithUnverifiedEmail === true || (typeof this.config.preventLoginWithUnverifiedEmail === 'function' && await Promise.resolve(this.config.preventLoginWithUnverifiedEmail(request)) === true);
952+
const verifyUserEmails = async () =>
953+
this.config.verifyUserEmails === true ||
954+
(typeof this.config.verifyUserEmails === 'function' &&
955+
(await Promise.resolve(this.config.verifyUserEmails(request))) === true);
956+
const preventLoginWithUnverifiedEmail = async () =>
957+
this.config.preventLoginWithUnverifiedEmail === true ||
958+
(typeof this.config.preventLoginWithUnverifiedEmail === 'function' &&
959+
(await Promise.resolve(this.config.preventLoginWithUnverifiedEmail(request))) === true);
946960
// If verification is required
947-
if (await verifyUserEmails() && await preventLoginWithUnverifiedEmail()) {
961+
if ((await verifyUserEmails()) && (await preventLoginWithUnverifiedEmail())) {
948962
this.storage.rejectSignup = true;
949963
return;
950964
}
@@ -1436,6 +1450,23 @@ RestWrite.prototype.runDatabaseOperation = function () {
14361450
`Cannot modify user ${this.query.objectId}.`
14371451
);
14381452
}
1453+
// Handle authData updates for _User class
1454+
if (
1455+
this.className === '_User' &&
1456+
this.query &&
1457+
this.data &&
1458+
Object.prototype.hasOwnProperty.call(this.data, 'authData')
1459+
) {
1460+
if (!this.auth.isMaster && !this.auth.isMaintenance) {
1461+
// For non-master key requests, remove authData from the update
1462+
delete this.data.authData;
1463+
// If no other fields to update, return early
1464+
if (Object.keys(this.data).length === 0) {
1465+
this.response = { response: {} };
1466+
return Promise.resolve();
1467+
}
1468+
}
1469+
}
14391470

14401471
if (this.className === '_Product' && this.data.download) {
14411472
this.data.downloadName = this.data.download.name;
@@ -1746,7 +1777,9 @@ RestWrite.prototype.buildParseObjects = function () {
17461777
}
17471778
let curObj = parentVal;
17481779
for (let i = 1; i < splittedKey.length - 1; i++) {
1749-
if (typeof curObj[splittedKey[i]] === 'undefined') curObj[splittedKey[i]] = {};
1780+
if (typeof curObj[splittedKey[i]] === 'undefined') {
1781+
curObj[splittedKey[i]] = {};
1782+
}
17501783
curObj = curObj[splittedKey[i]];
17511784
}
17521785
curObj[splittedKey[splittedKey.length - 1]] = data[key];

0 commit comments

Comments
 (0)