Building a Web Assembly powered password generator

Building a Web Assembly powered password generator

- 6 mins

Building a Web Assembly-powered Password Generator with Rust and React

Introduction

In this tutorial, we will explore the fascinating intersection of Rust, Web Assembly (Wasm), and React by building a simple password generator. We’ll leverage the speed and performance benefits of Rust, compile it into Wasm, and seamlessly integrate it into a React application. By the end of this project, you’ll have a clear understanding of how these technologies work together.

Why Rust and Web Assembly?

Web Assembly is a low-level virtual machine that allows executing code at near-native speeds within web browsers. Rust, known for its speed and memory safety, is an ideal language for Wasm. Unlike high-level languages like JavaScript, Rust provides developers with low-level control and reliable performance, making it an excellent choice for Wasm.

Prerequisites

Before we dive into the project, ensure you have the following tools and knowledge:

Initializing the Rust Project

Let’s start by creating a new Rust Web Assembly project using the following command:

wasm-pack new wasm_pass

This command generates a Rust library crate with Web Assembly support. The crucial files are Cargo.toml, src/lib.rs, and src/utils.rs.

Dissecting the Boilerplate

Explore the generated project structure:

wasm_pass/
├── Cargo.toml
├── LICENSE_APACHE
├── LICENSE_MIT
├── README.md
└── src
    ├── lib.rs
    └── utils.rs

Initial Build

Build the project using:

wasm-pack build

This creates a pkg directory with the following artifacts:

pkg/
├── package.json
├── README.md
├── wasm_pass.wasm
├── wasm_pass.d.ts
└── wasm_pass.js

These files enable npm integration and contain the compiled Web Assembly code.

Writing Rust Code

Update the Cargo.toml file to include the rand crate:

[dependencies]
wasm-bindgen = "0.2.63"
rand = { version = "0.7.3", features = ["wasm-bindgen"] }

This adds the random number generation utility to our project. Run cargo build to download the new dependency.

Implement the password generator logic in src/lib.rs:

use wasm_bindgen::prelude::*;
use rand::Rng;

#[wasm_bindgen]
pub fn generate(len: usize) -> String {
    const CHARSET: &[u8] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\
                            abcdefghijklmnopqrstuvwxyz\
                            0123456789)(*&^%$#@!~".as_bytes();

    let mut rng = rand::thread_rng();

    let password: String = (0..len)
        .map(|_| {
            let idx = rng.gen_range(0, CHARSET.len());
            CHARSET[idx] as char
        })
        .collect();
    password
}

This function generates a random password of the specified length using the rand crate.

Testing the Code

Write a test for the generate function in src/lib.rs:

#[cfg(test)]
mod tests {
    use super::generate;

    #[test]
    fn test_generate() {
        let password = generate(20);
        assert_eq!(password.len(), 20);
    }
}

Run the tests with:

cargo test -- --show-output

Ensure the tests pass, confirming the functionality of the password generator.

Implementing Web Assembly in a React App

Create a React app in the app directory:

mkdir app
cd app
mkdir src
echo "/node_modules" > .gitignore
npm init -y

Install necessary dependencies:

npm install --save react react-dom
npm install --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader webpack webpack-cli webpack-dev-server html-webpack-plugin style-loader css-loader html-loader

Create the React app files: index.html, index.js, and App.js. Configure Babel with .babelrc and Webpack with webpack.config.js.

Finally, run the development server:

npm start

Using the Package in React

Update the App.js file to use the Rust-generated Web Assembly package:

import React, { useState, useCallback, useEffect } from "react";

const App = () => {
    const [password, setPassword] = useState("");
    const [input, setInput] = useState("");

    const handleChange = (e) => {
        setInput(e.target.value);
    };

    const generatePassword = useCallback(() => {
        const module = import("wasm-pass")
        module.then(({generate}) => {
            setPassword(generate(parseInt(input)))
        }).catch(err => {
            alert(err.toString())
        })
    }, [input]);

    useEffect(() => {
        generatePassword()
    }, [input]);

    return (
        <div>
            <p>Enter password length:</p>
            <input onChange={handleChange} type="number" value={input} />
            <button onClick={generatePassword}>Generate Password</button>
            <p>Your password:</p>
            <strong>{password}</strong>
        </div>
    );
};

export default App;

This React component allows users to input a password length, click a button, and receive a randomly generated password from the Rust Web Assembly package.

Conclusion

This tutorial showcases the integration of Rust and Web Assembly in a React application, providing a powerful blend of performance and modern front-end technologies. Explore further resources to deepen your understanding of Rust and Web Assembly:

Check the full working implementation of this project for reference. Happy coding!

Collins Muriuki

Collins Muriuki

Understanding the universe and explaining it to a three year old.

comments powered by Disqus
rss facebook twitter github gitlab youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora quora keybase