5 minute read

Intro

After I took a course from Udemy, I want to check my understanding of Rust using multiple approaches. The first is reading the source code and explain how it works. The second one is creating a real-life app using Rust. By using API or crawling, checking the air quality in Seoul and sending it to my email every 8 a.m. After the Covid-19, all kinds of the indoor fitness center are shutting down. I want to keep work out. The simple way is that I can run. Usually, before going out, I check the air quality and I get the idea of the automation. To build an app, I want to build using Rust Rocket as a backend and React as a frontend. Here is the starting point that setting up integrating Rust rocket and React.

Repository

https://github.com/devjunhong/rust_rocket_and_react

Dependency

  • Rust: rustc 1.50.0-nightly
  • Rust Rocket: 0.4.6
  • Cargo: 1.50.0-nightly
  • npm version: 6.14.10
  • create-react-app: 4.0.1

Create Rust Rocket Backend

$ cargo new backend

Creating a new Rust project is the first step. With this command, we can make the “backend” project.

Updating Cargo.toml

Since we are choosing Rocket as the backend, we are going to add the dependency project information into the “backend/Cargo.toml” file.

[dependencies]
rocket = "0.4.6"

Compiler Setting

Rocket requires a nightly version of Rust. We need to make sure the rust compiler version.

$ rustup --version 

To set the Rust compiler per-directory, we can use this command.

$ rustup override set nightly

Add sample code to the main.rs

#![feature(proc_macro_hygiene, decl_macro)]

#[macro_use] extern crate rocket; 

#[get("/")]
fn index() -> &'static str {
    "Hello, world!"
}

fn main() {
    rocket::ignite().mount("/", routes![index]).launch();
}

The sample code is from Rocket documentation [3]. From this point, we can use this command to launch the Rocket server. The current working directory is under the “backend/”. The full path is “/path/to/backend/”. In the console,

$ cargo run 

Then, we enter the address printed in the console with your browser. We will see. Okay, the backend project works now. hello_world_image

Create React frontend

$ create-react-app frontend

In the many tutorials, we can run the react app by hitting “npm run start”. Here was the strange point that I feel something missing. I have no idea how to run it locally without a server. This article shed light on. [1] Here’s the following.

Setting up package.json

{
  "name": "frontend",
  "version": "0.1.0",
  "homepage": "."
}

Adding the “homepage” key with the value “.” means the build output of index.html will point to the current “build” directory. The “index.html” finds its resource from the “build” directory. Concretely, it’s not the “index.html”, the browser.

$ npm run build

I can find a new directory under t”frontend” folder. “build”. Inside of it, we have “index.html”. Drawing the index.html(frontend/build/index.html) file on the browser, we can see the local react app. It’s time to integrate both.

local_image

Integrate Backend and Frontend

Let’s make sure what’s left. The backend server only knows the root access. The frontend project successfully creates “index.html”. Okay, if there’s root access again, then we need to point the “frontend/build/index.html” file. Go for it, we need to update “backend/src/main.rs”.

Update backend/src/main.rs

use std::path::Path; 
use rocket::response::NamedFile;

#[get("/")]
fn index() -> io::Result<NamedFile> {
  let page_directory_path = 
  format!("{}/../frontend/build", env!("CARGO_MANIFEST_DIR"));
  NamedFile::open(Path::new(&page_directory_path).join("index.html"))
}

The format macro and env macro are discussed here. The value of the “page_directory_path” variable is “/path/to/the/backend/../frontend/build”. That’s pointing “/path/to/the/frontend/build”. And the path will be combined with “index.html” by calling the join function.

Path::new(&page_directory_path).join("index.html")

This code points to the “/path/to/the/frontend/build/index.html” file. The open function read file in read-only mode. This is for the root path. If we have additional resources, then we need to route those too. To serve additional files, we need to create another function.

#[get("/<file..>")]
fn files(file: PathBuf) -> io::Result<NamedFile> {
  let page_directory_path = 
  format!("{}/../frontend/build", env!("CARGO_MANIFEST_DIR"));
  NamedFile::open(Path::new(&page_directory_path).join(file))
}

The get attribute should be mentioned first. [4] To match with multiple elements, we use dot-dot(“..”) operation. When the browser requests “http://localhost:8000/static/main.css”, the last part of the string (“static/main.css”) is the value of the “file” argument. The “page_directory_path” variable is what we’ve seen before. The same one. The value of it is “/path/to/the/frontend/build”. The pieces of the puzzle are complete. It is ready to serve CSS or JS files to make our page beautiful. I got idea from this repository.[2] Thank you.

Path Traversal Attack

According to [4], Rocket prevents the path traversal attack. If we can upper-level directory or file that is not allowed to be disclosed, we can see any information from the server. To test, we need to run the server first. And, we are going to use the curl command.

$ curl localhost:8000/

By using another console screen, we can enter the command. As expected, I see the exact source code when I enter the address (localhost:8000). We create a server. When we send a request, the server points “/path/to/the/frontend/build”. Let’s try curl request with this argument. “localhost:8000/../package.json”. The request means that showing the “/path/to/the/frontend/package.json” file. The message I got is 500 Internal Server Error.

Outro

In this post, we have a look at how to integrate Rust Rocket and react. It was interesting for me to check understandings and make it firm as well. I stucked on creating a react app without a server. And, I found this article [1]. It points out that we should understand favorite tools about what’s happening or what’s going on. I totally agree on this idea. Trying to describe the practical steps, I felt the missing things. This is why I write blog posts. Thank you. Any questions are welcome in the replies or reactions too. We can learn together.

Terms

A directory traversal (or path traversal) attack exploits insufficient security validation or sanitization of user-supplied file names, such that characters representing “traverse to parent directory” are passed through to the operating system’s file system API. [5]

cURL (pronounced ‘curl’[4]) is a computer software project providing a library (libcurl) and command-line tool (curl) for transferring data using various network protocols. [6]

References

[1] https://medium.com/@louis.raymond/why-cant-i-open-my-react-app-by-clicking-index-html-d1778f6324cf

[2] https://github.com/StefanoOrdine/rust-reactjs

[3] https://rocket.rs/v0.4/guide/getting-started/#hello-world

[4] https://rocket.rs/v0.4/guide/requests/#multiple-segments

[5] https://en.wikipedia.org/wiki/Directory_traversal_attack

[6] https://en.wikipedia.org/wiki/CURL

Tags:

Categories:

Updated:

Leave a comment