@greatapps/common 1.1.52 → 1.1.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modules/auth/actions/validate-session.action.mjs +2 -2
- package/dist/modules/auth/actions/validate-session.action.mjs.map +1 -1
- package/dist/modules/auth/services/auth.service.mjs +111 -38
- package/dist/modules/auth/services/auth.service.mjs.map +1 -1
- package/dist/modules/auth/utils/get-user-context.mjs +1 -1
- package/dist/modules/auth/utils/get-user-context.mjs.map +1 -1
- package/dist/modules/users/services/user.service.mjs +1 -1
- package/dist/modules/users/services/user.service.mjs.map +1 -1
- package/dist/providers/auth.provider.mjs +1 -0
- package/dist/providers/auth.provider.mjs.map +1 -1
- package/package.json +1 -1
- package/src/modules/auth/actions/validate-session.action.ts +2 -2
- package/src/modules/auth/schema.ts +3 -0
- package/src/modules/auth/services/auth.service.ts +157 -76
- package/src/modules/auth/utils/get-user-context.ts +1 -1
- package/src/modules/users/services/user.service.ts +1 -1
- package/src/providers/auth.provider.tsx +1 -0
|
@@ -28,14 +28,14 @@ async function validateSessionAction() {
|
|
|
28
28
|
const clientInfo = await getClientInfoFromRequest();
|
|
29
29
|
const isValid = await authService.validateSession(clientInfo);
|
|
30
30
|
if (!isValid) {
|
|
31
|
-
|
|
31
|
+
await authService.removeAuthCookie();
|
|
32
32
|
await redirectToLogin();
|
|
33
33
|
return false;
|
|
34
34
|
}
|
|
35
35
|
return true;
|
|
36
36
|
} catch (error) {
|
|
37
37
|
console.error("[validateSessionAction] Error:", error);
|
|
38
|
-
|
|
38
|
+
await authService.removeAuthCookie();
|
|
39
39
|
await redirectToLogin();
|
|
40
40
|
return false;
|
|
41
41
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/auth/actions/validate-session.action.ts"],"sourcesContent":["'use server';\r\n\r\nimport { redirect } from 'next/navigation';\r\nimport { cookies, headers } from 'next/headers';\r\nimport { authService } from '../services/auth.service';\r\nimport { getClientInfoFromRequest } from '../../../infra/utils/client-info';\r\n\r\nasync function redirectToLogin() {\r\n const h = await headers();\r\n const referer = h.get('referer') || '/';\r\n\r\n if (!referer) {\r\n redirect('/login');\r\n return;\r\n }\r\n\r\n const url = new URL(referer);\r\n\r\n if (['/login', '/register', '/forgot-password'].includes(url.pathname)) {\r\n return;\r\n }\r\n\r\n redirect('/login');\r\n}\r\n\r\nexport async function validateSessionAction(): Promise<boolean> {\r\n if (process.env.DUMMY_AUTH_TOKEN) return true;\r\n\r\n const cookieStore = await cookies();\r\n const cookie = cookieStore.get('greatapps')?.value;\r\n\r\n if (!cookie) {\r\n await redirectToLogin();\r\n return false;\r\n }\r\n\r\n try {\r\n const clientInfo = await getClientInfoFromRequest();\r\n const isValid = await authService.validateSession(clientInfo);\r\n\r\n if (!isValid) {\r\n
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/auth/actions/validate-session.action.ts"],"sourcesContent":["'use server';\r\n\r\nimport { redirect } from 'next/navigation';\r\nimport { cookies, headers } from 'next/headers';\r\nimport { authService } from '../services/auth.service';\r\nimport { getClientInfoFromRequest } from '../../../infra/utils/client-info';\r\n\r\nasync function redirectToLogin() {\r\n const h = await headers();\r\n const referer = h.get('referer') || '/';\r\n\r\n if (!referer) {\r\n redirect('/login');\r\n return;\r\n }\r\n\r\n const url = new URL(referer);\r\n\r\n if (['/login', '/register', '/forgot-password'].includes(url.pathname)) {\r\n return;\r\n }\r\n\r\n redirect('/login');\r\n}\r\n\r\nexport async function validateSessionAction(): Promise<boolean> {\r\n if (process.env.DUMMY_AUTH_TOKEN) return true;\r\n\r\n const cookieStore = await cookies();\r\n const cookie = cookieStore.get('greatapps')?.value;\r\n\r\n if (!cookie) {\r\n await redirectToLogin();\r\n return false;\r\n }\r\n\r\n try {\r\n const clientInfo = await getClientInfoFromRequest();\r\n const isValid = await authService.validateSession(clientInfo);\r\n\r\n if (!isValid) {\r\n await authService.removeAuthCookie();\r\n await redirectToLogin();\r\n return false;\r\n }\r\n\r\n return true;\r\n } catch (error) {\r\n console.error('[validateSessionAction] Error:', error);\r\n await authService.removeAuthCookie();\r\n await redirectToLogin();\r\n return false;\r\n }\r\n}\r\n"],"mappings":";AAEA,SAAS,gBAAgB;AACzB,SAAS,SAAS,eAAe;AACjC,SAAS,mBAAmB;AAC5B,SAAS,gCAAgC;AAEzC,eAAe,kBAAkB;AAC/B,QAAM,IAAI,MAAM,QAAQ;AACxB,QAAM,UAAU,EAAE,IAAI,SAAS,KAAK;AAEpC,MAAI,CAAC,SAAS;AACZ,aAAS,QAAQ;AACjB;AAAA,EACF;AAEA,QAAM,MAAM,IAAI,IAAI,OAAO;AAE3B,MAAI,CAAC,UAAU,aAAa,kBAAkB,EAAE,SAAS,IAAI,QAAQ,GAAG;AACtE;AAAA,EACF;AAEA,WAAS,QAAQ;AACnB;AAEA,eAAsB,wBAA0C;AAC9D,MAAI,QAAQ,IAAI,iBAAkB,QAAO;AAEzC,QAAM,cAAc,MAAM,QAAQ;AAClC,QAAM,SAAS,YAAY,IAAI,WAAW,GAAG;AAE7C,MAAI,CAAC,QAAQ;AACX,UAAM,gBAAgB;AACtB,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,aAAa,MAAM,yBAAyB;AAClD,UAAM,UAAU,MAAM,YAAY,gBAAgB,UAAU;AAE5D,QAAI,CAAC,SAAS;AACZ,YAAM,YAAY,iBAAiB;AACnC,YAAM,gBAAgB;AACtB,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,YAAQ,MAAM,kCAAkC,KAAK;AACrD,UAAM,YAAY,iBAAiB;AACnC,UAAM,gBAAgB;AACtB,WAAO;AAAA,EACT;AACF;","names":[]}
|
|
@@ -12,22 +12,12 @@ const COOKIE_OPTIONS = {
|
|
|
12
12
|
path: "/",
|
|
13
13
|
domain: process.env.DOMAIN_COOKIE
|
|
14
14
|
};
|
|
15
|
-
async function setAuthCookie(token) {
|
|
16
|
-
const cookieStore = await cookies();
|
|
17
|
-
cookieStore.set(AUTH_COOKIE_NAME, token, { ...COOKIE_OPTIONS, maxAge: COOKIE_MAX_AGE });
|
|
18
|
-
}
|
|
19
|
-
async function removeAuthCookie() {
|
|
20
|
-
const cookieStore = await cookies();
|
|
21
|
-
cookieStore.delete({ name: AUTH_COOKIE_NAME, ...COOKIE_OPTIONS });
|
|
22
|
-
}
|
|
23
|
-
async function getAuthCookie() {
|
|
24
|
-
if (process.env.DUMMY_AUTH_TOKEN) return process.env.DUMMY_AUTH_TOKEN;
|
|
25
|
-
const cookieStore = await cookies();
|
|
26
|
-
return cookieStore.get(AUTH_COOKIE_NAME)?.value;
|
|
27
|
-
}
|
|
28
15
|
async function setPending2FACookie(token) {
|
|
29
16
|
const cookieStore = await cookies();
|
|
30
|
-
cookieStore.set(PENDING_2FA_COOKIE_NAME, token, {
|
|
17
|
+
cookieStore.set(PENDING_2FA_COOKIE_NAME, token, {
|
|
18
|
+
...COOKIE_OPTIONS,
|
|
19
|
+
maxAge: PENDING_2FA_MAX_AGE
|
|
20
|
+
});
|
|
31
21
|
}
|
|
32
22
|
async function removePending2FACookie() {
|
|
33
23
|
const cookieStore = await cookies();
|
|
@@ -48,16 +38,24 @@ class AuthService {
|
|
|
48
38
|
agent: clientInfo.agent
|
|
49
39
|
});
|
|
50
40
|
if (response.status === 0) {
|
|
51
|
-
throw new ApiError(
|
|
41
|
+
throw new ApiError(
|
|
42
|
+
response.message || "E-mail ou senha incorretos",
|
|
43
|
+
response.code || "LOGIN_FAILED",
|
|
44
|
+
401
|
|
45
|
+
);
|
|
52
46
|
}
|
|
53
47
|
if (!response.cookie) {
|
|
54
|
-
throw new ApiError(
|
|
48
|
+
throw new ApiError(
|
|
49
|
+
"Resposta de autentica\xE7\xE3o inv\xE1lida",
|
|
50
|
+
"INVALID_RESPONSE",
|
|
51
|
+
500
|
|
52
|
+
);
|
|
55
53
|
}
|
|
56
54
|
if (response.two_factor_authentication) {
|
|
57
55
|
await setPending2FACookie(response.cookie);
|
|
58
56
|
return { twoFactorRequired: true };
|
|
59
57
|
}
|
|
60
|
-
await setAuthCookie(response.cookie);
|
|
58
|
+
await this.setAuthCookie(response.cookie);
|
|
61
59
|
return {
|
|
62
60
|
user: {},
|
|
63
61
|
accessToken: response.cookie,
|
|
@@ -68,7 +66,11 @@ class AuthService {
|
|
|
68
66
|
async verifyTwoFactor(code, clientInfo) {
|
|
69
67
|
const pendingCookie = await getPending2FACookie();
|
|
70
68
|
if (!pendingCookie) {
|
|
71
|
-
throw new ApiError(
|
|
69
|
+
throw new ApiError(
|
|
70
|
+
"Nenhuma autentica\xE7\xE3o 2FA pendente",
|
|
71
|
+
"NO_PENDING_2FA",
|
|
72
|
+
400
|
|
73
|
+
);
|
|
72
74
|
}
|
|
73
75
|
const payload = {
|
|
74
76
|
location: clientInfo.location,
|
|
@@ -78,14 +80,28 @@ class AuthService {
|
|
|
78
80
|
cookie: pendingCookie,
|
|
79
81
|
code
|
|
80
82
|
};
|
|
81
|
-
const response = await apiClient.post(
|
|
83
|
+
const response = await apiClient.post(
|
|
84
|
+
"/auth/code",
|
|
85
|
+
payload
|
|
86
|
+
);
|
|
82
87
|
if (response.status === 0) {
|
|
83
|
-
throw new ApiError(
|
|
88
|
+
throw new ApiError(
|
|
89
|
+
response.message || "C\xF3digo 2FA inv\xE1lido",
|
|
90
|
+
response.code || "TWO_FACTOR_FAILED",
|
|
91
|
+
401
|
|
92
|
+
);
|
|
84
93
|
}
|
|
85
94
|
if (!response.cookie) {
|
|
86
|
-
throw new ApiError(
|
|
95
|
+
throw new ApiError(
|
|
96
|
+
"Resposta de autentica\xE7\xE3o inv\xE1lida ap\xF3s 2FA",
|
|
97
|
+
"INVALID_RESPONSE",
|
|
98
|
+
500
|
|
99
|
+
);
|
|
87
100
|
}
|
|
88
|
-
await Promise.all([
|
|
101
|
+
await Promise.all([
|
|
102
|
+
this.setAuthCookie(response.cookie),
|
|
103
|
+
removePending2FACookie()
|
|
104
|
+
]);
|
|
89
105
|
return { success: true };
|
|
90
106
|
}
|
|
91
107
|
async isTwoFactorPending() {
|
|
@@ -123,12 +139,23 @@ class AuthService {
|
|
|
123
139
|
id_product: 1
|
|
124
140
|
}
|
|
125
141
|
};
|
|
126
|
-
const response = await apiClient.post(
|
|
142
|
+
const response = await apiClient.post(
|
|
143
|
+
"/accounts",
|
|
144
|
+
payload
|
|
145
|
+
);
|
|
127
146
|
if (response.status === 0) {
|
|
128
|
-
throw new ApiError(
|
|
147
|
+
throw new ApiError(
|
|
148
|
+
response.message || "Erro ao criar conta",
|
|
149
|
+
"REGISTER_FAILED",
|
|
150
|
+
400
|
|
151
|
+
);
|
|
129
152
|
}
|
|
130
153
|
if (!response.data || response.data.length === 0) {
|
|
131
|
-
throw new ApiError(
|
|
154
|
+
throw new ApiError(
|
|
155
|
+
"Resposta de registro inv\xE1lida",
|
|
156
|
+
"INVALID_RESPONSE",
|
|
157
|
+
500
|
|
158
|
+
);
|
|
132
159
|
}
|
|
133
160
|
const accountData = response.data[0];
|
|
134
161
|
return {
|
|
@@ -141,9 +168,13 @@ class AuthService {
|
|
|
141
168
|
};
|
|
142
169
|
}
|
|
143
170
|
async logout(clientInfo) {
|
|
144
|
-
const cookie = await
|
|
171
|
+
const cookie = await this.getToken();
|
|
145
172
|
if (!cookie) {
|
|
146
|
-
throw new ApiError(
|
|
173
|
+
throw new ApiError(
|
|
174
|
+
"Usu\xE1rio n\xE3o autenticado",
|
|
175
|
+
"NOT_AUTHENTICATED_LOGOUT",
|
|
176
|
+
401
|
|
177
|
+
);
|
|
147
178
|
}
|
|
148
179
|
const payload = {
|
|
149
180
|
location: clientInfo.location,
|
|
@@ -153,31 +184,54 @@ class AuthService {
|
|
|
153
184
|
cookie
|
|
154
185
|
};
|
|
155
186
|
try {
|
|
156
|
-
const response = await apiClient.post(
|
|
187
|
+
const response = await apiClient.post(
|
|
188
|
+
"/auth/logout",
|
|
189
|
+
payload
|
|
190
|
+
);
|
|
157
191
|
if (response.status === 0) {
|
|
158
|
-
throw new ApiError(
|
|
192
|
+
throw new ApiError(
|
|
193
|
+
response.message || "Erro ao realizar logout",
|
|
194
|
+
response.code || "LOGOUT_FAILED",
|
|
195
|
+
400
|
|
196
|
+
);
|
|
159
197
|
}
|
|
160
198
|
} finally {
|
|
161
|
-
await Promise.all([removeAuthCookie(), removePending2FACookie()]);
|
|
199
|
+
await Promise.all([this.removeAuthCookie(), removePending2FACookie()]);
|
|
162
200
|
}
|
|
163
201
|
return {
|
|
164
202
|
success: true
|
|
165
203
|
};
|
|
166
204
|
}
|
|
167
205
|
async forgotPassword(_data) {
|
|
168
|
-
throw new ApiError(
|
|
206
|
+
throw new ApiError(
|
|
207
|
+
"Recupera\xE7\xE3o de senha n\xE3o implementada",
|
|
208
|
+
"NOT_IMPLEMENTED",
|
|
209
|
+
501
|
|
210
|
+
);
|
|
169
211
|
}
|
|
170
212
|
async resetPassword(_data) {
|
|
171
|
-
throw new ApiError(
|
|
213
|
+
throw new ApiError(
|
|
214
|
+
"Redefini\xE7\xE3o de senha n\xE3o implementada",
|
|
215
|
+
"NOT_IMPLEMENTED",
|
|
216
|
+
501
|
|
217
|
+
);
|
|
172
218
|
}
|
|
173
219
|
async verifyEmail(_data) {
|
|
174
|
-
throw new ApiError(
|
|
220
|
+
throw new ApiError(
|
|
221
|
+
"Verifica\xE7\xE3o de email n\xE3o implementada",
|
|
222
|
+
"NOT_IMPLEMENTED",
|
|
223
|
+
501
|
|
224
|
+
);
|
|
175
225
|
}
|
|
176
226
|
async resendVerification(_data) {
|
|
177
|
-
throw new ApiError(
|
|
227
|
+
throw new ApiError(
|
|
228
|
+
"Reenvio de verifica\xE7\xE3o n\xE3o implementado",
|
|
229
|
+
"NOT_IMPLEMENTED",
|
|
230
|
+
501
|
|
231
|
+
);
|
|
178
232
|
}
|
|
179
233
|
async validateSession(clientInfo) {
|
|
180
|
-
const cookie = await
|
|
234
|
+
const cookie = await this.getToken();
|
|
181
235
|
if (!cookie) {
|
|
182
236
|
return false;
|
|
183
237
|
}
|
|
@@ -189,7 +243,10 @@ class AuthService {
|
|
|
189
243
|
agent: clientInfo.agent,
|
|
190
244
|
cookie
|
|
191
245
|
};
|
|
192
|
-
const response = await apiClient.post(
|
|
246
|
+
const response = await apiClient.post(
|
|
247
|
+
"/auth/keep",
|
|
248
|
+
payload
|
|
249
|
+
);
|
|
193
250
|
return response.status === 1;
|
|
194
251
|
} catch (error) {
|
|
195
252
|
console.error("[AuthService] validateSession error", error);
|
|
@@ -197,11 +254,27 @@ class AuthService {
|
|
|
197
254
|
}
|
|
198
255
|
}
|
|
199
256
|
async isAuthenticated() {
|
|
200
|
-
const token = await
|
|
257
|
+
const token = await this.getToken();
|
|
201
258
|
return !!token;
|
|
202
259
|
}
|
|
203
260
|
async getToken() {
|
|
204
|
-
|
|
261
|
+
if (process.env.DUMMY_AUTH_TOKEN) return process.env.DUMMY_AUTH_TOKEN;
|
|
262
|
+
const cookieStore = await cookies();
|
|
263
|
+
return cookieStore.get(AUTH_COOKIE_NAME)?.value;
|
|
264
|
+
}
|
|
265
|
+
async setAuthCookie(token) {
|
|
266
|
+
const cookieStore = await cookies();
|
|
267
|
+
cookieStore.set(AUTH_COOKIE_NAME, token, {
|
|
268
|
+
...COOKIE_OPTIONS,
|
|
269
|
+
maxAge: COOKIE_MAX_AGE
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
async removeAuthCookie() {
|
|
273
|
+
const cookieStore = await cookies();
|
|
274
|
+
cookieStore.delete({
|
|
275
|
+
name: AUTH_COOKIE_NAME,
|
|
276
|
+
...COOKIE_OPTIONS
|
|
277
|
+
});
|
|
205
278
|
}
|
|
206
279
|
}
|
|
207
280
|
const authService = new AuthService();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/auth/services/auth.service.ts"],"sourcesContent":["\r\nimport { cookies } from 'next/headers';\r\n\r\nimport { apiClient } from '../../../infra/api/client';\r\nimport { ApiError } from '../../../infra/api/types';\r\nimport { User } from '../../users/schema';\r\nimport {\r\n ClientInfo,\r\n ForgotPasswordRequest,\r\n ForgotPasswordResponse,\r\n GeoLocation,\r\n LoginApiResponse,\r\n LoginRequest,\r\n LoginResponse,\r\n LogoutApiResponse,\r\n LogoutRequest,\r\n LogoutResponse,\r\n RegisterApiRequest,\r\n RegisterApiResponse,\r\n RegisterRequest,\r\n RegisterResponse,\r\n ResendVerificationRequest,\r\n ResendVerificationResponse,\r\n ResetPasswordRequest,\r\n ResetPasswordResponse,\r\n SessionKeepRequest,\r\n SessionKeepResponse,\r\n TwoFactorApiResponse,\r\n TwoFactorRequest,\r\n TwoFactorResponse,\r\n VerifyEmailRequest,\r\n VerifyEmailResponse,\r\n} from '../schema';\r\n\r\nconst AUTH_COOKIE_NAME = 'greatapps';\r\nconst PENDING_2FA_COOKIE_NAME = 'greatapps_2fa_pending';\r\nconst COOKIE_MAX_AGE = 60 * 60 * 24 * 30;\r\nconst PENDING_2FA_MAX_AGE = 60 * 10; // 10 minutos para completar o 2FA\r\n\r\nconst COOKIE_OPTIONS = {\r\n httpOnly: true,\r\n secure: process.env.NODE_ENV === 'production',\r\n sameSite: 'lax' as const,\r\n path: '/',\r\n domain: process.env.DOMAIN_COOKIE,\r\n};\r\n\r\nasync function setAuthCookie(token: string): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.set(AUTH_COOKIE_NAME, token, { ...COOKIE_OPTIONS, maxAge: COOKIE_MAX_AGE });\r\n}\r\n\r\nasync function removeAuthCookie(): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.delete({ name: AUTH_COOKIE_NAME, ...COOKIE_OPTIONS });\r\n}\r\n\r\nasync function getAuthCookie(): Promise<string | undefined> {\r\n if (process.env.DUMMY_AUTH_TOKEN) return process.env.DUMMY_AUTH_TOKEN;\r\n const cookieStore = await cookies();\r\n return cookieStore.get(AUTH_COOKIE_NAME)?.value;\r\n}\r\n\r\nasync function setPending2FACookie(token: string): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.set(PENDING_2FA_COOKIE_NAME, token, { ...COOKIE_OPTIONS, maxAge: PENDING_2FA_MAX_AGE });\r\n}\r\n\r\nasync function removePending2FACookie(): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.delete({ name: PENDING_2FA_COOKIE_NAME, ...COOKIE_OPTIONS });\r\n}\r\n\r\nasync function getPending2FACookie(): Promise<string | undefined> {\r\n const cookieStore = await cookies();\r\n return cookieStore.get(PENDING_2FA_COOKIE_NAME)?.value;\r\n}\r\n\r\nclass AuthService {\r\n async login(credentials: LoginRequest, clientInfo: ClientInfo): Promise<LoginResponse> {\r\n const response = await apiClient.post<LoginApiResponse>('/auth/login', {\r\n email: credentials.email,\r\n password: credentials.password,\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n });\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'E-mail ou senha incorretos', 'LOGIN_FAILED', 401);\r\n }\r\n\r\n if (!response.cookie) {\r\n throw new ApiError('Resposta de autenticação inválida', 'INVALID_RESPONSE', 500);\r\n }\r\n\r\n if (response.two_factor_authentication) {\r\n // Armazena o cookie temporariamente até o 2FA ser concluído.\r\n // O cookie principal NÃO é setado aqui para evitar falso positivo em isAuthenticated().\r\n await setPending2FACookie(response.cookie);\r\n return { twoFactorRequired: true };\r\n }\r\n\r\n await setAuthCookie(response.cookie);\r\n\r\n return {\r\n user: {} as User,\r\n accessToken: response.cookie,\r\n refreshToken: '',\r\n expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),\r\n };\r\n }\r\n\r\n async verifyTwoFactor(code: number, clientInfo: ClientInfo): Promise<TwoFactorResponse> {\r\n const pendingCookie = await getPending2FACookie();\r\n\r\n if (!pendingCookie) {\r\n throw new ApiError('Nenhuma autenticação 2FA pendente', 'NO_PENDING_2FA', 400);\r\n }\r\n\r\n const payload: TwoFactorRequest = {\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n cookie: pendingCookie,\r\n code,\r\n };\r\n\r\n const response = await apiClient.post<TwoFactorApiResponse>('/auth/code', payload);\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'Código 2FA inválido', 'TWO_FACTOR_FAILED', 401);\r\n }\r\n\r\n if (!response.cookie) {\r\n throw new ApiError('Resposta de autenticação inválida após 2FA', 'INVALID_RESPONSE', 500);\r\n }\r\n\r\n await Promise.all([setAuthCookie(response.cookie), removePending2FACookie()]);\r\n\r\n return { success: true };\r\n }\r\n\r\n async isTwoFactorPending(): Promise<boolean> {\r\n const pending = await getPending2FACookie();\r\n return !!pending;\r\n }\r\n\r\n async register(data: RegisterRequest): Promise<RegisterResponse> {\r\n const today = new Date();\r\n const trialEndDate = new Date(today);\r\n trialEndDate.setDate(today.getDate() + 7); // 7 dias de trial\r\n\r\n const payload: RegisterApiRequest = {\r\n name: data.accountName,\r\n bussiness_type: data.businessType,\r\n language: 'pt-br',\r\n timezone: 'America/Sao_Paulo',\r\n currency: 'BRL',\r\n user: {\r\n id_api: '',\r\n name: data.name,\r\n last_name: data.lastName || '',\r\n rg: data.rg || '',\r\n cpf: data.cpf || '',\r\n gender: data.gender,\r\n email: data.email,\r\n phone: data.phone,\r\n password: data.password,\r\n profile: 'owner',\r\n language: 'pt-br',\r\n },\r\n subscription: {\r\n type: 'trial',\r\n id_cupom: '',\r\n id_plan: 1,\r\n due_date: trialEndDate.toISOString().split('T')[0],\r\n id_product: 1,\r\n },\r\n };\r\n\r\n const response = await apiClient.post<RegisterApiResponse>('/accounts', payload);\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'Erro ao criar conta', 'REGISTER_FAILED', 400);\r\n }\r\n\r\n if (!response.data || response.data.length === 0) {\r\n throw new ApiError('Resposta de registro inválida', 'INVALID_RESPONSE', 500);\r\n }\r\n\r\n const accountData = response.data[0];\r\n\r\n // Retornar sem token pois o registro não retorna cookie diretamente\r\n // O usuário precisará fazer login após o registro\r\n // O usuário completo será carregado após o login\r\n return {\r\n user: {} as User, // Placeholder, será preenchido após login\r\n accessToken: '',\r\n refreshToken: '',\r\n expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),\r\n requiresEmailVerification: !accountData.verified,\r\n };\r\n }\r\n\r\n async logout(clientInfo: ClientInfo): Promise<LogoutResponse> {\r\n const cookie = await getAuthCookie();\r\n\r\n if (!cookie) {\r\n throw new ApiError('Usuário não autenticado', 'NOT_AUTHENTICATED', 401);\r\n }\r\n\r\n const payload: LogoutRequest = {\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n cookie,\r\n };\r\n\r\n try {\r\n const response = await apiClient.post<LogoutApiResponse>('/auth/logout', payload);\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'Erro ao realizar logout', 'LOGOUT_FAILED', 400);\r\n }\r\n } finally {\r\n await Promise.all([removeAuthCookie(), removePending2FACookie()]);\r\n }\r\n\r\n return {\r\n success: true,\r\n };\r\n }\r\n\r\n async forgotPassword(_data: ForgotPasswordRequest): Promise<ForgotPasswordResponse> {\r\n throw new ApiError('Recuperação de senha não implementada', 'NOT_IMPLEMENTED', 501);\r\n }\r\n\r\n async resetPassword(_data: ResetPasswordRequest): Promise<ResetPasswordResponse> {\r\n throw new ApiError('Redefinição de senha não implementada', 'NOT_IMPLEMENTED', 501);\r\n }\r\n\r\n async verifyEmail(_data: VerifyEmailRequest): Promise<VerifyEmailResponse> {\r\n throw new ApiError('Verificação de email não implementada', 'NOT_IMPLEMENTED', 501);\r\n }\r\n\r\n async resendVerification(_data: ResendVerificationRequest): Promise<ResendVerificationResponse> {\r\n throw new ApiError('Reenvio de verificação não implementado', 'NOT_IMPLEMENTED', 501);\r\n }\r\n\r\n async validateSession(clientInfo: ClientInfo): Promise<boolean> {\r\n const cookie = await getAuthCookie();\r\n\r\n if (!cookie) {\r\n return false;\r\n }\r\n\r\n try {\r\n const payload: SessionKeepRequest = {\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n cookie,\r\n };\r\n\r\n const response = await apiClient.post<SessionKeepResponse>('/auth/keep', payload);\r\n\r\n return response.status === 1;\r\n } catch (error) {\r\n console.error('[AuthService] validateSession error', error);\r\n return false;\r\n }\r\n }\r\n\r\n async isAuthenticated(): Promise<boolean> {\r\n const token = await getAuthCookie();\r\n return !!token;\r\n }\r\n\r\n async getToken(): Promise<string | undefined> {\r\n return getAuthCookie();\r\n }\r\n}\r\n\r\nexport const authService = new AuthService();\r\n\r\nexport type { ClientInfo, GeoLocation };\r\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/auth/services/auth.service.ts"],"sourcesContent":["import { cookies } from \"next/headers\";\r\n\r\nimport { apiClient } from \"../../../infra/api/client\";\r\nimport { ApiError } from \"../../../infra/api/types\";\r\nimport { User } from \"../../users/schema\";\r\nimport {\r\n ClientInfo,\r\n ForgotPasswordRequest,\r\n ForgotPasswordResponse,\r\n GeoLocation,\r\n LoginApiResponse,\r\n LoginRequest,\r\n LoginResponse,\r\n LogoutApiResponse,\r\n LogoutRequest,\r\n LogoutResponse,\r\n RegisterApiRequest,\r\n RegisterApiResponse,\r\n RegisterRequest,\r\n RegisterResponse,\r\n ResendVerificationRequest,\r\n ResendVerificationResponse,\r\n ResetPasswordRequest,\r\n ResetPasswordResponse,\r\n SessionKeepRequest,\r\n SessionKeepResponse,\r\n TwoFactorApiResponse,\r\n TwoFactorRequest,\r\n TwoFactorResponse,\r\n VerifyEmailRequest,\r\n VerifyEmailResponse,\r\n} from \"../schema\";\r\n\r\nconst AUTH_COOKIE_NAME = \"greatapps\";\r\nconst PENDING_2FA_COOKIE_NAME = \"greatapps_2fa_pending\";\r\nconst COOKIE_MAX_AGE = 60 * 60 * 24 * 30;\r\nconst PENDING_2FA_MAX_AGE = 60 * 10; // 10 minutos para completar o 2FA\r\n\r\nconst COOKIE_OPTIONS = {\r\n httpOnly: true,\r\n secure: process.env.NODE_ENV === \"production\",\r\n sameSite: \"lax\" as const,\r\n path: \"/\",\r\n domain: process.env.DOMAIN_COOKIE,\r\n};\r\n\r\nasync function setPending2FACookie(token: string): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.set(PENDING_2FA_COOKIE_NAME, token, {\r\n ...COOKIE_OPTIONS,\r\n maxAge: PENDING_2FA_MAX_AGE,\r\n });\r\n}\r\n\r\nasync function removePending2FACookie(): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.delete({ name: PENDING_2FA_COOKIE_NAME, ...COOKIE_OPTIONS });\r\n}\r\n\r\nasync function getPending2FACookie(): Promise<string | undefined> {\r\n const cookieStore = await cookies();\r\n return cookieStore.get(PENDING_2FA_COOKIE_NAME)?.value;\r\n}\r\n\r\nclass AuthService {\r\n async login(\r\n credentials: LoginRequest,\r\n clientInfo: ClientInfo\r\n ): Promise<LoginResponse> {\r\n const response = await apiClient.post<LoginApiResponse>(\"/auth/login\", {\r\n email: credentials.email,\r\n password: credentials.password,\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n });\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(\r\n response.message || \"E-mail ou senha incorretos\",\r\n response.code || \"LOGIN_FAILED\",\r\n 401\r\n );\r\n }\r\n\r\n if (!response.cookie) {\r\n throw new ApiError(\r\n \"Resposta de autenticação inválida\",\r\n \"INVALID_RESPONSE\",\r\n 500\r\n );\r\n }\r\n\r\n if (response.two_factor_authentication) {\r\n await setPending2FACookie(response.cookie);\r\n return { twoFactorRequired: true };\r\n }\r\n\r\n await this.setAuthCookie(response.cookie);\r\n\r\n return {\r\n user: {} as User,\r\n accessToken: response.cookie,\r\n refreshToken: \"\",\r\n expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),\r\n };\r\n }\r\n\r\n async verifyTwoFactor(\r\n code: number,\r\n clientInfo: ClientInfo\r\n ): Promise<TwoFactorResponse> {\r\n const pendingCookie = await getPending2FACookie();\r\n\r\n if (!pendingCookie) {\r\n throw new ApiError(\r\n \"Nenhuma autenticação 2FA pendente\",\r\n \"NO_PENDING_2FA\",\r\n 400\r\n );\r\n }\r\n\r\n const payload: TwoFactorRequest = {\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n cookie: pendingCookie,\r\n code,\r\n };\r\n\r\n const response = await apiClient.post<TwoFactorApiResponse>(\r\n \"/auth/code\",\r\n payload\r\n );\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(\r\n response.message || \"Código 2FA inválido\",\r\n response.code || \"TWO_FACTOR_FAILED\",\r\n 401\r\n );\r\n }\r\n\r\n if (!response.cookie) {\r\n throw new ApiError(\r\n \"Resposta de autenticação inválida após 2FA\",\r\n \"INVALID_RESPONSE\",\r\n 500\r\n );\r\n }\r\n\r\n await Promise.all([\r\n this.setAuthCookie(response.cookie),\r\n removePending2FACookie(),\r\n ]);\r\n\r\n return { success: true };\r\n }\r\n\r\n async isTwoFactorPending(): Promise<boolean> {\r\n const pending = await getPending2FACookie();\r\n return !!pending;\r\n }\r\n\r\n async register(data: RegisterRequest): Promise<RegisterResponse> {\r\n const today = new Date();\r\n const trialEndDate = new Date(today);\r\n trialEndDate.setDate(today.getDate() + 7); // 7 dias de trial\r\n\r\n const payload: RegisterApiRequest = {\r\n name: data.accountName,\r\n bussiness_type: data.businessType,\r\n language: \"pt-br\",\r\n timezone: \"America/Sao_Paulo\",\r\n currency: \"BRL\",\r\n user: {\r\n id_api: \"\",\r\n name: data.name,\r\n last_name: data.lastName || \"\",\r\n rg: data.rg || \"\",\r\n cpf: data.cpf || \"\",\r\n gender: data.gender,\r\n email: data.email,\r\n phone: data.phone,\r\n password: data.password,\r\n profile: \"owner\",\r\n language: \"pt-br\",\r\n },\r\n subscription: {\r\n type: \"trial\",\r\n id_cupom: \"\",\r\n id_plan: 1,\r\n due_date: trialEndDate.toISOString().split(\"T\")[0],\r\n id_product: 1,\r\n },\r\n };\r\n\r\n const response = await apiClient.post<RegisterApiResponse>(\r\n \"/accounts\",\r\n payload\r\n );\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(\r\n response.message || \"Erro ao criar conta\",\r\n \"REGISTER_FAILED\",\r\n 400\r\n );\r\n }\r\n\r\n if (!response.data || response.data.length === 0) {\r\n throw new ApiError(\r\n \"Resposta de registro inválida\",\r\n \"INVALID_RESPONSE\",\r\n 500\r\n );\r\n }\r\n\r\n const accountData = response.data[0];\r\n\r\n // Retornar sem token pois o registro não retorna cookie diretamente\r\n // O usuário precisará fazer login após o registro\r\n // O usuário completo será carregado após o login\r\n return {\r\n user: {} as User, // Placeholder, será preenchido após login\r\n accessToken: \"\",\r\n refreshToken: \"\",\r\n expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),\r\n requiresEmailVerification: !accountData.verified,\r\n };\r\n }\r\n\r\n async logout(clientInfo: ClientInfo): Promise<LogoutResponse> {\r\n const cookie = await this.getToken();\r\n\r\n if (!cookie) {\r\n throw new ApiError(\r\n \"Usuário não autenticado\",\r\n \"NOT_AUTHENTICATED_LOGOUT\",\r\n 401\r\n );\r\n }\r\n\r\n const payload: LogoutRequest = {\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n cookie,\r\n };\r\n\r\n try {\r\n const response = await apiClient.post<LogoutApiResponse>(\r\n \"/auth/logout\",\r\n payload\r\n );\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(\r\n response.message || \"Erro ao realizar logout\",\r\n response.code || \"LOGOUT_FAILED\",\r\n 400\r\n );\r\n }\r\n } finally {\r\n await Promise.all([this.removeAuthCookie(), removePending2FACookie()]);\r\n }\r\n\r\n return {\r\n success: true,\r\n };\r\n }\r\n\r\n async forgotPassword(\r\n _data: ForgotPasswordRequest\r\n ): Promise<ForgotPasswordResponse> {\r\n throw new ApiError(\r\n \"Recuperação de senha não implementada\",\r\n \"NOT_IMPLEMENTED\",\r\n 501\r\n );\r\n }\r\n\r\n async resetPassword(\r\n _data: ResetPasswordRequest\r\n ): Promise<ResetPasswordResponse> {\r\n throw new ApiError(\r\n \"Redefinição de senha não implementada\",\r\n \"NOT_IMPLEMENTED\",\r\n 501\r\n );\r\n }\r\n\r\n async verifyEmail(_data: VerifyEmailRequest): Promise<VerifyEmailResponse> {\r\n throw new ApiError(\r\n \"Verificação de email não implementada\",\r\n \"NOT_IMPLEMENTED\",\r\n 501\r\n );\r\n }\r\n\r\n async resendVerification(\r\n _data: ResendVerificationRequest\r\n ): Promise<ResendVerificationResponse> {\r\n throw new ApiError(\r\n \"Reenvio de verificação não implementado\",\r\n \"NOT_IMPLEMENTED\",\r\n 501\r\n );\r\n }\r\n\r\n async validateSession(clientInfo: ClientInfo): Promise<boolean> {\r\n const cookie = await this.getToken();\r\n\r\n if (!cookie) {\r\n return false;\r\n }\r\n\r\n try {\r\n const payload: SessionKeepRequest = {\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n cookie,\r\n };\r\n\r\n const response = await apiClient.post<SessionKeepResponse>(\r\n \"/auth/keep\",\r\n payload\r\n );\r\n\r\n return response.status === 1;\r\n } catch (error) {\r\n console.error(\"[AuthService] validateSession error\", error);\r\n return false;\r\n }\r\n }\r\n\r\n async isAuthenticated(): Promise<boolean> {\r\n const token = await this.getToken();\r\n return !!token;\r\n }\r\n\r\n async getToken(): Promise<string | undefined> {\r\n if (process.env.DUMMY_AUTH_TOKEN) return process.env.DUMMY_AUTH_TOKEN;\r\n const cookieStore = await cookies();\r\n return cookieStore.get(AUTH_COOKIE_NAME)?.value;\r\n }\r\n\r\n private async setAuthCookie(token: string): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.set(AUTH_COOKIE_NAME, token, {\r\n ...COOKIE_OPTIONS,\r\n maxAge: COOKIE_MAX_AGE,\r\n });\r\n }\r\n\r\n async removeAuthCookie(): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.delete({\r\n name: AUTH_COOKIE_NAME,\r\n ...COOKIE_OPTIONS,\r\n });\r\n }\r\n}\r\n\r\nexport const authService = new AuthService();\r\n\r\nexport type { ClientInfo, GeoLocation };\r\n"],"mappings":"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","names":[]}
|
|
@@ -6,7 +6,7 @@ async function getUserContext() {
|
|
|
6
6
|
const cookieStore = await cookies();
|
|
7
7
|
const token = process.env.DUMMY_AUTH_TOKEN || cookieStore.get(AUTH_COOKIE_NAME)?.value;
|
|
8
8
|
if (!token) {
|
|
9
|
-
throw new ApiError("Usu\xE1rio n\xE3o autenticado", "
|
|
9
|
+
throw new ApiError("Usu\xE1rio n\xE3o autenticado", "NOT_AUTHENTICATED_GUC", 401);
|
|
10
10
|
}
|
|
11
11
|
try {
|
|
12
12
|
const payload = JSON.parse(atob(token.split(".")[1]));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/auth/utils/get-user-context.ts"],"sourcesContent":["import 'server-only';\r\n\r\nimport { cookies } from 'next/headers';\r\nimport { ApiError } from '../../../infra/api/types';\r\nimport { JWTPayload } from '../../users/schema';\r\n\r\nconst AUTH_COOKIE_NAME = 'greatapps';\r\n\r\nexport async function getUserContext(): Promise<{\r\n id_account: number;\r\n id_user: number;\r\n}> {\r\n const cookieStore = await cookies();\r\n const token = process.env.DUMMY_AUTH_TOKEN || cookieStore.get(AUTH_COOKIE_NAME)?.value;\r\n\r\n if (!token) {\r\n throw new ApiError('Usuário não autenticado', '
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/auth/utils/get-user-context.ts"],"sourcesContent":["import 'server-only';\r\n\r\nimport { cookies } from 'next/headers';\r\nimport { ApiError } from '../../../infra/api/types';\r\nimport { JWTPayload } from '../../users/schema';\r\n\r\nconst AUTH_COOKIE_NAME = 'greatapps';\r\n\r\nexport async function getUserContext(): Promise<{\r\n id_account: number;\r\n id_user: number;\r\n}> {\r\n const cookieStore = await cookies();\r\n const token = process.env.DUMMY_AUTH_TOKEN || cookieStore.get(AUTH_COOKIE_NAME)?.value;\r\n\r\n if (!token) {\r\n throw new ApiError('Usuário não autenticado', 'NOT_AUTHENTICATED_GUC', 401);\r\n }\r\n\r\n try {\r\n const payload = JSON.parse(atob(token.split('.')[1])) as JWTPayload;\r\n\r\n return {\r\n id_account: payload.id_account,\r\n id_user: payload.id_user,\r\n };\r\n } catch {\r\n throw new ApiError('Token inválido', 'INVALID_TOKEN', 401);\r\n }\r\n}\r\n"],"mappings":"AAAA,OAAO;AAEP,SAAS,eAAe;AACxB,SAAS,gBAAgB;AAGzB,MAAM,mBAAmB;AAEzB,eAAsB,iBAGnB;AACD,QAAM,cAAc,MAAM,QAAQ;AAClC,QAAM,QAAQ,QAAQ,IAAI,oBAAoB,YAAY,IAAI,gBAAgB,GAAG;AAEjF,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,SAAS,iCAA2B,yBAAyB,GAAG;AAAA,EAC5E;AAEA,MAAI;AACF,UAAM,UAAU,KAAK,MAAM,KAAK,MAAM,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC;AAEpD,WAAO;AAAA,MACL,YAAY,QAAQ;AAAA,MACpB,SAAS,QAAQ;AAAA,IACnB;AAAA,EACF,QAAQ;AACN,UAAM,IAAI,SAAS,qBAAkB,iBAAiB,GAAG;AAAA,EAC3D;AACF;","names":[]}
|
|
@@ -9,7 +9,7 @@ class UserService {
|
|
|
9
9
|
const cookieStore = await cookies();
|
|
10
10
|
const token = cookieStore.get(AUTH_COOKIE_NAME)?.value;
|
|
11
11
|
if (!token) {
|
|
12
|
-
throw new ApiError("N\xE3o autenticado", "
|
|
12
|
+
throw new ApiError("N\xE3o autenticado", "NOT_AUTHENTICATED_GAT", 401);
|
|
13
13
|
}
|
|
14
14
|
return token;
|
|
15
15
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/users/services/user.service.ts"],"sourcesContent":["\r\nimport { cookies } from 'next/headers';\r\n\r\nimport { ApiError } from '../../../infra/api/types';\r\nimport { GetUserDataResponse, JWTPayload, User } from '../schema';\r\nimport { findWhitelabel } from '../../whitelabel/actions/find-whitelabel.action';\r\n\r\nconst AUTH_COOKIE_NAME = 'greatapps';\r\nconst API_BASE_URL = process.env.GAPPS_R3_API_URL || 'https://r3-api.greatapps.dev.br';\r\n\r\nclass UserService {\r\n private async getAuthToken(): Promise<string> {\r\n if (process.env.DUMMY_AUTH_TOKEN) return process.env.DUMMY_AUTH_TOKEN;\r\n const cookieStore = await cookies();\r\n const token = cookieStore.get(AUTH_COOKIE_NAME)?.value;\r\n\r\n if (!token) {\r\n throw new ApiError('Não autenticado', '
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/users/services/user.service.ts"],"sourcesContent":["\r\nimport { cookies } from 'next/headers';\r\n\r\nimport { ApiError } from '../../../infra/api/types';\r\nimport { GetUserDataResponse, JWTPayload, User } from '../schema';\r\nimport { findWhitelabel } from '../../whitelabel/actions/find-whitelabel.action';\r\n\r\nconst AUTH_COOKIE_NAME = 'greatapps';\r\nconst API_BASE_URL = process.env.GAPPS_R3_API_URL || 'https://r3-api.greatapps.dev.br';\r\n\r\nclass UserService {\r\n private async getAuthToken(): Promise<string> {\r\n if (process.env.DUMMY_AUTH_TOKEN) return process.env.DUMMY_AUTH_TOKEN;\r\n const cookieStore = await cookies();\r\n const token = cookieStore.get(AUTH_COOKIE_NAME)?.value;\r\n\r\n if (!token) {\r\n throw new ApiError('Não autenticado', 'NOT_AUTHENTICATED_GAT', 401);\r\n }\r\n\r\n return token;\r\n }\r\n\r\n private decodeJWT(token: string): JWTPayload {\r\n try {\r\n return JSON.parse(atob(token.split('.')[1])) as JWTPayload;\r\n } catch {\r\n throw new ApiError('Token inválido', 'INVALID_TOKEN', 401);\r\n }\r\n }\r\n\r\n async findById(): Promise<User> {\r\n const token = await this.getAuthToken();\r\n const payload = this.decodeJWT(token);\r\n\r\n const { id_wl, id_account, id_user } = payload;\r\n const { token: wlToken } = await findWhitelabel();\r\n\r\n const url = `${API_BASE_URL}/v1/pt-br/${id_wl}/accounts/${id_account}/users/${id_user}`;\r\n\r\n const response = await fetch(url, {\r\n method: 'GET',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n authorization: wlToken,\r\n },\r\n });\r\n\r\n if (!response.ok) {\r\n throw new ApiError('Erro ao buscar dados do usuário', 'FETCH_ERROR', response.status);\r\n }\r\n\r\n const data = (await response.json()) as GetUserDataResponse;\r\n\r\n if (data.status === 0 || !data.data || data.data.length === 0) {\r\n throw new ApiError('Dados do usuário não encontrados', 'USER_NOT_FOUND', 404);\r\n }\r\n\r\n return data.data[0];\r\n }\r\n}\r\n\r\nexport const userService = new UserService();\r\n"],"mappings":"AACA,SAAS,eAAe;AAExB,SAAS,gBAAgB;AAEzB,SAAS,sBAAsB;AAE/B,MAAM,mBAAmB;AACzB,MAAM,eAAe,QAAQ,IAAI,oBAAoB;AAErD,MAAM,YAAY;AAAA,EAChB,MAAc,eAAgC;AAC5C,QAAI,QAAQ,IAAI,iBAAkB,QAAO,QAAQ,IAAI;AACrD,UAAM,cAAc,MAAM,QAAQ;AAClC,UAAM,QAAQ,YAAY,IAAI,gBAAgB,GAAG;AAEjD,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,SAAS,sBAAmB,yBAAyB,GAAG;AAAA,IACpE;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,UAAU,OAA2B;AAC3C,QAAI;AACF,aAAO,KAAK,MAAM,KAAK,MAAM,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC;AAAA,IAC7C,QAAQ;AACN,YAAM,IAAI,SAAS,qBAAkB,iBAAiB,GAAG;AAAA,IAC3D;AAAA,EACF;AAAA,EAEA,MAAM,WAA0B;AAC9B,UAAM,QAAQ,MAAM,KAAK,aAAa;AACtC,UAAM,UAAU,KAAK,UAAU,KAAK;AAEpC,UAAM,EAAE,OAAO,YAAY,QAAQ,IAAI;AACvC,UAAM,EAAE,OAAO,QAAQ,IAAI,MAAM,eAAe;AAEhD,UAAM,MAAM,GAAG,YAAY,aAAa,KAAK,aAAa,UAAU,UAAU,OAAO;AAErF,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,eAAe;AAAA,MACjB;AAAA,IACF,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,SAAS,sCAAmC,eAAe,SAAS,MAAM;AAAA,IACtF;AAEA,UAAM,OAAQ,MAAM,SAAS,KAAK;AAElC,QAAI,KAAK,WAAW,KAAK,CAAC,KAAK,QAAQ,KAAK,KAAK,WAAW,GAAG;AAC7D,YAAM,IAAI,SAAS,0CAAoC,kBAAkB,GAAG;AAAA,IAC9E;AAEA,WAAO,KAAK,KAAK,CAAC;AAAA,EACpB;AACF;AAEO,MAAM,cAAc,IAAI,YAAY;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/providers/auth.provider.tsx"],"sourcesContent":["\"use client\";\r\n\r\nimport {\r\n createContext,\r\n ReactNode,\r\n useCallback,\r\n useContext,\r\n useMemo,\r\n} from \"react\";\r\nimport {\r\n useUserQuery,\r\n useSetUserData,\r\n useInvalidateUser,\r\n useUserValidateSession,\r\n} from \"../modules/auth/hooks/useUserQuery\";\r\nimport { useLogin } from \"../modules/auth/hooks/login.hook\";\r\nimport { useRegister } from \"../modules/auth/hooks/register.hook\";\r\nimport { useLogout } from \"../modules/auth/hooks/logout.hook\";\r\nimport {\r\n AuthState,\r\n LoginRequest,\r\n RegisterRequest,\r\n} from \"../modules/auth/schema\";\r\nimport {\r\n useCurrentAccount,\r\n useInvalidateAccount,\r\n} from \"../modules/accounts/hooks/current-account.hook\";\r\nimport { useRouter } from \"next/navigation\";\r\n\r\ninterface AuthContextProps extends AuthState {\r\n login: (credentials: LoginRequest) => Promise<void>;\r\n register: (data: RegisterRequest) => Promise<void>;\r\n logout: () => Promise<void>;\r\n}\r\n\r\nexport const AuthContext = createContext<AuthContextProps | undefined>(\r\n undefined,\r\n);\r\n\r\ninterface AuthProviderProps {\r\n children: ReactNode;\r\n}\r\n\r\nexport function AuthProvider({ children }: AuthProviderProps) {\r\n const { data: user, isLoading: isQueryLoading } = useUserQuery();\r\n const { data: account, isLoading: isAccountLoading } = useCurrentAccount();\r\n const { isLoading: isSessionLoading } = useUserValidateSession();\r\n\r\n const setUserData = useSetUserData();\r\n const invalidateUser = useInvalidateUser();\r\n const invalidateAccount = useInvalidateAccount();\r\n\r\n const router = useRouter();\r\n\r\n const { mutateAsync: loginMutate, isPending: isLogging } = useLogin();\r\n const { mutateAsync: registerMutate, isPending: isRegistering } =\r\n useRegister();\r\n const { mutateAsync: logoutMutate, isPending: isLoggingOut } = useLogout();\r\n\r\n const isAuthenticated = !!user;\r\n const isLoading =\r\n isLogging ||\r\n isRegistering ||\r\n isLoggingOut ||\r\n isQueryLoading ||\r\n isAccountLoading ||\r\n isSessionLoading;\r\n\r\n const login = useCallback(\r\n async (credentials: LoginRequest): Promise<void> => {\r\n await loginMutate(credentials, {\r\n onSuccess: (data) => {\r\n invalidateUser();\r\n invalidateAccount();\r\n setUserData(data.user);\r\n },\r\n });\r\n },\r\n [setUserData, invalidateUser, invalidateAccount],\r\n );\r\n\r\n const register = useCallback(\r\n async (data: RegisterRequest): Promise<void> => {\r\n await registerMutate(data, {\r\n onSuccess: (data) => {\r\n invalidateUser();\r\n invalidateAccount();\r\n setUserData(data.user);\r\n },\r\n });\r\n },\r\n [setUserData, invalidateUser, invalidateAccount],\r\n );\r\n\r\n const logout = useCallback(async (): Promise<void> => {\r\n await logoutMutate(undefined, {\r\n onSuccess: () => {\r\n invalidateUser();\r\n router.push(\"/login\");\r\n },\r\n });\r\n }, [setUserData]);\r\n\r\n const value: AuthContextProps = useMemo(\r\n () => ({\r\n user: user ?? null,\r\n account: account ?? null,\r\n isAuthenticated,\r\n isLoading,\r\n login,\r\n register,\r\n logout,\r\n }),\r\n [user, isAuthenticated, isLoading, login, register, logout],\r\n );\r\n\r\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\r\n}\r\n\r\nexport function useAuth(): AuthContextProps {\r\n const context = useContext(AuthContext);\r\n\r\n if (context === undefined) {\r\n throw new Error(\"useAuth deve ser usado dentro de um AuthProvider\");\r\n }\r\n\r\n return context;\r\n}\r\n"],"mappings":";
|
|
1
|
+
{"version":3,"sources":["../../src/providers/auth.provider.tsx"],"sourcesContent":["\"use client\";\r\n\r\nimport {\r\n createContext,\r\n ReactNode,\r\n useCallback,\r\n useContext,\r\n useMemo,\r\n} from \"react\";\r\nimport {\r\n useUserQuery,\r\n useSetUserData,\r\n useInvalidateUser,\r\n useUserValidateSession,\r\n} from \"../modules/auth/hooks/useUserQuery\";\r\nimport { useLogin } from \"../modules/auth/hooks/login.hook\";\r\nimport { useRegister } from \"../modules/auth/hooks/register.hook\";\r\nimport { useLogout } from \"../modules/auth/hooks/logout.hook\";\r\nimport {\r\n AuthState,\r\n LoginRequest,\r\n RegisterRequest,\r\n} from \"../modules/auth/schema\";\r\nimport {\r\n useCurrentAccount,\r\n useInvalidateAccount,\r\n} from \"../modules/accounts/hooks/current-account.hook\";\r\nimport { useRouter } from \"next/navigation\";\r\n\r\ninterface AuthContextProps extends AuthState {\r\n login: (credentials: LoginRequest) => Promise<void>;\r\n register: (data: RegisterRequest) => Promise<void>;\r\n logout: () => Promise<void>;\r\n}\r\n\r\nexport const AuthContext = createContext<AuthContextProps | undefined>(\r\n undefined,\r\n);\r\n\r\ninterface AuthProviderProps {\r\n children: ReactNode;\r\n}\r\n\r\nexport function AuthProvider({ children }: AuthProviderProps) {\r\n const { data: user, isLoading: isQueryLoading } = useUserQuery();\r\n const { data: account, isLoading: isAccountLoading } = useCurrentAccount();\r\n const { isLoading: isSessionLoading } = useUserValidateSession();\r\n\r\n const setUserData = useSetUserData();\r\n const invalidateUser = useInvalidateUser();\r\n const invalidateAccount = useInvalidateAccount();\r\n\r\n const router = useRouter();\r\n\r\n const { mutateAsync: loginMutate, isPending: isLogging } = useLogin();\r\n const { mutateAsync: registerMutate, isPending: isRegistering } =\r\n useRegister();\r\n const { mutateAsync: logoutMutate, isPending: isLoggingOut } = useLogout();\r\n\r\n const isAuthenticated = !!user;\r\n const isLoading =\r\n isLogging ||\r\n isRegistering ||\r\n isLoggingOut ||\r\n isQueryLoading ||\r\n isAccountLoading ||\r\n isSessionLoading;\r\n\r\n const login = useCallback(\r\n async (credentials: LoginRequest): Promise<void> => {\r\n await loginMutate(credentials, {\r\n onSuccess: (data) => {\r\n if (data.twoFactorRequired) return;\r\n invalidateUser();\r\n invalidateAccount();\r\n setUserData(data.user);\r\n },\r\n });\r\n },\r\n [setUserData, invalidateUser, invalidateAccount],\r\n );\r\n\r\n const register = useCallback(\r\n async (data: RegisterRequest): Promise<void> => {\r\n await registerMutate(data, {\r\n onSuccess: (data) => {\r\n invalidateUser();\r\n invalidateAccount();\r\n setUserData(data.user);\r\n },\r\n });\r\n },\r\n [setUserData, invalidateUser, invalidateAccount],\r\n );\r\n\r\n const logout = useCallback(async (): Promise<void> => {\r\n await logoutMutate(undefined, {\r\n onSuccess: () => {\r\n invalidateUser();\r\n router.push(\"/login\");\r\n },\r\n });\r\n }, [setUserData]);\r\n\r\n const value: AuthContextProps = useMemo(\r\n () => ({\r\n user: user ?? null,\r\n account: account ?? null,\r\n isAuthenticated,\r\n isLoading,\r\n login,\r\n register,\r\n logout,\r\n }),\r\n [user, isAuthenticated, isLoading, login, register, logout],\r\n );\r\n\r\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\r\n}\r\n\r\nexport function useAuth(): AuthContextProps {\r\n const context = useContext(AuthContext);\r\n\r\n if (context === undefined) {\r\n throw new Error(\"useAuth deve ser usado dentro de um AuthProvider\");\r\n }\r\n\r\n return context;\r\n}\r\n"],"mappings":";AAqHS;AAnHT;AAAA,EACE;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,gBAAgB;AACzB,SAAS,mBAAmB;AAC5B,SAAS,iBAAiB;AAM1B;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,iBAAiB;AAQnB,MAAM,cAAc;AAAA,EACzB;AACF;AAMO,SAAS,aAAa,EAAE,SAAS,GAAsB;AAC5D,QAAM,EAAE,MAAM,MAAM,WAAW,eAAe,IAAI,aAAa;AAC/D,QAAM,EAAE,MAAM,SAAS,WAAW,iBAAiB,IAAI,kBAAkB;AACzE,QAAM,EAAE,WAAW,iBAAiB,IAAI,uBAAuB;AAE/D,QAAM,cAAc,eAAe;AACnC,QAAM,iBAAiB,kBAAkB;AACzC,QAAM,oBAAoB,qBAAqB;AAE/C,QAAM,SAAS,UAAU;AAEzB,QAAM,EAAE,aAAa,aAAa,WAAW,UAAU,IAAI,SAAS;AACpE,QAAM,EAAE,aAAa,gBAAgB,WAAW,cAAc,IAC5D,YAAY;AACd,QAAM,EAAE,aAAa,cAAc,WAAW,aAAa,IAAI,UAAU;AAEzE,QAAM,kBAAkB,CAAC,CAAC;AAC1B,QAAM,YACJ,aACA,iBACA,gBACA,kBACA,oBACA;AAEF,QAAM,QAAQ;AAAA,IACZ,OAAO,gBAA6C;AAClD,YAAM,YAAY,aAAa;AAAA,QAC7B,WAAW,CAAC,SAAS;AACnB,cAAI,KAAK,kBAAmB;AAC5B,yBAAe;AACf,4BAAkB;AAClB,sBAAY,KAAK,IAAI;AAAA,QACvB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACA,CAAC,aAAa,gBAAgB,iBAAiB;AAAA,EACjD;AAEA,QAAM,WAAW;AAAA,IACf,OAAO,SAAyC;AAC9C,YAAM,eAAe,MAAM;AAAA,QACzB,WAAW,CAACA,UAAS;AACnB,yBAAe;AACf,4BAAkB;AAClB,sBAAYA,MAAK,IAAI;AAAA,QACvB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACA,CAAC,aAAa,gBAAgB,iBAAiB;AAAA,EACjD;AAEA,QAAM,SAAS,YAAY,YAA2B;AACpD,UAAM,aAAa,QAAW;AAAA,MAC5B,WAAW,MAAM;AACf,uBAAe;AACf,eAAO,KAAK,QAAQ;AAAA,MACtB;AAAA,IACF,CAAC;AAAA,EACH,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,QAA0B;AAAA,IAC9B,OAAO;AAAA,MACL,MAAM,QAAQ;AAAA,MACd,SAAS,WAAW;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,MAAM,iBAAiB,WAAW,OAAO,UAAU,MAAM;AAAA,EAC5D;AAEA,SAAO,oBAAC,YAAY,UAAZ,EAAqB,OAAe,UAAS;AACvD;AAEO,SAAS,UAA4B;AAC1C,QAAM,UAAU,WAAW,WAAW;AAEtC,MAAI,YAAY,QAAW;AACzB,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AAEA,SAAO;AACT;","names":["data"]}
|
package/package.json
CHANGED
|
@@ -39,7 +39,7 @@ export async function validateSessionAction(): Promise<boolean> {
|
|
|
39
39
|
const isValid = await authService.validateSession(clientInfo);
|
|
40
40
|
|
|
41
41
|
if (!isValid) {
|
|
42
|
-
|
|
42
|
+
await authService.removeAuthCookie();
|
|
43
43
|
await redirectToLogin();
|
|
44
44
|
return false;
|
|
45
45
|
}
|
|
@@ -47,7 +47,7 @@ export async function validateSessionAction(): Promise<boolean> {
|
|
|
47
47
|
return true;
|
|
48
48
|
} catch (error) {
|
|
49
49
|
console.error('[validateSessionAction] Error:', error);
|
|
50
|
-
|
|
50
|
+
await authService.removeAuthCookie();
|
|
51
51
|
await redirectToLogin();
|
|
52
52
|
return false;
|
|
53
53
|
}
|
|
@@ -11,6 +11,7 @@ export interface ClientInfo {
|
|
|
11
11
|
export interface LoginApiResponse {
|
|
12
12
|
status: 0 | 1;
|
|
13
13
|
message: string;
|
|
14
|
+
code?: string;
|
|
14
15
|
cookie?: string;
|
|
15
16
|
two_factor_authentication?: boolean;
|
|
16
17
|
}
|
|
@@ -31,6 +32,7 @@ export interface TwoFactorRequest {
|
|
|
31
32
|
export interface TwoFactorApiResponse {
|
|
32
33
|
status: 0 | 1;
|
|
33
34
|
message: string;
|
|
35
|
+
code?: string;
|
|
34
36
|
cookie?: string;
|
|
35
37
|
}
|
|
36
38
|
|
|
@@ -231,6 +233,7 @@ export interface LogoutRequest {
|
|
|
231
233
|
export interface LogoutApiResponse {
|
|
232
234
|
status: 0 | 1;
|
|
233
235
|
message: string;
|
|
236
|
+
code?: string;
|
|
234
237
|
}
|
|
235
238
|
|
|
236
239
|
export interface LogoutResponse {
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
+
import { cookies } from "next/headers";
|
|
1
2
|
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
import { ApiError } from '../../../infra/api/types';
|
|
6
|
-
import { User } from '../../users/schema';
|
|
3
|
+
import { apiClient } from "../../../infra/api/client";
|
|
4
|
+
import { ApiError } from "../../../infra/api/types";
|
|
5
|
+
import { User } from "../../users/schema";
|
|
7
6
|
import {
|
|
8
7
|
ClientInfo,
|
|
9
8
|
ForgotPasswordRequest,
|
|
@@ -30,40 +29,27 @@ import {
|
|
|
30
29
|
TwoFactorResponse,
|
|
31
30
|
VerifyEmailRequest,
|
|
32
31
|
VerifyEmailResponse,
|
|
33
|
-
} from
|
|
32
|
+
} from "../schema";
|
|
34
33
|
|
|
35
|
-
const AUTH_COOKIE_NAME =
|
|
36
|
-
const PENDING_2FA_COOKIE_NAME =
|
|
34
|
+
const AUTH_COOKIE_NAME = "greatapps";
|
|
35
|
+
const PENDING_2FA_COOKIE_NAME = "greatapps_2fa_pending";
|
|
37
36
|
const COOKIE_MAX_AGE = 60 * 60 * 24 * 30;
|
|
38
37
|
const PENDING_2FA_MAX_AGE = 60 * 10; // 10 minutos para completar o 2FA
|
|
39
38
|
|
|
40
39
|
const COOKIE_OPTIONS = {
|
|
41
40
|
httpOnly: true,
|
|
42
|
-
secure: process.env.NODE_ENV ===
|
|
43
|
-
sameSite:
|
|
44
|
-
path:
|
|
41
|
+
secure: process.env.NODE_ENV === "production",
|
|
42
|
+
sameSite: "lax" as const,
|
|
43
|
+
path: "/",
|
|
45
44
|
domain: process.env.DOMAIN_COOKIE,
|
|
46
45
|
};
|
|
47
46
|
|
|
48
|
-
async function setAuthCookie(token: string): Promise<void> {
|
|
49
|
-
const cookieStore = await cookies();
|
|
50
|
-
cookieStore.set(AUTH_COOKIE_NAME, token, { ...COOKIE_OPTIONS, maxAge: COOKIE_MAX_AGE });
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async function removeAuthCookie(): Promise<void> {
|
|
54
|
-
const cookieStore = await cookies();
|
|
55
|
-
cookieStore.delete({ name: AUTH_COOKIE_NAME, ...COOKIE_OPTIONS });
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
async function getAuthCookie(): Promise<string | undefined> {
|
|
59
|
-
if (process.env.DUMMY_AUTH_TOKEN) return process.env.DUMMY_AUTH_TOKEN;
|
|
60
|
-
const cookieStore = await cookies();
|
|
61
|
-
return cookieStore.get(AUTH_COOKIE_NAME)?.value;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
47
|
async function setPending2FACookie(token: string): Promise<void> {
|
|
65
48
|
const cookieStore = await cookies();
|
|
66
|
-
cookieStore.set(PENDING_2FA_COOKIE_NAME, token, {
|
|
49
|
+
cookieStore.set(PENDING_2FA_COOKIE_NAME, token, {
|
|
50
|
+
...COOKIE_OPTIONS,
|
|
51
|
+
maxAge: PENDING_2FA_MAX_AGE,
|
|
52
|
+
});
|
|
67
53
|
}
|
|
68
54
|
|
|
69
55
|
async function removePending2FACookie(): Promise<void> {
|
|
@@ -77,8 +63,11 @@ async function getPending2FACookie(): Promise<string | undefined> {
|
|
|
77
63
|
}
|
|
78
64
|
|
|
79
65
|
class AuthService {
|
|
80
|
-
async login(
|
|
81
|
-
|
|
66
|
+
async login(
|
|
67
|
+
credentials: LoginRequest,
|
|
68
|
+
clientInfo: ClientInfo
|
|
69
|
+
): Promise<LoginResponse> {
|
|
70
|
+
const response = await apiClient.post<LoginApiResponse>("/auth/login", {
|
|
82
71
|
email: credentials.email,
|
|
83
72
|
password: credentials.password,
|
|
84
73
|
location: clientInfo.location,
|
|
@@ -88,35 +77,48 @@ class AuthService {
|
|
|
88
77
|
});
|
|
89
78
|
|
|
90
79
|
if (response.status === 0) {
|
|
91
|
-
throw new ApiError(
|
|
80
|
+
throw new ApiError(
|
|
81
|
+
response.message || "E-mail ou senha incorretos",
|
|
82
|
+
response.code || "LOGIN_FAILED",
|
|
83
|
+
401
|
|
84
|
+
);
|
|
92
85
|
}
|
|
93
86
|
|
|
94
87
|
if (!response.cookie) {
|
|
95
|
-
throw new ApiError(
|
|
88
|
+
throw new ApiError(
|
|
89
|
+
"Resposta de autenticação inválida",
|
|
90
|
+
"INVALID_RESPONSE",
|
|
91
|
+
500
|
|
92
|
+
);
|
|
96
93
|
}
|
|
97
94
|
|
|
98
95
|
if (response.two_factor_authentication) {
|
|
99
|
-
// Armazena o cookie temporariamente até o 2FA ser concluído.
|
|
100
|
-
// O cookie principal NÃO é setado aqui para evitar falso positivo em isAuthenticated().
|
|
101
96
|
await setPending2FACookie(response.cookie);
|
|
102
97
|
return { twoFactorRequired: true };
|
|
103
98
|
}
|
|
104
99
|
|
|
105
|
-
await setAuthCookie(response.cookie);
|
|
100
|
+
await this.setAuthCookie(response.cookie);
|
|
106
101
|
|
|
107
102
|
return {
|
|
108
103
|
user: {} as User,
|
|
109
104
|
accessToken: response.cookie,
|
|
110
|
-
refreshToken:
|
|
105
|
+
refreshToken: "",
|
|
111
106
|
expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),
|
|
112
107
|
};
|
|
113
108
|
}
|
|
114
109
|
|
|
115
|
-
async verifyTwoFactor(
|
|
110
|
+
async verifyTwoFactor(
|
|
111
|
+
code: number,
|
|
112
|
+
clientInfo: ClientInfo
|
|
113
|
+
): Promise<TwoFactorResponse> {
|
|
116
114
|
const pendingCookie = await getPending2FACookie();
|
|
117
115
|
|
|
118
116
|
if (!pendingCookie) {
|
|
119
|
-
throw new ApiError(
|
|
117
|
+
throw new ApiError(
|
|
118
|
+
"Nenhuma autenticação 2FA pendente",
|
|
119
|
+
"NO_PENDING_2FA",
|
|
120
|
+
400
|
|
121
|
+
);
|
|
120
122
|
}
|
|
121
123
|
|
|
122
124
|
const payload: TwoFactorRequest = {
|
|
@@ -128,17 +130,31 @@ class AuthService {
|
|
|
128
130
|
code,
|
|
129
131
|
};
|
|
130
132
|
|
|
131
|
-
const response = await apiClient.post<TwoFactorApiResponse>(
|
|
133
|
+
const response = await apiClient.post<TwoFactorApiResponse>(
|
|
134
|
+
"/auth/code",
|
|
135
|
+
payload
|
|
136
|
+
);
|
|
132
137
|
|
|
133
138
|
if (response.status === 0) {
|
|
134
|
-
throw new ApiError(
|
|
139
|
+
throw new ApiError(
|
|
140
|
+
response.message || "Código 2FA inválido",
|
|
141
|
+
response.code || "TWO_FACTOR_FAILED",
|
|
142
|
+
401
|
|
143
|
+
);
|
|
135
144
|
}
|
|
136
145
|
|
|
137
146
|
if (!response.cookie) {
|
|
138
|
-
throw new ApiError(
|
|
147
|
+
throw new ApiError(
|
|
148
|
+
"Resposta de autenticação inválida após 2FA",
|
|
149
|
+
"INVALID_RESPONSE",
|
|
150
|
+
500
|
|
151
|
+
);
|
|
139
152
|
}
|
|
140
153
|
|
|
141
|
-
await Promise.all([
|
|
154
|
+
await Promise.all([
|
|
155
|
+
this.setAuthCookie(response.cookie),
|
|
156
|
+
removePending2FACookie(),
|
|
157
|
+
]);
|
|
142
158
|
|
|
143
159
|
return { success: true };
|
|
144
160
|
}
|
|
@@ -156,39 +172,50 @@ class AuthService {
|
|
|
156
172
|
const payload: RegisterApiRequest = {
|
|
157
173
|
name: data.accountName,
|
|
158
174
|
bussiness_type: data.businessType,
|
|
159
|
-
language:
|
|
160
|
-
timezone:
|
|
161
|
-
currency:
|
|
175
|
+
language: "pt-br",
|
|
176
|
+
timezone: "America/Sao_Paulo",
|
|
177
|
+
currency: "BRL",
|
|
162
178
|
user: {
|
|
163
|
-
id_api:
|
|
179
|
+
id_api: "",
|
|
164
180
|
name: data.name,
|
|
165
|
-
last_name: data.lastName ||
|
|
166
|
-
rg: data.rg ||
|
|
167
|
-
cpf: data.cpf ||
|
|
181
|
+
last_name: data.lastName || "",
|
|
182
|
+
rg: data.rg || "",
|
|
183
|
+
cpf: data.cpf || "",
|
|
168
184
|
gender: data.gender,
|
|
169
185
|
email: data.email,
|
|
170
186
|
phone: data.phone,
|
|
171
187
|
password: data.password,
|
|
172
|
-
profile:
|
|
173
|
-
language:
|
|
188
|
+
profile: "owner",
|
|
189
|
+
language: "pt-br",
|
|
174
190
|
},
|
|
175
191
|
subscription: {
|
|
176
|
-
type:
|
|
177
|
-
id_cupom:
|
|
192
|
+
type: "trial",
|
|
193
|
+
id_cupom: "",
|
|
178
194
|
id_plan: 1,
|
|
179
|
-
due_date: trialEndDate.toISOString().split(
|
|
195
|
+
due_date: trialEndDate.toISOString().split("T")[0],
|
|
180
196
|
id_product: 1,
|
|
181
197
|
},
|
|
182
198
|
};
|
|
183
199
|
|
|
184
|
-
const response = await apiClient.post<RegisterApiResponse>(
|
|
200
|
+
const response = await apiClient.post<RegisterApiResponse>(
|
|
201
|
+
"/accounts",
|
|
202
|
+
payload
|
|
203
|
+
);
|
|
185
204
|
|
|
186
205
|
if (response.status === 0) {
|
|
187
|
-
throw new ApiError(
|
|
206
|
+
throw new ApiError(
|
|
207
|
+
response.message || "Erro ao criar conta",
|
|
208
|
+
"REGISTER_FAILED",
|
|
209
|
+
400
|
|
210
|
+
);
|
|
188
211
|
}
|
|
189
212
|
|
|
190
213
|
if (!response.data || response.data.length === 0) {
|
|
191
|
-
throw new ApiError(
|
|
214
|
+
throw new ApiError(
|
|
215
|
+
"Resposta de registro inválida",
|
|
216
|
+
"INVALID_RESPONSE",
|
|
217
|
+
500
|
|
218
|
+
);
|
|
192
219
|
}
|
|
193
220
|
|
|
194
221
|
const accountData = response.data[0];
|
|
@@ -198,18 +225,22 @@ class AuthService {
|
|
|
198
225
|
// O usuário completo será carregado após o login
|
|
199
226
|
return {
|
|
200
227
|
user: {} as User, // Placeholder, será preenchido após login
|
|
201
|
-
accessToken:
|
|
202
|
-
refreshToken:
|
|
228
|
+
accessToken: "",
|
|
229
|
+
refreshToken: "",
|
|
203
230
|
expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),
|
|
204
231
|
requiresEmailVerification: !accountData.verified,
|
|
205
232
|
};
|
|
206
233
|
}
|
|
207
234
|
|
|
208
235
|
async logout(clientInfo: ClientInfo): Promise<LogoutResponse> {
|
|
209
|
-
const cookie = await
|
|
236
|
+
const cookie = await this.getToken();
|
|
210
237
|
|
|
211
238
|
if (!cookie) {
|
|
212
|
-
throw new ApiError(
|
|
239
|
+
throw new ApiError(
|
|
240
|
+
"Usuário não autenticado",
|
|
241
|
+
"NOT_AUTHENTICATED_LOGOUT",
|
|
242
|
+
401
|
|
243
|
+
);
|
|
213
244
|
}
|
|
214
245
|
|
|
215
246
|
const payload: LogoutRequest = {
|
|
@@ -221,13 +252,20 @@ class AuthService {
|
|
|
221
252
|
};
|
|
222
253
|
|
|
223
254
|
try {
|
|
224
|
-
const response = await apiClient.post<LogoutApiResponse>(
|
|
255
|
+
const response = await apiClient.post<LogoutApiResponse>(
|
|
256
|
+
"/auth/logout",
|
|
257
|
+
payload
|
|
258
|
+
);
|
|
225
259
|
|
|
226
260
|
if (response.status === 0) {
|
|
227
|
-
throw new ApiError(
|
|
261
|
+
throw new ApiError(
|
|
262
|
+
response.message || "Erro ao realizar logout",
|
|
263
|
+
response.code || "LOGOUT_FAILED",
|
|
264
|
+
400
|
|
265
|
+
);
|
|
228
266
|
}
|
|
229
267
|
} finally {
|
|
230
|
-
await Promise.all([removeAuthCookie(), removePending2FACookie()]);
|
|
268
|
+
await Promise.all([this.removeAuthCookie(), removePending2FACookie()]);
|
|
231
269
|
}
|
|
232
270
|
|
|
233
271
|
return {
|
|
@@ -235,24 +273,46 @@ class AuthService {
|
|
|
235
273
|
};
|
|
236
274
|
}
|
|
237
275
|
|
|
238
|
-
async forgotPassword(
|
|
239
|
-
|
|
276
|
+
async forgotPassword(
|
|
277
|
+
_data: ForgotPasswordRequest
|
|
278
|
+
): Promise<ForgotPasswordResponse> {
|
|
279
|
+
throw new ApiError(
|
|
280
|
+
"Recuperação de senha não implementada",
|
|
281
|
+
"NOT_IMPLEMENTED",
|
|
282
|
+
501
|
|
283
|
+
);
|
|
240
284
|
}
|
|
241
285
|
|
|
242
|
-
async resetPassword(
|
|
243
|
-
|
|
286
|
+
async resetPassword(
|
|
287
|
+
_data: ResetPasswordRequest
|
|
288
|
+
): Promise<ResetPasswordResponse> {
|
|
289
|
+
throw new ApiError(
|
|
290
|
+
"Redefinição de senha não implementada",
|
|
291
|
+
"NOT_IMPLEMENTED",
|
|
292
|
+
501
|
|
293
|
+
);
|
|
244
294
|
}
|
|
245
295
|
|
|
246
296
|
async verifyEmail(_data: VerifyEmailRequest): Promise<VerifyEmailResponse> {
|
|
247
|
-
throw new ApiError(
|
|
297
|
+
throw new ApiError(
|
|
298
|
+
"Verificação de email não implementada",
|
|
299
|
+
"NOT_IMPLEMENTED",
|
|
300
|
+
501
|
|
301
|
+
);
|
|
248
302
|
}
|
|
249
303
|
|
|
250
|
-
async resendVerification(
|
|
251
|
-
|
|
304
|
+
async resendVerification(
|
|
305
|
+
_data: ResendVerificationRequest
|
|
306
|
+
): Promise<ResendVerificationResponse> {
|
|
307
|
+
throw new ApiError(
|
|
308
|
+
"Reenvio de verificação não implementado",
|
|
309
|
+
"NOT_IMPLEMENTED",
|
|
310
|
+
501
|
|
311
|
+
);
|
|
252
312
|
}
|
|
253
313
|
|
|
254
314
|
async validateSession(clientInfo: ClientInfo): Promise<boolean> {
|
|
255
|
-
const cookie = await
|
|
315
|
+
const cookie = await this.getToken();
|
|
256
316
|
|
|
257
317
|
if (!cookie) {
|
|
258
318
|
return false;
|
|
@@ -267,22 +327,43 @@ class AuthService {
|
|
|
267
327
|
cookie,
|
|
268
328
|
};
|
|
269
329
|
|
|
270
|
-
const response = await apiClient.post<SessionKeepResponse>(
|
|
330
|
+
const response = await apiClient.post<SessionKeepResponse>(
|
|
331
|
+
"/auth/keep",
|
|
332
|
+
payload
|
|
333
|
+
);
|
|
271
334
|
|
|
272
335
|
return response.status === 1;
|
|
273
336
|
} catch (error) {
|
|
274
|
-
console.error(
|
|
337
|
+
console.error("[AuthService] validateSession error", error);
|
|
275
338
|
return false;
|
|
276
339
|
}
|
|
277
340
|
}
|
|
278
341
|
|
|
279
342
|
async isAuthenticated(): Promise<boolean> {
|
|
280
|
-
const token = await
|
|
343
|
+
const token = await this.getToken();
|
|
281
344
|
return !!token;
|
|
282
345
|
}
|
|
283
346
|
|
|
284
347
|
async getToken(): Promise<string | undefined> {
|
|
285
|
-
|
|
348
|
+
if (process.env.DUMMY_AUTH_TOKEN) return process.env.DUMMY_AUTH_TOKEN;
|
|
349
|
+
const cookieStore = await cookies();
|
|
350
|
+
return cookieStore.get(AUTH_COOKIE_NAME)?.value;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
private async setAuthCookie(token: string): Promise<void> {
|
|
354
|
+
const cookieStore = await cookies();
|
|
355
|
+
cookieStore.set(AUTH_COOKIE_NAME, token, {
|
|
356
|
+
...COOKIE_OPTIONS,
|
|
357
|
+
maxAge: COOKIE_MAX_AGE,
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
async removeAuthCookie(): Promise<void> {
|
|
362
|
+
const cookieStore = await cookies();
|
|
363
|
+
cookieStore.delete({
|
|
364
|
+
name: AUTH_COOKIE_NAME,
|
|
365
|
+
...COOKIE_OPTIONS,
|
|
366
|
+
});
|
|
286
367
|
}
|
|
287
368
|
}
|
|
288
369
|
|
|
@@ -14,7 +14,7 @@ export async function getUserContext(): Promise<{
|
|
|
14
14
|
const token = process.env.DUMMY_AUTH_TOKEN || cookieStore.get(AUTH_COOKIE_NAME)?.value;
|
|
15
15
|
|
|
16
16
|
if (!token) {
|
|
17
|
-
throw new ApiError('Usuário não autenticado', '
|
|
17
|
+
throw new ApiError('Usuário não autenticado', 'NOT_AUTHENTICATED_GUC', 401);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
try {
|
|
@@ -15,7 +15,7 @@ class UserService {
|
|
|
15
15
|
const token = cookieStore.get(AUTH_COOKIE_NAME)?.value;
|
|
16
16
|
|
|
17
17
|
if (!token) {
|
|
18
|
-
throw new ApiError('Não autenticado', '
|
|
18
|
+
throw new ApiError('Não autenticado', 'NOT_AUTHENTICATED_GAT', 401);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
return token;
|
|
@@ -70,6 +70,7 @@ export function AuthProvider({ children }: AuthProviderProps) {
|
|
|
70
70
|
async (credentials: LoginRequest): Promise<void> => {
|
|
71
71
|
await loginMutate(credentials, {
|
|
72
72
|
onSuccess: (data) => {
|
|
73
|
+
if (data.twoFactorRequired) return;
|
|
73
74
|
invalidateUser();
|
|
74
75
|
invalidateAccount();
|
|
75
76
|
setUserData(data.user);
|