-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathimap.controller.ts
More file actions
141 lines (122 loc) · 4.27 KB
/
Copy pathimap.controller.ts
File metadata and controls
141 lines (122 loc) · 4.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import { User } from '@supabase/supabase-js';
import { NextFunction, Request, Response } from 'express';
import {
MiningSources,
OAuthMiningSourceCredentials
} from '../db/interfaces/MiningSources';
import azureOAuth2Client from '../services/OAuth2/azure';
import googleOAuth2Client from '../services/OAuth2/google';
import ImapBoxesFetcher from '../services/imap/ImapBoxesFetcher';
import ImapConnectionProvider from '../services/imap/ImapConnectionProvider';
import { ImapAuthError } from '../utils/errors';
import hashEmail from '../utils/helpers/hashHelpers';
import logger from '../utils/logger';
import { generateErrorObjectFromImapError } from './imap.helpers';
function getTokenAndProvider(data: OAuthMiningSourceCredentials) {
const { provider, accessToken, refreshToken, expiresAt } = data;
const client = provider === 'azure' ? azureOAuth2Client : googleOAuth2Client;
const token = client.createToken({
access_token: accessToken,
refresh_token: refreshToken,
expires_at: expiresAt
});
return { token, refreshToken, provider };
}
export default function initializeImapController(
miningSourceService: MiningSources
) {
return {
async getImapBoxes(req: Request, res: Response, next: NextFunction) {
const { email } = req.body;
let imapConnection: Awaited<
ReturnType<typeof ImapConnectionProvider.getSingleConnection>
> | null = null;
try {
const userId = (res.locals.user as User).id;
const sources = await miningSourceService.getSourcesForUser(
userId,
email
);
const data =
sources?.find((e) => e.email === email)?.credentials ?? null;
if (!data) {
res.status(400);
return next(
new Error('Unable to retrieve credentials for this mining source')
);
}
const isImapCredentials =
'tls' in data && 'email' in data && 'password' in data;
if (!('accessToken' in data) && !isImapCredentials) {
return res.status(400).send({
data: {
message: 'This mining source does not support IMAP folders lookup'
}
});
}
if ('accessToken' in data) {
const { token, refreshToken } = getTokenAndProvider(data);
if (!refreshToken)
return res.status(401).send({
data: { message: 'No Refresh Token' }
});
if (token.expired(1000)) {
return res.status(401).send({
data: { message: 'Access token is expired' }
});
}
}
imapConnection = await ImapConnectionProvider.getSingleConnection(
email,
'accessToken' in data
? {
oauthToken: data.accessToken
}
: {
host: data.host,
password: data.password,
tls: data.tls,
port: data.port
}
);
const imapBoxesFetcher = new ImapBoxesFetcher(imapConnection, logger);
const tree: any = await imapBoxesFetcher.getTree(email);
logger.info('Mining IMAP tree succeeded.', {
metadata: {
user: hashEmail(email, userId)
}
});
return res.status(200).send({
data: { message: 'IMAP folders fetched successfully!', folders: tree }
});
} catch (error: any) {
logger.error('Error during inbox fetch', {
message: error.message,
stack: error.stack,
code: error.code
});
if ([502, 503].includes(error?.output?.payload?.statusCode)) {
return res
.status(error?.output?.payload?.statusCode)
.send(error?.output?.payload?.error);
}
const generatedError = generateErrorObjectFromImapError(error);
if (generatedError instanceof ImapAuthError) {
return res.status(generatedError.status).send(generatedError);
}
return next(generatedError);
} finally {
if (imapConnection) {
try {
await imapConnection.logout();
} catch (logoutError) {
logger.warn(
'Unable to close IMAP connection cleanly.',
logoutError
);
}
}
}
}
};
}