Using Create React App with Phoenix

Written by Pete Corey on Apr 3, 2017.

Contrary to what I said a couple weeks ago, I’ve decided to build the front-end of Inject Detect, as a React application.

Wanting to get off the ground quickly, I wanted to use Create React App to generate my React application boilerplate and tooling. While I wanted to use Create React App, I still wanted my React app to live within the context of a Phoenix application.

How could I combine these two worlds?

It took a little fiddling, but I’ve landed on a configuration that is working amazingly well for my needs. Read on to find out how I integrate all of the magic of Create React App with the power of a Phoenix application!

Front-end Demolition

To start, we won’t need Brunch to manage our project’s front-end static assets.

When creating a new Phoenix project, either leave out Brunch (mix ... --no-brunch), or remove brunch from your existing project by removing the Brunch watcher from your config/dev.exs configuration, and by removing brunch-config.js, package.json, and the contents of node_modules and web/static.

We also won’t need any of the initial HTML templates a new Phoenix project generates for us.

You can skip the generation of these initial files by giving mix a --no-html flag, or you can just ignore them for now.

Now that we’ve torn a massive hole in the front-end of our Phoenix application, let’s fill it back in with a React application!

Creating a React App

We’ll be using Create React App to generate our React application’s boilerplate and to wire up our front-end tooling.

We want Create React App to work largely without any interference or tweaking, so we’ll create our new front-end application within the /priv folder of our Phoenix project:

cd priv
create-react-app hello_create_react_app

What you choose to call your React project is entirely up to you. In this case, I chose to replicate the name of the overarching Phoenix project.

To give myself a little extra control over the base index.html file generated by Create React App, I chose to immediately eject my React application at this point:

cd hello_create_react_app
npm run eject

You now have a fully functional front-end application. You can spin up your development server by running npm start within the priv/hello_create_react_app folder.

Your React application should automatically start serving from port 3000!

Front-end Meets Back-end

Now we’re in a strange spot.

In development our React application will spin up and run on port 3000 but has no out-of-the-box way to interact with our back-end. Similarly, our Phoenix application runs on port 4000, but no longer serves any kind of front-end.

How do we join the two?

The answer is fairly simple. Our React application should be built in such a way that it can be told to communicate with any back-end service over whatever medium we choose.

We configure this communication by passing in the URL of our backend service through environment variables. The Create React App tooling will populate env.process for us with any environment variables prefixed with REACT_APP_.

With this in mind, let’s connect our React application to our back-end using Apollo client:

