From 066ff725f6ecdb64032c7397701c614abf1f936a Mon Sep 17 00:00:00 2001
From: Philippe Auriach
Date: Mon, 14 Jun 2021 13:08:14 +0200
Subject: [PATCH] New Sandbox
---
.env.dist | 1 -
docs/usage.md | 8 ++---
ecosystem.config.js | 8 +----
package.json | 2 --
prod_deploy/.env | 1 -
prod_deploy/README.md | 10 +++---
spec/__mock__/config.js | 3 --
src/config/index.js | 8 -----
src/connectServer.js | 6 +++-
src/db/client.js | 31 ----------------
src/db/model/application.js | 25 -------------
src/db/model/developer.js | 18 ----------
src/db/model/index.js | 12 -------
src/db/parse.js | 56 -----------------------------
src/middleware/parseDashboard.js | 7 ----
src/middleware/parseSandbox.js | 28 ---------------
src/middleware/sandboxMiddleware.js | 41 +++++++++++++++++++++
src/parse/cloud/setBeforeSave.js | 5 ++-
src/parse/index.js | 36 -------------------
src/parse/schema/getClasses.js | 8 +++--
src/sandbox.js | 26 --------------
21 files changed, 65 insertions(+), 275 deletions(-)
delete mode 100644 src/db/client.js
delete mode 100644 src/db/model/application.js
delete mode 100644 src/db/model/developer.js
delete mode 100644 src/db/model/index.js
delete mode 100644 src/db/parse.js
delete mode 100644 src/middleware/parseSandbox.js
create mode 100644 src/middleware/sandboxMiddleware.js
delete mode 100644 src/parse/index.js
delete mode 100644 src/sandbox.js
diff --git a/.env.dist b/.env.dist
index 5a64939..eef3711 100644
--- a/.env.dist
+++ b/.env.dist
@@ -1,7 +1,6 @@
DEBUG=true
PUBLIC_URL=http://localhost:1337
APP_PORT=1337
-SANDBOX_PORT=1338
PARSE_APP_NAME=connect
PARSE_APP_ID=connect
diff --git a/docs/usage.md b/docs/usage.md
index 2106c1a..264c629 100644
--- a/docs/usage.md
+++ b/docs/usage.md
@@ -426,13 +426,9 @@ The response from batch will be a list with the same number of elements as the i
### Sandbox
Before use the production database you can use the sanbox environnement.
+Just add the following header to every requests you make to `/classes/*` or `/batch`:
-For that two changes should be done :
-
-- Every endpoint uri is `https://connect-project.io/parse-sandbox` instead of `https://connect-project.io/parse`
-- Change the header value `x-parse-application-id` to `connect-sandbox`.
-
-For the authentication you have to use the APP_TOKEN_SANDBOX instead of the APP_TOKEN.
+`x-is-sandbox: true`
## Schema Contribute
diff --git a/ecosystem.config.js b/ecosystem.config.js
index 8d83e9d..ef9a35e 100644
--- a/ecosystem.config.js
+++ b/ecosystem.config.js
@@ -4,13 +4,7 @@ module.exports = {
name: 'connect',
script: 'src/index.js',
watch: '.',
- ignore_watch : ["node_modules", "logs"],
- },
- {
- name: 'connect-sandbox',
- script: 'src/sandbox.js',
- watch: '.',
- ignore_watch : ["node_modules", "logs"],
+ ignore_watch: ['node_modules', 'logs'],
},
],
};
diff --git a/package.json b/package.json
index d1c55d9..b887f3c 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,6 @@
"description": "An open platform to save anonymous data coming from any application using this API",
"scripts": {
"start": "node src/index.js",
- "start.sandbox": "node src/sandbox.js",
"build": "webpack --mode production",
"build.dev": "webpack --mode development",
"eslint.check": "eslint --ext js,jsx .",
@@ -12,7 +11,6 @@
"prettier.check": "prettier --list-different .",
"prettier.fix": "prettier --write .",
"test": "jest --config spec/jest.config.js -i --forceExit --detectOpenHandles",
- "copyToSandbox": "./bin/migration.sh",
"performance": "node bin/performance.js"
},
"eslintConfig": {
diff --git a/prod_deploy/.env b/prod_deploy/.env
index 03381b1..2c38787 100644
--- a/prod_deploy/.env
+++ b/prod_deploy/.env
@@ -3,7 +3,6 @@ VERSION_NUMBER=1.0.0
# Set all domain value if it need to be change
PUBLIC_URL=https://connect-project.io/
APP_PORT=3000
-SANDBOX_PORT=3001
# Setup your custom key (a random string value)
PARSE_FILE_KEY=TOSETUP
diff --git a/prod_deploy/README.md b/prod_deploy/README.md
index f543248..770732e 100644
--- a/prod_deploy/README.md
+++ b/prod_deploy/README.md
@@ -23,10 +23,6 @@
- `var passwd = "connect"`
- `use connect`
- `db.createUser({user: user, pwd: passwd, roles: ["readWrite"]});`
- - `connect-api`
- - `db.createUser({user: user, pwd: passwd, roles: ["readWrite"]});`
- - `connect-sandbox`
- - `db.createUser({user: user, pwd: passwd, roles: ["readWrite"]});`
- Installer node et yarn (suivre https://classic.yarnpkg.com/en/docs/install/#centos-stable
@@ -64,7 +60,9 @@
- `curl -v localhost:3001/parse-sandbox`
## Configure crontab to renew the certificate
+
- run `sudo crontab -e` and add the following:
+
```
PATH=/sbin:/bin:/usr/sbin:/usr/bin
@@ -72,7 +70,9 @@ PATH=/sbin:/bin:/usr/sbin:/usr/bin
```
## Installation de webhook
+
Configuration de webhook pour effectuer la mise à jour du serveur de manière automatique
+
- `sudo mkdir /opt/webhook`
- `sudo chown $USER /opt/webhook`
- Download release from https://github.com/adnanh/webhook/releases and extract the `webhook` binary to `/opt/webhook`
@@ -85,11 +85,13 @@ Configuration de webhook pour effectuer la mise à jour du serveur de manière a
- `curl localhost:9990/hooks/deploy-connect` should answer: `Hook rules were not satisfied.`
- `sudo systemctl enable webhook`
- Add the following redirection to the nginx server:
+
```
location /hooks/ {
proxy_pass http://127.0.0.1:9990;
}
```
+
- `sudo nginx -s reload`
## Pare-feu
diff --git a/spec/__mock__/config.js b/spec/__mock__/config.js
index 02b34b1..a670b6a 100644
--- a/spec/__mock__/config.js
+++ b/spec/__mock__/config.js
@@ -3,8 +3,6 @@ module.exports = {
PUBLIC_URL: 'http://localhost:3000',
API_URL: 'http://localhost:3000',
APP_PORT: '3000',
- // SANDBOX_URL: 'http://localhost:3000',
- // SANDBOX_PORT: '3000',
PARSE_APP_NAME: 'test',
PARSE_APP_ID: 'test',
PARSE_FILE_KEY: 'test',
@@ -12,7 +10,6 @@ module.exports = {
PARSE_READONLY_MASTER_KEY: 'test_masterkey_readonly',
PARSE_DASHBOARD_MAINTENER_PWD: 'test',
PARSE_DASHBOARD_ROOT_PWD: 'test',
- PARSE_SANDBOX: false,
PARSE_SILENT: true,
MONGO_URI: 'mongodb://test:test@localhost:27017/test',
AUTH_SECRET: 'test',
diff --git a/src/config/index.js b/src/config/index.js
index 7e2dbb5..d6a6ead 100644
--- a/src/config/index.js
+++ b/src/config/index.js
@@ -21,11 +21,6 @@ testConfig(APP_PORT, 'APP_PORT');
const API_URL = `http://localhost:${APP_PORT}`;
-const { SANDBOX_PORT } = process.env;
-testConfig(SANDBOX_PORT, 'SANDBOX_PORT');
-
-const SANDBOX_URL = `http://localhost:${SANDBOX_PORT}`;
-
const { PARSE_APP_NAME } = process.env;
testConfig(PARSE_APP_NAME, 'PARSE_APP_NAME');
@@ -81,8 +76,6 @@ module.exports = {
PUBLIC_URL,
API_URL,
APP_PORT,
- SANDBOX_URL,
- SANDBOX_PORT,
PARSE_APP_NAME,
PARSE_APP_ID,
PARSE_FILE_KEY,
@@ -90,7 +83,6 @@ module.exports = {
PARSE_READONLY_MASTER_KEY,
PARSE_DASHBOARD_MAINTENER_PWD,
PARSE_DASHBOARD_ROOT_PWD,
- PARSE_SANDBOX: false,
PARSE_SILENT: false,
MONGO_URI,
AUTH_SECRET,
diff --git a/src/connectServer.js b/src/connectServer.js
index 6ce5cba..e49c5d3 100644
--- a/src/connectServer.js
+++ b/src/connectServer.js
@@ -8,9 +8,10 @@ const oauthApi = require('./oauth/oauth-routes');
const parseApi = require('./middleware/parse');
const parseDashboard = require('./middleware/parseDashboard');
const parseSwagger = require('./middleware/parseSwagger');
+const sandboxMiddleware = require('./middleware/sandboxMiddleware');
+const oauthMiddleware = require('./oauth/oauth-middleware');
const configFront = require('./config/front');
-const oauthMiddleware = require('./oauth/oauth-middleware');
class ConnectServer {
constructor(app, server) {
@@ -42,6 +43,9 @@ class ConnectServer {
app.use('/parse/batch', oauthMiddleware);
app.use('/parse/classes', oauthMiddleware);
+ app.use('/parse/batch', sandboxMiddleware);
+ app.use('/parse/classes', sandboxMiddleware);
+
// Serve the Parse API at /parse URL prefix
const parseMiddleware = await parseApi(parseCloudEvent);
app.use('/parse', parseMiddleware.app);
diff --git a/src/db/client.js b/src/db/client.js
deleted file mode 100644
index 29f84e1..0000000
--- a/src/db/client.js
+++ /dev/null
@@ -1,31 +0,0 @@
-const mongoose = require('mongoose');
-const { MONGO_URI } = require('../config');
-
-mongoose.set('useFindAndModify', false);
-mongoose.set('useCreateIndex', true);
-mongoose.set('useNewUrlParser', true);
-mongoose.set('useUnifiedTopology', true);
-
-let parseConnect;
-let apiConnect;
-let parseSandboxConnect;
-
-module.exports = () => {
- if (!parseConnect) {
- parseConnect = mongoose.createConnection(MONGO_URI);
- }
-
- if (!apiConnect) {
- apiConnect = mongoose.createConnection(`${MONGO_URI}-api`);
- }
-
- if (!parseSandboxConnect) {
- parseSandboxConnect = mongoose.createConnection(`${MONGO_URI}-sandbox`);
- }
-
- return {
- parseConnect,
- apiConnect,
- parseSandboxConnect,
- };
-};
diff --git a/src/db/model/application.js b/src/db/model/application.js
deleted file mode 100644
index b8ed426..0000000
--- a/src/db/model/application.js
+++ /dev/null
@@ -1,25 +0,0 @@
-const mongoose = require('mongoose');
-
-module.exports = (apiConnect) => {
- if (apiConnect.modelNames().includes('Application')) {
- return apiConnect.model('Application');
- }
-
- const applicationSchema = new mongoose.Schema({
- developer: {
- type: mongoose.Schema.Types.ObjectId,
- ref: 'Developer',
- },
- name: String,
- description: String,
- parse_name: { type: String, unique: true },
- token: String,
- token_sandbox: String,
- apple_store_link: String,
- google_market_link: String,
- create_at: { type: Date, default: Date.now },
- updated_at: { type: Date, default: Date.now },
- });
-
- return apiConnect.model('Application', applicationSchema);
-};
diff --git a/src/db/model/developer.js b/src/db/model/developer.js
deleted file mode 100644
index 3ec0926..0000000
--- a/src/db/model/developer.js
+++ /dev/null
@@ -1,18 +0,0 @@
-const mongoose = require('mongoose');
-
-module.exports = (apiConnect) => {
- if (apiConnect.modelNames().includes('Developer')) {
- return apiConnect.model('Developer');
- }
-
- const developerSchema = new mongoose.Schema({
- login: String,
- github_id: { type: Number, unique: true },
- company_name: String,
- email: String,
- create_at: { type: Date, default: Date.now },
- updated_at: { type: Date, default: Date.now },
- });
-
- return apiConnect.model('Developer', developerSchema);
-};
diff --git a/src/db/model/index.js b/src/db/model/index.js
deleted file mode 100644
index 1d07680..0000000
--- a/src/db/model/index.js
+++ /dev/null
@@ -1,12 +0,0 @@
-const connectClient = require('../client');
-const Developer = require('./developer');
-const Application = require('./application');
-
-module.exports = () => {
- const { apiConnect } = connectClient();
-
- return {
- Developer: Developer(apiConnect),
- Application: Application(apiConnect),
- };
-};
diff --git a/src/db/parse.js b/src/db/parse.js
deleted file mode 100644
index 0455901..0000000
--- a/src/db/parse.js
+++ /dev/null
@@ -1,56 +0,0 @@
-const mongoose = require('mongoose');
-const getClasses = require('../parse/schema/getClasses');
-const connectClient = require('./client');
-
-const modelMapping = new Map();
-const modeSandboxMapping = new Map();
-
-// Generate all mongoose schema and model for the parse db
-// eslint-disable-next-line max-statements
-const getParseModel = async function (sandbox) {
- const schemaClasses = await getClasses();
- const { parseConnect, parseSandboxConnect } = connectClient();
- const connect = sandbox ? parseSandboxConnect : parseConnect;
- const models = sandbox ? modeSandboxMapping : modelMapping;
-
- if (models.size > 0) {
- return models;
- }
-
- for (const schemaClass of schemaClasses) {
- const schema = new mongoose.Schema({
- _p_owner: String,
- });
-
- models.set(
- schemaClass.className,
- connect.model(schemaClass.className, schema, schemaClass.className),
- );
- }
-
- const userSchema = new mongoose.Schema({
- _id: String,
- username: String,
- });
-
- models.set('_User', connect.model('_User', userSchema, '_User'));
-
- const sessionSchema = new mongoose.Schema({
- _p_user: String,
- });
-
- models.set('_Session', connect.model('_Session', sessionSchema, '_Session'));
-
- const joinUsersSchema = new mongoose.Schema({
- relatedId: String,
- });
-
- models.set(
- '_Join:users:_Role',
- connect.model('_Join:users:_Role', joinUsersSchema, '_Join:users:_Role'),
- );
-
- return models;
-};
-
-module.exports = getParseModel;
diff --git a/src/middleware/parseDashboard.js b/src/middleware/parseDashboard.js
index 48aa7ca..ba6fa6e 100644
--- a/src/middleware/parseDashboard.js
+++ b/src/middleware/parseDashboard.js
@@ -19,13 +19,6 @@ module.exports = () =>
readOnlyMasterKey: PARSE_READONLY_MASTER_KEY,
appName: PARSE_APP_NAME,
},
- {
- serverURL: `${PUBLIC_URL}/parse-sandbox`,
- appId: `${PARSE_APP_ID}-sandbox`,
- masterKey: PARSE_MASTER_KEY,
- readOnlyMasterKey: PARSE_READONLY_MASTER_KEY,
- appName: `${PARSE_APP_NAME}-sandbox`,
- },
],
users: [
{
diff --git a/src/middleware/parseSandbox.js b/src/middleware/parseSandbox.js
deleted file mode 100644
index 4e3b3e5..0000000
--- a/src/middleware/parseSandbox.js
+++ /dev/null
@@ -1,28 +0,0 @@
-const { ParseServer } = require('parse-server');
-const {
- SANDBOX_URL,
- MONGO_URI,
- PARSE_APP_NAME,
- PARSE_APP_ID,
- PARSE_FILE_KEY,
- PARSE_MASTER_KEY,
- PARSE_READONLY_MASTER_KEY,
-} = require('../config');
-const cloud = require('../parse/cloud/main');
-
-module.exports = () =>
- new ParseServer({
- databaseURI: `${MONGO_URI}-sandbox`,
- cloud: (Parse) => {
- cloud(Parse);
- },
- appId: `${PARSE_APP_ID}-sandbox`,
- fileKey: PARSE_FILE_KEY,
- masterKey: PARSE_MASTER_KEY,
- readOnlyMasterKey: PARSE_READONLY_MASTER_KEY,
- appName: `${PARSE_APP_NAME}-sandbox`,
- allowClientClassCreation: false,
- enableAnonymousUsers: false,
- maxLimit: 100,
- serverURL: `${SANDBOX_URL}/parse-sandbox`,
- });
diff --git a/src/middleware/sandboxMiddleware.js b/src/middleware/sandboxMiddleware.js
new file mode 100644
index 0000000..8537049
--- /dev/null
+++ b/src/middleware/sandboxMiddleware.js
@@ -0,0 +1,41 @@
+/* eslint-disable max-statements */
+
+const changeUrl = (req, toReplace, replacement) => {
+ req.url = req.url.replace(toReplace, replacement);
+ req.originalUrl = req.originalUrl.replace(toReplace, replacement);
+ req.path = req.path.replace(toReplace, replacement);
+};
+
+const transformPathForSandbox = (originalPath) => {
+ const regexpResult = originalPath.match(/\/parse\/classes\/([a-zA-Z_]+)/);
+ if (regexpResult.length > 1) {
+ return '/parse/classes/Sandbox_' + regexpResult[1];
+ }
+};
+
+module.exports = (req, res, next) => {
+ if (req.headers['x-is-sandbox'] === 'true') {
+ const matchClass = req.originalUrl.match(/\/parse\/classes\/([a-zA-Z_]+)/);
+ if (matchClass.length > 1) {
+ const className = matchClass[1];
+ if (!className.startsWith('Sandbox_')) {
+ changeUrl(req, className, `Sandbox_${className}`);
+ }
+
+ return next();
+ }
+ if (
+ req.method === 'POST' &&
+ req.originalUrl.startsWith('/parse/batch') &&
+ req.body &&
+ Array.isArray(req.body.requests)
+ ) {
+ req.body.requests = req.body.requests.map((elt) => ({
+ ...elt,
+ path: transformPathForSandbox(elt.path) || elt.path,
+ }));
+ }
+ }
+
+ return next();
+};
diff --git a/src/parse/cloud/setBeforeSave.js b/src/parse/cloud/setBeforeSave.js
index d44a64c..22e51b5 100644
--- a/src/parse/cloud/setBeforeSave.js
+++ b/src/parse/cloud/setBeforeSave.js
@@ -38,7 +38,10 @@ module.exports = async (Parse) => {
throw new Parse.Error(403, 'Please use OAuth to authenticate');
}
- const schemaFile = `${__dirname}/../schema/classes/${schemaClass.className}.schema.json`;
+ const schemaFile = `${__dirname}/../schema/classes/${schemaClass.className.replace(
+ /^Sandbox_/,
+ '',
+ )}.schema.json`;
const jsonObject = req.object.toJSON();
// remove extra fields added by Parse to validate the JSON
delete jsonObject.createdAt;
diff --git a/src/parse/index.js b/src/parse/index.js
deleted file mode 100644
index 0489e9c..0000000
--- a/src/parse/index.js
+++ /dev/null
@@ -1,36 +0,0 @@
-const axios = require('axios');
-const {
- PARSE_APP_ID,
- PARSE_MASTER_KEY,
- API_URL,
- SANDBOX_URL,
-} = require('../config');
-
-class Parse {
- static async signUp(username, password, isSandbox) {
- const parseUrl = isSandbox
- ? `${SANDBOX_URL}/parse-sandbox`
- : `${API_URL}/parse`;
- const parseApi = isSandbox ? `${PARSE_APP_ID}-sandbox` : PARSE_APP_ID;
-
- const response = await axios({
- method: 'post',
- url: `${parseUrl}/users`,
- data: {
- username,
- password,
- },
- headers: {
- 'Content-Type': 'application/json',
- Accept: 'application/json',
- 'X-Parse-Application-Id': parseApi,
- 'X-Parse-Revocable-Session': 1,
- 'X-Parse-Master-Key': PARSE_MASTER_KEY,
- },
- });
-
- return response.data;
- }
-}
-
-module.exports = Parse;
diff --git a/src/parse/schema/getClasses.js b/src/parse/schema/getClasses.js
index 6b863e4..8545144 100644
--- a/src/parse/schema/getClasses.js
+++ b/src/parse/schema/getClasses.js
@@ -31,9 +31,12 @@ const swaggerTypeToParseType = function (element) {
return parseType;
};
-const getClass = function (file) {
+const getClass = function (file, isSandbox = false) {
return new Promise((resolve, reject) => {
- const className = path.parse(file).base.replace(/.schema.json$/, '');
+ let className = path.parse(file).base.replace(/.schema.json$/, '');
+ if (isSandbox) {
+ className = `Sandbox_${className}`;
+ }
fs.readFile(file, 'utf8', (err, data) => {
if (err) {
reject(err);
@@ -67,6 +70,7 @@ module.exports = function getClasses() {
const promises = [];
for (const file of files) {
promises.push(getClass(file));
+ promises.push(getClass(file, true));
}
Promise.all(promises).then((result) => {
classes = result;
diff --git a/src/sandbox.js b/src/sandbox.js
deleted file mode 100644
index ea69557..0000000
--- a/src/sandbox.js
+++ /dev/null
@@ -1,26 +0,0 @@
-const express = require('express');
-const cors = require('cors');
-
-const logger = require('./logger');
-const { SANDBOX_PORT } = require('./config');
-const parseSandbox = require('./middleware/parseSandbox');
-
-process.on('unhandledRejection', (err) => {
- throw err;
-});
-
-const app = express();
-
-const corsOptions = {
- origin: '*',
- optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
-};
-
-app.use(cors(corsOptions));
-
-// Serve the Parse API at /parse URL prefix
-app.use('/parse-sandbox', parseSandbox());
-
-app.listen(SANDBOX_PORT, () => {
- logger.info(`connect sandbox running on port ${SANDBOX_PORT}.`);
-});