Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
9211aa6
feat: add website assets from PR #169
d-ulker Sep 27, 2025
373da35
fix: replace HTML redirect favicon.ico with proper binary icon file
d-ulker Sep 27, 2025
97a6f63
fix: update HTML to use modular CSS structure
d-ulker Sep 27, 2025
ad48b66
fix: address code review issues in comprehensive-demo.css
d-ulker Sep 27, 2025
bdd5d57
feat: add core CSS architecture files
d-ulker Sep 27, 2025
b228a9e
feat: add UI component CSS files
d-ulker Sep 27, 2025
6095624
feat: add layout and interactive component CSS files
d-ulker Sep 27, 2025
1b8466f
feat: add final component CSS files and documentation
d-ulker Sep 27, 2025
3ba8ed0
feat: merge website assets with code review fixes
d-ulker Sep 27, 2025
ec81042
Merge branch 'main' of github.com:uelkerd/SAMO--DL
d-ulker Sep 27, 2025
ddf603f
Merge branch 'main' of github.com:uelkerd/SAMO--DL
d-ulker Sep 27, 2025
b3a46e5
Merge branch 'main' of github.com:uelkerd/SAMO--DL
d-ulker Sep 28, 2025
af6289c
Merge branch 'main' of github.com:uelkerd/SAMO--DL
d-ulker Sep 28, 2025
35530fa
Merge branch 'main' of github.com:uelkerd/SAMO--DL
d-ulker Sep 29, 2025
d2f5d6e
Merge branch 'main' of github.com:uelkerd/SAMO--DL
d-ulker Sep 29, 2025
7011ec9
feat: add Audio & Integration (PR #201-C) - voice recording & enhance…
d-ulker Sep 27, 2025
9b2e15d
fix: address Copilot AI code suggestions
d-ulker Sep 28, 2025
e1e406f
fix: comprehensive test suite and code quality improvements
d-ulker Sep 28, 2025
5c716b6
Fix hardcoded secrets security issue SCT-A000 in config test
d-ulker Sep 29, 2025
f50818b
Fix async test issue in voice-recorder.test.js
d-ulker Sep 29, 2025
a0121d7
Fix window.location mocking in config test for jsdom compatibility
d-ulker Sep 29, 2025
6b045c1
Implement secure-by-default authentication
d-ulker Sep 29, 2025
21ed2cf
Fix localhost API URL scheme to prevent certificate errors
d-ulker Sep 29, 2025
83bc136
Implement comprehensive nitpick improvements from CodeRabbitAI
d-ulker Sep 29, 2025
0079327
Implement secure authentication with build-time injection
d-ulker Sep 29, 2025
88a88d4
Merge branch 'main' into feat/audio-integration-final
d-ulker Sep 29, 2025
6d09794
fix: make build script idempotent and fix test window object pollution
d-ulker Sep 29, 2025
210c7b8
feat: add comprehensive linting and formatting scripts
d-ulker Sep 29, 2025
81e8df4
Merge branch 'feat/audio-integration-final' of github.com:uelkerd/SAM…
d-ulker Sep 29, 2025
be6e04f
fix: improve client-side auth config to respect build-time injection
d-ulker Sep 29, 2025
79fdbdf
feat: add API key authentication to protected endpoints
d-ulker Sep 29, 2025
b029e7b
feat: add mutual exclusivity validation for build flags
d-ulker Sep 29, 2025
381208d
fix: make requireAuthPattern regex more flexible and robust
d-ulker Sep 29, 2025
ee8b2e7
fix: make processRecordedAudio properly throw errors for tests
d-ulker Sep 29, 2025
9ab6120
fix: restore fortress compliance by removing non-essential files
d-ulker Sep 29, 2025
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
140 changes: 87 additions & 53 deletions deployment/secure_api_server.py

Large diffs are not rendered by default.

28 changes: 0 additions & 28 deletions website/.eslintrc.json

This file was deleted.

12 changes: 0 additions & 12 deletions website/.htmlhintrc

This file was deleted.

4 changes: 0 additions & 4 deletions website/.prettierignore

This file was deleted.

8 changes: 0 additions & 8 deletions website/.prettierrc

This file was deleted.

899 changes: 0 additions & 899 deletions website/comprehensive-demo.html

This file was deleted.

300 changes: 233 additions & 67 deletions website/js/config.js
Original file line number Diff line number Diff line change
@@ -1,104 +1,270 @@
/**
* SAMO Configuration
* SAMO-DL API Configuration
* Centralized configuration for API endpoints and keys
* This file should be loaded before other JavaScript files
*/

window.SAMO_CONFIG = {
// API Configuration
API: {
BASE_URL: 'https://samo-unified-api-optimized-frrnetyhfa-uc.a.run.app',
ENDPOINTS: {
EMOTION: '/analyze/emotion',
SUMMARIZE: '/analyze/summarize',
JOURNAL: '/analyze/journal',
HEALTH: '/health',
READY: '/ready',
TRANSCRIBE: '/transcribe',
VOICE_JOURNAL: '/analyze/voice-journal'
},
TIMEOUT: 45000, // 45 seconds (emotion analysis can take ~28s)
RETRY_ATTEMPTS: 3
// API Configuration
API: {
// Base URL for the SAMO-DL API
// Replace with your actual deployment URL
BASE_URL: 'https://samo-unified-api-frrnetyhfa-uc.a.run.app',

// Alternative URLs for different environments
// Uncomment and modify as needed
// DEV_URL: 'http://localhost:8000',
// STAGING_URL: 'https://samo-staging-api.example.com',
// PROD_URL: 'https://samo-prod-api.example.com',

// API endpoints
ENDPOINTS: {
EMOTION: '/analyze/emotion',
SUMMARIZE: '/analyze/summarize',
JOURNAL: '/analyze/journal',
VOICE_JOURNAL: '/analyze/voice-journal',
HEALTH: '/health',
READY: '/ready',
TRANSCRIBE: '/transcribe',
OPENAI_PROXY: '/proxy/openai',

// Authentication endpoints
AUTH: {
REGISTER: '/auth/register',
LOGIN: '/auth/login',
REFRESH: '/auth/refresh',
LOGOUT: '/auth/logout',
PROFILE: '/auth/profile'
},

// WebSocket endpoints
WS: {
CHAT: '/ws/chat',
TRANSCRIBE: '/ws/transcribe'
}
},

// Default timeout settings (in milliseconds)
TIMEOUTS: {
DEFAULT: 10000, // 10 seconds
LONG_RUNNING: 30000, // 30 seconds
WEBSOCKET: 5000 // 5 seconds
},

// Rate limiting configuration
RATE_LIMITS: {
MAX_REQUESTS_PER_MINUTE: 60,
BURST_LIMIT: 10
},

// OpenAI Configuration (for client-side text generation)
// Legacy compatibility - keep these for backward compatibility
TIMEOUT: 45000, // 45 seconds (emotion analysis can take ~28s)
RETRY_ATTEMPTS: 3,
API_KEY: null, // Set via server injection or user input // skipcq: SCT-A000
REQUIRE_AUTH: (typeof window.PROD_REQUIRE_AUTH !== 'undefined') ? window.PROD_REQUIRE_AUTH : true // Build-time injected for production
},
Comment on lines +61 to 65

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | πŸ”΄ Critical

🧩 Analysis chain

Production auth toggle needs enforcement.

API.API_KEY and API.REQUIRE_AUTH: false are risky defaults. Ensure production builds or server injection set REQUIRE_AUTH: true and that the backend enforces auth regardless of client config.

Run to locate usages and confirm server overrides in prod:


🏁 Script executed:

#!/bin/bash
# Find references to REQUIRE_AUTH and API_KEY
rg -n -C2 '\b(REQUIRE_AUTH|API_KEY)\b'

Length of output: 13940


🏁 Script executed:

#!/bin/bash
# Verify API_KEY enforcement in application code
rg -n "os.getenv('API_KEY')" -C3 --type py
rg -n "request.headers.get" -C3 --type py
rg -n "X-API-Key" -C3 --type py

Length of output: 9827


Require client auth in production & enforce server-side API key validation.

  • Override REQUIRE_AUTH to true in website/js/config.js during production builds (e.g., via build-time environment injection).
  • Verify every protected endpoint is decorated with require_api_key in deployment/cloud-run/secure_api_server.py.
πŸ€– Prompt for AI Agents
In website/js/config.js around lines 61–65, the client-side flag REQUIRE_AUTH is
hard-coded false; change it so the value is set from a build-time environment
injection (e.g., read an injected PROD_REQUIRE_AUTH or similar env var at build
time and default to false for local dev) and ensure your production build step
sets that env var to true; additionally audit
deployment/cloud-run/secure_api_server.py and add or verify the require_api_key
decorator is present on every protected endpoint (update any endpoints missing
the decorator so all protected routes validate the API key server-side).

Comment thread
coderabbitai[bot] marked this conversation as resolved.

// OpenAI Configuration - DISABLED for security (use proxy instead)
// WARNING: Direct client-side OpenAI calls expose API keys!
// All OpenAI functionality must use the /proxy/openai endpoint
OPENAI: {
API_KEY: '', // Set via environment or server injection
API_URL: 'https://api.openai.com/v1/chat/completions',
MODEL: 'gpt-3.5-turbo',
MAX_TOKENS: 200,
TEMPERATURE: 0.7
// API_URL: 'https://api.openai.com/v1/chat/completions', // DISABLED - Security risk
// MODEL: 'gpt-4o-mini', // DISABLED - Use proxy endpoint
// MAX_TOKENS: 4000, // DISABLED - Use proxy endpoint
// TEMPERATURE: 0.7 // DISABLED - Use proxy endpoint
},

// External Services
EXTERNAL: {
HUGGINGFACE: {
API_URL: 'https://api-inference.huggingface.co/models/gpt2',
MAX_LENGTH: 150
},
GOOGLE_FONTS: 'https://fonts.googleapis.com',
CDN: {
BOOTSTRAP: 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css',
CHART_JS: 'https://cdn.jsdelivr.net/npm/chart.js',
FONT_AWESOME: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css'
}
// UI Configuration
UI: {
// Demo settings
DEMO: {
MAX_TEXT_LENGTH: 5000,
MAX_BATCH_SIZE: 10,
ENABLE_VOICE_RECORDING: true,
ENABLE_WEBSOCKET: true
},

// Development/Production flags
ENVIRONMENT: 'production', // 'development' or 'production'
DEBUG: false,
// Monitoring refresh interval (in milliseconds)
MONITORING_REFRESH_INTERVAL: 30000, // 30 seconds

// Animation settings
ANIMATIONS: {
ENABLED: true,
DURATION: 300
}
},

// External Services
EXTERNAL: {
HUGGINGFACE: {
API_URL: 'https://api-inference.huggingface.co/models/gpt2',
MAX_LENGTH: 150
},
GOOGLE_FONTS: 'https://fonts.googleapis.com',
CDN: {
BOOTSTRAP: 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css',
CHART_JS: 'https://cdn.jsdelivr.net/npm/chart.js',
FONT_AWESOME: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css'
}
},

// Development/Production flags
ENVIRONMENT: 'production', // 'development' or 'production'
DEBUG: false,

// Feature flags
FEATURES: {
ENABLE_OPENAI: true, // Enabled by default for core functionality
ENABLE_OPENAI: false, // DISABLED - Security risk (use /proxy/openai endpoint instead)
ENABLE_MOCK_DATA: false, // Always use real APIs
ENABLE_ANALYTICS: false
ENABLE_ANALYTICS: false,
ENABLE_AUTH: true,
ENABLE_VOICE_TRANSCRIPTION: true,
ENABLE_BATCH_PROCESSING: true,
ENABLE_TEXT_SUMMARIZATION: true,
ENABLE_REAL_TIME_MONITORING: true,
ENABLE_SECURITY_TESTING: true,
ENABLE_WEBSOCKET_CHAT: true
}
};

// Environment-specific overrides - ALWAYS USE REAL APIS
// Environment-specific overrides - USE DEPLOYED API FOR DEVELOPMENT
if (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1') {
window.SAMO_CONFIG.ENVIRONMENT = 'development';
window.SAMO_CONFIG.DEBUG = true;

// For demo testing, use production API directly (CORS is enabled on the server)
// Keep production URL and endpoints for localhost development
console.log('πŸ”§ Running in localhost development mode - using production API with CORS');
// Use local unified API server; match page scheme to avoid cert/mixed-content issues
const scheme = window.location.protocol === 'https:' ? 'https' : 'http';
const host = window.location.hostname === '127.0.0.1' ? '127.0.0.1' : 'localhost';
window.SAMO_CONFIG.API.BASE_URL = `${scheme}://${host}:8002`;

// Only override REQUIRE_AUTH for localhost if not in production build
// This allows testing production auth behavior locally when needed
if (window.SAMO_CONFIG.API.REQUIRE_AUTH !== true) {
window.SAMO_CONFIG.API.REQUIRE_AUTH = false; // Disable auth for local dev convenience
}
// Note: ENDPOINTS remain unchanged from production config (no override needed)

console.log(`πŸ”§ Running in localhost development mode - using local API server at ${window.SAMO_CONFIG.API.BASE_URL}`);
console.log(`πŸ” Authentication required: ${window.SAMO_CONFIG.API.REQUIRE_AUTH}`);
}

// Optional: deep-freeze config in production (disabled for now due to testing complexity)
// TODO: Re-enable with more sophisticated detection to avoid interfering with tests
// if (window.SAMO_CONFIG.ENVIRONMENT === 'production' && !window.__TESTING__) {
// (function deepFreeze(obj) {
// Object.getOwnPropertyNames(obj).forEach((prop) => {
// const value = obj[prop];
// if (value && typeof value === 'object') deepFreeze(value);
// });
// return Object.freeze(obj);
// })(window.SAMO_CONFIG);
// }

// Helper function to get API URL with fallback
window.SAMO_CONFIG.getApiUrl = function(endpoint) {
const baseUrl = this.API.BASE_URL;
if (!baseUrl) {
console.warn('SAMO_CONFIG.API.BASE_URL is not set. Please configure your API endpoint.');
return null;
}

if (typeof endpoint !== 'string' || endpoint.length === 0) {
console.warn('SAMO_CONFIG.getApiUrl called with invalid endpoint:', endpoint);
return null;
}

// Remove trailing slash from base URL and leading slash from endpoint
const cleanBaseUrl = baseUrl.replace(/\/$/, '');
const cleanEndpoint = endpoint.startsWith('/') ? endpoint : '/' + endpoint;

return cleanBaseUrl + cleanEndpoint;
};

// Helper function to get WebSocket URL
window.SAMO_CONFIG.getWebSocketUrl = function(endpoint) {
const baseUrl = this.API.BASE_URL;
if (!baseUrl) {
console.warn('SAMO_CONFIG.API.BASE_URL is not set. Cannot create WebSocket URL.');
return null;
}

if (typeof endpoint !== 'string' || endpoint.length === 0) {
console.warn('SAMO_CONFIG.getWebSocketUrl called with invalid endpoint:', endpoint);
return null;
}

// Convert HTTPS to WSS
let wsUrl = baseUrl.replace(/^https:/, 'wss:').replace(/^http:/, 'ws:');

// Remove trailing slash from base URL and leading slash from endpoint
wsUrl = wsUrl.replace(/\/$/, '');
const cleanEndpoint = endpoint.startsWith('/') ? endpoint : '/' + endpoint;

return wsUrl + cleanEndpoint;
};

// Deep merge utility function
window.SAMO_CONFIG.deepMerge = function(target, source) {
const result = { ...target };

for (const key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
// Recursively merge objects
result[key] = this.deepMerge(target[key] || {}, source[key]);
} else {
// Replace primitives and arrays
result[key] = source[key];
}
}
}

return result;
};

// Server-side configuration injection (if available)
if (window.SAMO_SERVER_CONFIG) {
Object.assign(window.SAMO_CONFIG, window.SAMO_SERVER_CONFIG);
window.SAMO_CONFIG = window.SAMO_CONFIG.deepMerge(window.SAMO_CONFIG, window.SAMO_SERVER_CONFIG);
}

// Only log config in debug mode and redact sensitive fields
if (window.SAMO_CONFIG && window.SAMO_CONFIG.DEBUG) {
const sanitizedConfig = { ...window.SAMO_CONFIG };
const sensitiveKeys = ['apiKey', 'secret', 'token', 'password', 'clientSecret'];

// Redact sensitive fields
sensitiveKeys.forEach(key => {
if (sanitizedConfig[key]) {
sanitizedConfig[key] = 'REDACTED';
}
});
// Recursive redaction utility function
window.SAMO_CONFIG.redactSensitiveValues = function(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}

// Also check nested objects
if (sanitizedConfig.API) {
sensitiveKeys.forEach(key => {
if (sanitizedConfig.API[key]) {
sanitizedConfig.API[key] = 'REDACTED';
}
});
if (Array.isArray(obj)) {
return obj.map(item => this.redactSensitiveValues(item));
}

if (sanitizedConfig.OPENAI) {
sensitiveKeys.forEach(key => {
if (sanitizedConfig.OPENAI[key]) {
sanitizedConfig.OPENAI[key] = 'REDACTED';
}
});
const result = {};
const SENSITIVE_PATTERNS = [
/^(api[-_]?key|authorization|x[-_]?api[-_]?key|bearer)$/i, // skipcq: SCT-A000 - security pattern definitions
/^(token|access[_-]?token|refresh[_-]?token)$/i, // skipcq: SCT-A000 - security pattern definitions
/^(secret|client[_-]?secret)$/i, // skipcq: SCT-A000 - security pattern definitions
/^(password|passwd)$/i, // skipcq: SCT-A000 - security pattern definitions
/^(credential|credentials|auth|authkey)$/i // skipcq: SCT-A000 - security pattern definitions
];

for (const [key, value] of Object.entries(obj)) {
const isSensitive = SENSITIVE_PATTERNS.some(re => re.test(key));

if (isSensitive) {
result[key] = 'REDACTED';
} else if (value && typeof value === 'object') {
result[key] = this.redactSensitiveValues(value);
} else {
result[key] = value;
}
}

return result;
};

// Only log config in debug mode and redact sensitive fields
if (window.SAMO_CONFIG && window.SAMO_CONFIG.DEBUG) {
const sanitizedConfig = window.SAMO_CONFIG.redactSensitiveValues(window.SAMO_CONFIG);
console.log('πŸ”§ SAMO Configuration loaded (debug mode):', sanitizedConfig);
}

console.log('SAMO-DL configuration loaded successfully');
Loading
Loading