Initial LeakHub Release - AI System Prompt Discovery Platform

This commit is contained in:
EP
2025-08-21 19:14:40 -07:00
commit 60bf06caa7
20 changed files with 8395 additions and 0 deletions
+102
View File
@@ -0,0 +1,102 @@
// LeakHub Backend Configuration
const config = {
// Database settings
database: {
// Local storage (default)
type: 'localStorage',
// Backend options (uncomment to enable)
// type: 'mongodb',
// url: process.env.MONGODB_URI || 'mongodb://localhost:27017/leakhub',
// type: 'supabase',
// url: process.env.SUPABASE_URL,
// key: process.env.SUPABASE_ANON_KEY,
// type: 'firebase',
// config: {
// apiKey: process.env.FIREBASE_API_KEY,
// authDomain: process.env.FIREBASE_AUTH_DOMAIN,
// projectId: process.env.FIREBASE_PROJECT_ID,
// storageBucket: process.env.FIREBASE_STORAGE_BUCKET,
// messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID,
// appId: process.env.FIREBASE_APP_ID
// }
},
// API settings
api: {
port: process.env.PORT || 3000,
cors: {
origin: process.env.ALLOWED_ORIGINS?.split(',') || ['*'],
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization']
},
rateLimit: {
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
}
},
// Security settings
security: {
jwtSecret: process.env.JWT_SECRET || 'your-secret-key-change-this',
bcryptRounds: 12,
sessionTimeout: 24 * 60 * 60 * 1000 // 24 hours
},
// Analytics settings
analytics: {
enabled: process.env.ANALYTICS_ENABLED === 'true',
googleAnalyticsId: process.env.GOOGLE_ANALYTICS_ID,
mixpanelToken: process.env.MIXPANEL_TOKEN
},
// Email settings (for notifications)
email: {
enabled: process.env.EMAIL_ENABLED === 'true',
provider: process.env.EMAIL_PROVIDER || 'smtp',
smtp: {
host: process.env.SMTP_HOST,
port: process.env.SMTP_PORT || 587,
secure: process.env.SMTP_SECURE === 'true',
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS
}
}
},
// Feature flags
features: {
userRegistration: true,
emailVerification: false,
socialLogin: false,
realTimeUpdates: false,
advancedAnalytics: false,
exportData: true,
backupRestore: true
},
// Development settings
development: {
debug: process.env.NODE_ENV !== 'production',
mockData: process.env.MOCK_DATA === 'true',
hotReload: process.env.NODE_ENV === 'development'
}
};
// Environment-specific overrides
if (process.env.NODE_ENV === 'production') {
config.development.debug = false;
config.development.mockData = false;
config.development.hotReload = false;
}
if (process.env.NODE_ENV === 'test') {
config.database.type = 'memory';
config.security.jwtSecret = 'test-secret';
}
module.exports = config;
+274
View File
@@ -0,0 +1,274 @@
// Database abstraction layer for LeakHub
// Supports both localStorage and future backend APIs
class LeakHubDatabase {
constructor() {
this.storagePrefix = 'leakhub_';
this.apiEndpoint = null; // Will be set for backend mode
this.isBackendMode = false;
}
// Initialize database with optional backend endpoint
async init(backendUrl = null) {
if (backendUrl) {
this.apiEndpoint = backendUrl;
this.isBackendMode = true;
console.log('LeakHub: Backend mode enabled');
} else {
console.log('LeakHub: Local storage mode enabled');
}
}
// Generic storage methods
async get(key) {
if (this.isBackendMode) {
return await this._getFromBackend(key);
} else {
return this._getFromLocalStorage(key);
}
}
async set(key, value) {
if (this.isBackendMode) {
return await this._setToBackend(key, value);
} else {
return this._setToLocalStorage(key, value);
}
}
async delete(key) {
if (this.isBackendMode) {
return await this._deleteFromBackend(key);
} else {
return this._deleteFromLocalStorage(key);
}
}
// LocalStorage methods
_getFromLocalStorage(key) {
try {
const fullKey = this.storagePrefix + key;
const data = localStorage.getItem(fullKey);
return data ? JSON.parse(data) : null;
} catch (error) {
console.error('Error reading from localStorage:', error);
return null;
}
}
_setToLocalStorage(key, value) {
try {
const fullKey = this.storagePrefix + key;
localStorage.setItem(fullKey, JSON.stringify(value));
return true;
} catch (error) {
console.error('Error writing to localStorage:', error);
return false;
}
}
_deleteFromLocalStorage(key) {
try {
const fullKey = this.storagePrefix + key;
localStorage.removeItem(fullKey);
return true;
} catch (error) {
console.error('Error deleting from localStorage:', error);
return false;
}
}
// Backend API methods
async _getFromBackend(key) {
try {
const response = await fetch(`${this.apiEndpoint}/data/${key}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
}
});
if (response.ok) {
return await response.json();
} else {
console.error('Backend GET error:', response.status);
return null;
}
} catch (error) {
console.error('Error fetching from backend:', error);
return null;
}
}
async _setToBackend(key, value) {
try {
const response = await fetch(`${this.apiEndpoint}/data/${key}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(value)
});
return response.ok;
} catch (error) {
console.error('Error saving to backend:', error);
return false;
}
}
async _deleteFromBackend(key) {
try {
const response = await fetch(`${this.apiEndpoint}/data/${key}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
}
});
return response.ok;
} catch (error) {
console.error('Error deleting from backend:', error);
return false;
}
}
// Specific LeakHub data methods
async getLeakDatabase() {
return await this.get('leakDatabase') || [];
}
async setLeakDatabase(data) {
return await this.set('leakDatabase', data);
}
async getUserStats() {
return await this.get('userStats') || {};
}
async setUserStats(data) {
return await this.set('userStats', data);
}
async getLeakRequests() {
return await this.get('leakRequests') || [];
}
async setLeakRequests(data) {
return await this.set('leakRequests', data);
}
async getUserVotes() {
return await this.get('userVotes') || {};
}
async setUserVotes(data) {
return await this.set('userVotes', data);
}
async getDailyChallenge() {
return await this.get('dailyChallenge') || null;
}
async setDailyChallenge(data) {
return await this.set('dailyChallenge', data);
}
async getAverageSimilarity() {
return await this.get('avgSimilarity') || '0';
}
async setAverageSimilarity(value) {
return await this.set('avgSimilarity', value);
}
// Export/Import functionality
async exportData() {
const data = {
leakDatabase: await this.getLeakDatabase(),
userStats: await this.getUserStats(),
leakRequests: await this.getLeakRequests(),
userVotes: await this.getUserVotes(),
dailyChallenge: await this.getDailyChallenge(),
avgSimilarity: await this.getAverageSimilarity(),
exportDate: new Date().toISOString(),
version: '1.0.0'
};
return data;
}
async importData(data) {
try {
if (data.leakDatabase) await this.setLeakDatabase(data.leakDatabase);
if (data.userStats) await this.setUserStats(data.userStats);
if (data.leakRequests) await this.setLeakRequests(data.leakRequests);
if (data.userVotes) await this.setUserVotes(data.userVotes);
if (data.dailyChallenge) await this.setDailyChallenge(data.dailyChallenge);
if (data.avgSimilarity) await this.setAverageSimilarity(data.avgSimilarity);
return true;
} catch (error) {
console.error('Error importing data:', error);
return false;
}
}
// Backup and restore
async createBackup() {
const data = await this.exportData();
const backupKey = `backup_${Date.now()}`;
await this.set(backupKey, data);
return backupKey;
}
async restoreBackup(backupKey) {
const backup = await this.get(backupKey);
if (backup) {
return await this.importData(backup);
}
return false;
}
// Analytics and statistics
async getStatistics() {
const leakDatabase = await this.getLeakDatabase();
const userStats = await this.getUserStats();
return {
totalSubmissions: leakDatabase.length,
uniqueUsers: Object.keys(userStats).length,
totalScore: Object.values(userStats).reduce((sum, stats) => sum + (stats.totalScore || 0), 0),
verifiedLeaks: leakDatabase.filter(sub => sub.confidence >= 90).length,
firstDiscoveries: leakDatabase.filter(sub => sub.isFirstDiscovery).length,
targetTypes: this._countTargetTypes(leakDatabase),
recentActivity: this._getRecentActivity(leakDatabase)
};
}
_countTargetTypes(leakDatabase) {
const counts = {};
leakDatabase.forEach(sub => {
const type = sub.targetType || 'model';
counts[type] = (counts[type] || 0) + 1;
});
return counts;
}
_getRecentActivity(leakDatabase) {
const now = new Date();
const oneWeekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
return leakDatabase.filter(sub =>
new Date(sub.timestamp) > oneWeekAgo
).length;
}
}
// Create global instance
window.LeakHubDB = new LeakHubDatabase();
// Auto-initialize
window.LeakHubDB.init().then(() => {
console.log('LeakHub Database initialized');
});
+83
View File
@@ -0,0 +1,83 @@
// Serverless API endpoints for LeakHub
// This can be deployed to Vercel, Netlify, or other serverless platforms
// Mock database for serverless functions
const mockDatabase = {
leakDatabase: [],
userStats: {},
leakRequests: [],
userVotes: {},
dailyChallenge: null,
avgSimilarity: '0'
};
// CORS headers
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
'Content-Type': 'application/json'
};
// Helper function to get data
function getData(key) {
// In a real implementation, this would connect to a database
// For now, we'll use a simple in-memory store
return mockDatabase[key] || null;
}
// Helper function to set data
function setData(key, value) {
mockDatabase[key] = value;
return true;
}
// API handler for Vercel/Netlify
export default async function handler(req, res) {
// Handle CORS preflight
if (req.method === 'OPTIONS') {
return res.status(200).json({}, { headers: corsHeaders });
}
const { method, url, body } = req;
const path = url.split('/').pop(); // Get the last part of the URL
try {
switch (method) {
case 'GET':
if (path === 'data') {
const key = req.query.key;
const data = getData(key);
return res.status(200).json(data, { headers: corsHeaders });
}
break;
case 'POST':
if (path === 'data') {
const key = req.query.key;
const success = setData(key, body);
return res.status(200).json({ success }, { headers: corsHeaders });
}
break;
case 'DELETE':
if (path === 'data') {
const key = req.query.key;
const success = setData(key, null);
return res.status(200).json({ success }, { headers: corsHeaders });
}
break;
default:
return res.status(405).json({ error: 'Method not allowed' }, { headers: corsHeaders });
}
} catch (error) {
console.error('API Error:', error);
return res.status(500).json({ error: 'Internal server error' }, { headers: corsHeaders });
}
}
// Export for different serverless platforms
if (typeof module !== 'undefined' && module.exports) {
module.exports = handler;
}