Skip to content

Commit 2cc16b4

Browse files
authored
Merge branch 'alpha' into redis-store
2 parents 3af2584 + 0f1979f commit 2cc16b4

11 files changed

+189
-10
lines changed

changelogs/CHANGELOG_alpha.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,24 @@
1+
# [6.1.0-alpha.5](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.4...6.1.0-alpha.5) (2023-03-06)
2+
3+
4+
### Bug Fixes
5+
6+
* LiveQuery can return incorrectly formatted date ([#8456](https://github.com/parse-community/parse-server/issues/8456)) ([4ce135a](https://github.com/parse-community/parse-server/commit/4ce135a4fe930776044bc8fd786a4e17a0144e03))
7+
8+
# [6.1.0-alpha.4](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.3...6.1.0-alpha.4) (2023-03-06)
9+
10+
11+
### Bug Fixes
12+
13+
* Parameters missing in `afterFind` trigger of authentication adapters ([#8458](https://github.com/parse-community/parse-server/issues/8458)) ([ce34747](https://github.com/parse-community/parse-server/commit/ce34747e8af54cb0b6b975da38f779a5955d2d59))
14+
15+
# [6.1.0-alpha.3](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.2...6.1.0-alpha.3) (2023-03-06)
16+
17+
18+
### Features
19+
20+
* Add `afterFind` trigger to authentication adapters ([#8444](https://github.com/parse-community/parse-server/issues/8444)) ([c793bb8](https://github.com/parse-community/parse-server/commit/c793bb88e7485743c7ceb65fe419cde75833ff33))
21+
122
# [6.1.0-alpha.2](https://github.com/parse-community/parse-server/compare/6.1.0-alpha.1...6.1.0-alpha.2) (2023-03-05)
223

324

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "parse-server",
3-
"version": "6.1.0-alpha.2",
3+
"version": "6.1.0-alpha.5",
44
"description": "An express module providing a Parse-compatible API server",
55
"main": "lib/index.js",
66
"repository": {

spec/AuthenticationAdaptersV2.spec.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,19 @@ describe('Auth Adapter features', () => {
5959
validateLogin: () => Promise.resolve(),
6060
};
6161

62+
const modernAdapter3 = {
63+
validateAppId: () => Promise.resolve(),
64+
validateSetUp: () => Promise.resolve(),
65+
validateUpdate: () => Promise.resolve(),
66+
validateLogin: () => Promise.resolve(),
67+
validateOptions: () => Promise.resolve(),
68+
afterFind() {
69+
return {
70+
foo: 'bar',
71+
};
72+
},
73+
};
74+
6275
const wrongAdapter = {
6376
validateAppId: () => Promise.resolve(),
6477
};
@@ -332,6 +345,30 @@ describe('Auth Adapter features', () => {
332345
expect(user.getSessionToken()).toBeDefined();
333346
});
334347

348+
it('should strip out authData if required', async () => {
349+
const spy = spyOn(modernAdapter3, 'validateOptions').and.callThrough();
350+
const afterSpy = spyOn(modernAdapter3, 'afterFind').and.callThrough();
351+
await reconfigureServer({ auth: { modernAdapter3 }, silent: false });
352+
const user = new Parse.User();
353+
await user.save({ authData: { modernAdapter3: { id: 'modernAdapter3Data' } } });
354+
await user.fetch({ sessionToken: user.getSessionToken() });
355+
const authData = user.get('authData').modernAdapter3;
356+
expect(authData).toEqual({ foo: 'bar' });
357+
for (const call of afterSpy.calls.all()) {
358+
const args = call.args[0];
359+
if (args.user) {
360+
user._objCount = args.user._objCount;
361+
break;
362+
}
363+
}
364+
expect(afterSpy).toHaveBeenCalledWith(
365+
{ ip: '127.0.0.1', user, master: false },
366+
{ id: 'modernAdapter3Data' },
367+
undefined
368+
);
369+
expect(spy).toHaveBeenCalled();
370+
});
371+
335372
it('should throw if no triggers found', async () => {
336373
await reconfigureServer({ auth: { wrongAdapter } });
337374
const user = new Parse.User();

spec/MongoStorageAdapter.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
248248
expect(object.date[0] instanceof Date).toBeTrue();
249249
expect(object.bar.date[0] instanceof Date).toBeTrue();
250250
expect(object.foo.test.date[0] instanceof Date).toBeTrue();
251-
const obj = await new Parse.Query('MyClass').first({useMasterKey: true});
251+
const obj = await new Parse.Query('MyClass').first({ useMasterKey: true });
252252
expect(obj.get('date')[0] instanceof Date).toBeTrue();
253253
expect(obj.get('bar').date[0] instanceof Date).toBeTrue();
254254
expect(obj.get('foo').test.date[0] instanceof Date).toBeTrue();

spec/ParseLiveQueryServer.spec.js

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,49 @@ describe('ParseLiveQueryServer', function () {
754754
parseLiveQueryServer._onAfterSave(message);
755755
});
756756

757+
it('sends correct object for dates', async () => {
758+
jasmine.restoreLibrary('../lib/LiveQuery/QueryTools', 'matchesQuery');
759+
760+
const parseLiveQueryServer = new ParseLiveQueryServer({});
761+
762+
const date = new Date();
763+
const message = {
764+
currentParseObject: {
765+
date: { __type: 'Date', iso: date.toISOString() },
766+
__type: 'Object',
767+
key: 'value',
768+
className: testClassName,
769+
},
770+
};
771+
// Add mock client
772+
const clientId = 1;
773+
const client = addMockClient(parseLiveQueryServer, clientId);
774+
775+
const requestId2 = 2;
776+
777+
await addMockSubscription(parseLiveQueryServer, clientId, requestId2);
778+
779+
parseLiveQueryServer._matchesACL = function () {
780+
return Promise.resolve(true);
781+
};
782+
783+
parseLiveQueryServer._inflateParseObject(message);
784+
parseLiveQueryServer._onAfterSave(message);
785+
786+
// Make sure we send leave and enter command to client
787+
await timeout();
788+
789+
expect(client.pushCreate).toHaveBeenCalledWith(
790+
requestId2,
791+
{
792+
className: 'TestObject',
793+
key: 'value',
794+
date: { __type: 'Date', iso: date.toISOString() },
795+
},
796+
null
797+
);
798+
});
799+
757800
it('can handle object save command which does not match any subscription', async done => {
758801
const parseLiveQueryServer = new ParseLiveQueryServer({});
759802
// Make mock request message
@@ -1138,8 +1181,7 @@ describe('ParseLiveQueryServer', function () {
11381181
expect(toSend.original).toBeUndefined();
11391182
expect(spy).toHaveBeenCalledWith({
11401183
usage: 'Subscribing using fields parameter',
1141-
solution:
1142-
`Subscribe using "keys" instead.`,
1184+
solution: `Subscribe using "keys" instead.`,
11431185
});
11441186
});
11451187

@@ -1945,6 +1987,7 @@ describe('ParseLiveQueryServer', function () {
19451987
} else {
19461988
subscription.clientRequestIds = new Map([[clientId, [requestId]]]);
19471989
}
1990+
subscription.query = query.where;
19481991
return subscription;
19491992
}
19501993

src/Adapters/Auth/AuthAdapter.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,24 @@ export class AuthAdapter {
9393
challenge(challengeData, authData, options, request) {
9494
return Promise.resolve({});
9595
}
96+
97+
/**
98+
* Triggered when auth data is fetched
99+
* @param {Object} authData authData
100+
* @param {Object} options additional adapter options
101+
* @returns {Promise<Object>} Any overrides required to authData
102+
*/
103+
afterFind(authData, options) {
104+
return Promise.resolve({});
105+
}
106+
107+
/**
108+
* Triggered when the adapter is first attached to Parse Server
109+
* @param {Object} options Adapter Options
110+
*/
111+
validateOptions(options) {
112+
/* */
113+
}
96114
}
97115

98116
export default AuthAdapter;

src/Adapters/Auth/index.js

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,20 +154,27 @@ function loadAuthAdapter(provider, authOptions) {
154154
return;
155155
}
156156

157-
const adapter = defaultAdapter instanceof AuthAdapter ? defaultAdapter : Object.assign({}, defaultAdapter);
157+
const adapter =
158+
defaultAdapter instanceof AuthAdapter ? defaultAdapter : Object.assign({}, defaultAdapter);
158159
const keys = [
159160
'validateAuthData',
160161
'validateAppId',
161162
'validateSetUp',
162163
'validateLogin',
163164
'validateUpdate',
164165
'challenge',
165-
'policy'
166+
'validateOptions',
167+
'policy',
168+
'afterFind',
166169
];
167170
const defaultAuthAdapter = new AuthAdapter();
168171
keys.forEach(key => {
169172
const existing = adapter?.[key];
170-
if (existing && typeof existing === 'function' && existing.toString() === defaultAuthAdapter[key].toString()) {
173+
if (
174+
existing &&
175+
typeof existing === 'function' &&
176+
existing.toString() === defaultAuthAdapter[key].toString()
177+
) {
171178
adapter[key] = null;
172179
}
173180
});
@@ -184,6 +191,9 @@ function loadAuthAdapter(provider, authOptions) {
184191
});
185192
}
186193
}
194+
if (adapter.validateOptions) {
195+
adapter.validateOptions(providerOptions);
196+
}
187197

188198
return { adapter, appIds, providerOptions };
189199
}
@@ -204,9 +214,40 @@ module.exports = function (authOptions = {}, enableAnonymousUsers = true) {
204214
return { validator: authDataValidator(provider, adapter, appIds, providerOptions), adapter };
205215
};
206216

217+
const runAfterFind = async (req, authData) => {
218+
if (!authData) {
219+
return;
220+
}
221+
const adapters = Object.keys(authData);
222+
await Promise.all(
223+
adapters.map(async provider => {
224+
const authAdapter = getValidatorForProvider(provider);
225+
if (!authAdapter) {
226+
return;
227+
}
228+
const {
229+
adapter: { afterFind },
230+
providerOptions,
231+
} = authAdapter;
232+
if (afterFind && typeof afterFind === 'function') {
233+
const requestObject = {
234+
ip: req.config.ip,
235+
user: req.auth.user,
236+
master: req.auth.isMaster,
237+
};
238+
const result = afterFind(requestObject, authData[provider], providerOptions);
239+
if (result) {
240+
authData[provider] = result;
241+
}
242+
}
243+
})
244+
);
245+
};
246+
207247
return Object.freeze({
208248
getValidatorForProvider,
209249
setEnableAnonymousUsers,
250+
runAfterFind,
210251
});
211252
};
212253

src/LiveQuery/ParseLiveQueryServer.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import UserRouter from '../Routers/UsersRouter';
2424
import DatabaseController from '../Controllers/DatabaseController';
2525
import { isDeepStrictEqual } from 'util';
2626
import Deprecator from '../Deprecator/Deprecator';
27+
import deepcopy from 'deepcopy';
2728

2829
class ParseLiveQueryServer {
2930
clients: Map;
@@ -496,7 +497,7 @@ class ParseLiveQueryServer {
496497
if (!parseObject) {
497498
return false;
498499
}
499-
return matchesQuery(parseObject, subscription.query);
500+
return matchesQuery(deepcopy(parseObject), subscription.query);
500501
}
501502

502503
async _clearCachedRoles(userId: string) {

src/RestQuery.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,9 @@ RestQuery.prototype.execute = function (executeOptions) {
223223
.then(() => {
224224
return this.runAfterFindTrigger();
225225
})
226+
.then(() => {
227+
return this.handleAuthAdapters();
228+
})
226229
.then(() => {
227230
return this.response;
228231
});
@@ -842,6 +845,20 @@ RestQuery.prototype.runAfterFindTrigger = function () {
842845
});
843846
};
844847

848+
RestQuery.prototype.handleAuthAdapters = async function () {
849+
if (this.className !== '_User' || this.findOptions.explain) {
850+
return;
851+
}
852+
await Promise.all(
853+
this.response.results.map(result =>
854+
this.config.authDataManager.runAfterFind(
855+
{ config: this.config, auth: this.auth },
856+
result.authData
857+
)
858+
)
859+
);
860+
};
861+
845862
// Adds included values to the response.
846863
// Path is a list of field names.
847864
// Returns a promise for an augmented response.

src/Routers/UsersRouter.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ export class UsersRouter extends ClassesRouter {
292292
if (authDataResponse) {
293293
user.authDataResponse = authDataResponse;
294294
}
295+
await req.config.authDataManager.runAfterFind(req, user.authData);
295296

296297
return { response: user };
297298
}

0 commit comments

Comments
 (0)