mirror of
https://github.com/mvvasilev/findtheti.me.git
synced 2025-04-11 18:15:01 +03:00
Add SSL support, add not found page
This commit is contained in:
parent
30919f7700
commit
6f0913816e
15 changed files with 361 additions and 49 deletions
14
.env.example
14
.env.example
|
@ -1,3 +1,11 @@
|
|||
DATABASE_URL= // the url to the database ( example local postgres: postgres://postgres:postgres@localhost/findthetime )
|
||||
EVENT_UID_SIZE= // size of snowflake ids for events ( 20 )
|
||||
LOG_LEVEL= // see https://docs.rs/tracing-subscriber/0.3.15/tracing_subscriber/struct.EnvFilter.html#. Default is info
|
||||
DATABASE_URL= # the url to the database ( example local postgres: postgres://postgres:postgres@localhost/findthetime )
|
||||
EVENT_UID_SIZE= # size of snowflake ids for events ( 20 )
|
||||
LOG_LEVEL= # see https://docs.rs/tracing-subscriber/0.3.15/tracing_subscriber/struct.EnvFilter.html#. Default is info
|
||||
|
||||
HTTP_PORT= # 8080 by default
|
||||
|
||||
SSL_ENABLED= # false by default
|
||||
SSL_REDIRECT= # true by default
|
||||
SSL_PORT= # 8443 by default
|
||||
SSL_CERT_PATH= # no default, if SSL_ENABLED is true, this must be configured, or the backend will panic. In a docker environment, this is configured by default ( see Dockerfile )
|
||||
SSL_KEY_PATH= # no default, if SSL_ENABLED is true, this must be configured, or the backend will panic. In a docker environment, this is configured by default ( see Dockerfile )
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
/target
|
||||
.env
|
||||
.env
|
||||
.self-signed
|
110
Cargo.lock
generated
110
Cargo.lock
generated
|
@ -60,6 +60,12 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.77"
|
||||
|
@ -164,6 +170,29 @@ dependencies = [
|
|||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-server"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1ad46c3ec4e12f4a4b6835e173ba21c25e484c9d02b49770bf006ce5367c036"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"pin-project-lite",
|
||||
"rustls",
|
||||
"rustls-pemfile",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tower",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.69"
|
||||
|
@ -426,9 +455,10 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
|
|||
|
||||
[[package]]
|
||||
name = "findtheti-me"
|
||||
version = "0.1.4"
|
||||
version = "0.1.7"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"axum-server",
|
||||
"chrono",
|
||||
"dotenv",
|
||||
"env_logger",
|
||||
|
@ -1308,6 +1338,20 @@ version = "0.8.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"getrandom",
|
||||
"libc",
|
||||
"spin 0.9.8",
|
||||
"untrusted",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rsa"
|
||||
version = "0.9.6"
|
||||
|
@ -1347,6 +1391,44 @@ dependencies = [
|
|||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.21.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba"
|
||||
dependencies = [
|
||||
"log",
|
||||
"ring",
|
||||
"rustls-webpki",
|
||||
"sct",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35e4980fa29e4c4b212ffb3db068a564cbf560e51d3944b7c88bd8bf5bec64f4"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e9d979b3ce68192e42760c7810125eb6cf2ea10efae545a156063e61f314e2a"
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.101.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.14"
|
||||
|
@ -1365,6 +1447,16 @@ version = "1.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "sct"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.195"
|
||||
|
@ -1861,6 +1953,16 @@ dependencies = [
|
|||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-rustls"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
|
||||
dependencies = [
|
||||
"rustls",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.14"
|
||||
|
@ -2049,6 +2151,12 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.0"
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
[package]
|
||||
name = "findtheti-me"
|
||||
version = "0.1.4"
|
||||
version = "0.1.7"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
axum = { version = "0.7.3", features = ["macros", "tokio"] }
|
||||
axum-server = { version = "0.6.0", features = ["tls-rustls"] }
|
||||
chrono = { version = "0.4.31", features = ["serde"] }
|
||||
dotenv = "0.15.0"
|
||||
env_logger = "0.10.1"
|
||||
|
@ -16,6 +17,6 @@ serde = { version = "1.0.195", features = ["derive"] }
|
|||
serde_json = "1.0.111"
|
||||
sqlx = { version = "0.7.3", features = ["runtime-tokio", "postgres", "chrono"] }
|
||||
tokio = {version = "1.35.1", features = ["macros", "rt-multi-thread", "rt", "net"]}
|
||||
tower-http = { version = "0.5.0", features = ["fs", "trace"] }
|
||||
tower-http = { version = "0.5.0", features = ["fs", "trace", "cors"] }
|
||||
tracing = "0.1.40"
|
||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "std"] }
|
||||
|
|
12
Dockerfile
12
Dockerfile
|
@ -54,8 +54,14 @@ USER appuser
|
|||
ENV LOG_LEVEL=info
|
||||
ENV EVENT_UID_SIZE=20
|
||||
|
||||
ENV HTTP_PORT=8080
|
||||
|
||||
ENV SSL_ENABLED=false
|
||||
ENV SSL_REDIRECT=true
|
||||
ENV SSL_PORT=8443
|
||||
ENV SSL_CERT_PATH=/etc/findtheti-me/certs/server.cert
|
||||
ENV SSL_KEY_PATH=/etc/findtheti-me/certs/server.key
|
||||
|
||||
WORKDIR ./findtheti-me
|
||||
|
||||
ENTRYPOINT ["./findtheti-me"]
|
||||
|
||||
EXPOSE 8080/tcp
|
||||
CMD ["./findtheti-me"]
|
46
README.md
46
README.md
|
@ -9,15 +9,27 @@ Also, it is only compatible with PostgreSQL at the moment. It is required to hav
|
|||
|
||||
### Simple (With Docker)
|
||||
|
||||
To use `findtheti.me` with docker, simply run
|
||||
#### Without SSL
|
||||
|
||||
```sh
|
||||
docker run
|
||||
-e DATABASE_URL='postgresql://{postgres user}:{postgres password}@{postgres host}/{postgres database}'
|
||||
-p {port to run on}:8080
|
||||
mvv97/findthetime
|
||||
mvv97/findthetime:latest
|
||||
```
|
||||
|
||||
#### Example docker-compose.yml
|
||||
#### With SSL
|
||||
```sh
|
||||
docker run
|
||||
-e DATABASE_URL='postgresql://{postgres user}:{postgres password}@{postgres host}/{postgres database}'
|
||||
-e SSL_ENABLED='true'
|
||||
-v /data/findtheti-me/certs:/etc/findtheti-me/certs # Place your cert files in /data/findtheti-me/certs and ensure they have permissions of at least 644
|
||||
-p {http port to run on}:8080 # if SSL_REDIRECT=false, this can be skipped
|
||||
-p {ssl port to run on}:8443
|
||||
mvv97/findthetime:latest
|
||||
```
|
||||
|
||||
### Example docker-compose.yml
|
||||
```yml
|
||||
version: "3.4"
|
||||
|
||||
|
@ -38,10 +50,20 @@ services:
|
|||
restart: unless-stopped
|
||||
environment:
|
||||
DATABASE_URL: "postgres://${PG_USER:-findthetime}:${PG_PASS}@postgresql/${PG_DB:-findthetime}"
|
||||
SSL_ENABLED: 'true' # when this is set to false ( default ), the ssl port is not listened to.
|
||||
SSL_REDIRECT: 'true'
|
||||
SSL_PORT: '8443'
|
||||
SSL_CERT_PATH: '/etc/findtheti-me/certs/server.cert'
|
||||
SSL_KEY_PATH: '/etc/findtheti-me/certs/server.key'
|
||||
volumes:
|
||||
- '/data/findtheti-me/certs:/etc/findtheti-me/certs'
|
||||
ports:
|
||||
- '8080:8080'
|
||||
- '8443:8443'
|
||||
```
|
||||
|
||||
Ensure you have the necessary environment variables configured: `PG_DB`, `PG_USER` and `PG_PASS`.
|
||||
|
||||
### Advanced (Without Docker)
|
||||
|
||||
1. Compile Backend (`cargo build --release`)
|
||||
|
@ -60,6 +82,21 @@ installationDir/
|
|||
|
||||
Finally, run `./findtheti-me` in the root, and the application should start.
|
||||
|
||||
### Enable SSL
|
||||
|
||||
In order to enable SSL, configure `SSL_ENABLED=true`, `SSL_PORT` with the desired port ( `8443` by default ), and `SSL_CERT_PATH` and `SSL_KEY_PATH`
|
||||
with the paths to your certificate and key files ( `/etc/letsencrypt/live/your.domain/cert.pem` and `/etc/letsencrypt/live/your.domain/key.pem`, for example ).
|
||||
Ensure the permissions of these files are at least `644`, as the container user will need to be able to read them.
|
||||
|
||||
**Note that there is currently no support for encrypted private keys ( those that start with `-----BEGIN ENCRYPTED PRIVATE KEY-----`).
|
||||
Attempting to use such will be met with the error:**
|
||||
|
||||
```
|
||||
Unable to use files configured in 'SSL_CERT_PATH' or 'SSL_KEY_PATH': Custom { kind: Other, error: "private key format not supported" }
|
||||
```
|
||||
`findtheti.me` will automatically register a listener at the configured `HTTP_PORT` to redirect
|
||||
to the configured `SSL_PORT`. To disable this, configure `SSL_REDIRECT=false` ( `true` by default ).
|
||||
|
||||
## Setup For Development
|
||||
### Backend
|
||||
1. Create a PostgreSQL database
|
||||
|
@ -69,7 +106,8 @@ Finally, run `./findtheti-me` in the root, and the application should start.
|
|||
|
||||
### Frontend
|
||||
1. `yarn install`
|
||||
2. `yarn dev` ( or `yarn build`/`yarn preview` )
|
||||
2. If using SSL on the backend, change the proxy in `vite.config.ts` to reflect that.
|
||||
3. `yarn dev` ( or `yarn build`/`yarn preview` )
|
||||
|
||||
### Docker Build Image
|
||||
1. Do Backend and Frontend setups first
|
||||
|
|
|
@ -3,6 +3,7 @@ version: "3.4"
|
|||
services:
|
||||
|
||||
postgresql:
|
||||
container_name: db
|
||||
image: "docker.io/library/postgres:16-alpine"
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
|
@ -13,9 +14,17 @@ services:
|
|||
POSTGRES_DB: ${PG_DB:-findthetime}
|
||||
|
||||
findthetime:
|
||||
image: "docker.io/mvv97/findthetime:latest"
|
||||
build: .
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
DATABASE_URL: "postgres://${PG_USER:-findthetime}:${PG_PASS}@postgresql/${PG_DB:-findthetime}"
|
||||
DATABASE_URL: "postgres://${PG_USER:-findthetime}:${PG_PASS}@db/${PG_DB:-findthetime}"
|
||||
SSL_ENABLED: 'true' # when this is set to false ( default ), the ssl port is not listened to.
|
||||
SSL_REDIRECT: 'true'
|
||||
SSL_PORT: '8443'
|
||||
SSL_CERT_PATH: '/etc/findtheti-me/certs/server.cert'
|
||||
SSL_KEY_PATH: '/etc/findtheti-me/certs/server.key'
|
||||
volumes:
|
||||
- '/home/haedhutner/Workspace/findtheti-me/.self-signed:/etc/findtheti-me/certs'
|
||||
ports:
|
||||
- '8080:8080'
|
||||
- '8080:8080'
|
||||
- '8443:8443'
|
|
@ -4,6 +4,7 @@ import RootLayout from './pages/RootLayout'
|
|||
import NewEventPage from './pages/NewEventPage'
|
||||
import ExistingEventPage from './pages/ExistingEventPage'
|
||||
import ThankYouPage from './pages/ThankYouPage'
|
||||
import NotFoundPage from './pages/NotFoundPage'
|
||||
|
||||
function App() {
|
||||
return (
|
||||
|
@ -12,6 +13,7 @@ function App() {
|
|||
<Route path="/" element={<NewEventPage />} />
|
||||
<Route path="/:eventId" element={<ExistingEventPage />} />
|
||||
<Route path="/thank-you" element={<ThankYouPage />} />
|
||||
<Route path="/not-found" element={<NotFoundPage />} />
|
||||
</Routes>
|
||||
</RootLayout>
|
||||
)
|
||||
|
|
17
frontend/src/pages/NotFoundPage.tsx
Normal file
17
frontend/src/pages/NotFoundPage.tsx
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { Typography } from '@mui/material';
|
||||
import Grid from '@mui/material/Unstable_Grid2';
|
||||
|
||||
const NotFoundPage = () => {
|
||||
return (
|
||||
<Grid container>
|
||||
<Grid xs={12}>
|
||||
<Typography variant={"h2"}>404 Not Found!</Typography>
|
||||
</Grid>
|
||||
<Grid xs={12}>
|
||||
<Typography>Not sure what you were looking for, but you won't find it here.</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
export default NotFoundPage;
|
|
@ -12,6 +12,13 @@ const utils = {
|
|||
performRequest: (url: string | URL | Request, options?: RequestInit | undefined): Promise<any> => {
|
||||
return fetch(url, options).then(async resp => {
|
||||
if (!resp.ok) {
|
||||
|
||||
if (resp.status === 404) {
|
||||
window.location.replace(`${window.location.origin}/not-found`)
|
||||
|
||||
throw 'Not Found';
|
||||
}
|
||||
|
||||
let errorTextResult = await resp.text();
|
||||
|
||||
var errorMsg = errorTextResult;
|
||||
|
|
|
@ -9,7 +9,7 @@ export default defineConfig({
|
|||
server: {
|
||||
proxy: {
|
||||
"/api": {
|
||||
target: "http://localhost:8080",
|
||||
target: "https://localhost:8443",
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
},
|
||||
|
|
|
@ -14,7 +14,7 @@ use axum::{
|
|||
use serde::Serialize;
|
||||
use sqlx::{migrate::MigrateError, PgPool};
|
||||
|
||||
use crate::endpoints;
|
||||
use crate::{endpoints, config};
|
||||
|
||||
pub(crate) async fn routes() -> Result<Router, ApplicationError> {
|
||||
Ok(Router::new()
|
||||
|
@ -107,9 +107,7 @@ impl AppState {
|
|||
|
||||
pool
|
||||
},
|
||||
event_uid_size: env::var("EVENT_UID_SIZE")?
|
||||
.parse()
|
||||
.expect("EVENT_UID_SIZE is undefined. Must be a number."),
|
||||
event_uid_size: config::get_or_default("EVENT_UID_SIZE", 20),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
32
src/config.rs
Normal file
32
src/config.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
use std::{env, str::FromStr};
|
||||
|
||||
use axum::http::StatusCode;
|
||||
|
||||
use crate::api::ApplicationError;
|
||||
|
||||
pub const DEFAULT_HTTP_PORT: u16 = 8080;
|
||||
pub const DEFAULT_SSL_PORT: u16 = 8443;
|
||||
|
||||
pub const DEFAULT_SSL_ENABLED: bool = false;
|
||||
pub const DEFAULT_SSL_REDIRECT: bool = true;
|
||||
|
||||
pub fn get<T>(name: &str, fail_status_code: StatusCode) -> Result<T, ApplicationError> where T: FromStr {
|
||||
match env::var(name).map(|r| r.parse()) {
|
||||
Ok(Ok(a)) => Ok(a),
|
||||
_ => Err(ApplicationError::new(format!("Unabled to get or parse environment variable '{}'.", name), fail_status_code)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_or_default<T>(name: &str, default: T) -> T where T: FromStr {
|
||||
match env::var(name).map(|r| r.parse()) {
|
||||
Ok(Ok(a)) => a,
|
||||
_ => default,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_or_panic<T>(name: &str) -> T where T: FromStr {
|
||||
match get(name, StatusCode::INTERNAL_SERVER_ERROR) {
|
||||
Ok(r) => r,
|
||||
Err(e) => panic!("{}", e),
|
||||
}
|
||||
}
|
|
@ -156,7 +156,11 @@ pub async fn fetch_event(
|
|||
let res = conn
|
||||
.transaction(|txn| {
|
||||
Box::pin(async move {
|
||||
let event = db::fetch_event_by_snowflake_id(txn, event_snowflake_id).await?;
|
||||
let event = match db::fetch_event_by_snowflake_id(txn, event_snowflake_id).await {
|
||||
Ok(e) => e,
|
||||
Err(sqlx::Error::RowNotFound) => return Err(ApplicationError::new("No such event found".to_string(), StatusCode::NOT_FOUND)),
|
||||
Err(e) => return Err(e.into())
|
||||
};
|
||||
|
||||
Ok(EventDto {
|
||||
snowflake_id: event.snowflake_id,
|
||||
|
|
133
src/main.rs
133
src/main.rs
|
@ -1,22 +1,28 @@
|
|||
use std::net::SocketAddr;
|
||||
|
||||
use axum::Router;
|
||||
use axum::extract::Host;
|
||||
use axum::handler::HandlerWithoutStateExt;
|
||||
use axum::http::uri::Scheme;
|
||||
use axum::response::Redirect;
|
||||
use axum::{Router, BoxError};
|
||||
use axum::http::{Uri, StatusCode};
|
||||
use axum_server::tls_rustls::RustlsConfig;
|
||||
use dotenv::dotenv;
|
||||
use tokio::net::TcpListener;
|
||||
use tower_http::services::ServeFile;
|
||||
use tower_http::trace::TraceLayer;
|
||||
use tower_http::{services::ServeDir, trace};
|
||||
use tracing::Level;
|
||||
use tracing::{Level, instrument, info, warn};
|
||||
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
|
||||
|
||||
mod api;
|
||||
mod db;
|
||||
mod endpoints;
|
||||
mod entity;
|
||||
mod config;
|
||||
|
||||
#[instrument(name = "findtheti-me")]
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() {
|
||||
println!("Starting findtheti.me...");
|
||||
info!("Starting findtheti.me...");
|
||||
|
||||
dotenv().ok();
|
||||
|
||||
|
@ -25,37 +31,112 @@ async fn main() {
|
|||
.with(EnvFilter::from_env("LOG_LEVEL"))
|
||||
.init();
|
||||
|
||||
let router = init_router()
|
||||
.await
|
||||
.layer(
|
||||
TraceLayer::new_for_http()
|
||||
.make_span_with(trace::DefaultMakeSpan::new().level(Level::INFO))
|
||||
.on_response(trace::DefaultOnResponse::new().level(Level::INFO)),
|
||||
)
|
||||
.into_make_service_with_connect_info::<SocketAddr>();
|
||||
|
||||
let http_port = config::get_or_default("HTTP_PORT", config::DEFAULT_HTTP_PORT);
|
||||
|
||||
let ssl_enabled = config::get_or_default("SSL_ENABLED", config::DEFAULT_SSL_ENABLED);
|
||||
|
||||
if ssl_enabled {
|
||||
info!("SSL marked as enabled, will create http to https redirect.");
|
||||
|
||||
let (ssl_port, ssl_redirect, ssl_cert_path, ssl_key_path): (u16, bool, String, String) = (
|
||||
config::get_or_default("SSL_PORT", config::DEFAULT_SSL_PORT),
|
||||
config::get_or_default("SSL_REDIRECT", config::DEFAULT_SSL_REDIRECT),
|
||||
config::get_or_panic("SSL_CERT_PATH"),
|
||||
config::get_or_panic("SSL_KEY_PATH")
|
||||
);
|
||||
|
||||
let ssl_config = match RustlsConfig::from_pem_file(ssl_cert_path, ssl_key_path).await {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
panic!("Unable to use files configured in 'SSL_CERT_PATH' or 'SSL_KEY_PATH': {:?}", e);
|
||||
},
|
||||
};
|
||||
|
||||
if ssl_redirect {
|
||||
tokio::spawn(redirect_http_to_https(http_port, ssl_port));
|
||||
}
|
||||
|
||||
let addr = SocketAddr::from(([0, 0, 0, 0], ssl_port));
|
||||
|
||||
info!("Listening on {}", addr);
|
||||
|
||||
axum_server::bind_rustls(addr, ssl_config)
|
||||
.serve(router)
|
||||
.await
|
||||
.unwrap()
|
||||
} else {
|
||||
let addr = SocketAddr::from(([0, 0, 0, 0], http_port));
|
||||
|
||||
info!("Listening on {}", addr);
|
||||
|
||||
axum_server::bind(addr).serve(router).await.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async fn init_router() -> Router {
|
||||
let api_routes = api::routes().await.expect("Unable to create api routes");
|
||||
|
||||
let mut routes = Router::new().nest("/api", api_routes);
|
||||
|
||||
// If in release mod, serve static files
|
||||
// If in release mode, serve static files
|
||||
if !cfg!(debug_assertions) {
|
||||
println!("Initializing frontend routes...");
|
||||
info!("Initializing frontend routes...");
|
||||
|
||||
routes = routes
|
||||
.nest_service("/assets", ServeDir::new("./frontend/dist/assets"))
|
||||
.fallback_service(ServeFile::new("./frontend/dist/index.html"));
|
||||
}
|
||||
|
||||
println!("Routes initialized...");
|
||||
info!("Routes initialized...");
|
||||
|
||||
let addr = SocketAddr::from(([0, 0, 0, 0], 8080));
|
||||
|
||||
let listener = TcpListener::bind(addr).await.unwrap();
|
||||
|
||||
println!("Starting server...");
|
||||
|
||||
axum::serve(
|
||||
listener,
|
||||
routes
|
||||
.layer(
|
||||
TraceLayer::new_for_http()
|
||||
.make_span_with(trace::DefaultMakeSpan::new().level(Level::INFO))
|
||||
.on_response(trace::DefaultOnResponse::new().level(Level::INFO)),
|
||||
)
|
||||
.into_make_service_with_connect_info::<SocketAddr>(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
routes
|
||||
}
|
||||
|
||||
async fn redirect_http_to_https(http_port: u16, https_port: u16) {
|
||||
fn make_https(host: String, uri: Uri, http_port: u16, https_port: u16) -> Result<Uri, BoxError> {
|
||||
let mut parts = uri.into_parts();
|
||||
|
||||
parts.scheme = Some(Scheme::HTTPS);
|
||||
|
||||
if parts.path_and_query.is_none() {
|
||||
parts.path_and_query = Some("/".parse().unwrap());
|
||||
}
|
||||
|
||||
let https_host = host.replace(&http_port.to_string(), &https_port.to_string());
|
||||
parts.authority = Some(https_host.parse()?);
|
||||
|
||||
Ok(Uri::from_parts(parts)?)
|
||||
}
|
||||
|
||||
let redirect = move |Host(host): Host, uri: Uri| async move {
|
||||
match make_https(host, uri, http_port, https_port) {
|
||||
Ok(uri) => Ok(Redirect::permanent(&uri.to_string())),
|
||||
Err(error) => {
|
||||
|
||||
warn!(%error, "failed to convert URI to HTTPS");
|
||||
|
||||
Err(StatusCode::BAD_REQUEST)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let addr = SocketAddr::from(([0, 0, 0, 0], http_port));
|
||||
|
||||
let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
|
||||
|
||||
info!("HTTPS redirect listening on {}", listener.local_addr().unwrap());
|
||||
|
||||
axum::serve(listener, redirect.into_make_service())
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
Loading…
Add table
Reference in a new issue