GT AI OS Community Edition v2.0.33

Security hardening release addressing CodeQL and Dependabot alerts:

- Fix stack trace exposure in error responses
- Add SSRF protection with DNS resolution checking
- Implement proper URL hostname validation (replaces substring matching)
- Add centralized path sanitization to prevent path traversal
- Fix ReDoS vulnerability in email validation regex
- Improve HTML sanitization in validation utilities
- Fix capability wildcard matching in auth utilities
- Update glob dependency to address CVE
- Add CodeQL suppression comments for verified false positives

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
HackWeasel
2025-12-12 17:04:45 -05:00
commit b9dfb86260
746 changed files with 232071 additions and 0 deletions

216
packages/utils/dist/database.js vendored Normal file
View File

@@ -0,0 +1,216 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getTenantDatabasePath = getTenantDatabasePath;
exports.getTenantChromaCollection = getTenantChromaCollection;
exports.getTenantRedisPrefix = getTenantRedisPrefix;
exports.getTenantMinioBucket = getTenantMinioBucket;
exports.getSQLiteWALConfig = getSQLiteWALConfig;
exports.getSQLiteEncryptionConfig = getSQLiteEncryptionConfig;
exports.getTenantDatabaseSchema = getTenantDatabaseSchema;
exports.generateDocumentChunkId = generateDocumentChunkId;
exports.parseConnectionString = parseConnectionString;
exports.escapeSQLIdentifier = escapeSQLIdentifier;
exports.generateBackupFilename = generateBackupFilename;
// Database utility functions
const path_1 = __importDefault(require("path"));
const crypto_1 = __importDefault(require("crypto"));
/**
* Generate SQLite database path for tenant
*/
function getTenantDatabasePath(tenantDomain, dataDir = '/data') {
return path_1.default.join(dataDir, tenantDomain, 'app.db');
}
/**
* Generate ChromaDB collection name for tenant
*/
function getTenantChromaCollection(tenantDomain) {
// ChromaDB collection names must be alphanumeric with underscores
return `gt2_${tenantDomain.replace(/-/g, '_')}_documents`;
}
/**
* Generate Redis key prefix for tenant
*/
function getTenantRedisPrefix(tenantDomain) {
return `gt2:${tenantDomain}:`;
}
/**
* Generate MinIO bucket name for tenant
*/
function getTenantMinioBucket(tenantDomain) {
// MinIO bucket names must be lowercase and DNS-compliant
return `gt2-${tenantDomain}-files`;
}
/**
* Generate SQLite WAL mode configuration
*/
function getSQLiteWALConfig() {
return `
PRAGMA journal_mode=WAL;
PRAGMA synchronous=NORMAL;
PRAGMA cache_size=1000;
PRAGMA foreign_keys=ON;
PRAGMA temp_store=MEMORY;
`;
}
/**
* Generate SQLite encryption configuration
*/
function getSQLiteEncryptionConfig(encryptionKey) {
return `PRAGMA key='${encryptionKey}';`;
}
/**
* Create tenant database schema (SQLite)
*/
function getTenantDatabaseSchema() {
return `
-- Enable foreign key constraints
PRAGMA foreign_keys = ON;
-- Conversations for AI chat
CREATE TABLE IF NOT EXISTS conversations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
model_id TEXT NOT NULL,
system_prompt TEXT,
created_by TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Messages with full context tracking
CREATE TABLE IF NOT EXISTS messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
conversation_id INTEGER NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
role TEXT NOT NULL CHECK (role IN ('user', 'assistant', 'system')),
content TEXT NOT NULL,
model_used TEXT,
tokens_used INTEGER DEFAULT 0,
context_sources TEXT DEFAULT '[]', -- JSON array of document chunk IDs
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Documents with processing status
CREATE TABLE IF NOT EXISTS documents (
id INTEGER PRIMARY KEY AUTOINCREMENT,
filename TEXT NOT NULL,
file_type TEXT NOT NULL,
file_size INTEGER DEFAULT 0,
processing_status TEXT DEFAULT 'pending' CHECK (processing_status IN ('pending', 'processing', 'completed', 'failed')),
chunk_count INTEGER DEFAULT 0,
uploaded_by TEXT NOT NULL,
storage_path TEXT,
error_message TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Document chunks for RAG
CREATE TABLE IF NOT EXISTS document_chunks (
id TEXT PRIMARY KEY, -- UUID
document_id INTEGER NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
chunk_index INTEGER NOT NULL,
content TEXT NOT NULL,
metadata TEXT DEFAULT '{}', -- JSON metadata
embedding_id TEXT, -- Reference to ChromaDB embedding
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- User sessions and preferences
CREATE TABLE IF NOT EXISTS user_sessions (
id TEXT PRIMARY KEY, -- Session token
user_email TEXT NOT NULL,
expires_at DATETIME NOT NULL,
data TEXT DEFAULT '{}', -- JSON session data
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- User preferences
CREATE TABLE IF NOT EXISTS user_preferences (
user_email TEXT PRIMARY KEY,
preferences TEXT DEFAULT '{}', -- JSON preferences
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Usage tracking for tenant
CREATE TABLE IF NOT EXISTS usage_logs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_email TEXT NOT NULL,
action_type TEXT NOT NULL, -- 'chat', 'document_upload', 'document_query'
resource_used TEXT, -- Model name or resource identifier
tokens_used INTEGER DEFAULT 0,
success BOOLEAN DEFAULT TRUE,
metadata TEXT DEFAULT '{}', -- JSON metadata
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Indexes for performance
CREATE INDEX IF NOT EXISTS idx_conversations_created_by ON conversations(created_by);
CREATE INDEX IF NOT EXISTS idx_conversations_updated_at ON conversations(updated_at);
CREATE INDEX IF NOT EXISTS idx_messages_conversation_id ON messages(conversation_id);
CREATE INDEX IF NOT EXISTS idx_messages_created_at ON messages(created_at);
CREATE INDEX IF NOT EXISTS idx_documents_uploaded_by ON documents(uploaded_by);
CREATE INDEX IF NOT EXISTS idx_documents_status ON documents(processing_status);
CREATE INDEX IF NOT EXISTS idx_document_chunks_document_id ON document_chunks(document_id);
CREATE INDEX IF NOT EXISTS idx_usage_logs_user_email ON usage_logs(user_email);
CREATE INDEX IF NOT EXISTS idx_usage_logs_created_at ON usage_logs(created_at);
CREATE INDEX IF NOT EXISTS idx_user_sessions_expires_at ON user_sessions(expires_at);
-- Triggers for updated_at columns
CREATE TRIGGER IF NOT EXISTS update_conversations_updated_at
AFTER UPDATE ON conversations
BEGIN
UPDATE conversations SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
END;
CREATE TRIGGER IF NOT EXISTS update_documents_updated_at
AFTER UPDATE ON documents
BEGIN
UPDATE documents SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
END;
CREATE TRIGGER IF NOT EXISTS update_user_preferences_updated_at
AFTER UPDATE ON user_preferences
BEGIN
UPDATE user_preferences SET updated_at = CURRENT_TIMESTAMP WHERE user_email = NEW.user_email;
END;
`;
}
/**
* Generate unique document chunk ID
*/
function generateDocumentChunkId(documentId, chunkIndex) {
const data = `${documentId}-${chunkIndex}-${Date.now()}`;
return crypto_1.default.createHash('sha256').update(data).digest('hex').substring(0, 32);
}
/**
* Parse connection string for database configuration
*/
function parseConnectionString(connectionString) {
const url = new URL(connectionString);
return {
host: url.hostname,
port: url.port ? parseInt(url.port) : undefined,
database: url.pathname.substring(1), // Remove leading slash
username: url.username,
password: url.password,
options: Object.fromEntries(url.searchParams.entries())
};
}
/**
* Escape SQL identifiers (table names, column names, etc.)
*/
function escapeSQLIdentifier(identifier) {
return `"${identifier.replace(/"/g, '""')}"`;
}
/**
* Generate database backup filename
*/
function generateBackupFilename(tenantDomain, timestamp) {
const date = timestamp || new Date();
const dateString = date.toISOString().split('T')[0]; // YYYY-MM-DD
const timeString = date.toTimeString().split(' ')[0].replace(/:/g, '-'); // HH-MM-SS
return `gt2-${tenantDomain}-backup-${dateString}-${timeString}.db`;
}