const networkInterface = createNetworkInterface({
    uri: _.get(process.env, "REACT_APP_GRAPHQL_URL") || "http://localhost:4000/graphql"

Locally, we can set REACT_APP_GRAPHQL_URL when we spin up our Create React App tooling:

REACT_APP_GRAPHQL_URL="http://localhost:1337/graphql" npm start

During staging and production builds, we can set this environment variable to either our staging or production back-ends, respectively.

Lastly, we’ll need to configure our Phoenix server to allow requests from both of our development servers. Add the CORSPlug to your endpoint just before you plug in your router:

plug CORSPlug, origin: ["http://localhost:3000", "http://localhost:4000"]

For more flexibility, pull these CORS endpoints from an environmental configuration.

Deployment Freedom

Because our front-end application exists completely independently from our Phoenix application, we can deploy it anywhere.

Running npm run build in our priv/hello_create_react_app folder will build our application into a static bundle in the priv/hello_create_react_app/build folder.

This static bundle can be deployed anywhere you choose to deploy static assets, such as S3 or even GitHub Pages!

Because your front-end content is served elsewhere, your back-end Phoenix application will only be accessed to resolve queries or perform mutations, rather than to fetch every static asset requested by every user.

Out of the box, this inherent separation between the front-end and the back-end offers nice scaling opportunities for your application.

Serving React from Phoenix

While serving your front-end separately from your back-end can be a powerful tool, it’s often more of a burden when you’re just getting out of the gate.

Instead, it would be nice to be able to serve your front-end React application from your Phoenix application.

Thankfully, this is a breeze with a few configuration changes.

First things first, we want our application’s root URL to serve our react application, not a Phoenix template. Remove the get "/" hook from router.ex.

Now we’ll want to reconfigure our Phoenix endpoint to serve static assets from our React application’s build folder, not priv/static:

plug Plug.Static,
  at: "/", 
  from: "priv/hello_create_react_app/build/",
  only: ~w(index.html favicon.ico static)

Unfortunately, navigating to our root URL doesn’t load our application. However, navigating to /index.html does!

We’re almost there.

We need to tell Phoenix to load and serve static index.html files when they’re available. The plug_static_index_html plugin makes this a one line change.

Just before we wire up Plug.Static in our endpoint, configure the application’s root URL to serve index.html:

plug Plug.Static.IndexHtml,
  at: "/"

That’s it! We’re serving our React application statically from within our Phoenix application!

Now any deployments of our Phoenix application will contain and serve the last built React application in its entirety. Be sure to set your REACT_APP_ environment variables during your Phoenix release build process!

Final Thoughts

I’ve been developing with this setup for the past few weeks, and I’m extremely satisfied with it so far.

Using Create React App gets me off the ground quickly with a functioning boilerplate and fantastic tooling. I don’t have to waste time restructuring my Phoenix application or tweaking build configurations.

The ability to quickly integrate my React application with an Elixir-powered Phoenix back-end means that I don’t have to sacrifice speed of development for power or scalability.

Intercepting All Queries in a Meteor Application

Written by Pete Corey on Mar 27, 2017.

It’s probably no secret to you that I’m working on a new project called Inject Detect. As I mentioned last week, as a part of that project I need a way to intercept all MongoDB queries made by a Meteor application.

To figure out how to do this, we’ll need to spend a little time diving into the internals of Meteor to discover how it manages its MongoDB collections and drivers.

From there, we can create a Meteor package that intercepts all queries made against all MongoDB collections in an application.

Hold on tight, things are about to get heavy.

Exploring MongoInternals

One way of accomplishing our query interception goal is to monkey patch all of the query functions we care about, like find, findOne, remove, udpate, and upsert.

To do that, we first need to find out where those functions are defined.

It turns out that the functions we’re looking for are defined on the prototype of the MongoConnection object which is declared in the mongo Meteor package:

MongoConnection.prototype.find = function (collectionName, selector, options) {

When we instantiate a new Mongo.Collection in our application, we’re actually invoking the MongoConnection constructor.

So we want to monkey patch functions on MongoConnection. Unfortunately, the MongoConnection object isn’t exported by the mongo package, so we can’t access it directly from our own code.

How do we get to it?

Thankfully, MongoConnection is eventually assigned to MongoInternals.Connection, and the MongoInternals object is globally exported by the mongo package.

This MongoInternals object will be our entry-point for hooking into MongoDB queries at a very low level.

Monkey Patching MongoInternals

Since we know where to look, let’s get to work monkey patching our query functions.

Assuming we have a package already set up, the first thing we’ll do is import MongoInternals from the mongo Meteor package:

import { MongoInternals } from "meteor/mongo";

Let’s apply our first patch to find. First, we’ll save the original reference to find in a variable called _find:

const _find = MongoInternals.Connection.prototype.find;

Now that we’ve saved off a reference to the original find function, let’s override find on the MongoInternals.Connection prototype:

MongoInternals.Connection.prototype.find = function(collection, selector) {
    console.log(`Querying "${collection}" with ${JSON.stringify(selector)}.`);
    return _find.apply(this, arguments);

A diagram of a monkey patch.

We’ve successfully monkey patched the find function to print the collection and selector being queried before passing off the function call to the original find function (_find).

Let’s try it out in the shell:

> import "/imports/queryMonkeyPatcher"; // This is our monkey patching module
> Foo = new Mongo.Collection("foos");
> Foo.find({bar: "123"}).fetch();
Querying "foos" with {"bar": "123"}.
[{_id: "...", bar: "123"}]

As long as we import our code before we instantiate our collections, all calls to find in those collections will be routed through our new find function!

Now that we know our find monkey patch works, we can go ahead and repeat the procedure for the rest of the query functions we’re interested in.

How is This Useful?

This kind of low-level query interception can be thought of as collection hooks on steroids.

Josh Owens uses this kind of low-level hooking to explain every query made by an application with his Mongo Explainer Meteor package.

Similarly, Inject Detect will make use of this query-hooking-foo by collecting information on all queries made by your application and sending it off to be inspected for potential NoSQL Injection attacks.

This kind of low level hooking is an incredibly powerful tool that can accomplish some amazing things if used correctly.

How am I Building Inject Detect?

Written by Pete Corey on Mar 20, 2017.

I recently announced that I’m working on a new project called Inject Detect. It’s an understatement to say that I’m incredibly excited about this project!

Since announcing the project, I’ve spent the last couple weeks carefully considering my best steps forward. I’ve finally landed on what I believe is a solid plan of attack for building out Inject Detect, and I want to share it with the world.

Let’s dig into it!

What’s the Main Focus?

The first step in any project is to build a thorough understanding of the problem we’re trying to solve and understand how solving that problem brings value to our client or customer.

In the case of Inject Detect, our goal is to detect and notify Meteor application owners of NoSQL Injection attacks as they happen.

We give our customers real-time, actionable information to help them protect their applications and safeguard them against attack. A valuable by-product of this constant vigilance is peace of mind.

What does this mean for us?

We need to approach our solution with this value in the forefront of our mind. Everything we do should first and foremost maximize value for our customers.

High Level Architecture

From a very high level, Inject Detect is composed of two major components: a Meteor package that is installed in each monitored application, and a server to aggregate data sent from those applications and alert customers of potential NoSQL Injection attacks.

The Meteor package’s primary job is to hook into all queries made against a Meteor’s application’s MongoDB database and send that query information up to the server.

The server sifts through these incoming queries, comparing them to a set of expected queries for a given application. If an unexpected query is detected, the server sends a notification to the application owner, alerting them of a potential problem.

Collecting Queries on the Client

The fundamental function of Inject Detect is to sleuth over all queries made against a MongoDB database.

There are multiple ways of accomplishing this:

There are tools that use the MongoDB Profiler to observe queries in real-time. Unfortunately, the level of profiling required to intercept all queries can negatively affect database performance.

There are tools like MongoReplay that can be installed alongside MongoDB and act as proxies, intercepting MongoDB queries as they come in off the network. Unfortunately, installing these kinds of tools isn’t possible on hosted MongoDB solutions like Compose or Atlas.

So what are we left with?

The last option is to intercept queries at the application level. In the context of a Meteor application, this means hooking directly into the Mongo.Collection functionality at a low level.

Since this is the only option that won’t negatively impact database-level performance and will work for any type of MongoDB installation, this is the option for us.

But What About Sensitive Query Data?

Application owners may be concerned about sending full query objects off to a third-party service. Thankfully, Inject Detect doesn’t need to whole query object!

Imagine an application has a query that is used to authenticate a user based on their “resume token”:

  "services.resume.loginTokens.hashToken": "ABC123..."

In the wrong hands, this query information can be used to impersonate the user with the "ABC123..." resume token. This isn’t the kind of information you want to trust to third parties.

Fear not, Inject Detect respects your privacy!

Inject Detect only needs the structure of the query to detect potential NoSQL Inject attacks, not the fully populated query object.

In this example, we’d be send the following information up to the Inject Detect server:

  collection: "users",
  query: {
    "services.resume.loginTokens.hashToken": String

Rather than being sent the entire query object, complete with sensitive data, we’re sending a schema of the query.

We don’t care about the value of hashToken, we just care that it’s a String.

This is enough information to detect potential abuse, and keeps private customer data where it should be - safe and sound in your application.

Prioritizing Performance on the Client

But we have to consider more than just privacy…

It wouldn’t be the best idea to send a request to Inject Detect for every query made in a client application. The Inject Detect server would quickly be overwhelmed by a huge number of incoming requests, and the client application would be overburdened with outbound requests.

Talk about inefficient!

Instead, the client-side Meteor portion of Inject Detect batches queries as they’re intercepted and only sends them to the server every N seconds.

For the initial release of the application, I’m planning on sending query batches to the server at most once every thirty seconds.

This will alleviate any potential performance issues for both Inject Detect and applications using the Inject Detect Meteor package, and the cost of being as close to “hard real-time” as we can get.

The Inject Detect Server

The Inject Detect server will listen for incoming queries from your Meteor application and compare them against sets of known queries that are made by your application.

If an unexpected query is detected, Inject Detect will notify you immediately. Additionally, it will try to identify which query is being exploited to give you immediate insight into where to look in your application.

But what about the nuts and bolts?

For a variety of reasons, the Inject Detect server will be implemented as an Elixir application.

The “core domain” of the application will be implemented using Event Sourcing techniques. I’ve been using event-based systems extensively for client projects with great success.

The Inject Detect front-end application will initially be implemented as a Phoenix application for simplicity.

We’ll dig into these details in future posts.

Final Thoughts and Next Steps

I’m very excited to begin working on this project and even more excited to bring Inject Detect into the world.

NoSQL Injection seems to be one of the most widespread and under-acknowledged security issues in Meteor applications (and in many other applications using MongoDB).

Inject Detect will help application owners detect when these attacks happen, and help track down their root causes.

Next week, we’ll dive into the Meteor package side of Inject Detect and discuss how we can hook into all database queries made by a Meteor application at a low level.

In the meantime, focus on security!