├── db └── .gitkeep ├── db-images └── .gitkeep ├── src ├── client │ ├── styles │ │ ├── about.css │ │ ├── cards.jpg │ │ ├── create.css │ │ └── cards.css │ ├── components │ │ ├── model │ │ │ ├── model.css │ │ │ └── model.js │ │ ├── imagemodel │ │ │ ├── imagemodel.css │ │ │ └── imagemodel.js │ │ ├── license │ │ │ ├── licenseAttribution.css │ │ │ ├── licenseAttribution.test.tsx │ │ │ └── licenseAttribution.tsx │ │ ├── status │ │ │ ├── status.css │ │ │ ├── status.js │ │ │ └── status.test.js │ │ ├── leaderboard │ │ │ ├── leaderboard.css │ │ │ ├── leaderboard.test.js │ │ │ └── leaderboard.js │ │ ├── footer │ │ │ ├── footer.test.js │ │ │ └── footer.js │ │ ├── logo │ │ │ ├── logo.tsx │ │ │ └── logo.test.tsx │ │ ├── board │ │ │ ├── board.css │ │ │ ├── board.test.js │ │ │ └── board.js │ │ ├── dealtcard │ │ │ ├── dealtcard.test.js │ │ │ └── dealtcard.js │ │ ├── timer │ │ │ ├── timer.css │ │ │ ├── timer.test.js │ │ │ └── timer.js │ │ ├── threatbar │ │ │ ├── threatbar.css │ │ │ ├── threatbar.test.js │ │ │ └── threatbar.js │ │ ├── downloadbutton │ │ │ ├── downloadbutton.test.js │ │ │ └── downloadbutton.js │ │ ├── sidebar │ │ │ ├── sidebar.css │ │ │ ├── sidebar.test.js │ │ │ └── sidebar.js │ │ ├── copybutton │ │ │ ├── copybutton.test.js │ │ │ └── copybutton.js │ │ ├── deck │ │ │ ├── deck.test.js │ │ │ └── deck.js │ │ └── threatmodal │ │ │ ├── threatmodal.js │ │ │ └── threatmodal.test.js │ ├── utils │ │ └── utils.js │ ├── pages │ │ ├── __tests__ │ │ │ ├── app.test.tsx │ │ │ ├── about.test.tsx │ │ │ └── create.test.tsx │ │ ├── app.tsx │ │ └── about.tsx │ ├── jointjs │ │ └── joint-tm.css │ └── serviceWorker.js ├── react-app-env.d.ts ├── server │ ├── config.ts │ ├── __tests__ │ │ └── config.test.js │ ├── server.ts │ ├── gameServer.ts │ ├── ModelFlatFile.ts │ ├── publicApi.ts │ └── endpoints.js ├── utils │ ├── serverConfig.ts │ ├── constants.ts │ ├── __tests__ │ │ ├── cardDefinitions.test.ts │ │ └── utils.test.js │ ├── utils.ts │ └── cardDefinitions.ts ├── game │ ├── context.ts │ ├── threat.ts │ ├── setupData.ts │ ├── __tests__ │ │ ├── definitions.test.ts │ │ ├── eop.test.js │ │ └── utils.test.ts │ ├── gameState.ts │ ├── eop.ts │ ├── utils.ts │ ├── moves.ts │ └── definitions.ts └── index.tsx ├── .eslintignore ├── .prettierignore ├── .dockerignore ├── docs ├── eop.gif └── eop_cornucopia.png ├── .prettierrc.cjs ├── cornucopiaCards ├── style.css ├── cornucopia.png ├── package.json ├── LICENSE └── README.md ├── public ├── logo.png ├── favicon.ico ├── manifest.json └── index.html ├── .editorconfig ├── docker-compose.yml ├── .gitignore ├── docker ├── client.dockerfile ├── files │ └── etc │ │ └── nginx │ │ ├── conf.d │ │ └── default.conf │ │ └── nginx.conf └── server.dockerfile ├── .github └── workflows │ └── checks.yml ├── tsconfig.json ├── tsconfig.server.json ├── LICENSE ├── .eslintrc.cjs └── package.json /db/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /db-images/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/client/styles/about.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/client/components/model/model.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build/ 2 | build-server/ 3 | coverage/ -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | build/ 2 | build-server/ 3 | coverage/ 4 | -------------------------------------------------------------------------------- /src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | deploy/ 3 | build/ 4 | db/ 5 | **/*.test.js 6 | .heroku/ 7 | -------------------------------------------------------------------------------- /docs/eop.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dehydr8/elevation-of-privilege/HEAD/docs/eop.gif -------------------------------------------------------------------------------- /.prettierrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | trailingComma: 'all', 3 | singleQuote: true, 4 | }; 5 | -------------------------------------------------------------------------------- /cornucopiaCards/style.css: -------------------------------------------------------------------------------- 1 | .cornucopiacard { 2 | background-image: url("cornucopia.png"); 3 | } -------------------------------------------------------------------------------- /public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dehydr8/elevation-of-privilege/HEAD/public/logo.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dehydr8/elevation-of-privilege/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /docs/eop_cornucopia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dehydr8/elevation-of-privilege/HEAD/docs/eop_cornucopia.png -------------------------------------------------------------------------------- /src/client/styles/cards.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dehydr8/elevation-of-privilege/HEAD/src/client/styles/cards.jpg -------------------------------------------------------------------------------- /cornucopiaCards/cornucopia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dehydr8/elevation-of-privilege/HEAD/cornucopiaCards/cornucopia.png -------------------------------------------------------------------------------- /src/client/utils/utils.js: -------------------------------------------------------------------------------- 1 | export async function copyToClipboard(text) { 2 | return await navigator.clipboard.writeText(text); 3 | } 4 | -------------------------------------------------------------------------------- /src/client/components/imagemodel/imagemodel.css: -------------------------------------------------------------------------------- 1 | div.model { 2 | height: 100%; 3 | } 4 | 5 | div.deselect { 6 | position: absolute; 7 | height: 100%; 8 | width: 100%; 9 | } -------------------------------------------------------------------------------- /src/client/components/license/licenseAttribution.css: -------------------------------------------------------------------------------- 1 | .license-attribution { 2 | text-align: center; 3 | font-size: 70%; 4 | position: fixed; 5 | bottom: 0; 6 | right: 0; 7 | } 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | indent_style = space 7 | indent_size = 2 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /src/server/config.ts: -------------------------------------------------------------------------------- 1 | import { ModelFlatFile } from './ModelFlatFile'; 2 | 3 | export function getDatabase(): ModelFlatFile { 4 | return new ModelFlatFile({ 5 | dir: 'db', 6 | logging: false, 7 | }); 8 | } 9 | -------------------------------------------------------------------------------- /src/client/components/status/status.css: -------------------------------------------------------------------------------- 1 | span.status strong { 2 | vertical-align: top; 3 | display: inline-block; 4 | max-width: 40em; 5 | overflow: hidden; 6 | text-overflow: ellipsis; 7 | white-space: nowrap; 8 | } -------------------------------------------------------------------------------- /src/client/components/leaderboard/leaderboard.css: -------------------------------------------------------------------------------- 1 | .player-name { 2 | min-width: 120%; 3 | max-width: 0; 4 | overflow: hidden; 5 | text-overflow: ellipsis; 6 | white-space: nowrap; 7 | } 8 | 9 | .check-mark { 10 | text-align: center; 11 | } 12 | -------------------------------------------------------------------------------- /src/utils/serverConfig.ts: -------------------------------------------------------------------------------- 1 | export const SERVER_PORT = Number.parseInt(process.env.SERVER_PORT ?? '8000'); 2 | export const API_PORT = Number.parseInt(process.env.API_PORT ?? '8001'); 3 | export const INTERNAL_API_PORT = Number.parseInt( 4 | process.env.INTERNAL_API_PORT ?? '8002', 5 | ); 6 | -------------------------------------------------------------------------------- /src/game/context.ts: -------------------------------------------------------------------------------- 1 | import type { Ctx as BoardgameCtx } from 'boardgame.io'; 2 | 3 | export interface Ctx extends BoardgameCtx { 4 | gameover: number; 5 | random: Exclude; // we use the default plugins, including the random plugin, making this always available 6 | } 7 | -------------------------------------------------------------------------------- /src/game/threat.ts: -------------------------------------------------------------------------------- 1 | import type { Suit } from '../utils/cardDefinitions'; 2 | 3 | export interface Threat { 4 | modal: boolean; 5 | new: boolean; 6 | id?: string; 7 | owner?: string; 8 | title?: string; 9 | type?: Suit; 10 | severity?: string; 11 | description?: string; 12 | mitigation?: string; 13 | } 14 | -------------------------------------------------------------------------------- /src/game/setupData.ts: -------------------------------------------------------------------------------- 1 | import type { Suit } from '../utils/cardDefinitions'; 2 | import type { GameMode, ModelType } from '../utils/constants'; 3 | 4 | export interface SetupData { 5 | startSuit: Suit; 6 | gameMode: GameMode; 7 | modelType: ModelType; 8 | turnDuration: number; 9 | spectatorCredential: string; 10 | } 11 | -------------------------------------------------------------------------------- /src/client/components/footer/footer.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import Footer from './footer'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(