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
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ You may also venture on your own, adapting the following instructions to your ne
Set the following environment variables, via `.env` or your shell:
- `DOCKER_DB_ROOT_PASSWORD` will be used as the password for the database root user.
- `DATABASE_URL` is used for db connection. During development, this is `postgres://tau:tau@localhost:5432/tau`.
- `SECRET` will be used as high entropy data used for generating tokens.
- `FRONTEND_ORIGIN` will be used as an allowed [origin](https://developer.mozilla.org/en-US/docs/Glossary/Origin) for the purpose of [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS). Must be a valid URL.

Start the database with `docker compose --profile dev (up -d/down)`.
Run the migrations via sqlx-cli with `sqlx run migrate` or by other means.
Expand All @@ -22,10 +22,11 @@ Compile and run the project with `cargo`.
For deploying via docker, set the following environment variables:
- `DOCKER_DB_PASSWORD` which will be used as the password for the backend's database access user.
- `DOCKER_DB_ROOT_PASSWORD` will be used as the password for the database root user.
- `SECRET` will be used as high entropy data used for generating tokens.
- `FRONTEND_ORIGIN` will be used as an allowed [origin](https://developer.mozilla.org/en-US/docs/Glossary/Origin) for the purpose of [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS). Must be a valid URL (`http://localhost:3000` by default).
Then, run `docker compose --profile prod`.

### Optional configuration
- `SECRET` will be used as additional high entropy data used for generating tokens. By default, tau uses system entropy and the current UNIX timestamp.
- `PORT` will be used as the port the server listens on. The default is 2023.

The following example `.env` file is geared for both scenarios:
Expand All @@ -34,6 +35,7 @@ DATABASE_URL=postgres://tau:tau@localhost:5432/tau
SECRET=CENTRUMRWLYSONOSTARPOZNANCDNSBCD4L52SPM
DOCKER_DB_ROOT_PASSWORD=superdoopersecretpasswordthatcannotbeleaked
DOCKER_DB_PASSWORD=wedoingsecurityinhere
FRONTEND_ORIGIN=https://example.com
PORT=2019
```

Expand Down
2 changes: 2 additions & 0 deletions compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ services:
- DATABASE_URL=postgres://tau:${DOCKER_DB_PASSWORD}@db-prod:5432/tau
- PORT=${PORT}
- SECRET=${SECRET}
- FRONTEND_ORIGIN=${FRONTEND_ORIGIN}
depends_on:
db-prod:
condition: service_healthy
Expand Down Expand Up @@ -49,6 +50,7 @@ services:
- dbrootpassword
environment:
- POSTGRES_PASSWORD_FILE=/run/secrets/dbrootpassword
- FRONTEND_ORIGIN=http://localhost:3000
volumes:
- dbdevdata:/var/lib/postgresql/data
- ./dbinit-dev.sh:/docker-entrypoint-initdb.d/dbinit-dev.sh
Expand Down
3 changes: 1 addition & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use axum::Router;
use tokio::net::TcpListener;
use tower_cookies::CookieManagerLayer;
use tower_http::cors::{Any, CorsLayer};
use tracing::error;
use users::infradmin::guarantee_infrastructure_admin_exists;

Expand All @@ -25,7 +24,7 @@ async fn main() {
let app = Router::new()
.merge(routes::routes())
.with_state(state)
.layer(CorsLayer::new().allow_origin(Any).allow_methods(Any))
.layer(setup::configure_cors())
.layer(CookieManagerLayer::new());

let addr = setup::get_socket_addr();
Expand Down
33 changes: 33 additions & 0 deletions src/setup.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use axum::http::{header::CONTENT_TYPE, HeaderValue, Method};
use sqlx::{Pool, Postgres};
use std::net::{Ipv4Addr, SocketAddrV4};
use tokio::net::TcpListener;
use tower_http::cors::CorsLayer;
use tracing::{error, info, warn, Level};
use tracing_subscriber::FmtSubscriber;

Expand All @@ -9,6 +11,7 @@ use crate::database;
const CRYPTO_SECRET_CORRECT: &str = "Cryptographic SECRET is set.";
const CRYPTO_SECRET_NOT_SET: &str = "Cryptographic SECRET is not set. This may lead to increased predictability in token generation.";
const CRYPTO_SECRET_ERROR: &str = "Could not read SECRET. Is it valid UTF-8?";
const FRONTEND_ORIGIN_NOT_SET: &str = "FRONTEND_ORIGIN is not set. Please provide a valid URL leading to an accepted origin.";

pub fn initialise_logging() {
let subscriber = FmtSubscriber::builder()
Expand Down Expand Up @@ -94,3 +97,33 @@ pub fn check_secret_env_var() {
},
}
}

pub fn configure_cors() -> CorsLayer {
let default_origin = "http://localhost:3000".to_owned();
let result = std::env::var("FRONTEND_ORIGIN");

#[cfg(not(debug_assertions))]
if result.is_err() {
error!("{}", FRONTEND_ORIGIN_NOT_SET);
panic!();
}

let frontend_origin = result.unwrap_or(default_origin);
info!(
"FRONTEND_ORIGIN set to {}. Requests made from any other origins will be disallowed at browser level",
&frontend_origin
);
let layer = CorsLayer::new()
.allow_origin(frontend_origin.parse::<HeaderValue>().unwrap())
.allow_methods([
Method::GET,
Method::POST,
Method::DELETE,
Method::PATCH,
Method::PUT,
])
.allow_headers([CONTENT_TYPE])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, does it require us to specify allowed headers? Please tell me it doesn't. And let's not do that if we can avoid it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sadly, it does.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you tell me exactly why? How does this need manifest?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When trying to make requests at browser level, errors are returned: this one and others relating to it. This forced me to define allowed origins, methods and headers.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After testing this turns out to be true; I meant specifically Allowed-Headers, since the other ones are commonly seen and all. This is so extremely dumb. But yes, I concede. This works.

.allow_credentials(true);

return layer;
}