Skip to content

Commit

Permalink
Merge pull request #1 from ParsePlatform/master
Browse files Browse the repository at this point in the history
Pull from origin
  • Loading branch information
mihai-iorga committed Mar 18, 2016
2 parents 4cf11b2 + 1352652 commit 0199892
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 114 deletions.
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Parse Dashboard/parse-dashboard-config.json
6 changes: 2 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ We want to make contributing to this project as easy and transparent as
possible.

## Our Development Process
The standard installation method also clones the git repository, so you can start making and submitting changes right away.
Get started by cloning this repository and and running `npm install` inside it. Create a file called `parse-dashboad-config.json` in the Parse-Dashboard folder inside the repo, using the format described in the readme.

When working on the dashboard, use `npm run dashboard` and visit `localhost:4040` to see your dashboard. The `npm` script will automatically re-build your files when you change them, so after making a change, all you need to do is refresh the page.
When working on the dashboard, use `npm run dashboard` and visit `localhost:4040` to see your dashboard. The `npm run dashboard` script will automatically re-build your files when you change them, so after making a change, all you need to do is refresh the page.

When working on React components, use `npm run pig` and visit `localhost:4041` to view our component library and documentation (you can have both Dashboard and PIG running at once). The demos for each component are the primary way we test components, although there are also a small number of automated tests you can run with `npm test`. If you would like to create a new component that does not exist in the component library, use `npm run generate yourComponentName` to generate boilerplate code and quickly get started.

Expand Down Expand Up @@ -33,8 +33,6 @@ Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe
disclosure of security bugs. In those cases, please go through the process
outlined on that page and do not file a public issue.


## License
By contributing to Parse Dashboard, you agree that your contributions will be licensed
under its license.

159 changes: 108 additions & 51 deletions Parse-Dashboard/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,27 @@
* the root directory of this source tree.
*/
// Command line tool for npm start
"use strict"
const packageJson = require('package-json');
const basicAuth = require('basic-auth');
const path = require('path');
const jsonFile = require('json-file-plus');
const express = require('express');

var DEFAULT_DASHBOARD_CONFIG = __dirname + '/parse-dashboard-config.json';

var program = require("commander");
program.option('--port [port]', "the port to run parse-dashboard");
program.option('--config [config]', "the path to the configuration file");
program.option('--allowInsecureHTTP [allowInsecureHTTP]', 'set that flag when parse server is behind an HTTPS load balancer/proxy');
const program = require('commander');
program.option('--appId [appId]', 'the app Id of the app you would like to manage.');
program.option('--masterKey [masterKey]', 'the master key of the app you would like to manage.');
program.option('--serverURL [serverURL]', 'the server url of the app you would like to manage.');
program.option('--appName [appName]', 'the name of the app you would like to manage. Optional.');
program.option('--config [config]', 'the path to the configuration file');
program.option('--port [port]', 'the port to run parse-dashboard');
program.option('--allowInsecureHTTP [allowInsecureHTTP]', 'set this flag when you are running the dashboard behind an HTTPS load balancer or proxy with early SSL termination.');

program.parse(process.argv);

// collect the variables
var configFile = program.config || DEFAULT_DASHBOARD_CONFIG;
var port = program.port || process.env.PORT;
var allowInsecureHTTP = program.allowInsecureHTTP || process.env.PARSE_DASHBOARD_ALLOW_INSECURE_HTTP;

var packageJson = require('package-json');
var basicAuth = require('basic-auth');
var path = require('path');
var jsonFile = require('json-file-plus');
var express = require('express');
var app = express();
var currentVersionFeatures = require('../package.json').parseDashboardFeatures;

// Serve public files.
app.use(express.static(path.join(__dirname,'public')));
const currentVersionFeatures = require('../package.json').parseDashboardFeatures;

