Skip to content

Commit

Permalink
feat: dry handleAuthData for safer code maintenance in the futur
Browse files Browse the repository at this point in the history
  • Loading branch information
Moumouls committed Mar 17, 2024
1 parent 901aaf8 commit 1b492a9
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 22 deletions.
35 changes: 31 additions & 4 deletions spec/AuthenticationAdaptersV2.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,33 @@ describe('Auth Adapter features', () => {
expect(baseAdapter2.validateAuthData).toHaveBeenCalledTimes(2);
});

it('should not perform authData validation twice when data mutated', async () => {
spyOn(baseAdapter, 'validateAuthData').and.resolveTo({});
await reconfigureServer({
auth: { baseAdapter },
allowExpiredAuthDataToken: false,
});

const user = new Parse.User();

await user.save({
authData: {
baseAdapter: { id: 'baseAdapter', token: "sometoken1" },
},
});

expect(baseAdapter.validateAuthData).toHaveBeenCalledTimes(1);

const user2 = new Parse.User();
await user2.save({
authData: {
baseAdapter: { id: 'baseAdapter', token: "sometoken2" },
},
});

expect(baseAdapter.validateAuthData).toHaveBeenCalledTimes(2);
});

it('should require additional provider if configured', async () => {
await reconfigureServer({
auth: { baseAdapter, additionalAdapter },
Expand Down Expand Up @@ -860,7 +887,7 @@ describe('Auth Adapter features', () => {
auth: { challengeAdapter: throwInChallengeAdapter },
});
let logger = require('../lib/logger').logger;
spyOn(logger, 'error').and.callFake(() => {});
spyOn(logger, 'error').and.callFake(() => { });
await expectAsync(
requestWithExpectedError({
headers: headers,
Expand All @@ -885,7 +912,7 @@ describe('Auth Adapter features', () => {

await reconfigureServer({ auth: { modernAdapter: throwInSetup } });
logger = require('../lib/logger').logger;
spyOn(logger, 'error').and.callFake(() => {});
spyOn(logger, 'error').and.callFake(() => { });
let user = new Parse.User();
await expectAsync(
user.save({ authData: { modernAdapter: { id: 'modernAdapter' } } })
Expand All @@ -907,7 +934,7 @@ describe('Auth Adapter features', () => {

await reconfigureServer({ auth: { modernAdapter: throwInUpdate } });
logger = require('../lib/logger').logger;
spyOn(logger, 'error').and.callFake(() => {});
spyOn(logger, 'error').and.callFake(() => { });
user = new Parse.User();
await user.save({ authData: { modernAdapter: { id: 'updateAdapter' } } });
await expectAsync(
Expand Down Expand Up @@ -937,7 +964,7 @@ describe('Auth Adapter features', () => {
allowExpiredAuthDataToken: false,
});
logger = require('../lib/logger').logger;
spyOn(logger, 'error').and.callFake(() => {});
spyOn(logger, 'error').and.callFake(() => { });
user = new Parse.User();
await user.save({ authData: { modernAdapter: { id: 'modernAdapter' } } });
const user2 = new Parse.User();
Expand Down
16 changes: 8 additions & 8 deletions spec/ParseUser.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3350,7 +3350,7 @@ describe('Parse.User testing', () => {

it('should not allow updates to emailVerified', done => {
const emailAdapter = {
sendVerificationEmail: () => {},
sendVerificationEmail: () => { },
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => Promise.resolve(),
};
Expand Down Expand Up @@ -3386,7 +3386,7 @@ describe('Parse.User testing', () => {

it('should not retrieve hidden fields on GET users/me (#3432)', done => {
const emailAdapter = {
sendVerificationEmail: () => {},
sendVerificationEmail: () => { },
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => Promise.resolve(),
};
Expand Down Expand Up @@ -3429,7 +3429,7 @@ describe('Parse.User testing', () => {

it('should not retrieve hidden fields on GET users/id (#3432)', done => {
const emailAdapter = {
sendVerificationEmail: () => {},
sendVerificationEmail: () => { },
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => Promise.resolve(),
};
Expand Down Expand Up @@ -3477,7 +3477,7 @@ describe('Parse.User testing', () => {

it('should not retrieve hidden fields on login (#3432)', done => {
const emailAdapter = {
sendVerificationEmail: () => {},
sendVerificationEmail: () => { },
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => Promise.resolve(),
};
Expand Down Expand Up @@ -3521,7 +3521,7 @@ describe('Parse.User testing', () => {

it('should not allow updates to hidden fields', async () => {
const emailAdapter = {
sendVerificationEmail: () => {},
sendVerificationEmail: () => { },
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => Promise.resolve(),
};
Expand All @@ -3546,7 +3546,7 @@ describe('Parse.User testing', () => {

it('should allow updates to fields with maintenanceKey', async () => {
const emailAdapter = {
sendVerificationEmail: () => {},
sendVerificationEmail: () => { },
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => Promise.resolve(),
};
Expand Down Expand Up @@ -3576,8 +3576,8 @@ describe('Parse.User testing', () => {
expect(e.code).toBe(Parse.Error.OBJECT_NOT_FOUND);
expect(
e.message === 'Invalid username/password.' ||
e.message ===
'Your account is locked due to multiple failed login attempts. Please try again after 1 minute(s)'
e.message ===
'Your account is locked due to multiple failed login attempts. Please try again after 1 minute(s)'
).toBeTrue();
}
}
Expand Down
18 changes: 8 additions & 10 deletions src/RestWrite.js
Original file line number Diff line number Diff line change
Expand Up @@ -523,10 +523,15 @@ RestWrite.prototype.handleAuthData = async function (authData) {
const r = await Auth.findUsersWithAuthData(this.config, authData);
const results = this.filteredObjectsByACL(r);

if (results.length > 1) {
const userId = this.getUserId();
const userResult = results[0];

const foundUserIsNotCurrentUser = userId && userResult && userId !== userResult.objectId;

if (results.length > 1 || foundUserIsNotCurrentUser) {
// To avoid https://github.com/parse-community/parse-server/security/advisories/GHSA-8w3j-g983-8jh5
// Let's run some validation before throwing
await Auth.handleAuthDataValidation(authData, this, results[0]);
await Auth.handleAuthDataValidation(authData, this, userResult);
throw new Parse.Error(Parse.Error.ACCOUNT_ALREADY_LINKED, 'this auth is already used');
}

Expand All @@ -544,13 +549,6 @@ RestWrite.prototype.handleAuthData = async function (authData) {

// User found with provided authData
if (results.length === 1) {
const userId = this.getUserId();
const userResult = results[0];
// Prevent duplicate authData id
if (userId && userId !== userResult.objectId) {
await Auth.handleAuthDataValidation(authData, this, results[0]);
throw new Parse.Error(Parse.Error.ACCOUNT_ALREADY_LINKED, 'this auth is already used');
}

this.storage.authProvider = Object.keys(authData).join(',');

Expand Down Expand Up @@ -1311,7 +1309,7 @@ RestWrite.prototype.handleInstallation = function () {
throw new Parse.Error(
132,
'Must specify installationId when deviceToken ' +
'matches multiple Installation objects'
'matches multiple Installation objects'
);
} else {
// Multiple device token matches and we specified an installation ID,
Expand Down

0 comments on commit 1b492a9

Please sign in to comment.