Rust CRUD API server and daemon to run the vote collectors
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
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
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).
/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 applicationlib.rs
- Entry point for the shared libraryconfig.rs
- Handle environment variablesschema.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
- Ruststruct
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.