var newFeaturesInLatestVersion = []
var newFeaturesInLatestVersion = [];
packageJson('parse-dashboard').then(latestPackage => {
if (latestPackage.parseDashboardFeatures instanceof Array) {
newFeaturesInLatestVersion = parseDashboardFeatures.filter(feature => {
Expand All @@ -41,26 +35,76 @@ packageJson('parse-dashboard').then(latestPackage => {
}
});

app.get('/parse-dashboard-config.json', function(req, res) {
jsonFile(configFile)
.then(config => {
config.data.apps.forEach((app) => {
if (!app.appName) {
return res.send({ success: false, error: 'An application is misconfigured, appName is required' });
const port = program.port || process.env.PORT || 4040;
const allowInsecureHTTP = program.allowInsecureHTTP || process.env.PARSE_DASHBOARD_ALLOW_INSECURE_HTTP;

let explicitConfigFileProvided = !!program.config;
let configFile = null;
let configFromCLI = null;
if (!program.config) {
if (program.serverURL && program.masterKey && program.appId) {
configFromCLI = {
data: {
apps: [
{
appId: program.appId,
serverURL: program.serverURL,
masterKey: program.masterKey,
appName: program.appName,
},
]
}
});
var response = {
};
} else if (!program.serverURL && !program.masterKey && !program.appName) {
configFile = path.join(__dirname, 'parse-dashboard-config.json');
}
} else {
configFile = program.config;
if (program.appId || program.serverURL || program.masterKey || program.appName) {
console.log('You must provide either a config file or required CLI options (app ID, Master Key, and server URL); not both.');
process.exit(3);
}
}

let p = null;
if (configFile) {
p = jsonFile(configFile);
} else if (configFromCLI) {
p = Promise.resolve(configFromCLI);
} else {
//Failed to load default config file.
console.log('You must provide either a config file or an app ID, Master Key, and server URL. See parse-dashboard --help for details.');
process.exit(4);
}
p.then(config => {
config.data.apps.forEach(app => {
if (!app.appName) {
app.appName = app.appId;
}
});

const app = express();

// Serve public files.
app.use(express.static(path.join(__dirname,'public')));

// Serve the configuration.
app.get('/parse-dashboard-config.json', function(req, res) {
const response = {
apps: config.data.apps,
newFeaturesInLatestVersion: newFeaturesInLatestVersion,
};
var users = config.data.users;
const users = config.data.users;

let auth = null;
//If they provide auth when their config has no users, ignore the auth
if (users) {
var auth = basicAuth(req);
auth = basicAuth(req);
}

//Based on advice from Doug Wilson here:
//https://github.com/expressjs/express/issues/2518
var requestIsLocal =
const requestIsLocal =
req.connection.remoteAddress === '127.0.0.1' ||
req.connection.remoteAddress === '::ffff:127.0.0.1' ||
req.connection.remoteAddress === '::1';
Expand All @@ -74,7 +118,7 @@ app.get('/parse-dashboard-config.json', function(req, res) {
return res.send({ success: false, error: 'Configure a user to access Parse Dashboard remotely' });
}

var successfulAuth =
const successfulAuth =
//they provided auth
auth &&
//there are configured users
Expand All @@ -86,7 +130,7 @@ app.get('/parse-dashboard-config.json', function(req, res) {
});
if (successfulAuth) {
//They provided correct auth
return res.send(response);
return res.json(response);
}

if (users || auth) {
Expand All @@ -103,22 +147,35 @@ app.get('/parse-dashboard-config.json', function(req, res) {
}
//We shouldn't get here. Fail closed.
res.send({ success: false, error: 'Something went wrong.' });
}, error => {
if (error instanceof SyntaxError) {
res.send({ success: false, error: 'Your parse-dashboard-config.json file contains invalid JSON.' });
} else if (error.code === 'ENOENT') {
res.send({ success: false, error: 'Your parse-dashboard-config.json file is missing.' });
});

// For every other request, go to index.html. Let client-side handle the rest.
app.get('/*', function(req, res) {
res.sendFile(__dirname + '/index.html');
});

// Start the server.
app.listen(port);

console.log(`The dashboard is now available at http://localhost:${port}/`);
}, error => {
if (error instanceof SyntaxError) {
console.log('Your config file contains invalid JSON. Exiting.');
process.exit(1);
} else if (error.code === 'ENOENT') {
if (explicitConfigFileProvided) {
console.log('Your config file is missing. Exiting.');
process.exit(2);
} else {
res.send({ success: false, error: 'There was a problem with your parse-dashboard-config.json file.' });
console.log('You must provide either a config file or required CLI options (app ID, Master Key, and server URL); not both.');
process.exit(3);
}
})
.catch(error => res.send({ success: false, error: 'There was a problem loading the dashboard.' }));
});

// For every other request, go to index.html. Let client-side handle the rest.
app.get('/*', function(req, res) {
res.sendFile(__dirname + '/index.html');
} else {
console.log('There was a problem with your config. Exiting.');
process.exit(-1);
}
})
.catch(error => {
console.log('There was a problem loading the dashboard. Exiting.');
process.exit(-1);
});

// Start the server, listening to port 4040.
app.listen(port || 4040);
69 changes: 25 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
# Parse Dashboard

Parse Dashboard is standalone dashboard for managing your Parse apps. You can use it to manage your [Parse Server](https://github.com/ParsePlatform/parse-server) apps and your apps that are running on [Parse.com](https://Parse.com).
Parse Dashboard is a standalone dashboard for managing your Parse apps. You can use it to manage your [Parse Server](https://github.com/ParsePlatform/parse-server) apps and your apps that are running on [Parse.com](https://Parse.com).

## Getting Started
# Getting Started

[Node.js](https://nodejs.org) version >= 4.3 is required to run the dashboard. Once you have Node you can install the dashboard by cloning this repo and running `npm install`.
[Node.js](https://nodejs.org) version >= 4.3 is required to run the dashboard. You also need to be using Parse Server version 2.1.4 or higher. Install the dashboard from `npm`.

```
git clone git@github.com:ParsePlatform/parse-dashboard.git
cd parse-dashboard
npm install
npm install -g parse-dashboard
```

Next add your app info into `parse-dashboard/Parse-Dashboard/parse-dashboard-config.json`. The file should match the following format, using the server URL, App ID, and Master Key from your Parse Server. The App Name can be anything you want, and is used to reference your app in the dashboard. **Make sure the server URL is a URL that can be accessed by your browser.**
You can launch the dashboard for an app with a single command by supplying an app ID, master key, URL, and name like this:

```
parse-dashboard --appId yourAppId --masterKey yourMasterKey --serverURL "https://example.com/parse" --appName optionalName
```

You can then visit the dashboard in your browser at http://localhost:4040. If you want to use a different port you can supply the --port option to parse-dashboard. You can use anything you want as the app name, or leave it out in which case the app ID will be used.

If you want to manage multiple apps from the same dashboard, you can start the dashboard with a config file. For example, you could put your info into a file called `parse-dashboard-config.json` and then start the dashboard using `parse-dashboard --config parse-dashboard-config.json`. The file should match the following format:

```
{
Expand All @@ -27,9 +33,7 @@ Next add your app info into `parse-dashboard/Parse-Dashboard/parse-dashboard-con
}
```

Ensure your Parse Server version is `>= 2.1.4`. The dashboard will not work with Parse Server instances with lower versions.

You can also manage your apps that are hosted on Parse.com from the same dashboard. For these apps, you must specify your rest key and javascript key, and set your server url to https://api.parse.com/1.
You can also manage apps that on Parse.com from the same dashboard. In your config file, you will need to add the `restKey` and `javascriptKey` as well as the other paramaters, which you can find on `dashboard.parse.com`. Set the serverURL to `http://api.parse.com/1`:

```
{
Expand All @@ -52,16 +56,19 @@ You can also manage your apps that are hosted on Parse.com from the same dashboa
}
```

Then execute `npm run dashboard` and visit [`http://localhost:4040`](http://localhost:4040) and you will be able to manage your parse apps.

![Parse Dashboard](.github/dash-shot.png)

# Advanced Usage

## Other options

You can set `appNameForURL` for each app to control the url of your app within the dashboard.
You can set `appNameForURL` in the config file for each app to control the url of your app within the dashboard. This can make it easier to use bookmarks or share links on your dashboard.

## Deploying the dashboard

If you want to require a username and password to access the dashboard, you can do so by adding usernames and passwords for HTTP Basic Auth to your configuration file:
Make sure the server URLs for your apps can be accessed by your browser. If you are deploying the dashboard, then `localhost` urls will not work.

In order to securely deploy the dashboard without leaking your apps master key, you will need to use HTTPS and Basic Auth. You can do this by adding usernames and passwords for HTTP Basic Auth to your configuration file.
```
{
"apps": [...],
Expand All @@ -78,23 +85,23 @@ If you want to require a username and password to access the dashboard, you can
}
```

HTTPS and Basic Auth are mandatory if you are accessing the dashboard remotely instead of accessing it from `localhost`.
The deployed dashboard detects if you are using a secure connection. If you are deploying the dashboard behind a load balancer or proxy that does early SSL termination, then the app won't be able to detect that the connection is secure. In this case, you can start the dashboard with the `--allowInsecureHTTP=1` option. You will then be responsible for ensureing that your proxy or load balancer only allows HTTPS.

## Run with Docker

It is easy to use it with Docker. First build the image:

```
```
docker build -t parse-dashboard .
```

Run the image with your ``config.json`` mounted as a volume

```
docker run -d -p 8080:4040 -v host/path/to/config.json:/src/Parse-Dashboard/parse-dashboard-config.json parse-dashboard
docker run -d -p 8080:4040 -v host/path/to/config.json:/src/Parse-Dashboard/parse-dashboard-config.json parse-dashboard
```

By default, the container will start the app at port 4040 inside the container. However, you can run custom command as well (see ``Deploying in production`` for custom setup).
By default, the container will start the app at port 4040 inside the container. However, you can run custom command as well (see ``Deploying in production`` for custom setup).

In this example, we want to run the application in production mode at port 80 of the host machine.

Expand All @@ -104,32 +111,6 @@ docker run -d -p 80:8080 -v host/path/to/config.json:/src/Parse-Dashboard/parse-

If you are not familiar with Docker, ``--port 8080`` with be passed in as argument to the entrypoint to form the full command ``npm start -- --port 8080``. The application will start at port 8080 inside the container and port ``8080`` will be mounted to port ``80`` on your host machine.

## Deploying in production

If you're deploying to a provider like Heroku, or Google App Engine, the SSL endpoint is terminated early and handled by the provider and you may encounter this error: `Parse Dashboard can only be remotely accessed via HTTPS`.

:warning: :warning: Before going further, make sure your server **cannot** be reachable via **HTTP**. See the provider documentation for force HTTPS connections to your deployment.

Set the environment variable `PARSE_DASHBOARD_ALLOW_INSECURE_HTTP=1` to tell parse server to skip the secure tests.

To start your server use:

`$ npm start`

Optionally you can use the command line arguments:

`$ npm start -- --config path/to/config.json --port 8080 --allowInsecureHTTP=1`

Or update you start script with the accoring configuration.

All paramters are optional and their default values are:


config: parse-dashboard/Parse-Dashboard/parse-dashboard-config.json
port: 4040
allowInsecureHTTP: false


## Contributing

We really want Parse to be yours, to see it grow and thrive in the open source community. Please see the [Contributing to Parse Dashboard guide](CONTRIBUTING.md).
Loading

0 comments on commit 0199892

Please sign in to comment.