# Trivabble Trivabble is free a network Scrabble game under the (AGPLv3 license)[LICENSE]. It is not in any way connected to Hasbro, who has the rights on the trademark Scrabble. Trivabble provides a board, a bag full of tiles, racks and a chat. People can play without registering and join each other by using the same game number. It features: - a board, a bag full of tiles, a rack for every player - a chat so people can communicate - a way to set the score of each player - support for different languages (set of tiles as well as the interface). Thanks to Wikipedia for providing data about tiles for each language (https://fr.wikipedia.org/wiki/Lettres_du_Scrabble) Trivabble does not implement any rule: you are free to play your way. It does not understand what you do and is not able to compute the score, like your real board game. Trivabble needs to be installed on a server, and is playable from a browser. It supports: - latest versions of Firefox and Chromium - Mobile browsers on Android - Safari 9 and later on the iPad It should work on any browser released after 2015, though we haven't tested it on Internet Explorer. This documentation is intented for people who want to install Trivabble on their server. If you just want to play, head to https://trivabble.org/. For contributions, see (contributing)[CONTRIBUTING.md]. ## Set up for production Note: Please be aware that this is alpha-quality software. We do our best to avoid breaking stuff but we might from time to time. With this out of the way… Trivabble is composed of two parts: the server and the client. - The server is a Javascript program that runs on Node JS. It waits for HTTP and WebSocket requests on a configurable port (default: 3000), and a configurable address (default: localhost). This server needs to run for Trivabble to work, and proxified through a Web server like Apache or Nginx. - The client is a set of static files that need to be server by a Web server ### Prerequisite You need to have: - Node (version 10 or later) - make - git - a Web server such as Apache or Nginx. On a Debian-based system, the following command will install make and node: apt install make nodejs git On some systems, the node binary does not exist and is called `nodejs` instead. Trivabble expects the Node binary to be `node`. On these systems, a `nodejs-legacy` package may exist to fix this. Otherwise, you will need to create a symblink. As for the web server, we will asume that you already have one running and correctly configured. ### Installation We will assume www-data is the UNIX user of your Web server. Adapt if necessary. 1. Set up the directories that will host the server and the client. Create a UNIX user for the Trivabble server and set the right permission: The server should be outside the root of your Web server. The client will be served by your Web server. Let's store the chosen paths in environment variables (adapt if necessary) and create these directories: ```sh export TRIVABBLE_SERVER_PATH=/opt/trivabble-server export TRIVABBLE_PUBLIC_PATH=/var/www/html/trivabble sudo groupadd trivabble sudo useradd -G trivabble trivabble sudo mkdir -p "$TRIVABBLE_PUBLIC_PATH" sudo chown www-data:www-data "$TRIVABBLE_PUBLIC_PATH" sudo chmod g+x "$TRIVABBLE_PUBLIC_PATH" sudo mkdir -p "$TRIVABBLE_SERVER_PATH" sudo chown trivabble:trivabble "$TRIVABBLE_PUBLIC_PATH" ``` 2. Clone the repository somewhere (in your HOME directory for instance): ```sh git clone https://gitlab.com/raphj/trivabble.git cd trivabble ``` 3. Get the latest production version: ```sh git checkout "$(git tag --list '[prod]*' --sort=v:refname | tail -1)" ``` 4. Make sure you still have your environment variable set (adapt if necessary): ```sh export TRIVABBLE_SERVER_PATH=/opt/trivabble-server export TRIVABBLE_PUBLIC_PATH=/var/www/html/trivabble ``` Also make sure you still are in the trivabble repository. 5. Run, as a user having sudo privileges: ```sh ./bin/upgrade-prod.sh --prod-public-dir "$TRIVABBLE_PUBLIC_PATH" --prod-server-dir "$TRIVABBLE_SERVER_PATH" --trivabble-chown trivabble:trivabble --webserver-chown www-data:www-data ``` This will: - run `make` so everything that needs to be build will be built, including the language files - transform Javascript files so they are compatible with older browsers - copy the server and client files to the chosen folders 6. (Optional) - In the public directory (`$TRIVABBLE_PUBLIC_PATH`), review `config.js.sample`. If there are values you would like to change, copy it to config.js and make the desired changes. 7. Run the Trivabble server. ```sh cd "$TRIVABBLE_SERVER_PATH" node trivabble-server ``` You may want to run this in a `screen` so you can leave the session and trivabble-server still runs in the background. Better yet, create a service for your init system: - create `/usr/local/bin/start-trivabble`: ``` #!/bin/sh cd /var/www/html/raph/raw/trivabble exec sudo -u www-data DEBUG_LOG=true nodejs trivabble-server.js ``` 8. Configure your web server. #### Content-Security Policy Header Trivabble loads 5 static javascript files, 2 static css files and a sound from its origin, and connects to the same server by SSE or websockets. Here is the recommended HTTP CSP header for Trivabble: ``` Content-Security-Policy: default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; connect-src 'self'; media-src 'self' ``` We advise you to set this up to improve the security of your setup. In the next two sections, we describe the configuration for Apache 2 and Nginx. #### Apache 2 On Apache 2, the relevant rules are: RewriteEngine on RewriteRule "^/?:trivabble/ws/(.*)" ws://localhost:3000/ws/$1 [P] ProxyPass "/:trivabble" http://localhost:3000/ retry=0 ProxyPassReverse "/:trivabble" http://localhost:3000/ You will need to enable modules `proxy_http`, `proxy_wstunnel` (if you do not disable websockets in `config.js`) and `rewrite`: ```sh a2enmod proxy_http a2enmod proxy_wstunnel a2enmod rewrite ``` :warning: Be careful to allow enough concurrent processes / threads / workers on your web server. Each player requires one long-standing connection (XHR, SSE or WebSocket), plus small requests when not using WebSockets. Long-standing connections may cause issues with Apache 2, and using HTTP 2 may lead to "interesting" behavior. ### Nginx Here is an example of an Nginx configuration for Trivabble: ``` server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name trivabble.example.org; location /:trivabble/ws/ { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_set_header Host $host; } location /:trivabble { proxy_pass http://127.0.0.1:3000; proxy_buffering off; } location /trivabble { alias /var/www/html/trivabble-public; } # SSL configuration here } ``` ## Enable the spell checker The process of building the dictionaries takes a lot of disk space and require huge amount of memory (around 1GB). Install `wget` and `aspell` (to have the `word-list-compress` command), and run: ```sh cd dict-dists-extractor make ``` If you want to limit spelling to a subset of languages, you can define the list by the `LANGS` variable before executing the `make` command such as: ```sh cd dict-dists-extractor LANGS="de en fr" make ``` This way, you only build English, French and German dictionaries. To deactivate spell checker at system level, you need to empty dictionary list contained into file `public/dict/list.js`. Such command can be used: ```sh echo > public/dict/list.js ``` ## Technical appendices ### Board extractor Wikipedia provides tile distributions (content of the bag and points) for various languages. Board languages are built from a Wikipedia page. #### General parsing Most board languages are extracted from the French version of the Wikipedia page which has a simple document structure. Parsing is done by a JS script named `make_board.js`: - each new language board is proceeded by a level 2 header containing language name, - tile points is followed by `point(s)` - tile letter and number of tiles are easy extracted by a regex which looks like `(letter) x(times)` #### Special languages Some languages are only defined into the English version. So we copy them into separated text files and parsing is done by an AWK named `make_board.awk`. ### Dictionary building process The spell checker in Trivabble is based on Aspell dictionaries. However, as Trivabble only uses a subset of letters (most accentuated characters have to be replaced by standard ones), we can't use Aspell engine straightforward; we need to build lists of words that only use playable characters. #### Overall concept In order to build dictionaries for various languages, we first need to retrieve Aspell dictionary lists. Then we retrieve the last versions of dictionaries for every languages and we build them. Thanks to two Aspell commands, we build the full list of words. Based on the distribution of tiles, we translate every derived (most of the time accentuated) character by the appropriate one, and finally we remove duplicated entries. #### Details on Makefile rules Rule '$(OBJ_DIR)/src.mk' retrieves on Aspell site the last version of the dictionary list, extract dictionary archive URL and build a sub-makefile with rules to retrieve every needed dictionary. Rule '%.dir' unpacks dictionary archives and build Aspell dictionary. Result directory is rename as LANG.dir Rule '%.low' expands a Aspell dictionary into a list of words (low means "List Of Words"". Phrases are split into words. Finally the list is ordered and clean from duplicated words. Rule '$(ROOT_DICT)/%.dict': - excludes words with numbers, dashes, apostrophes and other forbidden signs, - translates accentuated characters into standard ones, - up-case all words, - and remove duplicated words. This file can be used by Trivabble for spell checking. Last rule 'check-%' checks that file %.dict contains only words with characters base on language tile bag. #### Remarks Some lists of words are too huge (for example Hungarian or Turkish are agglutinative languages), so Trivabble will not be able to check spelling for those languages. Some languages don't have any Aspell dictionary. ### Credits Thanks [Laurent Mazet](http://www.softndesign.org/~mazet/) for many contributions. Thanks [Ysabeau](https://linuxfr.org/users/ysabeau/) for the design of the bag. Thanks every other past and future contributors who have written code, tickets, tested the game and who I have not mentionned here yet (please tell me if your name is missing!).