diff --git a/README.md b/README.md index 73be79c..b30af91 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ GOOGLE_CLIENT_SECRET= BETTER_AUTH_URL=http://localhost:3000 NUXT_PUBLIC_WEBPUSH_PUBLIC_KEY= -NUXT_WEBPUSH_PRIVATE_KEY= +WEBPUSH_PRIVATE_KEY= ``` ### Deployment @@ -33,6 +33,6 @@ BETTER_AUTH_SECRET= BETTER_AUTH_URL= NUXT_PUBLIC_WEBPUSH_PUBLIC_KEY= -NUXT_WEBPUSH_PRIVATE_KEY= +WEBPUSH_PRIVATE_KEY= NUXT_WEBPUSH_MAIL= ``` diff --git a/api/src/auth.rs b/api/src/auth.rs index f324dab..ae09b5a 100644 --- a/api/src/auth.rs +++ b/api/src/auth.rs @@ -36,7 +36,7 @@ impl FromRequestParts for User { .await .map_err(|_| (StatusCode::UNAUTHORIZED, "Authorization header missing"))?; - let jwks = reqwest::get("http://localhost:3000/api/auth/jwks") + let jwks = reqwest::get(format!("{}/api/auth/jwks", state.constants.auth_api_base)) .await .map_err(|_| (StatusCode::UNAUTHORIZED, "Failed to fetch JWKS"))? .json::() @@ -47,8 +47,7 @@ impl FromRequestParts for User { .map_err(|_| (StatusCode::UNAUTHORIZED, "Failed to create decoding key"))?; let mut validation = jsonwebtoken::Validation::new(jsonwebtoken::Algorithm::EdDSA); - //TODO: correctly set audience - validation.set_audience(&["http://localhost:3000"]); + validation.set_audience(&[&state.constants.self_api_base]); let claims: Claims = jsonwebtoken::decode(bearer.token(), &key, &validation) .map_err(|e| { diff --git a/api/src/jobs/web_push_notifications.rs b/api/src/jobs/web_push_notifications.rs index 2ac9437..7a3b036 100644 --- a/api/src/jobs/web_push_notifications.rs +++ b/api/src/jobs/web_push_notifications.rs @@ -2,7 +2,7 @@ use chrono::Timelike; use serde_json::json; use std::time::Duration; use tokio::time; -use tracing::warn; +use tracing::{info, warn}; use web_push::{ ContentEncoding, HyperWebPushClient, VapidSignatureBuilder, WebPushClient, WebPushMessageBuilder, @@ -26,7 +26,7 @@ pub async fn run_web_push_job(state: AppState) { } async fn check_and_send_notifications(state: &AppState) { - let Some(web_push_key) = &state.web_push_key else { + let Some(web_push_key) = &state.constants.web_push_key else { warn!("no webPush privatKey set"); return; }; @@ -54,8 +54,6 @@ async fn check_and_send_notifications(state: &AppState) { .await .unwrap(); - warn!(?subscriptions); - for subscription in subscriptions { let sig_builder = VapidSignatureBuilder::from_base64(web_push_key, &subscription) .unwrap() @@ -74,7 +72,7 @@ async fn check_and_send_notifications(state: &AppState) { let result = web_push_client.send(builder.build().unwrap()).await; - warn!( + info!( "sent notification to subscription: {:?} - {:?}", subscription, result ); diff --git a/api/src/lib.rs b/api/src/lib.rs index 3df5991..7dc3d72 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -1,5 +1,6 @@ use axum::Router; use color_eyre::eyre; +use http::header::{ACCEPT, AUTHORIZATION, CONTENT_TYPE}; use migration::{Migrator, MigratorTrait}; use sea_orm::{ConnectionTrait, Database, DatabaseConnection}; use tower::ServiceBuilder; @@ -24,19 +25,32 @@ struct AppState { db_connection: DatabaseConnection, event_service: EventService, test_user: Option, + constants: Constants, +} + +#[derive(Clone)] +pub struct Constants { web_push_key: Option, + auth_api_base: String, + self_api_base: String, } pub async fn app( db_url: &str, test_user: Option, web_push_key: Option, + auth_api_base: Option, + self_api_base: Option, ) -> eyre::Result { let state = AppState { db_connection: init_db(db_url).await?, event_service: EventService::new(), test_user, - web_push_key, + constants: Constants { + web_push_key, + auth_api_base: auth_api_base.unwrap_or_else(|| "http://localhost:3000".to_string()), + self_api_base: self_api_base.unwrap_or_else(|| "http://localhost:8080".to_string()), + }, }; run_web_push_job(state.clone()).await; @@ -53,7 +67,7 @@ pub async fn app( ) .layer( CorsLayer::new() - .allow_headers(Any) + .allow_headers([AUTHORIZATION, CONTENT_TYPE, ACCEPT]) .allow_origin(Any) .allow_methods(Any), ), diff --git a/api/src/main.rs b/api/src/main.rs index a9489b2..6c67d46 100644 --- a/api/src/main.rs +++ b/api/src/main.rs @@ -1,11 +1,11 @@ use api::app; use color_eyre::eyre; use std::env; -use tracing::Level; +use tracing::{Level, info}; #[tokio::main] async fn main() -> eyre::Result<()> { - tracing_subscriber::fmt().with_max_level(Level::WARN).init(); + tracing_subscriber::fmt().with_max_level(Level::INFO).init(); dotenvy::dotenv().ok(); let db_url = @@ -14,7 +14,12 @@ async fn main() -> eyre::Result<()> { let web_push_key = env::var("WEBPUSH_PRIVATE_KEY").ok(); - let app = app(&db_url, None, web_push_key).await?; + let auth_api_base = env::var("AUTH_API_BASE").ok(); + let self_api_base = env::var("SELF_API_BASE").ok(); + + info!("Starting server on port {}", port); + + let app = app(&db_url, None, web_push_key, auth_api_base, self_api_base).await?; let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{port}")) .await diff --git a/api/tests/common/client.rs b/api/tests/common/client.rs index 5c9257a..258b634 100644 --- a/api/tests/common/client.rs +++ b/api/tests/common/client.rs @@ -132,6 +132,8 @@ pub async fn get_client() -> Client { "sqlite://../.data/data_db.sqlite?mode=rwc", Some(user), None, + None, + None, ) .await .unwrap(); diff --git a/app/composables/useAuthToken.ts b/app/composables/useAuthToken.ts index c3b455f..b042c54 100644 --- a/app/composables/useAuthToken.ts +++ b/app/composables/useAuthToken.ts @@ -1,6 +1,5 @@ let tokenPromise: Promise | null = null; -// TODO: handle not being logged in export function useAuthToken() { const tokenData = useState("auth-token", () => null); diff --git a/app/stores/useCategoryStore.ts b/app/stores/useCategoryStore.ts index b9b1186..8d9ff6d 100644 --- a/app/stores/useCategoryStore.ts +++ b/app/stores/useCategoryStore.ts @@ -62,7 +62,7 @@ export const useCategoryStore = defineStore("categories", { icon, }; - this.data.unshift(label); + this.data.push(label); const { $api } = useNuxtApp(); await $api(`/api/categories`, { diff --git a/app/stores/useTagStore.ts b/app/stores/useTagStore.ts index f53def0..bf6ddaa 100644 --- a/app/stores/useTagStore.ts +++ b/app/stores/useTagStore.ts @@ -61,7 +61,7 @@ export const useTagStore = defineStore("tags", { color, }; - this.data.unshift(label); + this.data.push(label); const { $api } = useNuxtApp(); await $api(`/api/tags`, { diff --git a/app/stores/useTodoStore.ts b/app/stores/useTodoStore.ts index 15439e9..e7a86f2 100644 --- a/app/stores/useTodoStore.ts +++ b/app/stores/useTodoStore.ts @@ -1,12 +1,11 @@ import { defineStore } from "pinia"; +import type { SSE } from "sse.js"; import { v4 } from "uuid"; import { filterTodos } from "~/composables/useFilteredTodos"; import { updateOrInsertAfterTodo } from "~~/shared/array"; import { toLocalDateString } from "~~/shared/date"; import type { Todo, TodoData, UUID } from "~~/shared/types"; -import type { SSE } from "sse.js"; - export const useTodoStore = defineStore("todos", { state: (): { data: Todo[]; sse: SSE | undefined } => ({ data: [], diff --git a/app/utils/authClient.ts b/app/utils/authClient.ts index 1258dba..83d2c69 100644 --- a/app/utils/authClient.ts +++ b/app/utils/authClient.ts @@ -1,6 +1,6 @@ import { apiKeyClient } from "@better-auth/api-key/client"; -import { createAuthClient } from "better-auth/vue"; import { jwtClient } from "better-auth/client/plugins"; +import { createAuthClient } from "better-auth/vue"; export const authClient = createAuthClient({ plugins: [apiKeyClient(), jwtClient()], diff --git a/server/utils/auth.ts b/server/utils/auth.ts index 4dbd10e..a508a52 100644 --- a/server/utils/auth.ts +++ b/server/utils/auth.ts @@ -1,8 +1,7 @@ import { DatabaseSync } from "node:sqlite"; import { apiKey } from "@better-auth/api-key"; import { betterAuth } from "better-auth"; -import { testUtils } from "better-auth/plugins"; -import { jwt } from "better-auth/plugins"; +import { jwt, testUtils } from "better-auth/plugins"; export const auth = betterAuth({ database: new DatabaseSync("./.data/sqlite.db"), @@ -24,6 +23,11 @@ export const auth = betterAuth({ }, }), testUtils(), - jwt(), + jwt({ + jwt: { + audience: process.env.NUXT_PUBLIC_API_BASE ?? "http://localhost:8080", + expirationTime: "7d", + }, + }), ], });