Js
Js
[Link]();
const groq = new Groq({ apiKey: [Link].GROQ_API_KEY });
// ----------------------------
// Initialize Backblaze B2 & Multer
// ----------------------------
const b2 = new B2({
applicationKeyId: [Link].B2_APPLICATION_KEY_ID,
applicationKey: [Link].B2_APPLICATION_KEY
});
const upload = multer({ storage: [Link]() });
// ----------------------------
// Serve Static Files & Fallback Route
// ----------------------------
[Link]([Link]([Link](__dirname, 'public')));
[Link]("/", (req, res) => {
[Link]([Link](__dirname, 'public', '[Link]'));
});
// ----------------------------
// File Upload Endpoint (Backblaze B2)
// ----------------------------
[Link]('/upload', [Link]('file'), async (req, res) => {
if (![Link]) {
return [Link](400).json({ error: 'No file uploaded.' });
}
try {
await [Link]();
const { data: { uploadUrl, authorizationToken } } = await [Link]({
bucketId: [Link].B2_BUCKET_ID
});
const fileBuffer = [Link];
const fileName = [Link];
await [Link]({
uploadUrl,
uploadAuthToken: authorizationToken,
fileName,
data: fileBuffer,
contentType: [Link]
});
const publicUrl = `${[Link].B2_BUCKET_URL}/${fileName}`;
[Link]({ url: publicUrl });
} catch (err) {
[Link]('Error uploading file:', err);
[Link](500).json({ error: 'Error uploading the file.' });
}
});
// ----------------------------
// Transcription Endpoint (Groq API)
// ----------------------------
[Link]("/transcribe", [Link]('audio'), async (req, res) => {
try {
let audioBuffer;
let filename;
if ([Link]) {
audioBuffer = [Link];
filename = [Link];
const MAX_FILE_SIZE = 25 * 1024 * 1024;
if ([Link] > MAX_FILE_SIZE) {
return [Link](400).json({ error: "File size exceeds 25MB limit." });
}
const supportedTypes = [
'audio/flac', 'audio/mp3', 'audio/mp4', 'audio/mpeg',
'audio/mpga', 'audio/m4a', 'audio/ogg', 'audio/wav', 'audio/webm'
];
if () {
return [Link](400).json({
error: "Unsupported file type. Supported types: flac, mp3, mp4, mpeg,
mpga, m4a, ogg, wav, webm"
});
}
} else if ([Link] && [Link]) {
const audioUrl = [Link];
[Link]("Fetching audio from URL:", audioUrl);
const response = await fetch(audioUrl);
if (![Link]) {
return [Link](400).json({ error: `Failed to fetch audio from URL.
Status: ${[Link]}` });
}
const contentType = [Link]('content-type');
if (contentType) [Link]("Fetched content-type:", contentType);
audioBuffer = [Link](await [Link]());
filename = [Link](audioUrl) || `audio_${[Link]()}.mp3`;
const MAX_FILE_SIZE = 25 * 1024 * 1024;
if ([Link] > MAX_FILE_SIZE) {
return [Link](400).json({ error: "File size exceeds 25MB limit." });
}
} else {
return [Link](400).json({ error: "No audio provided. Please upload a
file or provide a URL." });
}
if (!audioBuffer) {
return [Link](400).json({ error: "Failed to process audio." });
}
[Link](tempPath);
[Link](`Temporary file deleted: ${tempPath}`);
// ----------------------------
// Session Middleware
// ----------------------------
[Link](session({
secret: [Link].SESSION_SECRET || 'your-secret-key',
resave: false,
saveUninitialized: true,
cookie: {
secure: [Link].NODE_ENV === 'production',
maxAge: 24 * 60 * 60 * 1000
}
}));
// ----------------------------
// Initialize PostgreSQL Personal Database Pool
// ----------------------------
const personalPool = new Pool({
connectionString: [Link].DATABASE_PUBLIC_URL || [Link].DATABASE_URL,
ssl: [Link].NODE_ENV === 'production' ? { rejectUnauthorized: false } :
false,
});
// ----------------------------
// Initialize MongoDB (General Database) with Mongoose
// ----------------------------
const dbName = "openchat";
const generalDbURI = [Link].GENERAL_MONGO_URI ||
`mongodb+srv://londonjeremie:Narnia2010@[Link]/${dbName}?ret
ryWrites=true&w=majority`;
[Link](generalDbURI)
.then(() => {
[Link](`✅ Connected to MongoDB general database: "${dbName}" created
successfully!`);
})
.catch((error) => [Link]('❌ Connection error to MongoDB general
database:', error));
// ----------------------------
// Create or Update Tables in Personal Database
// ----------------------------
[Link](`
DO $$
BEGIN
-- Create users table if it doesn't exist
IF NOT EXISTS (
SELECT 1 FROM information_schema.tables
WHERE table_schema='public' AND table_name='users'
) THEN
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username TEXT UNIQUE NOT NULL,
password TEXT,
online BOOLEAN DEFAULT FALSE,
push_subscription TEXT,
public_key TEXT,
private_key TEXT,
symmetric_key TEXT
);
ELSE
-- Add symmetric_key column if it doesn't exist
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema='public' AND table_name='users' AND
column_name='symmetric_key'
) THEN
ALTER TABLE users ADD COLUMN symmetric_key TEXT;
END IF;
END IF;
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_name='users' AND column_name='private_key'
) THEN
ALTER TABLE users ADD COLUMN private_key TEXT;
END IF;
END $$;
`, (err) => {
if (err) {
[Link]('Error setting up database schema:', err);
} else {
[Link]('Database schema setup successfully.');
}
});
// ----------------------------
// Helper Functions for Authenticator and Registration
// ----------------------------
function generateAuthenticator() {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
let result = '';
for (let i = 0; i < 8; i++) {
result += [Link]([Link]([Link]() * [Link]));
}
return result;
}
try {
// Double-check if username already exists
const existingUser = await [Link]({ username }).exec();
if (existingUser) {
throw new Error(`Username '${username}' already exists in general
database`);
}
await [Link]();
return authentificator;
} catch (err) {
[Link](`Error registering user '${username}' in general database:`,
err);
return [Link](
{
key: privateKey,
padding: [Link].RSA_PKCS1_OAEP_PADDING
},
[Link](encryptedMessage, 'base64')
).toString();
} catch (err) {
[Link]('RSA decryption error:', err);
return encryptedMessage;
}
}
// ----------------------------
// New Endpoint to Link External Databases (Bidirectional Insertion)
// ----------------------------
// When a user (e.g. Alice) submits another user's authenticator (e.g. Bob's),
// - Step 1: Insert a record into the central external_databases for the
current user (Alice)
// using her own username as owner and storing Bob's authenticator
and Bob's database URL.
// - Step 2: Retrieve Alice's general record.
// - Step 3: Connect to Bob's external database (using Bob's database URL) and
insert a record
// so that Bob's external database now has a reciprocal record for
Alice.
// ----------------------------
// New Endpoint to Link External Databases (Bidirectional Insertion)
// ----------------------------
[Link]('/link-database', async (req, res) => {
// The linking user (e.g. Alice) sends in her own username and the
authenticator of the target user (e.g. Bob)
const { externalAuthenticator, username } = [Link];
// currentUser is the linking user (Alice)
const currentUser = [Link] || username;
if (!externalAuthenticator || !currentUser) {
return [Link](400).json({ error: 'Authenticator and username are
required.' });
}
try {
// 0. First, check if the authenticator belongs to the current user to
prevent self-linking
const currentUserRecord = await [Link]({ username: currentUser
}).exec();
if (!currentUserRecord) {
return [Link](404).json({ error: 'Current user not found in general
database.' });
}
if ([Link] > 0) {
return [Link](400).json({ error: 'Databases are already linked.' });
}
if ([Link] === 0 ||
![Link][0].public_key) {
return [Link](400).json({ error: 'Current user public key not found.'
});
}
try {
targetExtPool = new Pool({
connectionString: targetUser.database_url,
ssl: [Link].NODE_ENV === 'production' ? { rejectUnauthorized: false
} : false,
});
// 4. Insert into Alice's external_databases table a record for Bob with his
public key
try {
await [Link](
'INSERT INTO external_databases (username, authentificator,
database_url, public_key) VALUES ($1, $2, $3, $4) ON CONFLICT DO NOTHING',
[[Link], externalAuthenticator, targetUser.database_url,
targetUserPublicKey]
);
} catch (err) {
[Link]('Error inserting external database record:', err);
return [Link](500).json({ error: 'Error inserting external database
record.' });
}
[Link]({
message: 'External database linked successfully.',
linkedUser: [Link]
});
} catch (err) {
[Link]('Error connecting to or inserting into target database:',
err);
return [Link](500).json({
error: 'Error connecting to target database. Please verify the
authenticator is correct.'
});
} finally {
if (targetExtPool) {
[Link]();
}
}
} catch (err) {
[Link]('Error linking database:', err);
[Link](500).json({ error: 'Internal server error: ' + [Link] });
}
});
// ----------------------------
// Helper Function: Save Message to an External Database
// ----------------------------
async function saveMessageExternal(database_url, sender, receiver, msg,
fileData) {
const extPool = new Pool({
connectionString: database_url,
ssl: [Link].NODE_ENV === 'production' ? { rejectUnauthorized: false } :
false,
});
try {
if (fileData) {
const query = `
INSERT INTO messages (sender, receiver, message, file_url, file_name,
file_type, file_size)
VALUES ($1, $2, $3, $4, $5, $6, $7)
`;
const placeholderMessage = 'File attachment';
await [Link](query, [sender, receiver, placeholderMessage,
[Link], [Link], [Link], [Link]]);
} else {
await [Link]('INSERT INTO messages (sender, receiver, message)
VALUES ($1, $2, $3)', [sender, receiver, msg]);
}
} catch (err) {
[Link]('Error inserting message into external DB:', err);
} finally {
[Link]();
}
}
// ----------------------------
// Track Users and Their Socket Connections
// ----------------------------
const users = {}; // { username: { socketId, online, pushSubscription } }
// ----------------------------
// Web Push Configuration
// ----------------------------
[Link](
'[Link]
[Link].VAPID_PUBLIC_KEY,
[Link].VAPID_PRIVATE_KEY
);
// ----------------------------
// Create HTTP Server and Attach [Link]
// ----------------------------
const server = createServer(app);
const io = new Server(server);
// ----------------------------
// Load Combined Users for a Socket (Local + External)
// ----------------------------
async function loadCombinedUsers(socket) {
const currentUser = [Link];
try {
const localResult = await [Link](
'SELECT username, online FROM users WHERE username <> $1',
[currentUser]
);
let allUsers = [Link];
const externalLinksResult = await [Link](
'SELECT * FROM external_databases WHERE username = $1',
[currentUser]
);
for (const link of [Link]) {
const externalPool = new Pool({
connectionString: link.database_url,
ssl: [Link].NODE_ENV === 'production' ? { rejectUnauthorized: false
} : false,
});
const externalUsersResult = await [Link](
'SELECT username, online FROM users WHERE username <> $1',
[currentUser]
);
allUsers = [Link]([Link]);
[Link]();
}
const uniqueUsers = {};
[Link](u => { uniqueUsers[[Link]] = u; });
const userList = [Link](uniqueUsers);
[Link]('users', userList);
[Link](`Users list for ${currentUser} updated:`, userList);
} catch (err) {
[Link](`Error fetching users list for ${currentUser}:`, err);
}
}
// ----------------------------
// [Link] Events
// ----------------------------
[Link]('connection', (socket) => {
[Link]('A user connected');
if (existingGeneralUser) {
[Link](`Username '${username}' already exists in general
database.`);
return [Link]('signup failed', 'Username already exists in our
system.');
}
if ([Link] > 0) {
[Link](`Username '${username}' already exists in personal
database.`);
return [Link]('signup failed', 'Username already exists in local
database.');
}
} catch (err) {
[Link]('Error during signup:', err);
[Link]('signup failed', 'Registration failed. Please try again
later.');
}
});
try {
// Get recipient's public key for E2E encryption
let recipientPublicKey = null;
const userQuery = await [Link](
'SELECT public_key FROM users WHERE username = $1',
[to]
);
// Cross-database messaging
const recipientExternalResult = await [Link](
'SELECT * FROM external_databases WHERE username = $1',
[to]
);
if ([Link] > 0) {
const recipientDB = [Link][0];
saveMessageToExternalDB(
recipientDB.database_url,
[Link],
to,
recipientEncryptedMsg,
null,
true // E2E encrypted
);
}
} catch (err) {
[Link]('Error in chat message:', err);
}
});
try {
// Get recipient's public key for encryption
let recipientPublicKey = null;
const userQuery = await [Link](
'SELECT public_key FROM users WHERE username = $1',
[to]
);
if ([Link] > 0) {
const recipientDB = [Link][0];
saveMessageToExternalDB(
recipientDB.database_url,
[Link],
to,
null,
{
fileUrl: recipientEncryptedUrl,
name: recipientEncryptedName,
type: recipientEncryptedType,
size
},
true
);
}
} catch (err) {
[Link]('Error in file message:', err);
}
});
[Link]('load messages', ({ user }) => {
if ([Link] && user) {
loadPrivateMessageHistory([Link], user, (messages) => {
[Link]('chat history', messages);
});
} else {
[Link]('chat history', []);
}
});
[Link]('disconnect', () => {
if ([Link]) {
[Link]('UPDATE users SET online = FALSE WHERE username = $1',
[[Link]], (err) => {
if (err) [Link]('Error marking user offline:', err);
if (users[[Link]]) {
users[[Link]].online = false;
}
for (const [id, sock] of [Link]("/").sockets) {
if ([Link]) {
loadCombinedUsers(sock);
}
}
});
}
[Link]('A user disconnected');
});
// ----------------------------
// Helper Functions (Outside [Link])
// ----------------------------
async function loginUser(socket, username) {
await [Link]('UPDATE users SET online = TRUE WHERE username = $1',
[username]);
users[username] = { socketId: [Link], online: true };
[Link] = username;
if ([Link] > 0) {
const user = [Link][0];
if (!user.public_key || !user.private_key) {
[Link](`User ${username} is missing RSA keys. Generating...`);
const { publicKey, privateKey } = generateKeyPair();
await [Link](
'UPDATE users SET public_key = $1, private_key = $2 WHERE username =
$3',
[publicKey, privateKey, username]
);
}
if (!user.symmetric_key) {
[Link](`User ${username} is missing symmetric key. Generating...`);
const symmetricKey = generateSymmetricKey();
await [Link](
'UPDATE users SET symmetric_key = $1 WHERE username = $2',
[symmetricKey, username]
);
}
}
} catch (error) {
[Link]('Error checking/generating keys for', username, error);
}
let authentificator = 'Not set';
try {
const generalUser = await [Link]({ username }).exec();
if (generalUser && [Link]) {
authentificator = [Link];
}
} catch (error) {
[Link]('Error retrieving authentificator for', username, error);
}
loadCombinedUsers(socket);
if (shouldDecrypt) {
try {
if (isSentByMe && symmetricKey) {
// Decrypt self-messages with symmetric key
if (!isFileMessage && [Link]) {
finalMessage = decryptWithSymmetricKey(symmetricKey,
[Link]);
}
if (isFileMessage) {
if (row.file_url) finalFileUrl =
decryptWithSymmetricKey(symmetricKey, row.file_url);
if (row.file_name) finalFileName =
decryptWithSymmetricKey(symmetricKey, row.file_name);
if (row.file_type) finalFileType =
decryptWithSymmetricKey(symmetricKey, row.file_type);
}
} else if (!isSentByMe && privateKey) {
// Decrypt messages from others with private key (E2E)
if (!isFileMessage && [Link]) {
finalMessage = decryptWithPrivateKey(privateKey,
[Link]);
}
if (isFileMessage) {
if (row.file_url) finalFileUrl =
decryptWithPrivateKey(privateKey, row.file_url);
if (row.file_name) finalFileName =
decryptWithPrivateKey(privateKey, row.file_name);
if (row.file_type) finalFileType =
decryptWithPrivateKey(privateKey, row.file_type);
}
}
} catch (decryptError) {
[Link]('Error decrypting message content:',
decryptError);
// Keep the original values if decryption fails
}
}
callback(messages);
});
});
}
);
callback(messages);
});
}
}
function formatDate(date) {
const options = { year: '2-digit', month: '2-digit', day: '2-digit' };
return new Date(date).toLocaleDateString('en-GB', options);
}
function formatTime(date) {
const d = new Date(date);
return `${[Link]().toString().padStart(2,
'0')}:${[Link]().toString().padStart(2, '0')}`;
}
function formatDayLabel(date) {
const today = new Date();
const messageDate = new Date(date);
const todayString = [Link]();
const yesterday = new Date();
[Link]([Link]() - 1);
const yesterdayString = [Link]();
if (todayString === [Link]()) {
return "Today";
} else if (yesterdayString === [Link]()) {
return "Yesterday";
} else {
return formatDate(messageDate);
}
}
function generateMessageId() {
return `${[Link]()}${[Link]().toString(36).substring(2, 9)}`;
}
try {
// First check if schema is compatible with our current code
const schemaCheck = await [Link](`
SELECT EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_name = 'messages'
AND column_name = 'is_encrypted'
) as has_is_encrypted
`);
if (fileData) {
// Construct the query based on schema compatibility
const query = hasIsEncrypted ?
`INSERT INTO messages (sender, receiver, message, file_url, file_name,
file_type, file_size, is_encrypted)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)` :
`INSERT INTO messages (sender, receiver, message, file_url, file_name,
file_type, file_size)
VALUES ($1, $2, $3, $4, $5, $6, $7)`;
// ----------------------------
// Start the Server
// ----------------------------
[Link](port, () => {
[Link](`Server running on [Link]
});