@greatapps/common 1.1.53 → 1.1.56
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/services/auth.service.mjs +90 -20
- 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/schema.ts +4 -1
- package/src/modules/auth/services/auth.service.ts +134 -57
- 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
|
@@ -14,7 +14,10 @@ const COOKIE_OPTIONS = {
|
|
|
14
14
|
};
|
|
15
15
|
async function setPending2FACookie(token) {
|
|
16
16
|
const cookieStore = await cookies();
|
|
17
|
-
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
|
+
});
|
|
18
21
|
}
|
|
19
22
|
async function removePending2FACookie() {
|
|
20
23
|
const cookieStore = await cookies();
|
|
@@ -35,12 +38,20 @@ class AuthService {
|
|
|
35
38
|
agent: clientInfo.agent
|
|
36
39
|
});
|
|
37
40
|
if (response.status === 0) {
|
|
38
|
-
throw new ApiError(
|
|
41
|
+
throw new ApiError(
|
|
42
|
+
response.message || "E-mail ou senha incorretos",
|
|
43
|
+
response.code || "LOGIN_FAILED",
|
|
44
|
+
401
|
|
45
|
+
);
|
|
39
46
|
}
|
|
40
47
|
if (!response.cookie) {
|
|
41
|
-
throw new ApiError(
|
|
48
|
+
throw new ApiError(
|
|
49
|
+
"Resposta de autentica\xE7\xE3o inv\xE1lida",
|
|
50
|
+
"INVALID_RESPONSE",
|
|
51
|
+
500
|
|
52
|
+
);
|
|
42
53
|
}
|
|
43
|
-
if (response.
|
|
54
|
+
if (response.two_factor_required) {
|
|
44
55
|
await setPending2FACookie(response.cookie);
|
|
45
56
|
return { twoFactorRequired: true };
|
|
46
57
|
}
|
|
@@ -55,7 +66,11 @@ class AuthService {
|
|
|
55
66
|
async verifyTwoFactor(code, clientInfo) {
|
|
56
67
|
const pendingCookie = await getPending2FACookie();
|
|
57
68
|
if (!pendingCookie) {
|
|
58
|
-
throw new ApiError(
|
|
69
|
+
throw new ApiError(
|
|
70
|
+
"Nenhuma autentica\xE7\xE3o 2FA pendente",
|
|
71
|
+
"NO_PENDING_2FA",
|
|
72
|
+
400
|
|
73
|
+
);
|
|
59
74
|
}
|
|
60
75
|
const payload = {
|
|
61
76
|
location: clientInfo.location,
|
|
@@ -65,14 +80,28 @@ class AuthService {
|
|
|
65
80
|
cookie: pendingCookie,
|
|
66
81
|
code
|
|
67
82
|
};
|
|
68
|
-
const response = await apiClient.post(
|
|
83
|
+
const response = await apiClient.post(
|
|
84
|
+
"/auth/code",
|
|
85
|
+
payload
|
|
86
|
+
);
|
|
69
87
|
if (response.status === 0) {
|
|
70
|
-
throw new ApiError(
|
|
88
|
+
throw new ApiError(
|
|
89
|
+
response.message || "C\xF3digo 2FA inv\xE1lido",
|
|
90
|
+
response.code || "TWO_FACTOR_FAILED",
|
|
91
|
+
401
|
|
92
|
+
);
|
|
71
93
|
}
|
|
72
94
|
if (!response.cookie) {
|
|
73
|
-
throw new ApiError(
|
|
95
|
+
throw new ApiError(
|
|
96
|
+
"Resposta de autentica\xE7\xE3o inv\xE1lida ap\xF3s 2FA",
|
|
97
|
+
"INVALID_RESPONSE",
|
|
98
|
+
500
|
|
99
|
+
);
|
|
74
100
|
}
|
|
75
|
-
await Promise.all([
|
|
101
|
+
await Promise.all([
|
|
102
|
+
this.setAuthCookie(response.cookie),
|
|
103
|
+
removePending2FACookie()
|
|
104
|
+
]);
|
|
76
105
|
return { success: true };
|
|
77
106
|
}
|
|
78
107
|
async isTwoFactorPending() {
|
|
@@ -110,12 +139,23 @@ class AuthService {
|
|
|
110
139
|
id_product: 1
|
|
111
140
|
}
|
|
112
141
|
};
|
|
113
|
-
const response = await apiClient.post(
|
|
142
|
+
const response = await apiClient.post(
|
|
143
|
+
"/accounts",
|
|
144
|
+
payload
|
|
145
|
+
);
|
|
114
146
|
if (response.status === 0) {
|
|
115
|
-
throw new ApiError(
|
|
147
|
+
throw new ApiError(
|
|
148
|
+
response.message || "Erro ao criar conta",
|
|
149
|
+
"REGISTER_FAILED",
|
|
150
|
+
400
|
|
151
|
+
);
|
|
116
152
|
}
|
|
117
153
|
if (!response.data || response.data.length === 0) {
|
|
118
|
-
throw new ApiError(
|
|
154
|
+
throw new ApiError(
|
|
155
|
+
"Resposta de registro inv\xE1lida",
|
|
156
|
+
"INVALID_RESPONSE",
|
|
157
|
+
500
|
|
158
|
+
);
|
|
119
159
|
}
|
|
120
160
|
const accountData = response.data[0];
|
|
121
161
|
return {
|
|
@@ -130,7 +170,11 @@ class AuthService {
|
|
|
130
170
|
async logout(clientInfo) {
|
|
131
171
|
const cookie = await this.getToken();
|
|
132
172
|
if (!cookie) {
|
|
133
|
-
throw new ApiError(
|
|
173
|
+
throw new ApiError(
|
|
174
|
+
"Usu\xE1rio n\xE3o autenticado",
|
|
175
|
+
"NOT_AUTHENTICATED_LOGOUT",
|
|
176
|
+
401
|
|
177
|
+
);
|
|
134
178
|
}
|
|
135
179
|
const payload = {
|
|
136
180
|
location: clientInfo.location,
|
|
@@ -140,9 +184,16 @@ class AuthService {
|
|
|
140
184
|
cookie
|
|
141
185
|
};
|
|
142
186
|
try {
|
|
143
|
-
const response = await apiClient.post(
|
|
187
|
+
const response = await apiClient.post(
|
|
188
|
+
"/auth/logout",
|
|
189
|
+
payload
|
|
190
|
+
);
|
|
144
191
|
if (response.status === 0) {
|
|
145
|
-
throw new ApiError(
|
|
192
|
+
throw new ApiError(
|
|
193
|
+
response.message || "Erro ao realizar logout",
|
|
194
|
+
response.code || "LOGOUT_FAILED",
|
|
195
|
+
400
|
|
196
|
+
);
|
|
146
197
|
}
|
|
147
198
|
} finally {
|
|
148
199
|
await Promise.all([this.removeAuthCookie(), removePending2FACookie()]);
|
|
@@ -152,16 +203,32 @@ class AuthService {
|
|
|
152
203
|
};
|
|
153
204
|
}
|
|
154
205
|
async forgotPassword(_data) {
|
|
155
|
-
throw new ApiError(
|
|
206
|
+
throw new ApiError(
|
|
207
|
+
"Recupera\xE7\xE3o de senha n\xE3o implementada",
|
|
208
|
+
"NOT_IMPLEMENTED",
|
|
209
|
+
501
|
|
210
|
+
);
|
|
156
211
|
}
|
|
157
212
|
async resetPassword(_data) {
|
|
158
|
-
throw new ApiError(
|
|
213
|
+
throw new ApiError(
|
|
214
|
+
"Redefini\xE7\xE3o de senha n\xE3o implementada",
|
|
215
|
+
"NOT_IMPLEMENTED",
|
|
216
|
+
501
|
|
217
|
+
);
|
|
159
218
|
}
|
|
160
219
|
async verifyEmail(_data) {
|
|
161
|
-
throw new ApiError(
|
|
220
|
+
throw new ApiError(
|
|
221
|
+
"Verifica\xE7\xE3o de email n\xE3o implementada",
|
|
222
|
+
"NOT_IMPLEMENTED",
|
|
223
|
+
501
|
|
224
|
+
);
|
|
162
225
|
}
|
|
163
226
|
async resendVerification(_data) {
|
|
164
|
-
throw new ApiError(
|
|
227
|
+
throw new ApiError(
|
|
228
|
+
"Reenvio de verifica\xE7\xE3o n\xE3o implementado",
|
|
229
|
+
"NOT_IMPLEMENTED",
|
|
230
|
+
501
|
|
231
|
+
);
|
|
165
232
|
}
|
|
166
233
|
async validateSession(clientInfo) {
|
|
167
234
|
const cookie = await this.getToken();
|
|
@@ -176,7 +243,10 @@ class AuthService {
|
|
|
176
243
|
agent: clientInfo.agent,
|
|
177
244
|
cookie
|
|
178
245
|
};
|
|
179
|
-
const response = await apiClient.post(
|
|
246
|
+
const response = await apiClient.post(
|
|
247
|
+
"/auth/keep",
|
|
248
|
+
payload
|
|
249
|
+
);
|
|
180
250
|
return response.status === 1;
|
|
181
251
|
} catch (error) {
|
|
182
252
|
console.error("[AuthService] validateSession error", error);
|
|
@@ -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 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 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(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([this.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 this.getToken();\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([this.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 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>('/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 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\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\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":[]}
|
|
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_required) {\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":"AAAA,SAAS,eAAe;AAExB,SAAS,iBAAiB;AAC1B,SAAS,gBAAgB;AA8BzB,MAAM,mBAAmB;AACzB,MAAM,0BAA0B;AAChC,MAAM,iBAAiB,KAAK,KAAK,KAAK;AACtC,MAAM,sBAAsB,KAAK;AAEjC,MAAM,iBAAiB;AAAA,EACrB,UAAU;AAAA,EACV,QAAQ,QAAQ,IAAI,aAAa;AAAA,EACjC,UAAU;AAAA,EACV,MAAM;AAAA,EACN,QAAQ,QAAQ,IAAI;AACtB;AAEA,eAAe,oBAAoB,OAA8B;AAC/D,QAAM,cAAc,MAAM,QAAQ;AAClC,cAAY,IAAI,yBAAyB,OAAO;AAAA,IAC9C,GAAG;AAAA,IACH,QAAQ;AAAA,EACV,CAAC;AACH;AAEA,eAAe,yBAAwC;AACrD,QAAM,cAAc,MAAM,QAAQ;AAClC,cAAY,OAAO,EAAE,MAAM,yBAAyB,GAAG,eAAe,CAAC;AACzE;AAEA,eAAe,sBAAmD;AAChE,QAAM,cAAc,MAAM,QAAQ;AAClC,SAAO,YAAY,IAAI,uBAAuB,GAAG;AACnD;AAEA,MAAM,YAAY;AAAA,EAChB,MAAM,MACJ,aACA,YACwB;AACxB,UAAM,WAAW,MAAM,UAAU,KAAuB,eAAe;AAAA,MACrE,OAAO,YAAY;AAAA,MACnB,UAAU,YAAY;AAAA,MACtB,UAAU,WAAW;AAAA,MACrB,IAAI,WAAW;AAAA,MACf,UAAU,WAAW;AAAA,MACrB,OAAO,WAAW;AAAA,IACpB,CAAC;AAED,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI;AAAA,QACR,SAAS,WAAW;AAAA,QACpB,SAAS,QAAQ;AAAA,QACjB;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,QAAQ;AACpB,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,SAAS,qBAAqB;AAChC,YAAM,oBAAoB,SAAS,MAAM;AACzC,aAAO,EAAE,mBAAmB,KAAK;AAAA,IACnC;AAEA,UAAM,KAAK,cAAc,SAAS,MAAM;AAExC,WAAO;AAAA,MACL,MAAM,CAAC;AAAA,MACP,aAAa,SAAS;AAAA,MACtB,cAAc;AAAA,MACd,WAAW,IAAI,KAAK,KAAK,IAAI,IAAI,iBAAiB,GAAI,EAAE,YAAY;AAAA,IACtE;AAAA,EACF;AAAA,EAEA,MAAM,gBACJ,MACA,YAC4B;AAC5B,UAAM,gBAAgB,MAAM,oBAAoB;AAEhD,QAAI,CAAC,eAAe;AAClB,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,UAA4B;AAAA,MAChC,UAAU,WAAW;AAAA,MACrB,IAAI,WAAW;AAAA,MACf,UAAU,WAAW;AAAA,MACrB,OAAO,WAAW;AAAA,MAClB,QAAQ;AAAA,MACR;AAAA,IACF;AAEA,UAAM,WAAW,MAAM,UAAU;AAAA,MAC/B;AAAA,MACA;AAAA,IACF;AAEA,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI;AAAA,QACR,SAAS,WAAW;AAAA,QACpB,SAAS,QAAQ;AAAA,QACjB;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,QAAQ;AACpB,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,QAAQ,IAAI;AAAA,MAChB,KAAK,cAAc,SAAS,MAAM;AAAA,MAClC,uBAAuB;AAAA,IACzB,CAAC;AAED,WAAO,EAAE,SAAS,KAAK;AAAA,EACzB;AAAA,EAEA,MAAM,qBAAuC;AAC3C,UAAM,UAAU,MAAM,oBAAoB;AAC1C,WAAO,CAAC,CAAC;AAAA,EACX;AAAA,EAEA,MAAM,SAAS,MAAkD;AAC/D,UAAM,QAAQ,oBAAI,KAAK;AACvB,UAAM,eAAe,IAAI,KAAK,KAAK;AACnC,iBAAa,QAAQ,MAAM,QAAQ,IAAI,CAAC;AAExC,UAAM,UAA8B;AAAA,MAClC,MAAM,KAAK;AAAA,MACX,gBAAgB,KAAK;AAAA,MACrB,UAAU;AAAA,MACV,UAAU;AAAA,MACV,UAAU;AAAA,MACV,MAAM;AAAA,QACJ,QAAQ;AAAA,QACR,MAAM,KAAK;AAAA,QACX,WAAW,KAAK,YAAY;AAAA,QAC5B,IAAI,KAAK,MAAM;AAAA,QACf,KAAK,KAAK,OAAO;AAAA,QACjB,QAAQ,KAAK;AAAA,QACb,OAAO,KAAK;AAAA,QACZ,OAAO,KAAK;AAAA,QACZ,UAAU,KAAK;AAAA,QACf,SAAS;AAAA,QACT,UAAU;AAAA,MACZ;AAAA,MACA,cAAc;AAAA,QACZ,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS;AAAA,QACT,UAAU,aAAa,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,QACjD,YAAY;AAAA,MACd;AAAA,IACF;AAEA,UAAM,WAAW,MAAM,UAAU;AAAA,MAC/B;AAAA,MACA;AAAA,IACF;AAEA,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI;AAAA,QACR,SAAS,WAAW;AAAA,QACpB;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,QAAQ,SAAS,KAAK,WAAW,GAAG;AAChD,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,cAAc,SAAS,KAAK,CAAC;AAKnC,WAAO;AAAA,MACL,MAAM,CAAC;AAAA;AAAA,MACP,aAAa;AAAA,MACb,cAAc;AAAA,MACd,WAAW,IAAI,KAAK,KAAK,IAAI,IAAI,iBAAiB,GAAI,EAAE,YAAY;AAAA,MACpE,2BAA2B,CAAC,YAAY;AAAA,IAC1C;AAAA,EACF;AAAA,EAEA,MAAM,OAAO,YAAiD;AAC5D,UAAM,SAAS,MAAM,KAAK,SAAS;AAEnC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,UAAyB;AAAA,MAC7B,UAAU,WAAW;AAAA,MACrB,IAAI,WAAW;AAAA,MACf,UAAU,WAAW;AAAA,MACrB,OAAO,WAAW;AAAA,MAClB;AAAA,IACF;AAEA,QAAI;AACF,YAAM,WAAW,MAAM,UAAU;AAAA,QAC/B;AAAA,QACA;AAAA,MACF;AAEA,UAAI,SAAS,WAAW,GAAG;AACzB,cAAM,IAAI;AAAA,UACR,SAAS,WAAW;AAAA,UACpB,SAAS,QAAQ;AAAA,UACjB;AAAA,QACF;AAAA,MACF;AAAA,IACF,UAAE;AACA,YAAM,QAAQ,IAAI,CAAC,KAAK,iBAAiB,GAAG,uBAAuB,CAAC,CAAC;AAAA,IACvE;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,IACX;AAAA,EACF;AAAA,EAEA,MAAM,eACJ,OACiC;AACjC,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,cACJ,OACgC;AAChC,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,OAAyD;AACzE,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,mBACJ,OACqC;AACrC,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,gBAAgB,YAA0C;AAC9D,UAAM,SAAS,MAAM,KAAK,SAAS;AAEnC,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,UAA8B;AAAA,QAClC,UAAU,WAAW;AAAA,QACrB,IAAI,WAAW;AAAA,QACf,UAAU,WAAW;AAAA,QACrB,OAAO,WAAW;AAAA,QAClB;AAAA,MACF;AAEA,YAAM,WAAW,MAAM,UAAU;AAAA,QAC/B;AAAA,QACA;AAAA,MACF;AAEA,aAAO,SAAS,WAAW;AAAA,IAC7B,SAAS,OAAO;AACd,cAAQ,MAAM,uCAAuC,KAAK;AAC1D,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,kBAAoC;AACxC,UAAM,QAAQ,MAAM,KAAK,SAAS;AAClC,WAAO,CAAC,CAAC;AAAA,EACX;AAAA,EAEA,MAAM,WAAwC;AAC5C,QAAI,QAAQ,IAAI,iBAAkB,QAAO,QAAQ,IAAI;AACrD,UAAM,cAAc,MAAM,QAAQ;AAClC,WAAO,YAAY,IAAI,gBAAgB,GAAG;AAAA,EAC5C;AAAA,EAEA,MAAc,cAAc,OAA8B;AACxD,UAAM,cAAc,MAAM,QAAQ;AAClC,gBAAY,IAAI,kBAAkB,OAAO;AAAA,MACvC,GAAG;AAAA,MACH,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,mBAAkC;AACtC,UAAM,cAAc,MAAM,QAAQ;AAClC,gBAAY,OAAO;AAAA,MACjB,MAAM;AAAA,MACN,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AACF;AAEO,MAAM,cAAc,IAAI,YAAY;","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
|
@@ -11,8 +11,9 @@ 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_required?: boolean;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export type LoginResponse =
|
|
@@ -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,24 +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
47
|
async function setPending2FACookie(token: string): Promise<void> {
|
|
49
48
|
const cookieStore = await cookies();
|
|
50
|
-
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
|
+
});
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
async function removePending2FACookie(): Promise<void> {
|
|
@@ -61,8 +63,11 @@ async function getPending2FACookie(): Promise<string | undefined> {
|
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
class AuthService {
|
|
64
|
-
async login(
|
|
65
|
-
|
|
66
|
+
async login(
|
|
67
|
+
credentials: LoginRequest,
|
|
68
|
+
clientInfo: ClientInfo
|
|
69
|
+
): Promise<LoginResponse> {
|
|
70
|
+
const response = await apiClient.post<LoginApiResponse>("/auth/login", {
|
|
66
71
|
email: credentials.email,
|
|
67
72
|
password: credentials.password,
|
|
68
73
|
location: clientInfo.location,
|
|
@@ -72,16 +77,22 @@ class AuthService {
|
|
|
72
77
|
});
|
|
73
78
|
|
|
74
79
|
if (response.status === 0) {
|
|
75
|
-
throw new ApiError(
|
|
80
|
+
throw new ApiError(
|
|
81
|
+
response.message || "E-mail ou senha incorretos",
|
|
82
|
+
response.code || "LOGIN_FAILED",
|
|
83
|
+
401
|
|
84
|
+
);
|
|
76
85
|
}
|
|
77
86
|
|
|
78
87
|
if (!response.cookie) {
|
|
79
|
-
throw new ApiError(
|
|
88
|
+
throw new ApiError(
|
|
89
|
+
"Resposta de autenticação inválida",
|
|
90
|
+
"INVALID_RESPONSE",
|
|
91
|
+
500
|
|
92
|
+
);
|
|
80
93
|
}
|
|
81
94
|
|
|
82
|
-
if (response.
|
|
83
|
-
// Armazena o cookie temporariamente até o 2FA ser concluído.
|
|
84
|
-
// O cookie principal NÃO é setado aqui para evitar falso positivo em isAuthenticated().
|
|
95
|
+
if (response.two_factor_required) {
|
|
85
96
|
await setPending2FACookie(response.cookie);
|
|
86
97
|
return { twoFactorRequired: true };
|
|
87
98
|
}
|
|
@@ -91,16 +102,23 @@ class AuthService {
|
|
|
91
102
|
return {
|
|
92
103
|
user: {} as User,
|
|
93
104
|
accessToken: response.cookie,
|
|
94
|
-
refreshToken:
|
|
105
|
+
refreshToken: "",
|
|
95
106
|
expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),
|
|
96
107
|
};
|
|
97
108
|
}
|
|
98
109
|
|
|
99
|
-
async verifyTwoFactor(
|
|
110
|
+
async verifyTwoFactor(
|
|
111
|
+
code: number,
|
|
112
|
+
clientInfo: ClientInfo
|
|
113
|
+
): Promise<TwoFactorResponse> {
|
|
100
114
|
const pendingCookie = await getPending2FACookie();
|
|
101
115
|
|
|
102
116
|
if (!pendingCookie) {
|
|
103
|
-
throw new ApiError(
|
|
117
|
+
throw new ApiError(
|
|
118
|
+
"Nenhuma autenticação 2FA pendente",
|
|
119
|
+
"NO_PENDING_2FA",
|
|
120
|
+
400
|
|
121
|
+
);
|
|
104
122
|
}
|
|
105
123
|
|
|
106
124
|
const payload: TwoFactorRequest = {
|
|
@@ -112,17 +130,31 @@ class AuthService {
|
|
|
112
130
|
code,
|
|
113
131
|
};
|
|
114
132
|
|
|
115
|
-
const response = await apiClient.post<TwoFactorApiResponse>(
|
|
133
|
+
const response = await apiClient.post<TwoFactorApiResponse>(
|
|
134
|
+
"/auth/code",
|
|
135
|
+
payload
|
|
136
|
+
);
|
|
116
137
|
|
|
117
138
|
if (response.status === 0) {
|
|
118
|
-
throw new ApiError(
|
|
139
|
+
throw new ApiError(
|
|
140
|
+
response.message || "Código 2FA inválido",
|
|
141
|
+
response.code || "TWO_FACTOR_FAILED",
|
|
142
|
+
401
|
|
143
|
+
);
|
|
119
144
|
}
|
|
120
145
|
|
|
121
146
|
if (!response.cookie) {
|
|
122
|
-
throw new ApiError(
|
|
147
|
+
throw new ApiError(
|
|
148
|
+
"Resposta de autenticação inválida após 2FA",
|
|
149
|
+
"INVALID_RESPONSE",
|
|
150
|
+
500
|
|
151
|
+
);
|
|
123
152
|
}
|
|
124
153
|
|
|
125
|
-
await Promise.all([
|
|
154
|
+
await Promise.all([
|
|
155
|
+
this.setAuthCookie(response.cookie),
|
|
156
|
+
removePending2FACookie(),
|
|
157
|
+
]);
|
|
126
158
|
|
|
127
159
|
return { success: true };
|
|
128
160
|
}
|
|
@@ -140,39 +172,50 @@ class AuthService {
|
|
|
140
172
|
const payload: RegisterApiRequest = {
|
|
141
173
|
name: data.accountName,
|
|
142
174
|
bussiness_type: data.businessType,
|
|
143
|
-
language:
|
|
144
|
-
timezone:
|
|
145
|
-
currency:
|
|
175
|
+
language: "pt-br",
|
|
176
|
+
timezone: "America/Sao_Paulo",
|
|
177
|
+
currency: "BRL",
|
|
146
178
|
user: {
|
|
147
|
-
id_api:
|
|
179
|
+
id_api: "",
|
|
148
180
|
name: data.name,
|
|
149
|
-
last_name: data.lastName ||
|
|
150
|
-
rg: data.rg ||
|
|
151
|
-
cpf: data.cpf ||
|
|
181
|
+
last_name: data.lastName || "",
|
|
182
|
+
rg: data.rg || "",
|
|
183
|
+
cpf: data.cpf || "",
|
|
152
184
|
gender: data.gender,
|
|
153
185
|
email: data.email,
|
|
154
186
|
phone: data.phone,
|
|
155
187
|
password: data.password,
|
|
156
|
-
profile:
|
|
157
|
-
language:
|
|
188
|
+
profile: "owner",
|
|
189
|
+
language: "pt-br",
|
|
158
190
|
},
|
|
159
191
|
subscription: {
|
|
160
|
-
type:
|
|
161
|
-
id_cupom:
|
|
192
|
+
type: "trial",
|
|
193
|
+
id_cupom: "",
|
|
162
194
|
id_plan: 1,
|
|
163
|
-
due_date: trialEndDate.toISOString().split(
|
|
195
|
+
due_date: trialEndDate.toISOString().split("T")[0],
|
|
164
196
|
id_product: 1,
|
|
165
197
|
},
|
|
166
198
|
};
|
|
167
199
|
|
|
168
|
-
const response = await apiClient.post<RegisterApiResponse>(
|
|
200
|
+
const response = await apiClient.post<RegisterApiResponse>(
|
|
201
|
+
"/accounts",
|
|
202
|
+
payload
|
|
203
|
+
);
|
|
169
204
|
|
|
170
205
|
if (response.status === 0) {
|
|
171
|
-
throw new ApiError(
|
|
206
|
+
throw new ApiError(
|
|
207
|
+
response.message || "Erro ao criar conta",
|
|
208
|
+
"REGISTER_FAILED",
|
|
209
|
+
400
|
|
210
|
+
);
|
|
172
211
|
}
|
|
173
212
|
|
|
174
213
|
if (!response.data || response.data.length === 0) {
|
|
175
|
-
throw new ApiError(
|
|
214
|
+
throw new ApiError(
|
|
215
|
+
"Resposta de registro inválida",
|
|
216
|
+
"INVALID_RESPONSE",
|
|
217
|
+
500
|
|
218
|
+
);
|
|
176
219
|
}
|
|
177
220
|
|
|
178
221
|
const accountData = response.data[0];
|
|
@@ -182,8 +225,8 @@ class AuthService {
|
|
|
182
225
|
// O usuário completo será carregado após o login
|
|
183
226
|
return {
|
|
184
227
|
user: {} as User, // Placeholder, será preenchido após login
|
|
185
|
-
accessToken:
|
|
186
|
-
refreshToken:
|
|
228
|
+
accessToken: "",
|
|
229
|
+
refreshToken: "",
|
|
187
230
|
expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),
|
|
188
231
|
requiresEmailVerification: !accountData.verified,
|
|
189
232
|
};
|
|
@@ -193,7 +236,11 @@ class AuthService {
|
|
|
193
236
|
const cookie = await this.getToken();
|
|
194
237
|
|
|
195
238
|
if (!cookie) {
|
|
196
|
-
throw new ApiError(
|
|
239
|
+
throw new ApiError(
|
|
240
|
+
"Usuário não autenticado",
|
|
241
|
+
"NOT_AUTHENTICATED_LOGOUT",
|
|
242
|
+
401
|
|
243
|
+
);
|
|
197
244
|
}
|
|
198
245
|
|
|
199
246
|
const payload: LogoutRequest = {
|
|
@@ -205,10 +252,17 @@ class AuthService {
|
|
|
205
252
|
};
|
|
206
253
|
|
|
207
254
|
try {
|
|
208
|
-
const response = await apiClient.post<LogoutApiResponse>(
|
|
255
|
+
const response = await apiClient.post<LogoutApiResponse>(
|
|
256
|
+
"/auth/logout",
|
|
257
|
+
payload
|
|
258
|
+
);
|
|
209
259
|
|
|
210
260
|
if (response.status === 0) {
|
|
211
|
-
throw new ApiError(
|
|
261
|
+
throw new ApiError(
|
|
262
|
+
response.message || "Erro ao realizar logout",
|
|
263
|
+
response.code || "LOGOUT_FAILED",
|
|
264
|
+
400
|
|
265
|
+
);
|
|
212
266
|
}
|
|
213
267
|
} finally {
|
|
214
268
|
await Promise.all([this.removeAuthCookie(), removePending2FACookie()]);
|
|
@@ -219,20 +273,42 @@ class AuthService {
|
|
|
219
273
|
};
|
|
220
274
|
}
|
|
221
275
|
|
|
222
|
-
async forgotPassword(
|
|
223
|
-
|
|
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
|
+
);
|
|
224
284
|
}
|
|
225
285
|
|
|
226
|
-
async resetPassword(
|
|
227
|
-
|
|
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
|
+
);
|
|
228
294
|
}
|
|
229
295
|
|
|
230
296
|
async verifyEmail(_data: VerifyEmailRequest): Promise<VerifyEmailResponse> {
|
|
231
|
-
throw new ApiError(
|
|
297
|
+
throw new ApiError(
|
|
298
|
+
"Verificação de email não implementada",
|
|
299
|
+
"NOT_IMPLEMENTED",
|
|
300
|
+
501
|
|
301
|
+
);
|
|
232
302
|
}
|
|
233
303
|
|
|
234
|
-
async resendVerification(
|
|
235
|
-
|
|
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
|
+
);
|
|
236
312
|
}
|
|
237
313
|
|
|
238
314
|
async validateSession(clientInfo: ClientInfo): Promise<boolean> {
|
|
@@ -251,11 +327,14 @@ class AuthService {
|
|
|
251
327
|
cookie,
|
|
252
328
|
};
|
|
253
329
|
|
|
254
|
-
const response = await apiClient.post<SessionKeepResponse>(
|
|
330
|
+
const response = await apiClient.post<SessionKeepResponse>(
|
|
331
|
+
"/auth/keep",
|
|
332
|
+
payload
|
|
333
|
+
);
|
|
255
334
|
|
|
256
335
|
return response.status === 1;
|
|
257
336
|
} catch (error) {
|
|
258
|
-
console.error(
|
|
337
|
+
console.error("[AuthService] validateSession error", error);
|
|
259
338
|
return false;
|
|
260
339
|
}
|
|
261
340
|
}
|
|
@@ -271,7 +350,6 @@ class AuthService {
|
|
|
271
350
|
return cookieStore.get(AUTH_COOKIE_NAME)?.value;
|
|
272
351
|
}
|
|
273
352
|
|
|
274
|
-
|
|
275
353
|
private async setAuthCookie(token: string): Promise<void> {
|
|
276
354
|
const cookieStore = await cookies();
|
|
277
355
|
cookieStore.set(AUTH_COOKIE_NAME, token, {
|
|
@@ -280,7 +358,6 @@ class AuthService {
|
|
|
280
358
|
});
|
|
281
359
|
}
|
|
282
360
|
|
|
283
|
-
|
|
284
361
|
async removeAuthCookie(): Promise<void> {
|
|
285
362
|
const cookieStore = await cookies();
|
|
286
363
|
cookieStore.delete({
|
|
@@ -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);
|