gated content
This commit is contained in:
parent
2f17370938
commit
d49b031eb9
6
.astro/content.d.ts
vendored
6
.astro/content.d.ts
vendored
@ -164,9 +164,11 @@ declare module 'astro:content' {
|
||||
type DataEntryMap = {
|
||||
"knowledgebase": Record<string, {
|
||||
id: string;
|
||||
body?: string;
|
||||
render(): Render[".md"];
|
||||
slug: string;
|
||||
body: string;
|
||||
collection: "knowledgebase";
|
||||
data: any;
|
||||
data: InferEntrySchema<"knowledgebase">;
|
||||
rendered?: RenderedContent;
|
||||
filePath?: string;
|
||||
}>;
|
||||
|
@ -30,6 +30,7 @@ NODE_ENV=development
|
||||
# Set to true to require authentication (RECOMMENDED for production)
|
||||
AUTHENTICATION_NECESSARY_CONTRIBUTIONS=false
|
||||
AUTHENTICATION_NECESSARY_AI=false
|
||||
AUTHENTICATION_NECESSARY_GATEDCONTENT=true
|
||||
|
||||
# OIDC Provider Configuration
|
||||
OIDC_ENDPOINT=https://your-nextcloud.com/index.php/apps/oidc
|
||||
|
@ -16,6 +16,11 @@ const knowledgebaseCollection = defineCollection({
|
||||
tags: z.array(z.string()).default([]),
|
||||
|
||||
published: z.boolean().default(true),
|
||||
gated_content: z.boolean().default(false), // NEW: Gated content flag
|
||||
|
||||
})
|
||||
});
|
||||
|
||||
export const collections = {
|
||||
knowledgebase: knowledgebaseCollection
|
||||
};
|
@ -6,6 +6,7 @@ last_updated: 2025-07-20
|
||||
author: "Claude 4 Sonnett (Prompt: Mario Stöckl)"
|
||||
difficulty: "advanced"
|
||||
categories: ["incident-response", "malware-analysis", "network-forensics"]
|
||||
gated_content: true
|
||||
tags: ["web-based", "endpoint-monitoring", "artifact-extraction", "scripting", "live-forensics", "hunting"]
|
||||
sections:
|
||||
overview: true
|
||||
|
6
src/env.d.ts
vendored
6
src/env.d.ts
vendored
@ -25,9 +25,9 @@ declare global {
|
||||
findToolByIdentifier: (tools: any[], identifier: string) => any | undefined;
|
||||
isToolHosted: (tool: any) => boolean;
|
||||
|
||||
checkClientAuth: (context?: string) => Promise<{authenticated: boolean; authRequired: boolean; expires?: string}>;
|
||||
requireClientAuth: (callback?: () => void, returnUrl?: string, context?: string) => Promise<boolean>;
|
||||
showIfAuthenticated: (selector: string, context?: string) => Promise<void>;
|
||||
checkClientAuth: (context?: 'contributions' | 'ai' | 'general' | 'gatedcontent') => Promise<{authenticated: boolean; authRequired: boolean; expires?: string}>;
|
||||
requireClientAuth: (callback?: () => void, returnUrl?: string, context?: 'contributions' | 'ai' | 'general' | 'gatedcontent') => Promise<boolean>;
|
||||
showIfAuthenticated: (selector: string, context?: 'contributions' | 'ai' | 'general' | 'gatedcontent') => Promise<void>;
|
||||
setupAuthButtons: (selector?: string) => void;
|
||||
|
||||
scrollToElement: (element: Element | null, options?: ScrollIntoViewOptions) => void;
|
||||
|
@ -9,13 +9,16 @@ export const GET: APIRoute = async ({ request }) => {
|
||||
return await handleAPIRequest(async () => {
|
||||
const contributionAuth = await withAPIAuth(request, 'contributions');
|
||||
const aiAuth = await withAPIAuth(request, 'ai');
|
||||
const gatedContentAuth = await withAPIAuth(request, 'gatedcontent'); // ADDED
|
||||
|
||||
return apiResponse.success({
|
||||
authenticated: contributionAuth.authenticated || aiAuth.authenticated,
|
||||
authenticated: contributionAuth.authenticated || aiAuth.authenticated || gatedContentAuth.authenticated,
|
||||
contributionAuthRequired: contributionAuth.authRequired,
|
||||
aiAuthRequired: aiAuth.authRequired,
|
||||
gatedContentAuthRequired: gatedContentAuth.authRequired, // ADDED
|
||||
contributionAuthenticated: contributionAuth.authenticated,
|
||||
aiAuthenticated: aiAuth.authenticated,
|
||||
gatedContentAuthenticated: gatedContentAuth.authenticated, // ADDED
|
||||
expires: contributionAuth.session?.exp ? new Date(contributionAuth.session.exp * 1000).toISOString() : null
|
||||
});
|
||||
}, 'Status check failed');
|
||||
|
@ -166,6 +166,14 @@ const sortedTools = data.tools.sort((a: any, b: any) => a.name.localeCompare(b.n
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="checkbox-wrapper">
|
||||
<input type="checkbox" id="gated-content" name="gatedContent" />
|
||||
<span>🔒 Als geschützten Inhalt markieren (Authentifizierung erforderlich)</span>
|
||||
</label>
|
||||
<small class="form-help">Nur für interne oder vertrauliche Inhalte</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="reason" class="form-label">Grund für den Beitrag (Optional)</label>
|
||||
<textarea
|
||||
|
@ -3,12 +3,16 @@ import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
import { getCollection } from 'astro:content';
|
||||
import { getToolsData } from '../utils/dataService.js';
|
||||
import ContributionButton from '../components/ContributionButton.astro';
|
||||
import { isGatedContentAuthRequired } from '../utils/auth.js';
|
||||
|
||||
const data = await getToolsData();
|
||||
const allKnowledgebaseEntries = await getCollection('knowledgebase', (entry) => {
|
||||
return entry.data.published !== false;
|
||||
});
|
||||
|
||||
// Check if gated content authentication is enabled globally
|
||||
const gatedContentAuthEnabled = isGatedContentAuthRequired();
|
||||
|
||||
const knowledgebaseEntries = allKnowledgebaseEntries.map((entry) => {
|
||||
const associatedTool = entry.data.tool_name
|
||||
? data.tools.find((tool: any) => tool.name === entry.data.tool_name)
|
||||
@ -23,6 +27,7 @@ const knowledgebaseEntries = allKnowledgebaseEntries.map((entry) => {
|
||||
difficulty: entry.data.difficulty,
|
||||
categories: entry.data.categories || [],
|
||||
tags: entry.data.tags || [],
|
||||
gated_content: entry.data.gated_content || false, // NEW: Include gated content flag
|
||||
|
||||
tool_name: entry.data.tool_name,
|
||||
related_tools: entry.data.related_tools || [],
|
||||
@ -39,6 +44,10 @@ const knowledgebaseEntries = allKnowledgebaseEntries.map((entry) => {
|
||||
});
|
||||
|
||||
knowledgebaseEntries.sort((a: any, b: any) => a.title.localeCompare(b.title));
|
||||
|
||||
// Count gated vs public articles for statistics
|
||||
const gatedCount = knowledgebaseEntries.filter(entry => entry.gated_content).length;
|
||||
const publicCount = knowledgebaseEntries.length - gatedCount;
|
||||
---
|
||||
|
||||
<BaseLayout title="Knowledgebase" description="Extended documentation and insights for DFIR tools">
|
||||
@ -52,6 +61,24 @@ knowledgebaseEntries.sort((a: any, b: any) => a.title.localeCompare(b.title));
|
||||
Praktische Erfahrungen, Konfigurationshinweise und Lektionen aus der Praxis
|
||||
</p>
|
||||
|
||||
{gatedContentAuthEnabled && gatedCount > 0 && (
|
||||
<div class="gated-content-info mb-4 p-3 rounded" style="background-color: var(--color-bg-secondary); border: 1px solid var(--color-border);">
|
||||
<div class="flex items-center justify-center gap-2 text-sm text-secondary">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"/>
|
||||
<circle cx="12" cy="16" r="1"/>
|
||||
<path d="M7 11V7a5 5 0 0 1 10 0v4"/>
|
||||
</svg>
|
||||
<span>
|
||||
{gatedCount} geschützte Artikel • {publicCount} öffentliche Artikel
|
||||
</span>
|
||||
</div>
|
||||
<p class="text-xs text-secondary mt-1">
|
||||
🔒 Geschützte Artikel erfordern Authentifizierung
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div class="flex gap-4 justify-center flex-wrap">
|
||||
<ContributionButton type="write" variant="primary" text="Artikel schreiben" style="padding: 0.75rem 1.5rem;" />
|
||||
<button onclick="window.scrollToElementById('kb-entries')" class="btn btn-secondary" style="padding: 0.75rem 1.5rem;">
|
||||
@ -60,7 +87,7 @@ knowledgebaseEntries.sort((a: any, b: any) => a.title.localeCompare(b.title));
|
||||
<line x1="21" y1="21" x2="16.65" y2="16.65"/>
|
||||
</svg>
|
||||
Artikel durchsuchen
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -107,6 +134,7 @@ knowledgebaseEntries.sort((a: any, b: any) => a.title.localeCompare(b.title));
|
||||
const isMethod = hasAssociatedTool && entry.associatedTool.type === 'method';
|
||||
const isConcept = hasAssociatedTool && entry.associatedTool.type === 'concept';
|
||||
const isStandalone = !hasAssociatedTool;
|
||||
const isGated = entry.gated_content === true;
|
||||
|
||||
const articleUrl = `/knowledgebase/${entry.slug}`;
|
||||
|
||||
@ -116,6 +144,7 @@ knowledgebaseEntries.sort((a: any, b: any) => a.title.localeCompare(b.title));
|
||||
id={`kb-${entry.slug}`}
|
||||
data-tool-name={entry.title.toLowerCase()}
|
||||
data-article-type={isStandalone ? 'standalone' : 'tool-associated'}
|
||||
data-gated={isGated}
|
||||
onclick={`window.location.href='${articleUrl}'`}
|
||||
>
|
||||
<!-- Card Header -->
|
||||
@ -125,6 +154,11 @@ knowledgebaseEntries.sort((a: any, b: any) => a.title.localeCompare(b.title));
|
||||
<div class="min-w-0 flex-1">
|
||||
<h3 class="text-lg font-semibold text-primary mb-1 leading-tight">
|
||||
{entry.title}
|
||||
{isGated && gatedContentAuthEnabled && (
|
||||
<span class="gated-indicator ml-2" title="Geschützter Inhalt - Authentifizierung erforderlich">
|
||||
🔒
|
||||
</span>
|
||||
)}
|
||||
</h3>
|
||||
<div class="flex gap-2 flex-wrap mb-2">
|
||||
{isStandalone && <span class="badge" style="background-color: var(--color-accent); color: white;">Artikel</span>}
|
||||
@ -134,6 +168,7 @@ knowledgebaseEntries.sort((a: any, b: any) => a.title.localeCompare(b.title));
|
||||
{hasValidProjectUrl && <span class="badge badge-primary">CC24-Server</span>}
|
||||
{hasAssociatedTool && entry.associatedTool.license !== 'Proprietary' && !isMethod && !isConcept && <span class="badge badge-success">Open Source</span>}
|
||||
<span class="badge badge-error">📖</span>
|
||||
{isGated && gatedContentAuthEnabled && <span class="badge badge-warning">🔒</span>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -145,7 +180,7 @@ knowledgebaseEntries.sort((a: any, b: any) => a.title.localeCompare(b.title));
|
||||
<polyline points="15 3 21 3 21 9"/>
|
||||
<line x1="10" y1="14" x2="21" y2="3"/>
|
||||
</svg>
|
||||
Öffnen
|
||||
{isGated && gatedContentAuthEnabled ? 'Anmelden' : 'Öffnen'}
|
||||
</a>
|
||||
<button
|
||||
class="btn btn-secondary btn-sm"
|
||||
@ -168,6 +203,16 @@ knowledgebaseEntries.sort((a: any, b: any) => a.title.localeCompare(b.title));
|
||||
<!-- Description -->
|
||||
<p class="text-secondary mb-4 leading-relaxed">
|
||||
{entry.description}
|
||||
{isGated && gatedContentAuthEnabled && (
|
||||
<span class="gated-content-hint ml-2 text-xs">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display: inline; margin-right: 0.25rem;">
|
||||
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"/>
|
||||
<circle cx="12" cy="16" r="1"/>
|
||||
<path d="M7 11V7a5 5 0 0 1 10 0v4"/>
|
||||
</svg>
|
||||
Authentifizierung erforderlich
|
||||
</span>
|
||||
)}
|
||||
</p>
|
||||
|
||||
<!-- Metadata Footer -->
|
||||
@ -299,7 +344,26 @@ knowledgebaseEntries.sort((a: any, b: any) => a.title.localeCompare(b.title));
|
||||
lastScrollY = window.scrollY;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.gated-indicator {
|
||||
font-size: 0.875rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.gated-content-hint {
|
||||
color: var(--color-warning);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.kb-entry[data-gated="true"] {
|
||||
border-left: 3px solid var(--color-warning);
|
||||
}
|
||||
|
||||
.gated-content-info {
|
||||
border-left: 4px solid var(--color-warning) !important;
|
||||
}
|
||||
</style>
|
||||
</BaseLayout>
|
@ -2,6 +2,7 @@
|
||||
import { getCollection } from 'astro:content';
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import { getToolsData } from '../../utils/dataService.js';
|
||||
import { isGatedContentAuthRequired } from '../../utils/auth.js';
|
||||
|
||||
export const prerender = true;
|
||||
|
||||
@ -20,6 +21,13 @@ export async function getStaticPaths() {
|
||||
|
||||
const { entry }: { entry: any } = Astro.props;
|
||||
|
||||
// Check if this article is gated and if gated content auth is required globally
|
||||
const isGatedContent = entry.data.gated_content === true;
|
||||
const gatedContentAuthRequired = isGatedContentAuthRequired();
|
||||
const requiresAuth = isGatedContent && gatedContentAuthRequired;
|
||||
|
||||
console.log(`[GATED CONTENT] Article: ${entry.data.title}, Gated: ${isGatedContent}, Auth Required: ${requiresAuth}`);
|
||||
|
||||
const { Content } = await entry.render();
|
||||
|
||||
const data = await getToolsData();
|
||||
@ -52,6 +60,68 @@ const currentUrl = Astro.url.href;
|
||||
---
|
||||
|
||||
<BaseLayout title={entry.data.title} description={entry.data.description}>
|
||||
{requiresAuth && (
|
||||
<script define:vars={{ requiresAuth, articleTitle: entry.data.title }}>
|
||||
// Client-side authentication check for gated content
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
if (!requiresAuth) return;
|
||||
|
||||
console.log('[GATED CONTENT] Checking client-side auth for: ' + articleTitle);
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/auth/status');
|
||||
const authStatus = await response.json();
|
||||
|
||||
const isAuthenticated = authStatus.gatedContentAuthenticated || false;
|
||||
const authRequired = authStatus.gatedContentAuthRequired || false;
|
||||
|
||||
console.log('[GATED CONTENT] Auth status - Required: ' + authRequired + ', Authenticated: ' + isAuthenticated);
|
||||
|
||||
if (authRequired && !isAuthenticated) {
|
||||
console.log('[GATED CONTENT] Redirecting for authentication: ' + articleTitle);
|
||||
|
||||
// Show loading message briefly
|
||||
const contentArea = document.querySelector('.article-content');
|
||||
if (contentArea) {
|
||||
contentArea.innerHTML = [
|
||||
'<div style="text-align: center; padding: 3rem;">',
|
||||
'<div style="font-size: 3rem; margin-bottom: 1rem;">🔒</div>',
|
||||
'<h3 style="margin-bottom: 1rem;">Authentifizierung erforderlich</h3>',
|
||||
'<p style="margin-bottom: 2rem;">Sie werden zur Anmeldung weitergeleitet...</p>',
|
||||
'</div>'
|
||||
].join('');
|
||||
}
|
||||
|
||||
// Redirect to login after brief delay
|
||||
setTimeout(() => {
|
||||
const currentUrl = encodeURIComponent(window.location.href);
|
||||
window.location.href = '/api/auth/login?returnTo=' + currentUrl;
|
||||
}, 1000);
|
||||
} else {
|
||||
console.log('[GATED CONTENT] Access granted for: ' + articleTitle);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[GATED CONTENT] Auth check failed:', error);
|
||||
// On error, show auth required message
|
||||
if (requiresAuth) {
|
||||
const contentArea = document.querySelector('.article-content');
|
||||
if (contentArea) {
|
||||
const loginUrl = '/api/auth/login?returnTo=' + encodeURIComponent(window.location.href);
|
||||
contentArea.innerHTML = [
|
||||
'<div style="text-align: center; padding: 3rem;">',
|
||||
'<div style="font-size: 3rem; margin-bottom: 1rem;">⚠️</div>',
|
||||
'<h3 style="margin-bottom: 1rem;">Authentifizierungsfehler</h3>',
|
||||
'<p style="margin-bottom: 2rem;">Bitte versuchen Sie es später erneut oder melden Sie sich an.</p>',
|
||||
'<a href="' + loginUrl + '" class="btn btn-primary">Anmelden</a>',
|
||||
'</div>'
|
||||
].join('');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
)}
|
||||
|
||||
<div class="article-layout">
|
||||
<!-- Article Header -->
|
||||
<header class="article-header">
|
||||
@ -77,8 +147,24 @@ const currentUrl = Astro.url.href;
|
||||
<h1 class="article-title">
|
||||
{displayTool?.icon && <span class="article-icon">{displayTool.icon}</span>}
|
||||
{entry.data.title}
|
||||
{isGatedContent && (
|
||||
<span class="gated-indicator" title="Geschützter Inhalt - Authentifizierung erforderlich">
|
||||
🔒
|
||||
</span>
|
||||
)}
|
||||
</h1>
|
||||
<p class="article-description">{entry.data.description}</p>
|
||||
|
||||
{isGatedContent && gatedContentAuthRequired && (
|
||||
<div class="gated-content-notice">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-right: 0.5rem;">
|
||||
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"/>
|
||||
<circle cx="12" cy="16" r="1"/>
|
||||
<path d="M7 11V7a5 5 0 0 1 10 0v4"/>
|
||||
</svg>
|
||||
<span>Dieser Artikel enthält geschützte Inhalte</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div class="article-metadata-grid">
|
||||
@ -96,6 +182,7 @@ const currentUrl = Astro.url.href;
|
||||
</>
|
||||
)}
|
||||
<span class="badge badge-error">📖</span>
|
||||
{isGatedContent && <span class="badge badge-warning">🔒</span>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -477,5 +564,23 @@ const currentUrl = Astro.url.href;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.gated-indicator {
|
||||
font-size: 0.875rem;
|
||||
opacity: 0.8;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.gated-content-notice {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.75rem 1rem;
|
||||
background-color: var(--color-warning-bg, rgba(255, 193, 7, 0.1));
|
||||
border: 1px solid var(--color-warning, #ffc107);
|
||||
border-radius: 0.375rem;
|
||||
color: var(--color-warning-text, #856404);
|
||||
font-size: 0.875rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
</style>
|
||||
</BaseLayout>
|
@ -112,27 +112,6 @@ class AuditService {
|
||||
};
|
||||
}
|
||||
|
||||
getDebugInfo(): {
|
||||
config: AuditConfig;
|
||||
environment: Record<string, any>;
|
||||
context: string;
|
||||
} {
|
||||
const context = typeof process !== 'undefined' ? 'server' : 'client';
|
||||
|
||||
return {
|
||||
config: this.config,
|
||||
environment: {
|
||||
FORENSIC_AUDIT_ENABLED: env('FORENSIC_AUDIT_ENABLED'),
|
||||
FORENSIC_AUDIT_DETAIL_LEVEL: env('FORENSIC_AUDIT_DETAIL_LEVEL'),
|
||||
FORENSIC_AUDIT_RETENTION_HOURS: env('FORENSIC_AUDIT_RETENTION_HOURS'),
|
||||
FORENSIC_AUDIT_MAX_ENTRIES: env('FORENSIC_AUDIT_MAX_ENTRIES'),
|
||||
processEnvKeys: typeof process !== 'undefined' ? Object.keys(process.env).filter(k => k.includes('AUDIT')) : [],
|
||||
importMetaEnvAvailable: typeof import.meta !== 'undefined' && !!(import.meta as any).env
|
||||
},
|
||||
context
|
||||
};
|
||||
}
|
||||
|
||||
addEntry(
|
||||
phase: string,
|
||||
action: string,
|
||||
@ -397,15 +376,3 @@ class AuditService {
|
||||
|
||||
export const auditService = new AuditService();
|
||||
export type { ProcessedAuditTrail, CompressedAuditEntry };
|
||||
|
||||
export const debugAuditService = {
|
||||
getDebugInfo() {
|
||||
return auditService.getDebugInfo();
|
||||
},
|
||||
isEnabled() {
|
||||
return auditService.isEnabled();
|
||||
},
|
||||
getConfig() {
|
||||
return auditService.getConfig();
|
||||
}
|
||||
};
|
@ -1,4 +1,4 @@
|
||||
// src/utils/auth.js (FIXED - Cleaned up and enhanced debugging)
|
||||
// src/utils/auth.js (ENHANCED - Added gated content support)
|
||||
import type { AstroGlobal } from 'astro';
|
||||
import crypto from 'crypto';
|
||||
import { config } from 'dotenv';
|
||||
@ -27,7 +27,7 @@ export interface AuthContext {
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export type AuthContextType = 'contributions' | 'ai' | 'general';
|
||||
export type AuthContextType = 'contributions' | 'ai' | 'general' | 'gatedcontent';
|
||||
|
||||
export interface UserInfo {
|
||||
sub?: string;
|
||||
@ -260,6 +260,8 @@ function getAuthRequirement(context: AuthContextType): boolean {
|
||||
return process.env.AUTHENTICATION_NECESSARY_CONTRIBUTIONS !== 'false';
|
||||
case 'ai':
|
||||
return process.env.AUTHENTICATION_NECESSARY_AI !== 'false';
|
||||
case 'gatedcontent':
|
||||
return process.env.AUTHENTICATION_NECESSARY_GATEDCONTENT !== 'false';
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
@ -387,3 +389,13 @@ export async function withAPIAuth(request: Request, context: AuthContextType = '
|
||||
export function getAuthRequirementForContext(context: AuthContextType): boolean {
|
||||
return getAuthRequirement(context);
|
||||
}
|
||||
|
||||
// NEW: Helper function to check if gated content requires authentication
|
||||
export function isGatedContentAuthRequired(): boolean {
|
||||
return getAuthRequirement('gatedcontent');
|
||||
}
|
||||
|
||||
// NEW: Check if specific content should be gated
|
||||
export function shouldGateContent(isGatedContent: boolean): boolean {
|
||||
return isGatedContent && isGatedContentAuthRequired();
|
||||
}
|
@ -48,12 +48,6 @@ class EmbeddingsService {
|
||||
|
||||
private async checkEnabledStatus(): Promise<void> {
|
||||
try {
|
||||
console.log('[EMBEDDINGS] Debug env check:', {
|
||||
AI_EMBEDDINGS_ENABLED: process.env.AI_EMBEDDINGS_ENABLED,
|
||||
envKeys: Object.keys(process.env).filter(k => k.includes('EMBEDDINGS')).length,
|
||||
allEnvKeys: Object.keys(process.env).length
|
||||
});
|
||||
|
||||
const envEnabled = process.env.AI_EMBEDDINGS_ENABLED;
|
||||
|
||||
if (envEnabled === 'true') {
|
||||
@ -466,12 +460,3 @@ class EmbeddingsService {
|
||||
const embeddingsService = new EmbeddingsService();
|
||||
|
||||
export { embeddingsService, type EmbeddingData, type SimilarityResult };
|
||||
|
||||
export const debugEmbeddings = {
|
||||
async recheckEnvironment() {
|
||||
return embeddingsService.forceRecheckEnvironment();
|
||||
},
|
||||
getStatus() {
|
||||
return embeddingsService.getStats();
|
||||
}
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user