Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
codenames/static/img/codes/**/*.jpg
codenames/static/img/cards/**/*.jpg
32 changes: 32 additions & 0 deletions .github/workflows/lint-docker.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Linting Dockerfile

on:
push:
branches:
- "main"
paths:
- 'Dockerfile'
pull_request:
paths:
- 'Dockerfile'

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

permissions:
contents: read

jobs:
linting:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: false

- name: Hadolint Dockerfile Linter
uses: hadolint/hadolint-action@v3.1.0
with:
dockerfile: Dockerfile
60 changes: 60 additions & 0 deletions .github/workflows/lint-python.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Linting Python
# https://medium.com/swlh/enhancing-code-quality-with-github-actions-67561c6f7063

on:
push:
branches:
- "main"
paths:
- '**.py'
- src/requirements.txt
pull_request:
paths:
- '**.py'
- src/requirements.txt

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

permissions:
checks: write
contents: write

jobs:
linting:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: false

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.13

- name: Install Python dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt

- name: Install Python linters
run: pip install flake8 pylint

- name: Run linters
uses: wearerequired/lint-action@v2
with:
flake8: true
flake8_args: |
--ignore=E501
continue_on_error: false
pylint: true
# https://github.com/pylint-dev/pylint/issues/8138
pylint_args: |
--disable=missing-module-docstring \
--disable=missing-class-docstring \
--disable=missing-function-docstring \
--disable=line-too-long \
--disable=too-few-public-methods \
--disable=W0511
48 changes: 48 additions & 0 deletions .github/workflows/lint-yaml.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Linting YAML

on:
push:
branches:
- "main"
paths:
- '**.yaml'
- '**.yml'
pull_request:
paths:
- '**.yaml'
- '**.yml'

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

permissions:
contents: read

jobs:
linting:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: false

- name: yaml-lint
uses: ibiqlik/action-yamllint@v3
with:
config_data: |
extends: default
rules:
comments:
level: error
comments-indentation:
level: error
document-end: disable
document-start: disable
line-length: disable
truthy:
allowed-values:
- 'true'
- 'false'
- 'on'
45 changes: 45 additions & 0 deletions .github/workflows/sast.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Static Application Security Testing (SAST)

on:
push:
branches:
- "main"
pull_request:
workflow_dispatch:

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

permissions:
contents: read

jobs:
sast:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: false
fetch-depth: 0

- name: Dependency Scanning (SCA)
uses: anchore/scan-action@v6.3.0
with:
path: "."
fail-build: true
output-format: table


- name: Create empty ".truffleignore" in case it doesn't exist
run: touch .truffleignore

- name: "Secret Scanning"
id: trufflehog
uses: trufflesecurity/trufflehog@v3.89.2
continue-on-error: false
with:
path: ./
base: ${{ github.head_ref }}
extra_args: --exclude-paths=.truffleignore
2 changes: 2 additions & 0 deletions .hadolint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ignored:
- DL3013 # Pin versions in pip. Instead of `pip install <package>` use `pip install <package>==<version>` or `pip install --requirement <requirements file>`
17 changes: 17 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
FROM python:3.13-alpine
LABEL authors="Schluggi"

WORKDIR /app

COPY codenames /app/codenames
COPY words2img /app/words2img
COPY requirements.txt /app/requirements.txt

RUN pip install --no-cache-dir --upgrade pip gunicorn eventlet
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt \
&& rm -f /app/requirements.txt

RUN python words2img/words2img.py

EXPOSE 5000
ENTRYPOINT ["gunicorn", "--worker-class", "eventlet", "-w", "2", "-b", "0.0.0.0:5000", "codenames:app"]
123 changes: 49 additions & 74 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,104 +1,79 @@
# Codenames

<a href="https://www.buymeacoffee.com/schluggi" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/white_img.png" alt="Buy Me A Coffee" style="height: auto !important;width: auto !important;" ></a>

