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
9 changes: 9 additions & 0 deletions common/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,14 @@ pub struct OauthConfig {
#[serde(default)]
pub api_store_backend: OauthApiStoreBackend,
pub allowed_cors_origins: Vec<String>,
#[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)]
Expand All @@ -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(),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions docker/demo/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 1 addition & 0 deletions docker/demo/docker-compose.demo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions docker/deployment/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 1 addition & 0 deletions mono/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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/

Expand Down
2 changes: 1 addition & 1 deletion mono/src/api/oauth/api_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
16 changes: 9 additions & 7 deletions mono/src/api/oauth/campsite_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Client>,
// cookie_store: Arc<Jar>,
api_base_url: String,
session_cookie: String,
}

#[async_trait]
Expand All @@ -41,18 +39,19 @@ 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()
.expect("Failed to build client");
Self {
client: Arc::new(client),
api_base_url,
session_cookie,
}
}

Expand All @@ -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")?;
Expand Down
5 changes: 4 additions & 1 deletion mono/src/server/http_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
4 changes: 2 additions & 2 deletions mono/tests/campsite_api_store_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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() {
Expand Down
5 changes: 3 additions & 2 deletions mono/tests/login_user_extractor_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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<Value>)> {
// Format cookie with prefix: _campsite_api_session=<value>
// Format cookie with prefix: {session_cookie}=<value>
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() {
Expand Down
4 changes: 3 additions & 1 deletion moon/apps/web/.env.runtime
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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__

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Set the runtime cookie-name env for the UI

In the unified image path, this value is baked into the Next build as the placeholder shown here and docker-entrypoint.sh only rewrites it when NEXT_PUBLIC_CAMPSITE_API_SESSION_COOKIE is present. I checked the demo compose env block and both .env.example files added in this change, and they set only MEGA_OAUTH__CAMPSITE_API_SESSION_COOKIE, not the NEXT_PUBLIC_ value, so the shipped demo/default UI keeps looking for __rt_campsite_api_session_cookie__ in apiCookieHeaders instead of forwarding the real _campsite_api_session cookie on SSR/middleware requests. Please pass the public cookie-name env (or avoid placeholdering the default) anywhere the runtime placeholders are expected to be resolved.

Useful? React with 👍 / 👎.

3 changes: 2 additions & 1 deletion moon/apps/web/docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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'; }
Expand Down
9 changes: 5 additions & 4 deletions moon/apps/web/utils/apiCookieHeaders.ts
Original file line number Diff line number Diff line change
@@ -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<string, string> = { 'x-campsite-ssr-secret': process.env.SSR_SECRET || '' }

export function apiCookieHeaders(cookies: NextApiRequestCookies) {
let headers: Record<string, string> = {}

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 }
Expand Down
18 changes: 13 additions & 5 deletions moon/apps/web/utils/queryClient.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -63,8 +70,6 @@ export function reauthorizeSSOUrl({

type Method = 'DELETE' | 'POST' | 'PUT'

const ApiCookieName = '_campsite_api_session'

interface FetcherProps {
method?: Method
body?: unknown
Expand All @@ -78,9 +83,12 @@ export async function fetcher<T>(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'
}
Expand Down
4 changes: 4 additions & 0 deletions moon/packages/config/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading