Fondation
This commit is contained in:
parent
7c01525bac
commit
0c7dfe861a
1217
AUDIT_COMPLET.md
Normal file
1217
AUDIT_COMPLET.md
Normal file
File diff suppressed because it is too large
Load Diff
@ -46,7 +46,6 @@ export async function POST(request: Request) {
|
||||
|
||||
logger.debug('[NOTIFICATIONS_UPDATE] Count updated', {
|
||||
userIdHash: Buffer.from(session.user.id).toString('base64').slice(0, 12),
|
||||
source,
|
||||
count,
|
||||
itemsCount: items?.length || 0,
|
||||
});
|
||||
|
||||
@ -79,7 +79,7 @@ export async function GET(request: Request) {
|
||||
return NextResponse.json({ error: 'Server configuration error' }, { status: 500 });
|
||||
}
|
||||
|
||||
logger.debug('[ROCKET_CHAT] Using Rocket.Chat base URL', { baseUrl });
|
||||
logger.debug('[ROCKET_CHAT] Using Rocket.Chat base URL');
|
||||
|
||||
// Step 1: Use admin token to authenticate
|
||||
const adminHeaders = {
|
||||
|
||||
@ -186,9 +186,7 @@ async function fetchTwentyTasks(userId?: string): Promise<TwentyTask[]> {
|
||||
}
|
||||
`;
|
||||
|
||||
logger.debug('[TWENTY_CRM_TASKS] Fetching tasks from Twenty CRM', {
|
||||
apiUrl: apiUrl.replace(/\/graphql$/, ''), // Log without /graphql for security
|
||||
});
|
||||
logger.debug('[TWENTY_CRM_TASKS] Fetching tasks from Twenty CRM');
|
||||
|
||||
const response = await fetch(apiUrl, {
|
||||
method: 'POST',
|
||||
|
||||
@ -253,7 +253,9 @@ export async function getImapConnection(
|
||||
|
||||
// If a connection is being established, wait for it
|
||||
if (connection.isConnecting && connection.connectionPromise) {
|
||||
logger.debug('[IMAP] Waiting for existing connection', { connectionKey });
|
||||
logger.debug('[IMAP] Waiting for existing connection', {
|
||||
connectionKeyHash: Buffer.from(connectionKey).toString('base64').slice(0, 12),
|
||||
});
|
||||
try {
|
||||
const client = await connection.connectionPromise;
|
||||
connection.lastUsed = Date.now();
|
||||
@ -278,7 +280,9 @@ export async function getImapConnection(
|
||||
if (connection.client && connection.client.usable) {
|
||||
// Touch the connection to mark it as recently used
|
||||
connection.lastUsed = Date.now();
|
||||
logger.debug('[IMAP] Reusing existing connection', { connectionKey });
|
||||
logger.debug('[IMAP] Reusing existing connection', {
|
||||
connectionKeyHash: Buffer.from(connectionKey).toString('base64').slice(0, 12),
|
||||
});
|
||||
|
||||
// Update session data in Redis
|
||||
await updateSessionData(userId, accountId);
|
||||
@ -376,7 +380,7 @@ export async function getImapConnection(
|
||||
// MICROSOFT FIX: Detect Microsoft accounts by hostname and set OAuth flag
|
||||
if (extendedCreds.host === 'outlook.office365.com') {
|
||||
logger.debug('[IMAP] Microsoft account detected, enabling OAuth', {
|
||||
email: extendedCreds.email,
|
||||
emailHash: Buffer.from(extendedCreds.email || '').toString('base64').slice(0, 12),
|
||||
});
|
||||
extendedCreds.useOAuth = true;
|
||||
|
||||
@ -387,7 +391,7 @@ export async function getImapConnection(
|
||||
const cachedCreds = await getCachedEmailCredentials(userId, accountId);
|
||||
if (cachedCreds && cachedCreds.refreshToken) {
|
||||
logger.debug('[IMAP] Found refresh token in Redis for account', {
|
||||
email: extendedCreds.email,
|
||||
emailHash: Buffer.from(extendedCreds.email || '').toString('base64').slice(0, 12),
|
||||
});
|
||||
extendedCreds.refreshToken = cachedCreds.refreshToken;
|
||||
extendedCreds.accessToken = cachedCreds.accessToken;
|
||||
@ -397,12 +401,12 @@ export async function getImapConnection(
|
||||
await cacheEmailCredentials(userId, accountId, extendedCreds);
|
||||
} else {
|
||||
logger.warn('[IMAP] No refresh token found in Redis cache', {
|
||||
email: extendedCreds.email,
|
||||
emailHash: Buffer.from(extendedCreds.email || '').toString('base64').slice(0, 12),
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error('[IMAP] Error retrieving cached credentials', {
|
||||
email: extendedCreds.email,
|
||||
emailHash: Buffer.from(extendedCreds.email || '').toString('base64').slice(0, 12),
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
});
|
||||
}
|
||||
@ -412,7 +416,7 @@ export async function getImapConnection(
|
||||
// If using OAuth, ensure we have a fresh token
|
||||
if (extendedCreds.useOAuth) {
|
||||
logger.debug('[IMAP] Account configured to use OAuth', {
|
||||
email: extendedCreds.email,
|
||||
emailHash: Buffer.from(extendedCreds.email || '').toString('base64').slice(0, 12),
|
||||
});
|
||||
|
||||
if (!extendedCreds.accessToken) {
|
||||
@ -423,14 +427,14 @@ export async function getImapConnection(
|
||||
|
||||
try {
|
||||
logger.debug('[IMAP] Ensuring fresh token for OAuth account', {
|
||||
email: extendedCreds.email,
|
||||
emailHash: Buffer.from(extendedCreds.email || '').toString('base64').slice(0, 12),
|
||||
});
|
||||
const { accessToken, success } = await ensureFreshToken(userId, extendedCreds.email);
|
||||
|
||||
if (success && accessToken) {
|
||||
extendedCreds.accessToken = accessToken;
|
||||
logger.debug('[IMAP] Successfully refreshed token', {
|
||||
email: extendedCreds.email,
|
||||
emailHash: Buffer.from(extendedCreds.email || '').toString('base64').slice(0, 12),
|
||||
});
|
||||
} else {
|
||||
logger.error('[IMAP] Failed to refresh token', {
|
||||
@ -503,7 +507,7 @@ export async function getImapConnection(
|
||||
|
||||
// Handle connection error
|
||||
logger.error('[IMAP] Failed to create connection', {
|
||||
connectionKey,
|
||||
connectionKeyHash: Buffer.from(connectionKey).toString('base64').slice(0, 12),
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
delete connectionPool[connectionKey];
|
||||
@ -526,7 +530,6 @@ async function createImapConnection(credentials: EmailCredentials, connectionKey
|
||||
|
||||
logger.debug('[IMAP] Creating ImapFlow client with credentials metadata', {
|
||||
emailHash: Buffer.from(extendedCreds.email || '').toString('base64').slice(0, 12),
|
||||
host: extendedCreds.host,
|
||||
port: extendedCreds.port,
|
||||
hasPassword: !!extendedCreds.password,
|
||||
useOAuth: !!extendedCreds.useOAuth,
|
||||
@ -564,16 +567,16 @@ async function createImapConnection(credentials: EmailCredentials, connectionKey
|
||||
} else {
|
||||
// No authentication method available
|
||||
logger.error('[IMAP] No authentication method found for connection', {
|
||||
connectionKey,
|
||||
connectionKeyHash: Buffer.from(connectionKey).toString('base64').slice(0, 12),
|
||||
hasPassword: !!extendedCreds.password,
|
||||
useOAuth: !!extendedCreds.useOAuth,
|
||||
hasAccessToken: !!extendedCreds.accessToken,
|
||||
});
|
||||
throw new Error(`No authentication method available for ${connectionKey} - need either password or OAuth token`);
|
||||
throw new Error('No authentication method available - need either password or OAuth token');
|
||||
}
|
||||
|
||||
logger.debug('[IMAP] Creating ImapFlow client', {
|
||||
connectionKey,
|
||||
connectionKeyHash: Buffer.from(connectionKey).toString('base64').slice(0, 12),
|
||||
authType: extendedCreds.useOAuth ? 'OAuth' : 'Password',
|
||||
});
|
||||
|
||||
@ -592,14 +595,15 @@ async function createImapConnection(credentials: EmailCredentials, connectionKey
|
||||
|
||||
try {
|
||||
logger.debug('[IMAP] Connecting to server', {
|
||||
host: extendedCreds.host,
|
||||
port: extendedCreds.port,
|
||||
});
|
||||
await client.connect();
|
||||
logger.debug('[IMAP] Connected to server', { connectionKey });
|
||||
logger.debug('[IMAP] Connected to server', {
|
||||
connectionKeyHash: Buffer.from(connectionKey).toString('base64').slice(0, 12),
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('[IMAP] Failed to connect to server', {
|
||||
connectionKey,
|
||||
connectionKeyHash: Buffer.from(connectionKey).toString('base64').slice(0, 12),
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
throw error;
|
||||
@ -608,7 +612,7 @@ async function createImapConnection(credentials: EmailCredentials, connectionKey
|
||||
// Add error handler
|
||||
client.on('error', (err) => {
|
||||
logger.error('[IMAP] Connection error', {
|
||||
connectionKey,
|
||||
connectionKeyHash: Buffer.from(connectionKey).toString('base64').slice(0, 12),
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
});
|
||||
// Remove from pool on error
|
||||
|
||||
@ -86,14 +86,12 @@ export class NotificationRegistry {
|
||||
unread: count,
|
||||
};
|
||||
logger.debug('[NOTIFICATION_REGISTRY] Count updated', {
|
||||
source,
|
||||
previousCount: previousSourceCount,
|
||||
newCount: count,
|
||||
});
|
||||
} else {
|
||||
// Count hasn't changed, but refresh the TTL to keep it alive
|
||||
logger.debug('[NOTIFICATION_REGISTRY] Count unchanged, refreshing TTL', {
|
||||
source,
|
||||
count,
|
||||
});
|
||||
}
|
||||
@ -117,7 +115,6 @@ export class NotificationRegistry {
|
||||
|
||||
logger.debug('[NOTIFICATION_REGISTRY] Count updated', {
|
||||
userIdHash: Buffer.from(userId).toString('base64').slice(0, 12),
|
||||
source,
|
||||
count,
|
||||
totalUnread: currentCount.unread,
|
||||
previousCount: previousSourceCount,
|
||||
@ -143,13 +140,11 @@ export class NotificationRegistry {
|
||||
|
||||
logger.debug('[NOTIFICATION_REGISTRY] Items stored', {
|
||||
userIdHash: Buffer.from(userId).toString('base64').slice(0, 12),
|
||||
source,
|
||||
itemsCount: items.length,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('[NOTIFICATION_REGISTRY] Error storing items', {
|
||||
userIdHash: Buffer.from(userId).toString('base64').slice(0, 12),
|
||||
source,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
}
|
||||
@ -170,7 +165,7 @@ export class NotificationRegistry {
|
||||
logger.debug('[NOTIFICATION_REGISTRY] Count retrieved from cache', {
|
||||
userIdHash: Buffer.from(userId).toString('base64').slice(0, 12),
|
||||
totalUnread: count.unread,
|
||||
sources: Object.keys(count.sources),
|
||||
sourcesCount: Object.keys(count.sources).length,
|
||||
});
|
||||
return count;
|
||||
}
|
||||
@ -238,10 +233,9 @@ export class NotificationRegistry {
|
||||
allItems.push(...transformed);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('[NOTIFICATION_REGISTRY] Error reading items', {
|
||||
source,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
logger.error('[NOTIFICATION_REGISTRY] Error reading items', {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -80,12 +80,16 @@ export async function ensureFreshToken(
|
||||
// If token is still valid, return current token
|
||||
if (creds.tokenExpiry && creds.accessToken &&
|
||||
creds.tokenExpiry > Date.now() + 5 * 60 * 1000) {
|
||||
logger.debug('[TOKEN_REFRESH] Token still valid, no refresh needed', { email: email.substring(0, 5) + '***' });
|
||||
logger.debug('[TOKEN_REFRESH] Token still valid, no refresh needed', {
|
||||
emailHash: Buffer.from(email.toLowerCase()).toString('base64').slice(0, 12),
|
||||
});
|
||||
return { accessToken: creds.accessToken, success: true };
|
||||
}
|
||||
|
||||
// Token is expired or about to expire, refresh it
|
||||
logger.debug('[TOKEN_REFRESH] Refreshing token', { email: email.substring(0, 5) + '***' });
|
||||
logger.debug('[TOKEN_REFRESH] Refreshing token', {
|
||||
emailHash: Buffer.from(email.toLowerCase()).toString('base64').slice(0, 12),
|
||||
});
|
||||
const tokens = await refreshAccessToken(creds.refreshToken);
|
||||
|
||||
// Update Redis cache with new tokens
|
||||
|
||||
Loading…
Reference in New Issue
Block a user