courrier multi account restore compose
This commit is contained in:
parent
3e6953a4a4
commit
6b37f0062d
152
lib/redis.ts
152
lib/redis.ts
@ -101,6 +101,7 @@ interface EmailCredentials {
|
||||
smtp_secure?: boolean;
|
||||
display_name?: string;
|
||||
color?: string;
|
||||
id?: string; // Add ID field to identify accounts
|
||||
}
|
||||
|
||||
interface ImapSessionData {
|
||||
@ -115,52 +116,67 @@ interface ImapSessionData {
|
||||
*/
|
||||
export async function cacheEmailCredentials(
|
||||
userId: string,
|
||||
credentials: EmailCredentials
|
||||
credentials: EmailCredentials | EmailCredentials[]
|
||||
): Promise<void> {
|
||||
const redis = getRedisClient();
|
||||
const key = KEYS.CREDENTIALS(userId);
|
||||
|
||||
// Validate credentials before caching
|
||||
if (!credentials.email || !credentials.host || !credentials.password) {
|
||||
console.error(`Cannot cache incomplete credentials for user ${userId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log(`Caching credentials for user ${userId}`);
|
||||
|
||||
// Create a copy without the password to store
|
||||
const secureCredentials: EmailCredentials = {
|
||||
email: credentials.email,
|
||||
host: credentials.host,
|
||||
port: credentials.port,
|
||||
secure: credentials.secure ?? true,
|
||||
// Include the extended fields
|
||||
...(credentials.smtp_host && { smtp_host: credentials.smtp_host }),
|
||||
...(credentials.smtp_port && { smtp_port: credentials.smtp_port }),
|
||||
...(credentials.smtp_secure !== undefined && { smtp_secure: credentials.smtp_secure }),
|
||||
...(credentials.display_name && { display_name: credentials.display_name }),
|
||||
...(credentials.color && { color: credentials.color })
|
||||
};
|
||||
// Handle both single account and array of accounts
|
||||
const accountsToCache = Array.isArray(credentials) ? credentials : [credentials];
|
||||
|
||||
// Encrypt password
|
||||
if (credentials.password) {
|
||||
try {
|
||||
const encrypted = encryptData(credentials.password);
|
||||
console.log(`Successfully encrypted password for user ${userId}`);
|
||||
secureCredentials.encryptedPassword = encrypted;
|
||||
} catch (encryptError) {
|
||||
console.error(`Failed to encrypt password for user ${userId}:`, encryptError);
|
||||
// Don't proceed with caching if encryption fails
|
||||
return;
|
||||
const secureAccounts = await Promise.all(accountsToCache.map(async (account) => {
|
||||
// Validate credentials before caching
|
||||
if (!account.email || !account.host || !account.password) {
|
||||
console.error(`Cannot cache incomplete credentials for account ${account.email}`);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
console.warn(`No password provided for user ${userId}, skipping credential caching`);
|
||||
|
||||
// Create a copy without the password to store
|
||||
const secureCredentials: EmailCredentials = {
|
||||
id: account.id,
|
||||
email: account.email,
|
||||
host: account.host,
|
||||
port: account.port,
|
||||
secure: account.secure ?? true,
|
||||
// Include the extended fields
|
||||
...(account.smtp_host && { smtp_host: account.smtp_host }),
|
||||
...(account.smtp_port && { smtp_port: account.smtp_port }),
|
||||
...(account.smtp_secure !== undefined && { smtp_secure: account.smtp_secure }),
|
||||
...(account.display_name && { display_name: account.display_name }),
|
||||
...(account.color && { color: account.color })
|
||||
};
|
||||
|
||||
// Encrypt password
|
||||
if (account.password) {
|
||||
try {
|
||||
const encrypted = encryptData(account.password);
|
||||
console.log(`Successfully encrypted password for account ${account.email}`);
|
||||
secureCredentials.encryptedPassword = encrypted;
|
||||
} catch (encryptError) {
|
||||
console.error(`Failed to encrypt password for account ${account.email}:`, encryptError);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
console.warn(`No password provided for account ${account.email}, skipping credential caching`);
|
||||
return null;
|
||||
}
|
||||
|
||||
return secureCredentials;
|
||||
}));
|
||||
|
||||
// Filter out any null values from failed encryption
|
||||
const validAccounts = secureAccounts.filter(acc => acc !== null);
|
||||
|
||||
if (validAccounts.length === 0) {
|
||||
console.warn(`No valid accounts to cache for user ${userId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
await redis.set(key, JSON.stringify(secureCredentials), 'EX', TTL.CREDENTIALS);
|
||||
console.log(`Credentials cached for user ${userId}`);
|
||||
await redis.set(key, JSON.stringify(validAccounts), 'EX', TTL.CREDENTIALS);
|
||||
console.log(`Cached ${validAccounts.length} accounts for user ${userId}`);
|
||||
} catch (error) {
|
||||
console.error(`Error caching credentials for user ${userId}:`, error);
|
||||
}
|
||||
@ -169,7 +185,7 @@ export async function cacheEmailCredentials(
|
||||
/**
|
||||
* Get email credentials from Redis
|
||||
*/
|
||||
export async function getEmailCredentials(userId: string): Promise<EmailCredentials | null> {
|
||||
export async function getEmailCredentials(userId: string): Promise<EmailCredentials[] | null> {
|
||||
const redis = getRedisClient();
|
||||
const key = KEYS.CREDENTIALS(userId);
|
||||
|
||||
@ -180,37 +196,47 @@ export async function getEmailCredentials(userId: string): Promise<EmailCredenti
|
||||
return null;
|
||||
}
|
||||
|
||||
const creds = JSON.parse(credStr) as EmailCredentials;
|
||||
const creds = JSON.parse(credStr) as EmailCredentials[];
|
||||
|
||||
if (!creds.encryptedPassword) {
|
||||
console.warn(`No encrypted password found for user ${userId}`);
|
||||
return null;
|
||||
}
|
||||
// Handle both single account (backward compatibility) and array of accounts
|
||||
const accounts = Array.isArray(creds) ? creds : [creds];
|
||||
|
||||
try {
|
||||
// Decrypt the password
|
||||
const password = decryptData(creds.encryptedPassword);
|
||||
const decryptedAccounts = await Promise.all(accounts.map(async (account) => {
|
||||
if (!account.encryptedPassword) {
|
||||
console.warn(`No encrypted password found for account ${account.email}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Return the full credentials with decrypted password
|
||||
return {
|
||||
email: creds.email,
|
||||
password,
|
||||
host: creds.host,
|
||||
port: creds.port,
|
||||
secure: creds.secure ?? true,
|
||||
// Include the extended fields if they exist in the cache
|
||||
...(creds.smtp_host && { smtp_host: creds.smtp_host }),
|
||||
...(creds.smtp_port && { smtp_port: creds.smtp_port }),
|
||||
...(creds.smtp_secure !== undefined && { smtp_secure: creds.smtp_secure }),
|
||||
...(creds.display_name && { display_name: creds.display_name }),
|
||||
...(creds.color && { color: creds.color })
|
||||
};
|
||||
} catch (decryptError) {
|
||||
console.error(`Failed to decrypt password for user ${userId}:`, decryptError);
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
// Decrypt the password
|
||||
const password = decryptData(account.encryptedPassword);
|
||||
|
||||
// Return the full credentials with decrypted password
|
||||
return {
|
||||
id: account.id,
|
||||
email: account.email,
|
||||
password,
|
||||
host: account.host,
|
||||
port: account.port,
|
||||
secure: account.secure ?? true,
|
||||
smtp_host: account.smtp_host,
|
||||
smtp_port: account.smtp_port,
|
||||
smtp_secure: account.smtp_secure,
|
||||
display_name: account.display_name,
|
||||
color: account.color
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`Failed to decrypt password for account ${account.email}:`, error);
|
||||
return null;
|
||||
}
|
||||
}));
|
||||
|
||||
// Filter out any null values from failed decryption
|
||||
const validAccounts = decryptedAccounts.filter(acc => acc !== null);
|
||||
|
||||
return validAccounts.length > 0 ? validAccounts : null;
|
||||
} catch (error) {
|
||||
console.error(`Error retrieving credentials for user ${userId}:`, error);
|
||||
console.error(`Error getting credentials for user ${userId}:`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -417,6 +443,6 @@ export async function invalidateUserEmailCache(
|
||||
*/
|
||||
export async function getCachedEmailCredentials(
|
||||
userId: string
|
||||
): Promise<EmailCredentials | null> {
|
||||
): Promise<EmailCredentials[] | null> {
|
||||
return getEmailCredentials(userId);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user