Add circular dependency detection to CI (#7316)
* add circular dependency detection to CI * fixed Auth-RestWrite circular dependency * updated package lock * fixed Logger circular dependency * fix lint
This commit is contained in:
20
.github/workflows/ci.yml
vendored
20
.github/workflows/ci.yml
vendored
@@ -52,6 +52,26 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
- run: npm run lint
|
- run: npm run lint
|
||||||
|
check-circular:
|
||||||
|
name: Circular Dependencies
|
||||||
|
timeout-minutes: 5
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Use Node.js ${{ matrix.NODE_VERSION }}
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
- name: Cache Node.js modules
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: ~/.npm
|
||||||
|
key: ${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-node-${{ matrix.NODE_VERSION }}-
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
- run: npm run madge:circular
|
||||||
check-mongo:
|
check-mongo:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
|
|||||||
1202
package-lock.json
generated
1202
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -91,6 +91,7 @@
|
|||||||
"jsdoc": "3.6.3",
|
"jsdoc": "3.6.3",
|
||||||
"jsdoc-babel": "0.5.0",
|
"jsdoc-babel": "0.5.0",
|
||||||
"lint-staged": "10.2.3",
|
"lint-staged": "10.2.3",
|
||||||
|
"madge": "4.0.2",
|
||||||
"mock-mail-adapter": "file:spec/support/MockMailAdapter",
|
"mock-mail-adapter": "file:spec/support/MockMailAdapter",
|
||||||
"mongodb-runner": "4.8.1",
|
"mongodb-runner": "4.8.1",
|
||||||
"mongodb-version-list": "1.0.0",
|
"mongodb-version-list": "1.0.0",
|
||||||
@@ -122,7 +123,8 @@
|
|||||||
"start": "node ./bin/parse-server",
|
"start": "node ./bin/parse-server",
|
||||||
"prettier": "prettier --write '{src,spec}/{**/*,*}.js'",
|
"prettier": "prettier --write '{src,spec}/{**/*,*}.js'",
|
||||||
"prepare": "npm run build",
|
"prepare": "npm run build",
|
||||||
"postinstall": "node -p 'require(\"./postinstall.js\")()'"
|
"postinstall": "node -p 'require(\"./postinstall.js\")()'",
|
||||||
|
"madge:circular": "node_modules/.bin/madge ./src --circular"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
|
|||||||
35
src/Auth.js
35
src/Auth.js
@@ -1,4 +1,3 @@
|
|||||||
const cryptoUtils = require('./cryptoUtils');
|
|
||||||
const RestQuery = require('./RestQuery');
|
const RestQuery = require('./RestQuery');
|
||||||
const Parse = require('parse/node');
|
const Parse = require('parse/node');
|
||||||
|
|
||||||
@@ -299,39 +298,6 @@ Auth.prototype._getAllRolesNamesForRoleIds = function (roleIDs, names = [], quer
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const createSession = function (
|
|
||||||
config,
|
|
||||||
{ userId, createdWith, installationId, additionalSessionData }
|
|
||||||
) {
|
|
||||||
const token = 'r:' + cryptoUtils.newToken();
|
|
||||||
const expiresAt = config.generateSessionExpiresAt();
|
|
||||||
const sessionData = {
|
|
||||||
sessionToken: token,
|
|
||||||
user: {
|
|
||||||
__type: 'Pointer',
|
|
||||||
className: '_User',
|
|
||||||
objectId: userId,
|
|
||||||
},
|
|
||||||
createdWith,
|
|
||||||
restricted: false,
|
|
||||||
expiresAt: Parse._encode(expiresAt),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (installationId) {
|
|
||||||
sessionData.installationId = installationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.assign(sessionData, additionalSessionData);
|
|
||||||
// We need to import RestWrite at this point for the cyclic dependency it has to it
|
|
||||||
const RestWrite = require('./RestWrite');
|
|
||||||
|
|
||||||
return {
|
|
||||||
sessionData,
|
|
||||||
createSession: () =>
|
|
||||||
new RestWrite(config, master(config), '_Session', null, sessionData).execute(),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
Auth,
|
Auth,
|
||||||
master,
|
master,
|
||||||
@@ -339,5 +305,4 @@ module.exports = {
|
|||||||
readOnly,
|
readOnly,
|
||||||
getAuthForSessionToken,
|
getAuthForSessionToken,
|
||||||
getAuthForLegacySessionToken,
|
getAuthForLegacySessionToken,
|
||||||
createSession,
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ based on the parameters passed
|
|||||||
|
|
||||||
// _adapter is private, use Symbol
|
// _adapter is private, use Symbol
|
||||||
var _adapter = Symbol();
|
var _adapter = Symbol();
|
||||||
import Config from '../Config';
|
|
||||||
|
|
||||||
export class AdaptableController {
|
export class AdaptableController {
|
||||||
constructor(adapter, appId, options) {
|
constructor(adapter, appId, options) {
|
||||||
@@ -28,10 +27,6 @@ export class AdaptableController {
|
|||||||
return this[_adapter];
|
return this[_adapter];
|
||||||
}
|
}
|
||||||
|
|
||||||
get config() {
|
|
||||||
return Config.get(this.appId);
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedAdapterType() {
|
expectedAdapterType() {
|
||||||
throw new Error('Subclasses should implement expectedAdapterType()');
|
throw new Error('Subclasses should implement expectedAdapterType()');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import MailAdapter from '../Adapters/Email/MailAdapter';
|
|||||||
import rest from '../rest';
|
import rest from '../rest';
|
||||||
import Parse from 'parse/node';
|
import Parse from 'parse/node';
|
||||||
import AccountLockout from '../AccountLockout';
|
import AccountLockout from '../AccountLockout';
|
||||||
|
import Config from '../Config';
|
||||||
|
|
||||||
var RestQuery = require('../RestQuery');
|
var RestQuery = require('../RestQuery');
|
||||||
var Auth = require('../Auth');
|
var Auth = require('../Auth');
|
||||||
@@ -14,6 +15,10 @@ export class UserController extends AdaptableController {
|
|||||||
super(adapter, appId, options);
|
super(adapter, appId, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get config() {
|
||||||
|
return Config.get(this.appId);
|
||||||
|
}
|
||||||
|
|
||||||
validateAdapter(adapter) {
|
validateAdapter(adapter) {
|
||||||
// Allow no adapter
|
// Allow no adapter
|
||||||
if (!adapter && !this.shouldVerifyEmails) {
|
if (!adapter && !this.shouldVerifyEmails) {
|
||||||
|
|||||||
@@ -857,7 +857,7 @@ RestWrite.prototype.createSessionToken = async function () {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { sessionData, createSession } = Auth.createSession(this.config, {
|
const { sessionData, createSession } = RestWrite.createSession(this.config, {
|
||||||
userId: this.objectId(),
|
userId: this.objectId(),
|
||||||
createdWith: {
|
createdWith: {
|
||||||
action: this.storage['authProvider'] ? 'login' : 'signup',
|
action: this.storage['authProvider'] ? 'login' : 'signup',
|
||||||
@@ -873,6 +873,37 @@ RestWrite.prototype.createSessionToken = async function () {
|
|||||||
return createSession();
|
return createSession();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
RestWrite.createSession = function (
|
||||||
|
config,
|
||||||
|
{ userId, createdWith, installationId, additionalSessionData }
|
||||||
|
) {
|
||||||
|
const token = 'r:' + cryptoUtils.newToken();
|
||||||
|
const expiresAt = config.generateSessionExpiresAt();
|
||||||
|
const sessionData = {
|
||||||
|
sessionToken: token,
|
||||||
|
user: {
|
||||||
|
__type: 'Pointer',
|
||||||
|
className: '_User',
|
||||||
|
objectId: userId,
|
||||||
|
},
|
||||||
|
createdWith,
|
||||||
|
restricted: false,
|
||||||
|
expiresAt: Parse._encode(expiresAt),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (installationId) {
|
||||||
|
sessionData.installationId = installationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(sessionData, additionalSessionData);
|
||||||
|
|
||||||
|
return {
|
||||||
|
sessionData,
|
||||||
|
createSession: () =>
|
||||||
|
new RestWrite(config, Auth.master(config), '_Session', null, sessionData).execute(),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// Delete email reset tokens if user is changing password or email.
|
// Delete email reset tokens if user is changing password or email.
|
||||||
RestWrite.prototype.deleteEmailResetTokenIfNeeded = function () {
|
RestWrite.prototype.deleteEmailResetTokenIfNeeded = function () {
|
||||||
if (this.className !== '_User' || this.query === null) {
|
if (this.className !== '_User' || this.query === null) {
|
||||||
@@ -978,7 +1009,7 @@ RestWrite.prototype.handleSession = function () {
|
|||||||
additionalSessionData[key] = this.data[key];
|
additionalSessionData[key] = this.data[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
const { sessionData, createSession } = Auth.createSession(this.config, {
|
const { sessionData, createSession } = RestWrite.createSession(this.config, {
|
||||||
userId: this.auth.user.id,
|
userId: this.auth.user.id,
|
||||||
createdWith: {
|
createdWith: {
|
||||||
action: 'create',
|
action: 'create',
|
||||||
@@ -1258,7 +1289,7 @@ RestWrite.prototype.handleInstallation = function () {
|
|||||||
return promise;
|
return promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
// If we short-circuted the object response - then we need to make sure we expand all the files,
|
// If we short-circuited the object response - then we need to make sure we expand all the files,
|
||||||
// since this might not have a query, meaning it won't return the full result back.
|
// since this might not have a query, meaning it won't return the full result back.
|
||||||
// TODO: (nlutsenko) This should die when we move to per-class based controllers on _Session/_User
|
// TODO: (nlutsenko) This should die when we move to per-class based controllers on _Session/_User
|
||||||
RestWrite.prototype.expandFilesForExistingObjects = function () {
|
RestWrite.prototype.expandFilesForExistingObjects = function () {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import ClassesRouter from './ClassesRouter';
|
|||||||
import Parse from 'parse/node';
|
import Parse from 'parse/node';
|
||||||
import rest from '../rest';
|
import rest from '../rest';
|
||||||
import Auth from '../Auth';
|
import Auth from '../Auth';
|
||||||
|
import RestWrite from '../RestWrite';
|
||||||
|
|
||||||
export class SessionsRouter extends ClassesRouter {
|
export class SessionsRouter extends ClassesRouter {
|
||||||
className() {
|
className() {
|
||||||
@@ -41,7 +42,7 @@ export class SessionsRouter extends ClassesRouter {
|
|||||||
if (!user) {
|
if (!user) {
|
||||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'invalid session');
|
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'invalid session');
|
||||||
}
|
}
|
||||||
const { sessionData, createSession } = Auth.createSession(config, {
|
const { sessionData, createSession } = RestWrite.createSession(config, {
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
createdWith: {
|
createdWith: {
|
||||||
action: 'upgrade',
|
action: 'upgrade',
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import Auth from '../Auth';
|
|||||||
import passwordCrypto from '../password';
|
import passwordCrypto from '../password';
|
||||||
import { maybeRunTrigger, Types as TriggerTypes } from '../triggers';
|
import { maybeRunTrigger, Types as TriggerTypes } from '../triggers';
|
||||||
import { promiseEnsureIdempotency } from '../middlewares';
|
import { promiseEnsureIdempotency } from '../middlewares';
|
||||||
|
import RestWrite from '../RestWrite';
|
||||||
|
|
||||||
export class UsersRouter extends ClassesRouter {
|
export class UsersRouter extends ClassesRouter {
|
||||||
className() {
|
className() {
|
||||||
@@ -218,7 +219,7 @@ export class UsersRouter extends ClassesRouter {
|
|||||||
req.config
|
req.config
|
||||||
);
|
);
|
||||||
|
|
||||||
const { sessionData, createSession } = Auth.createSession(req.config, {
|
const { sessionData, createSession } = RestWrite.createSession(req.config, {
|
||||||
userId: user.objectId,
|
userId: user.objectId,
|
||||||
createdWith: {
|
createdWith: {
|
||||||
action: 'login',
|
action: 'login',
|
||||||
|
|||||||
Reference in New Issue
Block a user