Skip to content

Commit

Permalink
Merge pull request #118 from TNG/switch-to-vite
Browse files Browse the repository at this point in the history
Switch from CRA to Vite
  • Loading branch information
ghost91- authored Aug 12, 2024
2 parents e1aef63 + 5368a7d commit dd64e05
Show file tree
Hide file tree
Showing 70 changed files with 10,325 additions and 18,531 deletions.
9 changes: 9 additions & 0 deletions .changeset/nervous-cows-shave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@eop/client": major
---

Replace CRA with Vite

BREAKING CHANGE:

- Environment variables now need to be prefixed with `VITE_` instead of `REACT_APP_`
55 changes: 35 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Elevation of Privilege
======================
# Elevation of Privilege

[![Tests](https://github.com/tng/elevation-of-privilege/actions/workflows/checks.yml/badge.svg)](https://github.com/tng/elevation-of-privilege/actions/workflows/checks.yml)

**Improve both: your application's security and your developer's awareness!**
Expand All @@ -12,20 +12,19 @@ This application implements an online version of the card games [Elevation of Pr

[<img style="height:50px;cursor:pointer;float:right" src="docs/img/playit.svg"/>](https://threats-demo.thenerdgroup.de/)

*(Disclaimer: This demo instance is for testing purposes only. Do not add sensitive data!)*
_(Disclaimer: This demo instance is for testing purposes only. Do not add sensitive data!)_

[![Example](docs/eop.gif)](https://threats-demo.thenerdgroup.de/)


### Why Threat Modeling?

Nowadays, security is a topic that concerns every IT project. What if a malicious actor (for financial, ideological or any other reasons) wants to corrupt the system you are building? What if some skilled person wants to break in and steal your intellectual property or the data you are holding?

Threat Modeling is a systematic approach to the question "[What can go wrong?](https://www.threatmodelingmanifesto.org/)". It helps you and your team to take an attacker's perspective and understand your system aside from its features and business value. You will collect threats to your system and mitigate their risk before they get exploited and harm your business.
Threat Modeling is a systematic approach to the question "[What can go wrong?](https://www.threatmodelingmanifesto.org/)". It helps you and your team to take an attacker's perspective and understand your system aside from its features and business value. You will collect threats to your system and mitigate their risk before they get exploited and harm your business.

### And why Serious Games?

The idea to perform threat modeling on a system using a serious card game as developed by the security department at Microsoft. At its core, threat modeling should be done continuously as part of the (agile) development process. Thus, it should also be done by the developers, as they are the real experts on the system.
The idea to perform threat modeling on a system using a serious card game as developed by the security department at Microsoft. At its core, threat modeling should be done continuously as part of the (agile) development process. Thus, it should also be done by the developers, as they are the real experts on the system.

Microsoft's game allows developers, architects and security experts to find threats to the system even if they do not have a strong background in IT security. It is a threat catalog that guides the player's thoughts to new and unusual perspectives on the system, just as an attacker would do. Gamification makes this a fun thing to do and keeps the players motivated to find creative attacks.

Expand Down Expand Up @@ -65,9 +64,9 @@ Inspired by this, the game [Cornucopia](https://owasp.org/www-project-cornucopia

When uploading an architectural model of your system you can choose between different formats:

* an image (`.jpg`, `.png`, `.svg`, ...)
* JSON model generated with [OWASP Threat Dragon](https://owasp.org/www-project-threat-dragon/)
* no upload (this might be relevant you must comply to strict confidentiality regulation and want to supply the model via some different channel)
- an image (`.jpg`, `.png`, `.svg`, ...)
- JSON model generated with [OWASP Threat Dragon](https://owasp.org/www-project-threat-dragon/)
- no upload (this might be relevant you must comply to strict confidentiality regulation and want to supply the model via some different channel)

When starting the game you can configure the game mode and generate unique links for each of your players. With these links the players with their own hand of cards.

Expand All @@ -86,22 +85,25 @@ The frontend and backend are written in TypeScript and use [boardgame.io](https:
This repository uses [npm workspaces](https://docs.npmjs.com/cli/v10/using-npm/workspaces) to structure the different sub-packages and [Turborepo](https://turbo.build/repo) as a build system and task runner.

### Running the app

There are two components that need to be started in order to run the game.

1. Server
2. UI/Client

#### Docker

To start a dockerized version of the game use

```bash
docker compose up --build
```

This will start the app on port `8080` and make it accessible at [http://localhost:8080/](http://localhost:8080/).
The docker-compose setup starts two containers:
The docker-compose setup starts two containers:

* `threats-client`: running `nginx` as a reverse proxy and serving the react application
* `threats-server`: running the Node.js backend: public API and game server
- `threats-client`: running `nginx` as a reverse proxy and serving the react application
- `threats-server`: running the Node.js backend: public API and game server

![docker-compose setup](docs/docker-setup.svg)

Expand All @@ -125,7 +127,7 @@ This will build any dependencies of the server if necessary and then start the b
listening on the following ports:

| Application | Description | Environment Variable | Default |
|-------------|-------------------------------------------------------------------|----------------------|---------|
| ----------- | ----------------------------------------------------------------- | -------------------- | ------- |
| Server | The game server for boardgame, exposes socket.io endpoints | `SERVER_PORT` | 8000 |
| Lobby API | Internal API for lobby operations, should not be exposed publicly | `INTERNAL_API_PORT` | 8002 |
| Public API | Public API to create games and retrieve game info | `API_PORT` | 8001 |
Expand All @@ -148,36 +150,48 @@ The UI can be started in dev mode using
npx turbo run dev --filter=@eop/client
```

The UI is accessible at [http://localhost:3000/](http://localhost:3000/).
The UI is accessible at [http://localhost:5173/](http://localhost:5173/).

The UI can also be built and served statically (see the [Dockerfile](apps/client/Dockerfile)). It assumes that it can access the public API at `/api` and the websocket connection at `/socket.io`, on the same origin that it was served at. Usually, this means you will need some kind of reverse proxy to pass those connections on to the server. See the [nginx configuration](apps/client/nginx/etc/nginx/) for more details.

You can also build the client manually by running
To build the client, run

```bash
npx turbo run build --filter=@eop/client
```

The UI can also be built and served statically (see the [Dockerfile](apps/client/Dockerfile)). Keep in mind that the values of the port numbers will be hard coded in the generated files.
To start it in production mode, run

```bash
npx turbo run start --filter=@eop/client
```

To build both the client and the server, just run

```bash
npx turbo run build
```

Similarly, you can also start both the server and client in production mode:

```bash
npx turbo run start
```

#### Imprint and privacy notices

Links to imprint and privacy notices can be included into the client, if the environment variables

```bash
export REACT_APP_EOP_IMPRINT="https://example.tld/imprint/"
export REACT_APP_EOP_PRIVACY="https://example.tld/privacy/"
export VITE_EOP_IMPRINT="https://example.tld/imprint/"
export VITE_EOP_PRIVACY="https://example.tld/privacy/"
```

are set when building the app.
When building the client via docker these env vars can be set by defining `build-args`

```bash
docker build --build-arg "REACT_APP_EOP_IMPRINT=https://example.tld/imprint/" --build-arg "REACT_APP_EOP_PRIVACY=https://example.tld/privacy/" -f apps/client/Dockerfile . -t "some-tag"
docker build --build-arg "VITE_EOP_IMPRINT=https://example.tld/imprint/" --build-arg "VITE_EOP_PRIVACY=https://example.tld/privacy/" -f apps/client/Dockerfile . -t "some-tag"
```

### Versioning
Expand All @@ -201,13 +215,14 @@ npx changeset version
and committing and pushing the changes.

## Credits

The initial version of this online game was developed in 2018 by [dehydr8](https://github.com/dehydr8), working for Careem at that time. This repository is a fork of the [original one](https://github.com/dehydr8/elevation-of-privilege) including further maintenance and developments like the introduction of alternative card decks. We would like to thank dehydr8 for his great work in setting up this game.

The card game Elevation of Privilege was originally invented by [Adam Shostack](https://adam.shostack.org/) at Microsoft and is licensed under [CC BY 3.0](https://creativecommons.org/licenses/by/3.0/). The [EoP Whitepaper](http://download.microsoft.com/download/F/A/E/FAE1434F-6D22-4581-9804-8B60C04354E4/EoP_Whitepaper.pdf) written by Adam can be downloaded which describes the motivation, experience and lessons learned in creating the game.

The card game Cornucopia was originally developed by the [OWASP Foundation](https://owasp.org/). In this application a slightly modified version of the original card game is used. This can be found in the subfolder `cornucopiaCards/`. As the original, the modified version is licensed under [CC BY-SA 3.0](https://creativecommons.org/licenses/by-sa/3.0/).

The card game Elevation of MLsec was developed at [Kantega AS](https://www.kantega.no/). This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license (https://creativecommons.org/licenses/by-sa/4.0/).
The card game Elevation of MLsec was developed at [Kantega AS](https://www.kantega.no/). This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license (https://creativecommons.org/licenses/by-sa/4.0/).

The motivation for creating this online version of the game at Careem was due to a large number of teams working remotely across several geographies and we wanted to scale our method of teaching threat modeling to our engineering teams.

Expand Down
12 changes: 6 additions & 6 deletions apps/client/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ COPY --from=pruner /app/out/json/ .
COPY --from=pruner /app/out/package-lock.json ./package-lock.json
RUN npm ci
COPY --from=pruner /app/out/full/ .
ARG REACT_APP_EOP_IMPRINT
ARG REACT_APP_EOP_PRIVACY
ARG REACT_APP_EOP_BANNER_TEXT
ENV REACT_APP_EOP_IMPRINT=$REACT_APP_EOP_IMPRINT
ENV REACT_APP_EOP_PRIVACY=$REACT_APP_EOP_PRIVACY
ENV REACT_APP_EOP_BANNER_TEXT=$REACT_APP_EOP_BANNER_TEXT
ARG VITE_EOP_IMPRINT
ARG VITE_EOP_PRIVACY
ARG VITE_EOP_BANNER_TEXT
ENV VITE_EOP_IMPRINT=$VITE_EOP_IMPRINT
ENV VITE_EOP_PRIVACY=$VITE_EOP_PRIVACY
ENV VITE_EOP_BANNER_TEXT=$VITE_EOP_BANNER_TEXT
RUN npx turbo run build

FROM nginxinc/nginx-unprivileged:1.27.0-alpine
Expand Down
2 changes: 1 addition & 1 deletion apps/client/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import tseslint from 'typescript-eslint';

export default tseslint.config(
{ ignores: ['build/'] },
{ languageOptions: { parserOptions: { project: './tsconfig.json' } } },
{ languageOptions: { parserOptions: { project: './tsconfig.*.json' } } },
{ settings: { react: { version: 'detect' } } },
react,
...config,
Expand Down
6 changes: 3 additions & 3 deletions apps/client/public/index.html → apps/client/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<link rel="shortcut icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="manifest" href="/manifest.json" />
<title>Elevation of Privilege</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>
36 changes: 12 additions & 24 deletions apps/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
"version": "0.24.0",
"main": "src/client/index.tsx",
"scripts": {
"build": "react-scripts build",
"dev": "react-scripts start",
"test": "react-scripts test --watchAll=false",
"test:watch": "react-scripts test",
"build": "tsc -b tsconfig.app.json && vite build",
"dev": "vite",
"start": "vite preview",
"test": "vitest run",
"test:watch": "vitest",
"lint": "eslint .",
"fixlint": "eslint . --fix",
"checkformat": "prettier . --check",
Expand All @@ -33,11 +34,10 @@
"superagent": "^9.0.2"
},
"devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@eop/eslint-config": "*",
"@eop/prettier-config": "*",
"@eop/typescript-config": "*",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/jest-dom": "^6.4.6",
"@testing-library/react": "^12.1.5",
"@testing-library/user-event": "^14.5.2",
"@types/backbone": "^1.4.19",
Expand All @@ -46,27 +46,15 @@
"@types/react-helmet": "^6.1.11",
"@types/react-router-dom": "^5.3.3",
"@types/superagent": "^8.1.7",
"@vitejs/plugin-react-swc": "^3.7.0",
"eslint-plugin-react": "^7.34.3",
"jsdom": "^24.1.0",
"nock": "^13.3.8",
"prettier": "^3.3.2",
"react-scripts": "^5.0.1",
"typescript": "^4.8.4",
"typescript-eslint": "^8.0.0-alpha.37"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
"typescript": "^5.5.3",
"typescript-eslint": "^8.0.0-alpha.37",
"vite": "^5.3.3",
"vitest": "^1.6.0"
},
"private": true
}
13 changes: 7 additions & 6 deletions apps/client/src/components/banner/banner.test.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import React from 'react';
import { vi, describe, it, afterEach, expect } from 'vitest';

import Banner from './banner';

describe('Banner', () => {
const envBackup = process.env;

afterEach(() => (process.env = envBackup));
afterEach(() => {
vi.unstubAllEnvs();
});

it('should render link if env var is defined', async () => {
// given
process.env.REACT_APP_EOP_BANNER_TEXT = 'This is a banner text';
vi.stubEnv('VITE_EOP_BANNER_TEXT', 'This is a banner text');
render(<Banner />);

// when
Expand All @@ -21,7 +23,6 @@ describe('Banner', () => {

it('should not render link if env var is not defined', () => {
// given
process.env.REACT_APP_EOP_BANNER_TEXT = '';
render(<Banner />);

// when
Expand Down
6 changes: 2 additions & 4 deletions apps/client/src/components/banner/banner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ import type { FC } from 'react';
import './banner.css';

const Banner: FC = () => {
if (process.env.REACT_APP_EOP_BANNER_TEXT) {
return (
<div className="banner">{process.env.REACT_APP_EOP_BANNER_TEXT}</div>
);
if (import.meta.env.VITE_EOP_BANNER_TEXT) {
return <div className="banner">{import.meta.env.VITE_EOP_BANNER_TEXT}</div>;
}
return null;
};
Expand Down
Loading

0 comments on commit dd64e05

Please sign in to comment.