fix auth endpoint
This commit is contained in:
parent
5f190fbf02
commit
336bfa0c99
File diff suppressed because one or more lines are too long
60
.env
Normal file
60
.env
Normal file
@ -0,0 +1,60 @@
|
||||
# ===========================================
|
||||
# ForensicPathways Environment Configuration
|
||||
# ===========================================
|
||||
|
||||
# === Authentication Configuration ===
|
||||
AUTHENTICATION_NECESSARY=false
|
||||
AUTHENTICATION_NECESSARY_CONTRIBUTIONS=false
|
||||
AUTHENTICATION_NECESSARY_AI=false
|
||||
AUTH_SECRET=your-secret-key-change-in-production
|
||||
|
||||
# OIDC Configuration (if authentication enabled)
|
||||
OIDC_ENDPOINT=https://cloud.cc24.dev/index.php/apps/oidc/
|
||||
OIDC_CLIENT_ID=your-client-id
|
||||
OIDC_CLIENT_SECRET=your-client-secret
|
||||
|
||||
# === AI Configuration ===
|
||||
# Main AI API (for analysis stage, choose a good model)
|
||||
AI_API_ENDPOINT=https://llm.mikoshi.de/
|
||||
AI_API_KEY=69feb44e7567babf1bef9df9ccc34d64ce1660547ba2c1b70e88571289fa713f
|
||||
AI_MODEL=mistral/mistral-medium-latest
|
||||
|
||||
# Selector AI (for selection stage, choode a good model)
|
||||
AI_SELECTOR_ENDPOINT=https://llm.mikoshi.de/
|
||||
AI_SELECTOR_API_KEY=69feb44e7567babf1bef9df9ccc34d64ce1660547ba2c1b70e88571289fa713f
|
||||
AI_SELECTOR_MODEL=mistral/mistral-medium-latest
|
||||
|
||||
# Analyzer AI (for analysis stage, smaller model sufficient)
|
||||
AI_ANALYZER_ENDPOINT=https://llm.mikoshi.de/
|
||||
AI_ANALYZER_API_KEY=69feb44e7567babf1bef9df9ccc34d64ce1660547ba2c1b70e88571289fa713f
|
||||
AI_ANALYZER_MODEL=mistral/mistral-small-latest
|
||||
|
||||
# === Embeddings Configuration ===
|
||||
# Enable/disable semantic embeddings pre-selection
|
||||
AI_EMBEDDINGS_ENABLED=true
|
||||
|
||||
# Embeddings API (Mistral recommended)
|
||||
AI_EMBEDDINGS_ENDPOINT=https://api.mistral.ai/v1/embeddings
|
||||
AI_EMBEDDINGS_API_KEY=ZSpt6VsczlGttlGnugm5Vbh5m9w423wL
|
||||
AI_EMBEDDINGS_MODEL=mistral-embed
|
||||
|
||||
# Embeddings performance settings
|
||||
AI_EMBEDDINGS_BATCH_SIZE=20
|
||||
AI_EMBEDDINGS_BATCH_DELAY_MS=1000
|
||||
AI_EMBEDDING_CANDIDATES=30
|
||||
AI_SIMILARITY_THRESHOLD=0.3
|
||||
|
||||
# === AI Processing Configuration ===
|
||||
AI_MAX_SELECTED_ITEMS=15
|
||||
AI_RATE_LIMIT_DELAY_MS=2000
|
||||
|
||||
# === Application Configuration ===
|
||||
PUBLIC_BASE_URL=http://localhost:4321
|
||||
NODE_ENV=development
|
||||
|
||||
# Nextcloud Integration (Optional)
|
||||
NEXTCLOUD_ENDPOINT=https://your-nextcloud.com
|
||||
NEXTCLOUD_USERNAME=your-username
|
||||
NEXTCLOUD_PASSWORD=your-password
|
||||
NEXTCLOUD_UPLOAD_PATH=/kb-media
|
||||
NEXTCLOUD_PUBLIC_URL=https://your-nextcloud.com/s/
|
67
.env.example
67
.env.example
@ -2,34 +2,55 @@
|
||||
# ForensicPathways Environment Configuration
|
||||
# ===========================================
|
||||
|
||||
# Authentication & OIDC (Required)
|
||||
AUTH_SECRET=change-this-to-a-strong-secret-key-in-production
|
||||
# === Authentication Configuration ===
|
||||
AUTHENTICATION_NECESSARY=false
|
||||
AUTHENTICATION_NECESSARY_CONTRIBUTIONS=false
|
||||
AUTHENTICATION_NECESSARY_AI=false
|
||||
AUTH_SECRET=your-secret-key-change-in-production
|
||||
|
||||
# OIDC Configuration (if authentication enabled)
|
||||
OIDC_ENDPOINT=https://your-oidc-provider.com
|
||||
OIDC_CLIENT_ID=your-oidc-client-id
|
||||
OIDC_CLIENT_SECRET=your-oidc-client-secret
|
||||
OIDC_CLIENT_ID=your-client-id
|
||||
OIDC_CLIENT_SECRET=your-client-secret
|
||||
|
||||
# Auth Scopes - set to true in prod
|
||||
AUTHENTICATION_NECESSARY_CONTRIBUTIONS=true
|
||||
AUTHENTICATION_NECESSARY_AI=true
|
||||
|
||||
# Application Configuration (Required)
|
||||
PUBLIC_BASE_URL=https://your-domain.com
|
||||
NODE_ENV=production
|
||||
|
||||
# AI Service Configuration (Required for AI features)
|
||||
AI_MODEL=mistral-large-latest
|
||||
# === AI Configuration ===
|
||||
# Main AI API (for analysis stage, choose a good model)
|
||||
AI_API_ENDPOINT=https://api.mistral.ai
|
||||
AI_API_KEY=your-mistral-api-key
|
||||
AI_RATE_LIMIT_DELAY_MS=1000
|
||||
AI_API_KEY=your-anthropic-api-key
|
||||
AI_MODEL=claude-sonnet-4-20250514
|
||||
|
||||
# Git Integration (Required for contributions)
|
||||
GIT_REPO_URL=https://git.cc24.dev/mstoeck3/forensic-pathways
|
||||
GIT_PROVIDER=gitea
|
||||
GIT_API_ENDPOINT=https://git.cc24.dev/api/v1
|
||||
GIT_API_TOKEN=your-git-api-token
|
||||
# Selector AI (for selection stage, choode a good model)
|
||||
AI_SELECTOR_ENDPOINT=https://api.mistral.ai
|
||||
AI_SELECTOR_API_KEY=your-anthropic-api-key
|
||||
AI_SELECTOR_MODEL=claude-sonnet-4-20250514
|
||||
|
||||
# File Upload Configuration (Optional)
|
||||
LOCAL_UPLOAD_PATH=./public/uploads
|
||||
# Analyzer AI (for analysis stage, smaller model sufficient)
|
||||
AI_ANALYZER_ENDPOINT=https://api.mistral.ai
|
||||
AI_ANALYZER_API_KEY=your-anthropic-api-key
|
||||
AI_ANALYZER_MODEL=claude-sonnet-4-20250514
|
||||
|
||||
# === Embeddings Configuration ===
|
||||
# Enable/disable semantic embeddings pre-selection
|
||||
AI_EMBEDDINGS_ENABLED=true
|
||||
|
||||
# Embeddings API (Mistral recommended)
|
||||
AI_EMBEDDINGS_ENDPOINT=https://api.mistral.ai/v1/embeddings
|
||||
AI_EMBEDDINGS_API_KEY=your-mistral-api-key
|
||||
AI_EMBEDDINGS_MODEL=mistral-embed
|
||||
|
||||
# Embeddings performance settings
|
||||
AI_EMBEDDINGS_BATCH_SIZE=20
|
||||
AI_EMBEDDINGS_BATCH_DELAY_MS=1000
|
||||
AI_EMBEDDING_CANDIDATES=30
|
||||
AI_SIMILARITY_THRESHOLD=0.3
|
||||
|
||||
# === AI Processing Configuration ===
|
||||
AI_MAX_SELECTED_ITEMS=15
|
||||
AI_RATE_LIMIT_DELAY_MS=2000
|
||||
|
||||
# === Application Configuration ===
|
||||
PUBLIC_BASE_URL=http://localhost:4321
|
||||
NODE_ENV=development
|
||||
|
||||
# Nextcloud Integration (Optional)
|
||||
NEXTCLOUD_ENDPOINT=https://your-nextcloud.com
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -85,3 +85,4 @@ temp/
|
||||
.astro/data-store.json
|
||||
.astro/content.d.ts
|
||||
prompt.md
|
||||
.env
|
||||
|
25
src/pages/auth/login.ts
Normal file
25
src/pages/auth/login.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import type { APIRoute } from 'astro';
|
||||
import { getAuthRequirementForContext } from '../../utils/auth.js';
|
||||
|
||||
export const prerender = false;
|
||||
|
||||
export const GET: APIRoute = async ({ url }) => {
|
||||
const returnTo = url.searchParams.get('returnTo') || '/';
|
||||
|
||||
const authRequired = getAuthRequirementForContext('general') ||
|
||||
getAuthRequirementForContext('contributions') ||
|
||||
getAuthRequirementForContext('ai');
|
||||
|
||||
if (!authRequired) {
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: { 'Location': returnTo }
|
||||
});
|
||||
}
|
||||
|
||||
if (!process.env.OIDC_ENDPOINT) {
|
||||
return new Response('Authentication is enabled but not configured', { status: 500 });
|
||||
}
|
||||
|
||||
return new Response('OIDC login not implemented yet', { status: 501 });
|
||||
};
|
24
src/pages/auth/status.ts
Normal file
24
src/pages/auth/status.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import type { APIRoute } from 'astro';
|
||||
import { withAPIAuth, getAuthRequirementForContext } from '../../utils/auth.js';
|
||||
|
||||
export const prerender = false;
|
||||
|
||||
export const GET: APIRoute = async ({ request }) => {
|
||||
const contributionAuth = await withAPIAuth(request, 'contributions');
|
||||
const aiAuth = await withAPIAuth(request, 'ai');
|
||||
const generalAuth = await withAPIAuth(request, 'general');
|
||||
|
||||
return new Response(JSON.stringify({
|
||||
authenticated: generalAuth.authenticated,
|
||||
authRequired: getAuthRequirementForContext('general'),
|
||||
contributionAuthenticated: contributionAuth.authenticated,
|
||||
contributionAuthRequired: getAuthRequirementForContext('contributions'),
|
||||
aiAuthenticated: aiAuth.authenticated,
|
||||
aiAuthRequired: getAuthRequirementForContext('ai'),
|
||||
userId: contributionAuth.userId || 'anonymous',
|
||||
expires: contributionAuth.session?.exp ? new Date(contributionAuth.session.exp * 1000).toISOString() : null
|
||||
}), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
};
|
@ -45,11 +45,18 @@ export interface AuthStateData {
|
||||
function getEnv(key: string): string {
|
||||
const value = process.env[key];
|
||||
if (!value) {
|
||||
throw new Error(`Missing environment variable: ${key}`);
|
||||
console.warn(`[AUTH] Missing environment variable: ${key}`);
|
||||
return '';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function isAnyAuthEnabled(): boolean {
|
||||
return getAuthRequirement('general') ||
|
||||
getAuthRequirement('contributions') ||
|
||||
getAuthRequirement('ai');
|
||||
}
|
||||
|
||||
export function getSessionFromRequest(request: Request): string | null {
|
||||
const cookieHeader = request.headers.get('cookie');
|
||||
console.log('[DEBUG] Cookie header:', cookieHeader ? 'present' : 'missing');
|
||||
@ -141,9 +148,17 @@ export function generateState(): string {
|
||||
}
|
||||
|
||||
export function generateAuthUrl(state: string): string {
|
||||
if (!isAnyAuthEnabled()) {
|
||||
throw new Error('Authentication is disabled');
|
||||
}
|
||||
|
||||
const oidcEndpoint = getEnv('OIDC_ENDPOINT');
|
||||
const clientId = getEnv('OIDC_CLIENT_ID');
|
||||
const publicBaseUrl = getEnv('PUBLIC_BASE_URL');
|
||||
const publicBaseUrl = getEnv('PUBLIC_BASE_URL') || 'http://localhost:4321';
|
||||
|
||||
if (!oidcEndpoint || !clientId) {
|
||||
throw new Error('OIDC configuration incomplete');
|
||||
}
|
||||
|
||||
const params = new URLSearchParams({
|
||||
response_type: 'code',
|
||||
@ -153,16 +168,24 @@ export function generateAuthUrl(state: string): string {
|
||||
state: state
|
||||
});
|
||||
|
||||
return `${oidcEndpoint}/apps/oidc/authorize?${params.toString()}`;
|
||||
return `${oidcEndpoint}/authorize?${params.toString()}`;
|
||||
}
|
||||
|
||||
export async function exchangeCodeForTokens(code: string): Promise<{ access_token: string }> {
|
||||
if (!isAnyAuthEnabled()) {
|
||||
throw new Error('Authentication is disabled');
|
||||
}
|
||||
|
||||
const oidcEndpoint = getEnv('OIDC_ENDPOINT');
|
||||
const clientId = getEnv('OIDC_CLIENT_ID');
|
||||
const clientSecret = getEnv('OIDC_CLIENT_SECRET');
|
||||
const publicBaseUrl = getEnv('PUBLIC_BASE_URL');
|
||||
const publicBaseUrl = getEnv('PUBLIC_BASE_URL') || 'http://localhost:4321';
|
||||
|
||||
const response = await fetch(`${oidcEndpoint}/apps/oidc/token`, {
|
||||
if (!oidcEndpoint || !clientId || !clientSecret) {
|
||||
throw new Error('OIDC configuration incomplete');
|
||||
}
|
||||
|
||||
const response = await fetch(`${oidcEndpoint}/token`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
@ -185,9 +208,17 @@ export async function exchangeCodeForTokens(code: string): Promise<{ access_toke
|
||||
}
|
||||
|
||||
export async function getUserInfo(accessToken: string): Promise<UserInfo> {
|
||||
if (!isAnyAuthEnabled()) {
|
||||
throw new Error('Authentication is disabled');
|
||||
}
|
||||
|
||||
const oidcEndpoint = getEnv('OIDC_ENDPOINT');
|
||||
|
||||
const response = await fetch(`${oidcEndpoint}/apps/oidc/userinfo`, {
|
||||
if (!oidcEndpoint) {
|
||||
throw new Error('OIDC configuration incomplete');
|
||||
}
|
||||
|
||||
const response = await fetch(`${oidcEndpoint}/userinfo`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${accessToken}`
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user