diff --git a/common/src/config/mod.rs b/common/src/config/mod.rs index 5ade091cc..68985c341 100644 --- a/common/src/config/mod.rs +++ b/common/src/config/mod.rs @@ -660,6 +660,14 @@ pub struct OauthConfig { #[serde(default)] pub api_store_backend: OauthApiStoreBackend, pub allowed_cors_origins: Vec, + #[serde(default = "default_campsite_api_session_cookie")] + pub campsite_api_session_cookie: String, +} + +pub const DEFAULT_CAMPSITE_API_SESSION_COOKIE: &str = "_campsite_api_session"; + +fn default_campsite_api_session_cookie() -> String { + DEFAULT_CAMPSITE_API_SESSION_COOKIE.to_string() } #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)] @@ -685,6 +693,7 @@ impl Default for OauthConfig { .into_iter() .map(|s| s.to_string()) .collect(), + campsite_api_session_cookie: default_campsite_api_session_cookie(), } } } diff --git a/docker/demo/.env.example b/docker/demo/.env.example index c128903b0..519b02079 100644 --- a/docker/demo/.env.example +++ b/docker/demo/.env.example @@ -99,6 +99,7 @@ MEGA_BUILD__ENABLE_BUILD=true MEGA_BUILD__ORION_SERVER=http://orion_server:8004 MEGA_OAUTH__CAMPSITE_API_DOMAIN=http://api.gitmono.local:18080 +MEGA_OAUTH__CAMPSITE_API_SESSION_COOKIE=_campsite_api_session MEGA_OAUTH__UI_DOMAIN=http://app.gitmono.local MEGA_OAUTH__COOKIE_DOMAIN=gitmono.local MEGA_OAUTH__ALLOWED_CORS_ORIGINS="http://app.gitmono.local" diff --git a/docker/demo/docker-compose.demo.yml b/docker/demo/docker-compose.demo.yml index a55dd1018..1a8ec4bef 100644 --- a/docker/demo/docker-compose.demo.yml +++ b/docker/demo/docker-compose.demo.yml @@ -150,6 +150,7 @@ services: # Campsite integration (OAuth / SSO etc.) MEGA_OAUTH__CAMPSITE_API_DOMAIN: ${MEGA_OAUTH__CAMPSITE_API_DOMAIN:-http://campsite_api:8080} + MEGA_OAUTH__CAMPSITE_API_SESSION_COOKIE: ${MEGA_OAUTH__CAMPSITE_API_SESSION_COOKIE:-_campsite_api_session} MEGA_OAUTH__UI_DOMAIN: ${MEGA_OAUTH__UI_DOMAIN:-http://app.gitmono.local} MEGA_OAUTH__COOKIE_DOMAIN: ${MEGA_OAUTH__COOKIE_DOMAIN:-localhost} # Note: allowed_cors_origins expects an array format in TOML diff --git a/docker/deployment/.env.example b/docker/deployment/.env.example index bc917216a..667c9b2cc 100644 --- a/docker/deployment/.env.example +++ b/docker/deployment/.env.example @@ -92,6 +92,7 @@ MEGA_BUILD__ENABLE_BUILD=true MEGA_BUILD__ORION_SERVER=http://orion_server:8004 MEGA_OAUTH__CAMPSITE_API_DOMAIN=http://api.gitmono.local:18080 +MEGA_OAUTH__CAMPSITE_API_SESSION_COOKIE=_campsite_api_session MEGA_OAUTH__UI_DOMAIN=http://app.gitmono.local MEGA_OAUTH__COOKIE_DOMAIN=gitmono.local MEGA_OAUTH__ALLOWED_CORS_ORIGINS="http://app.gitmono.local" diff --git a/mono/Dockerfile b/mono/Dockerfile index bb0529f4f..9dcaea0d5 100644 --- a/mono/Dockerfile +++ b/mono/Dockerfile @@ -38,6 +38,7 @@ COPY orion/buck/Cargo.toml orion/buck/ COPY orion-scheduler/Cargo.toml orion-scheduler/ COPY orion-server/Cargo.toml orion-server/ COPY clients/orion-client/Cargo.toml clients/orion-client/ +COPY clients/orion-scheduler-client/Cargo.toml clients/orion-scheduler-client/ COPY saturn/Cargo.toml saturn/ COPY vault/Cargo.toml vault/ diff --git a/mono/src/api/oauth/api_store.rs b/mono/src/api/oauth/api_store.rs index 7adeb2997..bde917484 100644 --- a/mono/src/api/oauth/api_store.rs +++ b/mono/src/api/oauth/api_store.rs @@ -16,7 +16,7 @@ pub enum OAuthApiStore { } impl OAuthApiStore { - pub fn session_cookie_name(&self) -> &'static str { + pub fn session_cookie_name(&self) -> &str { match self { OAuthApiStore::Campsite(store) => store.session_cookie_name(), OAuthApiStore::Tinyship(store) => store.session_cookie_name(), diff --git a/mono/src/api/oauth/campsite_store.rs b/mono/src/api/oauth/campsite_store.rs index e2feeb662..c303d7fd8 100644 --- a/mono/src/api/oauth/campsite_store.rs +++ b/mono/src/api/oauth/campsite_store.rs @@ -12,13 +12,11 @@ use tower_sessions::{ use crate::api::oauth::model::{CampsiteUserJson, LoginUser}; -static CAMPSITE_API_COOKIE: &str = "_campsite_api_session"; - #[derive(Debug, Clone)] pub struct CampsiteApiStore { client: Arc, - // cookie_store: Arc, api_base_url: String, + session_cookie: String, } #[async_trait] @@ -41,11 +39,11 @@ impl SessionStore for CampsiteApiStore { } impl CampsiteApiStore { - pub fn session_cookie_name(&self) -> &'static str { - CAMPSITE_API_COOKIE + pub fn session_cookie_name(&self) -> &str { + &self.session_cookie } - pub fn new(api_base_url: String) -> Self { + pub fn new(api_base_url: String, session_cookie: String) -> Self { let client = Client::builder() .no_proxy() .build() @@ -53,6 +51,7 @@ impl CampsiteApiStore { Self { client: Arc::new(client), api_base_url, + session_cookie, } } @@ -68,7 +67,10 @@ impl CampsiteApiStore { let resp = self .client .get(url) - .header(COOKIE, format!("{}={}", CAMPSITE_API_COOKIE, cookie_value)) + .header( + COOKIE, + format!("{}={}", self.session_cookie_name(), cookie_value), + ) .send() .await .context("failed to send request to campsite API")?; diff --git a/mono/src/server/http_server.rs b/mono/src/server/http_server.rs index 91d328a0a..24d4eced0 100644 --- a/mono/src/server/http_server.rs +++ b/mono/src/server/http_server.rs @@ -397,7 +397,10 @@ pub async fn app(ctx: AppContext, host: String, port: u16) -> Router { build_dispatch, Some(match oauth_config.api_store_backend { common::config::OauthApiStoreBackend::Campsite => { - OAuthApiStore::Campsite(CampsiteApiStore::new(oauth_config.campsite_api_domain)) + OAuthApiStore::Campsite(CampsiteApiStore::new( + oauth_config.campsite_api_domain.clone(), + oauth_config.campsite_api_session_cookie.clone(), + )) } common::config::OauthApiStoreBackend::Tinyship => { OAuthApiStore::Tinyship(TinyshipApiStore::new(oauth_config.tinyship_api_domain)) diff --git a/mono/tests/campsite_api_store_tests.rs b/mono/tests/campsite_api_store_tests.rs index 41b4fa406..f49356620 100644 --- a/mono/tests/campsite_api_store_tests.rs +++ b/mono/tests/campsite_api_store_tests.rs @@ -36,13 +36,13 @@ mod common; +use ::common::config::DEFAULT_CAMPSITE_API_SESSION_COOKIE; use anyhow::{Context, Result}; use common::*; use qlean::{Distro, GuestArch, Image, ImageConfig, MachineConfig, with_machine}; use serde_json::Value; const TEST_COOKIE: &str = "test_session_cookie"; -const CAMPSITE_API_COOKIE_NAME: &str = "_campsite_api_session"; // ============================================================================ // Test phases - directly calling Campsite API @@ -54,7 +54,7 @@ async fn call_campsite_api( cookie: Option<&str>, ) -> Result<(u16, Value)> { let cookie_arg = cookie - .map(|c| format!("Cookie: {}={}", CAMPSITE_API_COOKIE_NAME, c)) + .map(|c| format!("Cookie: {}={}", DEFAULT_CAMPSITE_API_SESSION_COOKIE, c)) .unwrap_or_default(); let cmd = if cookie.is_some() { diff --git a/mono/tests/login_user_extractor_tests.rs b/mono/tests/login_user_extractor_tests.rs index 1a2c0e8d6..9e1872756 100644 --- a/mono/tests/login_user_extractor_tests.rs +++ b/mono/tests/login_user_extractor_tests.rs @@ -34,6 +34,7 @@ mod common; use std::time::Duration; +use ::common::config::DEFAULT_CAMPSITE_API_SESSION_COOKIE; use anyhow::{Context, Result}; use common::*; use qlean::{Distro, GuestArch, Image, ImageConfig, MachineConfig, with_machine}; @@ -47,11 +48,11 @@ const CAMPSITE_API_PORT: u16 = 8080; /// Call Campsite API /v1/users/me endpoint async fn call_users_me(vm: &mut qlean::Machine, cookie: &str) -> Result<(u16, Option)> { - // Format cookie with prefix: _campsite_api_session= + // Format cookie with prefix: {session_cookie}= let cookie_header = if cookie.is_empty() { "".to_string() } else { - format!("_campsite_api_session={}", cookie) + format!("{}={}", DEFAULT_CAMPSITE_API_SESSION_COOKIE, cookie) }; let cmd = if cookie.is_empty() { diff --git a/moon/apps/web/.env.runtime b/moon/apps/web/.env.runtime index b8da280d2..722421bfc 100644 --- a/moon/apps/web/.env.runtime +++ b/moon/apps/web/.env.runtime @@ -12,7 +12,8 @@ # Provide the real values at runtime (ECS task definition / Cloud Run env): # NEXT_PUBLIC_API_URL, NEXT_PUBLIC_INTERNAL_API_URL, NEXT_PUBLIC_MONO_API_URL, # NEXT_PUBLIC_ORION_API_URL, NEXT_PUBLIC_AUTH_URL, NEXT_PUBLIC_WEB_URL, -# NEXT_PUBLIC_SYNC_URL, NEXT_PUBLIC_CRATES_PRO_URL +# NEXT_PUBLIC_SYNC_URL, NEXT_PUBLIC_CRATES_PRO_URL, +# NEXT_PUBLIC_CAMPSITE_API_SESSION_COOKIE # ============================================================================= NEXT_PUBLIC_API_URL=https://rt-api.placeholder.local @@ -23,3 +24,4 @@ NEXT_PUBLIC_AUTH_URL=https://rt-auth.placeholder.local NEXT_PUBLIC_WEB_URL=https://rt-web.placeholder.local NEXT_PUBLIC_SYNC_URL=wss://rt-sync.placeholder.local NEXT_PUBLIC_CRATES_PRO_URL=https://rt-crates-pro.placeholder.local +NEXT_PUBLIC_CAMPSITE_API_SESSION_COOKIE=__rt_campsite_api_session_cookie__ diff --git a/moon/apps/web/docker-entrypoint.sh b/moon/apps/web/docker-entrypoint.sh index d165a75d5..344301d62 100755 --- a/moon/apps/web/docker-entrypoint.sh +++ b/moon/apps/web/docker-entrypoint.sh @@ -25,7 +25,8 @@ https://rt-orion-api.placeholder.local${TAB}NEXT_PUBLIC_ORION_API_URL https://rt-auth.placeholder.local${TAB}NEXT_PUBLIC_AUTH_URL https://rt-web.placeholder.local${TAB}NEXT_PUBLIC_WEB_URL wss://rt-sync.placeholder.local${TAB}NEXT_PUBLIC_SYNC_URL -https://rt-crates-pro.placeholder.local${TAB}NEXT_PUBLIC_CRATES_PRO_URL" +https://rt-crates-pro.placeholder.local${TAB}NEXT_PUBLIC_CRATES_PRO_URL +__rt_campsite_api_session_cookie__${TAB}NEXT_PUBLIC_CAMPSITE_API_SESSION_COOKIE" # Escape a string for safe use on the left (regex) side of a sed s||| command. escape_regex() { printf '%s' "$1" | sed -e 's/[.[\*^$()+?{|/\\]/\\&/g'; } diff --git a/moon/apps/web/utils/apiCookieHeaders.ts b/moon/apps/web/utils/apiCookieHeaders.ts index 0c0538def..9e6b8601b 100644 --- a/moon/apps/web/utils/apiCookieHeaders.ts +++ b/moon/apps/web/utils/apiCookieHeaders.ts @@ -1,16 +1,17 @@ import { NextApiRequestCookies } from 'next/dist/server/api-utils' -const ApiCookieName = '_campsite_api_session' +import { CAMPSITE_API_SESSION_COOKIE } from '@gitmono/config' export const SsrSecretHeader: Record = { 'x-campsite-ssr-secret': process.env.SSR_SECRET || '' } export function apiCookieHeaders(cookies: NextApiRequestCookies) { let headers: Record = {} - if (cookies[ApiCookieName]) { - const apiCookie = encodeURIComponent(cookies[ApiCookieName]) + const sessionCookie = cookies[CAMPSITE_API_SESSION_COOKIE] + if (sessionCookie) { + const apiCookie = encodeURIComponent(sessionCookie) - headers['Cookie'] = `${ApiCookieName}=${apiCookie}` + headers['Cookie'] = `${CAMPSITE_API_SESSION_COOKIE}=${apiCookie}` } return { ...headers, ...SsrSecretHeader } diff --git a/moon/apps/web/utils/queryClient.ts b/moon/apps/web/utils/queryClient.ts index c916af111..b65444f3b 100644 --- a/moon/apps/web/utils/queryClient.ts +++ b/moon/apps/web/utils/queryClient.ts @@ -1,6 +1,13 @@ import { InfiniteData, QueryClient, QueryKey } from '@tanstack/react-query' -import { MONO_API_URL, ORION_API_URL, RAILS_API_URL, RAILS_AUTH_URL, RAILS_INTERNAL_API_URL } from '@gitmono/config' +import { + CAMPSITE_API_SESSION_COOKIE, + MONO_API_URL, + ORION_API_URL, + RAILS_API_URL, + RAILS_AUTH_URL, + RAILS_INTERNAL_API_URL +} from '@gitmono/config' import { Api, ApiError, DataTag } from '@gitmono/types' import { ApiErrorResponse } from './types' @@ -63,8 +70,6 @@ export function reauthorizeSSOUrl({ type Method = 'DELETE' | 'POST' | 'PUT' -const ApiCookieName = '_campsite_api_session' - interface FetcherProps { method?: Method body?: unknown @@ -78,9 +83,12 @@ export async function fetcher(url: string, { method, body, cookies }: Fetcher let credentials: RequestCredentials | undefined if (cookies) { - const apiCookie = encodeURIComponent(cookies[ApiCookieName]) + const sessionCookie = cookies[CAMPSITE_API_SESSION_COOKIE] + if (sessionCookie) { + const apiCookie = encodeURIComponent(sessionCookie) - headers.append('Cookie', `${ApiCookieName}=${apiCookie}`) + headers.append('Cookie', `${CAMPSITE_API_SESSION_COOKIE}=${apiCookie}`) + } } else { credentials = 'include' } diff --git a/moon/packages/config/src/index.ts b/moon/packages/config/src/index.ts index 20e409f78..e0b906e75 100644 --- a/moon/packages/config/src/index.ts +++ b/moon/packages/config/src/index.ts @@ -32,6 +32,10 @@ export const ORION_API_URL = process.env.NEXT_PUBLIC_ORION_API_URL || 'https://o // eslint-disable-next-line turbo/no-undeclared-env-vars export const RAILS_AUTH_URL = process.env.NEXT_PUBLIC_AUTH_URL || 'https://auth.gitmega.com' +// eslint-disable-next-line turbo/no-undeclared-env-vars +export const CAMPSITE_API_SESSION_COOKIE = + process.env.NEXT_PUBLIC_CAMPSITE_API_SESSION_COOKIE || '_campsite_api_session' + /* Not using an env variable because we use this variable in the browser, which requires extra config with Next.js to send env variables to the browser.