Skip to content

Latest commit

 

History

History

collector

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Electronic Voting Collector

Rust CRUD API server and daemon to run the vote collectors


Compiling and Running

Please see the server README.md for instructions on compiling the code and configuring the database. Each collector should run in its own separate database instance. In the .env file, you will need to manually specify the DATABASE_URL for each collector when running migrations.

When running the code, you will need to specify a number (1, 2, ...) as a parameter to indicate which collector to run. This flag is used in the .env file to prefix environment variables specific to each collector, allowing you to use one file for all collectors. You can also optionally specify the port and/or host using --port (or -p) and --host (or -h) command-line arguments. These values override any environment values specified in the .env files. Use the --help flag to list all command-line options.

# Start Collector 1 on port 3024
cargo run -- 1 -p 3024

# Start Collector 5 on a custom host with port 3456
cargo run -- 5 -h 192.168.1.234 --port 3456

Be sure to specify the --release flag for the production server:

cargo run --release -- 1

Database

See the Server README.md file for details on configuring the PostgreSQL database.

When running the database migrations, you will need to set DATABASE_URL (no prefix) environment variable individually to configure each database separately. Alternatively, this can be passed in as a command-line argument to the diesel command.

The reposity provides a useful run-diesel.sh Bash script to automate this process by passing the $C{i}_DATABASE_URL variable to diesel. Using this script allows you to run a diesel command on all collector databases at once:

Usage: run-diesel.sh <start> <end> <...diesel arguments>

For example: run-diesel.sh 5 10 migration run
  - Runs migrations for collectors 5 to 10

Environment Variables

For running the collector, you will need to specify certain environment variables. This can be done using the following files:

  • .env - Environment variables shared by both development and production systems
  • .env.development - Environment variables only on development system
  • .env.production - Environment variables only on production system

Alternatively, these values can be passed in using command-line parameters when running the API server. The command-line parameters override any values set in the .env files.

Variable Command-line Flag Required Default Value Description
Collector Argument Yes Index of the collector (1, 2, ...)
C{i}_HOST --host No 127.0.0.1 IP address to use for running collector i. If you use the localhost IP address, then you cannot connect to the API server from an external location. This must be an IP address and not a domain name.
C{i}_PORT --port No 4000 + i Port number for collector i. (4001, 4002, ...)
C{i}_USE_HTTPS --use-https No false If true, then use HTTPS instead of HTTP for API requests. HTTPS encryption is performed using the OpenSSL library.
C{i}_KEY_FILE --key-file Only If USE_HTTPS Private key file for OpenSSL. This should be an unencrypted .pem file.
C{i}_CERT_FILE --cert-file Only If USE_HTTPS Certificate file for OpenSSL. This should be the unencrypted .pem file generated using the private key. For compatibility with some applications, this should be the full chain file and not just the certificate.
C{i}_DATABASE_URL --database-url Yes PostgreSQL Connection URI for accessing the collector i database.
JWT_SECRET --jwt_secret, -s No Hidden... Secret value for signing the JSON Web Token
MEDIATOR_URL --mediator-url Yes Base URL to access the mediator. If running on the same machine as the API server with default settings, this value can be set to http://localhost:3004.
COLLECTOR_SECRET --collector-secret No Hidden... Shared secret value used by the collectors to ensure the public keys are faithfully published by the mediator.

Since the same executable is used for all collectors, many of the environment variables need to be prefixed with a C{i]_, where i is the collector index (like C1_, C2_, ...). The command-line flags do not require this prefix, as the collector index is known when running the program (It is a required argument).


Code Structure

  • /src - All source code files for the API server
  • /migrations - Database migrations for the PostgreSQL database

Main files in the /src directory:

  • main.rs - Entry point for the collector application
  • lib.rs - Entry point for the shared library
  • config.rs - Handle environment variables
  • schema.rs - Auto-generated file by Diesel ORM that exports the database tables for Rust

Main folders in the /src directory:

  • /auth - Structures and functions for authentication and authorization using JSON Web Tokens
  • /db - Structures and functions needed for running the database
  • /errors - Structures and functions for error handling across the application
  • /handlers - All REST API handlers
  • /models - Rust struct definitions for tables in the database
  • /protocol - Structures and functions specific to the electronic voting protocol
  • /utils - Miscellaneous helper functions
  • /views - Shared structures that define the return types from the API handlers

Note: The collector daemon compiles both a shared library and a main executable. Using this structure enables other binary utilities (/src/bin directory) to access the data types and API handlers. Although this project doesn't have any utilities currently, this may be useful in the future.

Upon initialization, the collector communicates with the mediator to register all networking information (like IP address and port). Each collector should be pre-assigned a unique UUID and can also be given a website-friendly name. If a collector is ever restarted, calling this handler again will update the database to contain the most recent network and name information. (Just be sure to use the same UUID when calling the handler again, or it will register a new collector instead.)

In the current implementation, a collector can never be unregistered from the system once registered, or otherwise some elections could not be verified anymore. At some point, there might be a way to "move" data from one collector to another, but this feature is not currently supported.

The collectors communicate using WebSockets for the verification protocol. Websocket communication is handled using the VerificationWebsocketActor Actix Actor.

See the Server README.md file for more details on authentication, database structures, and error handling.