I like the game cardboard game [codenames](https://en.wikipedia.org/wiki/Codenames_\(board_game\)) and now that COVID-19 is part of our life I have played a lot online with my friends on [this](https://www.horsepaste.com/) website. But I realized that I want to play codename pictures instead. So I've decided to create my own.

I like the game cardboard game [codenames](https://en.wikipedia.org/wiki/Codenames_\(board_game\)) and now that COVID-19 is
part of our life I have played a lot online with my friends on [this](https://www.horsepaste.com/) website. But I
realized that I want to play codename pictures instead. So I've decided to create my own.
# Features

## Features
- Realtime online multiplayer
- Multiple game modes:
- Codename classic (with words)
- Codename pictures
- Codename pictures
- Does not include any images (for copyright reasons, but you can import your own)
- Just like the codenames board game...

## Requirements
- Python >= 3.6
- [Almost every](https://docs.sqlalchemy.org/en/13/core/engines.html#database-urls) database engine is supported (SQLite
in memory by default)

## Installation & Quickstart
1. Clone this repo
2. Create a virtualenv and join them
3. Install python requirements
```shell script
$ pip3 install -r requirements.txt
```
4. Generate text images (for the classic mode)
```shell script
$ ./words2img/words2img.py
```
Optional: [Import images](https://github.com/Schluggi/codenames#import-images) for picture mode
5. Configuration
- 5.1 Create a secret key by running `python3 -c "import os; print(os.urandom(24).hex())"` and insert that key into the
`config.py`
6. Test your setup by running `flask run`
7. If everything works as expected, you should now be able to play at `http://localhost:5000`

## Configuring
### Add new words or languages
- Just like the codenames board game but online

# Quickstart

## Docker

```commandline
docker run -p 5000:5000 -e GAME_MODES="pictures,classic_de,classic_en,classic_en-undercover" <placeholder>:latest
```

## Git

```commandline
git clone git@github.com:Schluggi/codenames.git
cd codenames
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python3 ./words2img/words2img.py
flask --app codenames run
```

Optional: [Import images](https://github.com/Schluggi/codenames#import-images) for picture mode

# Configuring

## Environment variables

| name | Description | required | default |
|------------|------------------------------------------------|----------|------------------------------------------------------|
| GAME_MODES | A comma separated list of available game modes | No | pictures,classic_de,classic_en,classic_en-undercover |
| SECRET_KEY | A secret key to encrypt the user sessions | No | \<a random key will be created\> |

## Add new words or languages

In this example we'll add france as language for the classic mode.

1. Create a language file: `./words2img/words/fr.txt` (one word each line)
2. Run the script (existing files will be overwritten)
```shell script
$ python3 ./words2img/words2img.py
```commandline
python3 ./words2img/words2img.py
```
3. Append `classic_fr` to the `GAME_MODES` list in the `config.py`
3. Append `classic_fr` to your `GAME_MODES` environment variable

## Import images

### Import images
To get the best experience it's recommend to buy the original cardboard game and scan all images. In my case I scanned
all pictures with 400dpi and used [picpunch](https://github.com/Schluggi/picpunch) to cut them to size and render for
all pictures with 400dpi and used [picpunch](https://github.com/Schluggi/picpunch) to cut them to size and render for
web (`--border 5 --quallity 30`).The new images have to be placed into the corresponding folders.

The code images into (at least 20):

- `codenames/static/images/codes`

And the colored team cards (at least 1 each):
- `codenames/static/images/cards/assassin`

- `codenames/static/images/cards/assassin`
- `codenames/static/images/cards/blue`
- `codenames/static/images/cards/neutral`
- `codenames/static/images/cards/red`

The filename does not matter. But the file extension and type has to be JPEG/JPG.

### Apache2 with mod_wsgi
`flask run` works fine but you should'nt use it for production deployment. However you can use Apache2 instead.
If not already installed you have to install `libapache2-mod-wsgi-py3`. After installation you can create a virtualhost
like in this example:

```
<VirtualHost *:80>
ServerName codenames.example.org
Redirect / https://codenames.example.org/
</VirtualHost>

<VirtualHost *:443>
ServerName codenames.example.org

WSGIDaemonProcess wsgi_codenames user=www-data group=www-data processes=1 threads=5 python-home=python-home=/virtualenvs/codenames/
WSGIScriptAlias / /var/www/codenames/wsgi.py

SSLEngine On
SSLCertificateFile /etc/letsencrypt/live/codenames.example.org/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/codenames.example.org/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/codenames.example.org/chain.pem
SSLProtocol ALL -SSLv2 -SSLv3
SSLHonorCipherOrder On
SSLCipherSuite ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:
SSLCompression Off
Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"

<Directory /var/www/codenames/>
WSGIProcessGroup wsgi_codenames
WSGIApplicationGroup %{GLOBAL}
</Directory>
</VirtualHost>
```
I use Let's Encrypt for free ssl certificates. Please ensure that all paths are correct. After restating Apache2,
codenames should be run as part of the Apache2-daemon.
# Credits

## Credits
Created and maintained by Schluggi.
Loading
Loading