hazo_auth 4.1.0 → 4.3.0
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/README.md +230 -0
- package/SETUP_CHECKLIST.md +202 -0
- package/bin/hazo_auth.mjs +35 -0
- package/cli-src/assets/images/forgot_password_default.jpg +0 -0
- package/cli-src/assets/images/login_default.jpg +0 -0
- package/cli-src/assets/images/register_default.jpg +0 -0
- package/cli-src/assets/images/reset_password_default.jpg +0 -0
- package/cli-src/assets/images/verify_email_default.jpg +0 -0
- package/cli-src/cli/generate.ts +276 -0
- package/cli-src/cli/index.ts +207 -0
- package/cli-src/cli/init.ts +254 -0
- package/cli-src/cli/init_users.ts +376 -0
- package/cli-src/cli/validate.ts +581 -0
- package/cli-src/lib/already_logged_in_config.server.ts +46 -0
- package/cli-src/lib/app_logger.ts +24 -0
- package/cli-src/lib/auth/auth_cache.ts +220 -0
- package/cli-src/lib/auth/auth_rate_limiter.ts +121 -0
- package/cli-src/lib/auth/auth_types.ts +110 -0
- package/cli-src/lib/auth/auth_utils.server.ts +196 -0
- package/cli-src/lib/auth/hazo_get_auth.server.ts +512 -0
- package/cli-src/lib/auth/index.ts +23 -0
- package/cli-src/lib/auth/nextauth_config.ts +227 -0
- package/cli-src/lib/auth/scope_cache.ts +233 -0
- package/cli-src/lib/auth/server_auth.ts +88 -0
- package/cli-src/lib/auth/session_token_validator.edge.ts +91 -0
- package/cli-src/lib/auth_utility_config.server.ts +136 -0
- package/cli-src/lib/config/config_loader.server.ts +164 -0
- package/cli-src/lib/config/default_config.ts +199 -0
- package/cli-src/lib/email_verification_config.server.ts +63 -0
- package/cli-src/lib/file_types_config.server.ts +25 -0
- package/cli-src/lib/forgot_password_config.server.ts +63 -0
- package/cli-src/lib/hazo_connect_instance.server.ts +101 -0
- package/cli-src/lib/hazo_connect_setup.server.ts +194 -0
- package/cli-src/lib/hazo_connect_setup.ts +54 -0
- package/cli-src/lib/index.ts +46 -0
- package/cli-src/lib/login_config.server.ts +106 -0
- package/cli-src/lib/messages_config.server.ts +45 -0
- package/cli-src/lib/migrations/apply_migration.ts +105 -0
- package/cli-src/lib/my_settings_config.server.ts +135 -0
- package/cli-src/lib/oauth_config.server.ts +87 -0
- package/cli-src/lib/password_requirements_config.server.ts +40 -0
- package/cli-src/lib/profile_pic_menu_config.server.ts +138 -0
- package/cli-src/lib/profile_picture_config.server.ts +56 -0
- package/cli-src/lib/register_config.server.ts +101 -0
- package/cli-src/lib/reset_password_config.server.ts +103 -0
- package/cli-src/lib/scope_hierarchy_config.server.ts +151 -0
- package/cli-src/lib/services/email_service.ts +587 -0
- package/cli-src/lib/services/email_verification_service.ts +270 -0
- package/cli-src/lib/services/index.ts +16 -0
- package/cli-src/lib/services/login_service.ts +150 -0
- package/cli-src/lib/services/oauth_service.ts +494 -0
- package/cli-src/lib/services/password_change_service.ts +154 -0
- package/cli-src/lib/services/password_reset_service.ts +418 -0
- package/cli-src/lib/services/profile_picture_remove_service.ts +120 -0
- package/cli-src/lib/services/profile_picture_service.ts +451 -0
- package/cli-src/lib/services/profile_picture_source_mapper.ts +62 -0
- package/cli-src/lib/services/registration_service.ts +185 -0
- package/cli-src/lib/services/scope_labels_service.ts +348 -0
- package/cli-src/lib/services/scope_service.ts +778 -0
- package/cli-src/lib/services/session_token_service.ts +177 -0
- package/cli-src/lib/services/token_service.ts +240 -0
- package/cli-src/lib/services/user_profiles_cache.ts +189 -0
- package/cli-src/lib/services/user_profiles_service.ts +264 -0
- package/cli-src/lib/services/user_scope_service.ts +554 -0
- package/cli-src/lib/services/user_update_service.ts +141 -0
- package/cli-src/lib/ui_shell_config.server.ts +73 -0
- package/cli-src/lib/ui_sizes_config.server.ts +37 -0
- package/cli-src/lib/user_fields_config.server.ts +31 -0
- package/cli-src/lib/user_management_config.server.ts +39 -0
- package/cli-src/lib/user_profiles_config.server.ts +55 -0
- package/cli-src/lib/utils/api_route_helpers.ts +60 -0
- package/cli-src/lib/utils/error_sanitizer.ts +75 -0
- package/cli-src/lib/utils/password_validator.ts +65 -0
- package/cli-src/lib/utils.ts +11 -0
- package/cli-src/server/logging/logger_service.ts +56 -0
- package/dist/app/api/hazo_auth/forgot_password/route.d.ts.map +1 -1
- package/dist/app/api/hazo_auth/forgot_password/route.js +15 -0
- package/dist/app/api/hazo_auth/logout/route.d.ts.map +1 -1
- package/dist/app/api/hazo_auth/logout/route.js +31 -0
- package/dist/app/api/hazo_auth/me/route.d.ts.map +1 -1
- package/dist/app/api/hazo_auth/me/route.js +10 -0
- package/dist/cli/index.js +18 -0
- package/dist/cli/init_users.d.ts +17 -0
- package/dist/cli/init_users.d.ts.map +1 -0
- package/dist/cli/init_users.js +307 -0
- package/dist/components/layouts/forgot_password/hooks/use_forgot_password_form.d.ts +2 -0
- package/dist/components/layouts/forgot_password/hooks/use_forgot_password_form.d.ts.map +1 -1
- package/dist/components/layouts/forgot_password/hooks/use_forgot_password_form.js +8 -0
- package/dist/components/layouts/forgot_password/index.d.ts +7 -1
- package/dist/components/layouts/forgot_password/index.d.ts.map +1 -1
- package/dist/components/layouts/forgot_password/index.js +7 -2
- package/dist/components/layouts/login/index.d.ts +13 -1
- package/dist/components/layouts/login/index.d.ts.map +1 -1
- package/dist/components/layouts/login/index.js +11 -2
- package/dist/components/layouts/my_settings/components/connected_accounts_section.d.ts +17 -0
- package/dist/components/layouts/my_settings/components/connected_accounts_section.d.ts.map +1 -0
- package/dist/components/layouts/my_settings/components/connected_accounts_section.js +17 -0
- package/dist/components/layouts/my_settings/components/set_password_section.d.ts +26 -0
- package/dist/components/layouts/my_settings/components/set_password_section.d.ts.map +1 -0
- package/dist/components/layouts/my_settings/components/set_password_section.js +127 -0
- package/dist/components/layouts/my_settings/hooks/use_my_settings.d.ts +3 -0
- package/dist/components/layouts/my_settings/hooks/use_my_settings.d.ts.map +1 -1
- package/dist/components/layouts/my_settings/hooks/use_my_settings.js +9 -0
- package/dist/components/layouts/my_settings/index.d.ts.map +1 -1
- package/dist/components/layouts/my_settings/index.js +4 -2
- package/dist/components/layouts/shared/components/google_icon.d.ts +12 -0
- package/dist/components/layouts/shared/components/google_icon.d.ts.map +1 -0
- package/dist/components/layouts/shared/components/google_icon.js +9 -0
- package/dist/components/layouts/shared/components/google_sign_in_button.d.ts +21 -0
- package/dist/components/layouts/shared/components/google_sign_in_button.d.ts.map +1 -0
- package/dist/components/layouts/shared/components/google_sign_in_button.js +50 -0
- package/dist/components/layouts/shared/components/oauth_divider.d.ts +13 -0
- package/dist/components/layouts/shared/components/oauth_divider.d.ts.map +1 -0
- package/dist/components/layouts/shared/components/oauth_divider.js +13 -0
- package/dist/components/layouts/shared/config/layout_customization.d.ts +2 -7
- package/dist/components/layouts/shared/config/layout_customization.d.ts.map +1 -1
- package/dist/components/layouts/shared/hooks/use_auth_status.d.ts +3 -0
- package/dist/components/layouts/shared/hooks/use_auth_status.d.ts.map +1 -1
- package/dist/components/layouts/shared/hooks/use_auth_status.js +4 -0
- package/dist/components/layouts/shared/index.d.ts +5 -0
- package/dist/components/layouts/shared/index.d.ts.map +1 -1
- package/dist/components/layouts/shared/index.js +3 -0
- package/dist/components/ui/button.d.ts +1 -1
- package/dist/lib/auth/nextauth_config.d.ts +34 -0
- package/dist/lib/auth/nextauth_config.d.ts.map +1 -0
- package/dist/lib/auth/nextauth_config.js +171 -0
- package/dist/lib/config/default_config.d.ts +24 -0
- package/dist/lib/config/default_config.d.ts.map +1 -1
- package/dist/lib/config/default_config.js +14 -0
- package/dist/lib/index.d.ts +2 -0
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +1 -0
- package/dist/lib/login_config.server.d.ts +3 -0
- package/dist/lib/login_config.server.d.ts.map +1 -1
- package/dist/lib/login_config.server.js +4 -0
- package/dist/lib/oauth_config.server.d.ts +29 -0
- package/dist/lib/oauth_config.server.d.ts.map +1 -0
- package/dist/lib/oauth_config.server.js +40 -0
- package/dist/lib/services/login_service.d.ts.map +1 -1
- package/dist/lib/services/login_service.js +16 -1
- package/dist/lib/services/oauth_service.d.ts +88 -0
- package/dist/lib/services/oauth_service.d.ts.map +1 -0
- package/dist/lib/services/oauth_service.js +376 -0
- package/dist/lib/services/password_reset_service.d.ts +2 -0
- package/dist/lib/services/password_reset_service.d.ts.map +1 -1
- package/dist/lib/services/password_reset_service.js +10 -0
- package/dist/lib/services/registration_service.d.ts.map +1 -1
- package/dist/lib/services/registration_service.js +1 -0
- package/dist/lib/utils/password_validator.d.ts +19 -0
- package/dist/lib/utils/password_validator.d.ts.map +1 -0
- package/dist/lib/utils/password_validator.js +36 -0
- package/dist/server_pages/login.d.ts.map +1 -1
- package/dist/server_pages/login.js +6 -1
- package/dist/server_pages/login_client_wrapper.d.ts +5 -2
- package/dist/server_pages/login_client_wrapper.d.ts.map +1 -1
- package/dist/server_pages/login_client_wrapper.js +2 -2
- package/package.json +6 -2
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
import { createCrudService } from "hazo_connect/server";
|
|
2
|
+
import { randomUUID } from "crypto";
|
|
3
|
+
import { create_app_logger } from "../app_logger";
|
|
4
|
+
import { sanitize_error_for_user } from "../utils/error_sanitizer";
|
|
5
|
+
import { get_line_number } from "../utils/api_route_helpers";
|
|
6
|
+
import { get_oauth_config } from "../oauth_config.server";
|
|
7
|
+
// section: helpers
|
|
8
|
+
/**
|
|
9
|
+
* Handles Google OAuth login/registration flow
|
|
10
|
+
* 1. Check if user exists with google_id -> login
|
|
11
|
+
* 2. Check if user exists with email -> link Google account
|
|
12
|
+
* 3. Create new user with Google data
|
|
13
|
+
*
|
|
14
|
+
* @param adapter - The hazo_connect adapter instance
|
|
15
|
+
* @param data - Google OAuth user data
|
|
16
|
+
* @returns OAuth login result with user_id and status flags
|
|
17
|
+
*/
|
|
18
|
+
export async function handle_google_oauth_login(adapter, data) {
|
|
19
|
+
const logger = create_app_logger();
|
|
20
|
+
try {
|
|
21
|
+
const { google_id, email, name, profile_picture_url, email_verified } = data;
|
|
22
|
+
const oauth_config = get_oauth_config();
|
|
23
|
+
const users_service = createCrudService(adapter, "hazo_users");
|
|
24
|
+
const now = new Date().toISOString();
|
|
25
|
+
// Step 1: Check if user exists with this google_id
|
|
26
|
+
const users_by_google_id = await users_service.findBy({ google_id });
|
|
27
|
+
if (Array.isArray(users_by_google_id) && users_by_google_id.length > 0) {
|
|
28
|
+
const user = users_by_google_id[0];
|
|
29
|
+
// Update last_logon timestamp
|
|
30
|
+
await users_service.updateById(user.id, {
|
|
31
|
+
last_logon: now,
|
|
32
|
+
changed_at: now,
|
|
33
|
+
});
|
|
34
|
+
logger.info("oauth_service_google_login_existing_google_user", {
|
|
35
|
+
filename: "oauth_service.ts",
|
|
36
|
+
line_number: get_line_number(),
|
|
37
|
+
user_id: user.id,
|
|
38
|
+
email: user.email_address,
|
|
39
|
+
});
|
|
40
|
+
return {
|
|
41
|
+
success: true,
|
|
42
|
+
user_id: user.id,
|
|
43
|
+
is_new_user: false,
|
|
44
|
+
was_linked: false,
|
|
45
|
+
email: user.email_address,
|
|
46
|
+
name: user.name,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// Step 2: Check if user exists with this email
|
|
50
|
+
const users_by_email = await users_service.findBy({ email_address: email });
|
|
51
|
+
if (Array.isArray(users_by_email) && users_by_email.length > 0) {
|
|
52
|
+
const user = users_by_email[0];
|
|
53
|
+
const user_email_verified = user.email_verified;
|
|
54
|
+
// Check if auto-linking is enabled for unverified accounts
|
|
55
|
+
if (!user_email_verified && !oauth_config.auto_link_unverified_accounts) {
|
|
56
|
+
return {
|
|
57
|
+
success: false,
|
|
58
|
+
error: "An account with this email exists but is not verified. Please verify your email first.",
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
// Link Google account to existing user
|
|
62
|
+
const current_auth_providers = user.auth_providers || "email";
|
|
63
|
+
const new_auth_providers = current_auth_providers.includes("google")
|
|
64
|
+
? current_auth_providers
|
|
65
|
+
: `${current_auth_providers},google`;
|
|
66
|
+
const update_data = {
|
|
67
|
+
google_id,
|
|
68
|
+
auth_providers: new_auth_providers,
|
|
69
|
+
last_logon: now,
|
|
70
|
+
changed_at: now,
|
|
71
|
+
};
|
|
72
|
+
// If user was unverified and Google verified the email, mark as verified
|
|
73
|
+
if (!user_email_verified && email_verified) {
|
|
74
|
+
update_data.email_verified = true;
|
|
75
|
+
logger.info("oauth_service_auto_verified_email", {
|
|
76
|
+
filename: "oauth_service.ts",
|
|
77
|
+
line_number: get_line_number(),
|
|
78
|
+
user_id: user.id,
|
|
79
|
+
email,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
// Update name if not set and Google provides one
|
|
83
|
+
if (!user.name && name) {
|
|
84
|
+
update_data.name = name;
|
|
85
|
+
}
|
|
86
|
+
// Update profile picture if not set and Google provides one
|
|
87
|
+
if (!user.profile_picture_url && profile_picture_url) {
|
|
88
|
+
update_data.profile_picture_url = profile_picture_url;
|
|
89
|
+
update_data.profile_source = "custom"; // Use 'custom' for external URLs (Google profile pics)
|
|
90
|
+
}
|
|
91
|
+
await users_service.updateById(user.id, update_data);
|
|
92
|
+
logger.info("oauth_service_google_linked_to_existing", {
|
|
93
|
+
filename: "oauth_service.ts",
|
|
94
|
+
line_number: get_line_number(),
|
|
95
|
+
user_id: user.id,
|
|
96
|
+
email,
|
|
97
|
+
was_unverified: !user_email_verified,
|
|
98
|
+
});
|
|
99
|
+
return {
|
|
100
|
+
success: true,
|
|
101
|
+
user_id: user.id,
|
|
102
|
+
is_new_user: false,
|
|
103
|
+
was_linked: true,
|
|
104
|
+
email: user.email_address,
|
|
105
|
+
name: update_data.name || user.name,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
// Step 3: Create new user with Google data
|
|
109
|
+
const user_id = randomUUID();
|
|
110
|
+
const insert_data = {
|
|
111
|
+
id: user_id,
|
|
112
|
+
email_address: email,
|
|
113
|
+
password_hash: "", // Empty string for Google-only users
|
|
114
|
+
email_verified: email_verified, // Trust Google's verification
|
|
115
|
+
is_active: true,
|
|
116
|
+
login_attempts: 0,
|
|
117
|
+
google_id,
|
|
118
|
+
auth_providers: "google",
|
|
119
|
+
created_at: now,
|
|
120
|
+
changed_at: now,
|
|
121
|
+
last_logon: now,
|
|
122
|
+
};
|
|
123
|
+
if (name) {
|
|
124
|
+
insert_data.name = name;
|
|
125
|
+
}
|
|
126
|
+
if (profile_picture_url) {
|
|
127
|
+
insert_data.profile_picture_url = profile_picture_url;
|
|
128
|
+
insert_data.profile_source = "custom"; // Use 'custom' for external URLs (Google profile pics)
|
|
129
|
+
}
|
|
130
|
+
const inserted_users = await users_service.insert(insert_data);
|
|
131
|
+
if (!Array.isArray(inserted_users) || inserted_users.length === 0) {
|
|
132
|
+
return {
|
|
133
|
+
success: false,
|
|
134
|
+
error: "Failed to create user account",
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
logger.info("oauth_service_google_new_user_created", {
|
|
138
|
+
filename: "oauth_service.ts",
|
|
139
|
+
line_number: get_line_number(),
|
|
140
|
+
user_id,
|
|
141
|
+
email,
|
|
142
|
+
});
|
|
143
|
+
return {
|
|
144
|
+
success: true,
|
|
145
|
+
user_id,
|
|
146
|
+
is_new_user: true,
|
|
147
|
+
was_linked: false,
|
|
148
|
+
email,
|
|
149
|
+
name,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
const user_friendly_error = sanitize_error_for_user(error, {
|
|
154
|
+
logToConsole: true,
|
|
155
|
+
logToLogger: true,
|
|
156
|
+
logger,
|
|
157
|
+
context: {
|
|
158
|
+
filename: "oauth_service.ts",
|
|
159
|
+
line_number: get_line_number(),
|
|
160
|
+
email: data.email,
|
|
161
|
+
operation: "handle_google_oauth_login",
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
return {
|
|
165
|
+
success: false,
|
|
166
|
+
error: user_friendly_error,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Links a Google account to an existing user
|
|
172
|
+
* @param adapter - The hazo_connect adapter instance
|
|
173
|
+
* @param user_id - The user's ID
|
|
174
|
+
* @param google_id - Google's unique user ID
|
|
175
|
+
* @returns Result indicating success or failure
|
|
176
|
+
*/
|
|
177
|
+
export async function link_google_account(adapter, user_id, google_id) {
|
|
178
|
+
const logger = create_app_logger();
|
|
179
|
+
try {
|
|
180
|
+
const users_service = createCrudService(adapter, "hazo_users");
|
|
181
|
+
const now = new Date().toISOString();
|
|
182
|
+
// Get current user
|
|
183
|
+
const users = await users_service.findBy({ id: user_id });
|
|
184
|
+
if (!Array.isArray(users) || users.length === 0) {
|
|
185
|
+
return {
|
|
186
|
+
success: false,
|
|
187
|
+
error: "User not found",
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
const user = users[0];
|
|
191
|
+
// Check if Google is already linked
|
|
192
|
+
if (user.google_id) {
|
|
193
|
+
return {
|
|
194
|
+
success: false,
|
|
195
|
+
error: "Google account is already linked",
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
// Update auth_providers
|
|
199
|
+
const current_auth_providers = user.auth_providers || "email";
|
|
200
|
+
const new_auth_providers = current_auth_providers.includes("google")
|
|
201
|
+
? current_auth_providers
|
|
202
|
+
: `${current_auth_providers},google`;
|
|
203
|
+
await users_service.updateById(user_id, {
|
|
204
|
+
google_id,
|
|
205
|
+
auth_providers: new_auth_providers,
|
|
206
|
+
changed_at: now,
|
|
207
|
+
});
|
|
208
|
+
logger.info("oauth_service_google_account_linked", {
|
|
209
|
+
filename: "oauth_service.ts",
|
|
210
|
+
line_number: get_line_number(),
|
|
211
|
+
user_id,
|
|
212
|
+
});
|
|
213
|
+
return { success: true };
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
const user_friendly_error = sanitize_error_for_user(error, {
|
|
217
|
+
logToConsole: true,
|
|
218
|
+
logToLogger: true,
|
|
219
|
+
logger,
|
|
220
|
+
context: {
|
|
221
|
+
filename: "oauth_service.ts",
|
|
222
|
+
line_number: get_line_number(),
|
|
223
|
+
user_id,
|
|
224
|
+
operation: "link_google_account",
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
return {
|
|
228
|
+
success: false,
|
|
229
|
+
error: user_friendly_error,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Checks if a user has a password set (non-empty password_hash)
|
|
235
|
+
* @param adapter - The hazo_connect adapter instance
|
|
236
|
+
* @param user_id - The user's ID
|
|
237
|
+
* @returns True if user has a password set
|
|
238
|
+
*/
|
|
239
|
+
export async function user_has_password(adapter, user_id) {
|
|
240
|
+
try {
|
|
241
|
+
const users_service = createCrudService(adapter, "hazo_users");
|
|
242
|
+
const users = await users_service.findBy({ id: user_id });
|
|
243
|
+
if (!Array.isArray(users) || users.length === 0) {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
const password_hash = users[0].password_hash;
|
|
247
|
+
return password_hash !== null && password_hash !== undefined && password_hash !== "";
|
|
248
|
+
}
|
|
249
|
+
catch (_a) {
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Checks if a user has a password set by email
|
|
255
|
+
* @param adapter - The hazo_connect adapter instance
|
|
256
|
+
* @param email - The user's email address
|
|
257
|
+
* @returns True if user has a password set
|
|
258
|
+
*/
|
|
259
|
+
export async function user_has_password_by_email(adapter, email) {
|
|
260
|
+
try {
|
|
261
|
+
const users_service = createCrudService(adapter, "hazo_users");
|
|
262
|
+
const users = await users_service.findBy({ email_address: email });
|
|
263
|
+
if (!Array.isArray(users) || users.length === 0) {
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
const password_hash = users[0].password_hash;
|
|
267
|
+
return password_hash !== null && password_hash !== undefined && password_hash !== "";
|
|
268
|
+
}
|
|
269
|
+
catch (_a) {
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Gets a user's authentication providers and password status
|
|
275
|
+
* @param adapter - The hazo_connect adapter instance
|
|
276
|
+
* @param user_id - The user's ID
|
|
277
|
+
* @returns Auth providers array and has_password flag
|
|
278
|
+
*/
|
|
279
|
+
export async function get_user_auth_providers(adapter, user_id) {
|
|
280
|
+
try {
|
|
281
|
+
const users_service = createCrudService(adapter, "hazo_users");
|
|
282
|
+
const users = await users_service.findBy({ id: user_id });
|
|
283
|
+
if (!Array.isArray(users) || users.length === 0) {
|
|
284
|
+
return {
|
|
285
|
+
success: false,
|
|
286
|
+
error: "User not found",
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
const user = users[0];
|
|
290
|
+
const auth_providers_str = user.auth_providers || "email";
|
|
291
|
+
const auth_providers = auth_providers_str.split(",").map((p) => p.trim());
|
|
292
|
+
const password_hash = user.password_hash;
|
|
293
|
+
const has_password = password_hash !== null && password_hash !== undefined && password_hash !== "";
|
|
294
|
+
return {
|
|
295
|
+
success: true,
|
|
296
|
+
auth_providers,
|
|
297
|
+
has_password,
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
catch (error) {
|
|
301
|
+
const logger = create_app_logger();
|
|
302
|
+
const user_friendly_error = sanitize_error_for_user(error, {
|
|
303
|
+
logToConsole: true,
|
|
304
|
+
logToLogger: true,
|
|
305
|
+
logger,
|
|
306
|
+
context: {
|
|
307
|
+
filename: "oauth_service.ts",
|
|
308
|
+
line_number: get_line_number(),
|
|
309
|
+
user_id,
|
|
310
|
+
operation: "get_user_auth_providers",
|
|
311
|
+
},
|
|
312
|
+
});
|
|
313
|
+
return {
|
|
314
|
+
success: false,
|
|
315
|
+
error: user_friendly_error,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Sets a password for a user who doesn't have one (e.g., Google-only users)
|
|
321
|
+
* @param adapter - The hazo_connect adapter instance
|
|
322
|
+
* @param user_id - The user's ID
|
|
323
|
+
* @param password_hash - The hashed password to set
|
|
324
|
+
* @returns Result indicating success or failure
|
|
325
|
+
*/
|
|
326
|
+
export async function set_user_password(adapter, user_id, password_hash) {
|
|
327
|
+
const logger = create_app_logger();
|
|
328
|
+
try {
|
|
329
|
+
const users_service = createCrudService(adapter, "hazo_users");
|
|
330
|
+
const now = new Date().toISOString();
|
|
331
|
+
// Get current user
|
|
332
|
+
const users = await users_service.findBy({ id: user_id });
|
|
333
|
+
if (!Array.isArray(users) || users.length === 0) {
|
|
334
|
+
return {
|
|
335
|
+
success: false,
|
|
336
|
+
error: "User not found",
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
const user = users[0];
|
|
340
|
+
// Update password and auth_providers
|
|
341
|
+
const current_auth_providers = user.auth_providers || "";
|
|
342
|
+
const new_auth_providers = current_auth_providers.includes("email")
|
|
343
|
+
? current_auth_providers
|
|
344
|
+
: current_auth_providers
|
|
345
|
+
? `${current_auth_providers},email`
|
|
346
|
+
: "email";
|
|
347
|
+
await users_service.updateById(user_id, {
|
|
348
|
+
password_hash,
|
|
349
|
+
auth_providers: new_auth_providers,
|
|
350
|
+
changed_at: now,
|
|
351
|
+
});
|
|
352
|
+
logger.info("oauth_service_password_set", {
|
|
353
|
+
filename: "oauth_service.ts",
|
|
354
|
+
line_number: get_line_number(),
|
|
355
|
+
user_id,
|
|
356
|
+
});
|
|
357
|
+
return { success: true };
|
|
358
|
+
}
|
|
359
|
+
catch (error) {
|
|
360
|
+
const user_friendly_error = sanitize_error_for_user(error, {
|
|
361
|
+
logToConsole: true,
|
|
362
|
+
logToLogger: true,
|
|
363
|
+
logger,
|
|
364
|
+
context: {
|
|
365
|
+
filename: "oauth_service.ts",
|
|
366
|
+
line_number: get_line_number(),
|
|
367
|
+
user_id,
|
|
368
|
+
operation: "set_user_password",
|
|
369
|
+
},
|
|
370
|
+
});
|
|
371
|
+
return {
|
|
372
|
+
success: false,
|
|
373
|
+
error: user_friendly_error,
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
}
|
|
@@ -5,6 +5,8 @@ export type PasswordResetRequestData = {
|
|
|
5
5
|
export type PasswordResetRequestResult = {
|
|
6
6
|
success: boolean;
|
|
7
7
|
error?: string;
|
|
8
|
+
/** True if the user doesn't have a password set (Google-only user) */
|
|
9
|
+
no_password_set?: boolean;
|
|
8
10
|
};
|
|
9
11
|
export type PasswordResetData = {
|
|
10
12
|
token: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"password_reset_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/password_reset_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAQvD,MAAM,MAAM,wBAAwB,GAAG;IACrC,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"password_reset_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/password_reset_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAQvD,MAAM,MAAM,wBAAwB,GAAG;IACrC,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,gCAAgC,GAAG;IAC7C,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,kCAAkC,GAAG;IAC/C,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAGF;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,wBAAwB,GAC7B,OAAO,CAAC,0BAA0B,CAAC,CAgFrC;AAED;;;;;;GAMG;AACH,wBAAsB,6BAA6B,CACjD,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,gCAAgC,GACrC,OAAO,CAAC,kCAAkC,CAAC,CAgG7C;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,mBAAmB,CAAC,CAiK9B"}
|
|
@@ -29,6 +29,16 @@ export async function request_password_reset(adapter, data) {
|
|
|
29
29
|
}
|
|
30
30
|
const user = users[0];
|
|
31
31
|
const user_id = user.id;
|
|
32
|
+
// Check if user has a password set (Google-only users don't have a password)
|
|
33
|
+
const password_hash = user.password_hash;
|
|
34
|
+
if (!password_hash || password_hash === "") {
|
|
35
|
+
// User doesn't have a password - they need to set one via My Settings after logging in with Google
|
|
36
|
+
// Return success to prevent email enumeration, but include flag for UI handling
|
|
37
|
+
return {
|
|
38
|
+
success: true,
|
|
39
|
+
no_password_set: true,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
32
42
|
// Create password reset token using shared token service
|
|
33
43
|
const token_result = await create_token({
|
|
34
44
|
adapter,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registration_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/registration_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAcvD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAGF;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,kBAAkB,CAAC,
|
|
1
|
+
{"version":3,"file":"registration_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/registration_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAcvD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAGF;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,kBAAkB,CAAC,CAgJ7B"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type PasswordRequirementOptions = {
|
|
2
|
+
minimum_length: number;
|
|
3
|
+
require_uppercase: boolean;
|
|
4
|
+
require_lowercase: boolean;
|
|
5
|
+
require_number: boolean;
|
|
6
|
+
require_special: boolean;
|
|
7
|
+
};
|
|
8
|
+
export type PasswordValidationResult = {
|
|
9
|
+
valid: boolean;
|
|
10
|
+
errors: string[];
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Validates a password against specified requirements (server-side version)
|
|
14
|
+
* @param password - The password to validate
|
|
15
|
+
* @param requirements - Password requirement options
|
|
16
|
+
* @returns Validation result with valid flag and error messages
|
|
17
|
+
*/
|
|
18
|
+
export declare function validate_password(password: string, requirements: PasswordRequirementOptions): PasswordValidationResult;
|
|
19
|
+
//# sourceMappingURL=password_validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password_validator.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/password_validator.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,0BAA0B,GAAG;IACvC,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,cAAc,EAAE,OAAO,CAAC;IACxB,eAAe,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAGF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,0BAA0B,GACvC,wBAAwB,CAuC1B"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// section: helpers
|
|
2
|
+
/**
|
|
3
|
+
* Validates a password against specified requirements (server-side version)
|
|
4
|
+
* @param password - The password to validate
|
|
5
|
+
* @param requirements - Password requirement options
|
|
6
|
+
* @returns Validation result with valid flag and error messages
|
|
7
|
+
*/
|
|
8
|
+
export function validate_password(password, requirements) {
|
|
9
|
+
const errors = [];
|
|
10
|
+
if (!password || password.trim().length === 0) {
|
|
11
|
+
return {
|
|
12
|
+
valid: false,
|
|
13
|
+
errors: ["Password is required"],
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
if (password.length < requirements.minimum_length) {
|
|
17
|
+
errors.push(`Password must be at least ${requirements.minimum_length} characters`);
|
|
18
|
+
}
|
|
19
|
+
if (requirements.require_uppercase && !/[A-Z]/.test(password)) {
|
|
20
|
+
errors.push("Password must include at least one uppercase letter");
|
|
21
|
+
}
|
|
22
|
+
if (requirements.require_lowercase && !/[a-z]/.test(password)) {
|
|
23
|
+
errors.push("Password must include at least one lowercase letter");
|
|
24
|
+
}
|
|
25
|
+
if (requirements.require_number && !/\d/.test(password)) {
|
|
26
|
+
errors.push("Password must include at least one number");
|
|
27
|
+
}
|
|
28
|
+
if (requirements.require_special &&
|
|
29
|
+
!/[!@#$%^&*(),.?":{}|<>\-_+=\[\];'/\\]/.test(password)) {
|
|
30
|
+
errors.push("Password must include at least one special character");
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
valid: errors.length === 0,
|
|
34
|
+
errors,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/server_pages/login.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,MAAM,cAAc,GAAG;IAC3B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC;IAErC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC,CAAC;AAGF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EAChC,SAAS,EACT,SAAS,EACT,sBAAsB,GACvB,GAAE,cAAmB,
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/server_pages/login.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,MAAM,cAAc,GAAG;IAC3B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC;IAErC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC,CAAC;AAGF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EAChC,SAAS,EACT,SAAS,EACT,sBAAsB,GACvB,GAAE,cAAmB,2CAkCrB;AAGD,OAAO,EAAE,SAAS,EAAE,CAAC"}
|
|
@@ -35,7 +35,12 @@ export default function LoginPage({ image_src, image_alt, image_background_color
|
|
|
35
35
|
const finalImageAlt = image_alt || config.imageAlt;
|
|
36
36
|
const finalImageBackgroundColor = image_background_color || config.imageBackgroundColor;
|
|
37
37
|
// Pass serializable config to client wrapper
|
|
38
|
-
return (_jsx(LoginClientWrapper, { image_src: finalImageSrc, image_alt: finalImageAlt, image_background_color: finalImageBackgroundColor, redirectRoute: config.redirectRoute, successMessage: config.successMessage, alreadyLoggedInMessage: config.alreadyLoggedInMessage, showLogoutButton: config.showLogoutButton, showReturnHomeButton: config.showReturnHomeButton, returnHomeButtonLabel: config.returnHomeButtonLabel, returnHomePath: config.returnHomePath, forgotPasswordPath: config.forgotPasswordPath, forgotPasswordLabel: config.forgotPasswordLabel, createAccountPath: config.createAccountPath, createAccountLabel: config.createAccountLabel
|
|
38
|
+
return (_jsx(LoginClientWrapper, { image_src: finalImageSrc, image_alt: finalImageAlt, image_background_color: finalImageBackgroundColor, redirectRoute: config.redirectRoute, successMessage: config.successMessage, alreadyLoggedInMessage: config.alreadyLoggedInMessage, showLogoutButton: config.showLogoutButton, showReturnHomeButton: config.showReturnHomeButton, returnHomeButtonLabel: config.returnHomeButtonLabel, returnHomePath: config.returnHomePath, forgotPasswordPath: config.forgotPasswordPath, forgotPasswordLabel: config.forgotPasswordLabel, createAccountPath: config.createAccountPath, createAccountLabel: config.createAccountLabel, oauth: {
|
|
39
|
+
enable_google: config.oauth.enable_google,
|
|
40
|
+
enable_email_password: config.oauth.enable_email_password,
|
|
41
|
+
google_button_text: config.oauth.google_button_text,
|
|
42
|
+
oauth_divider_text: config.oauth.oauth_divider_text,
|
|
43
|
+
} }));
|
|
39
44
|
}
|
|
40
45
|
// Named export for direct imports
|
|
41
46
|
export { LoginPage };
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import type { LoginConfig } from "../lib/login_config.server";
|
|
2
|
+
import type { OAuthLayoutConfig } from "../components/layouts/login";
|
|
2
3
|
import type { StaticImageData } from "next/image";
|
|
3
|
-
export type LoginClientWrapperProps = Omit<LoginConfig, 'imageSrc' | 'imageAlt' | 'imageBackgroundColor'> & {
|
|
4
|
+
export type LoginClientWrapperProps = Omit<LoginConfig, 'imageSrc' | 'imageAlt' | 'imageBackgroundColor' | 'oauth'> & {
|
|
4
5
|
image_src: string | StaticImageData;
|
|
5
6
|
image_alt: string;
|
|
6
7
|
image_background_color: string;
|
|
8
|
+
/** OAuth configuration */
|
|
9
|
+
oauth?: OAuthLayoutConfig;
|
|
7
10
|
};
|
|
8
11
|
/**
|
|
9
12
|
* Client wrapper for LoginLayout
|
|
10
13
|
* Initializes hazo_connect data client on client side and passes config from server
|
|
11
14
|
*/
|
|
12
|
-
export declare function LoginClientWrapper({ image_src, image_alt, image_background_color, redirectRoute, successMessage, alreadyLoggedInMessage, showLogoutButton, showReturnHomeButton, returnHomeButtonLabel, returnHomePath, forgotPasswordPath, forgotPasswordLabel, createAccountPath, createAccountLabel, }: LoginClientWrapperProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export declare function LoginClientWrapper({ image_src, image_alt, image_background_color, redirectRoute, successMessage, alreadyLoggedInMessage, showLogoutButton, showReturnHomeButton, returnHomeButtonLabel, returnHomePath, forgotPasswordPath, forgotPasswordLabel, createAccountPath, createAccountLabel, oauth, }: LoginClientWrapperProps): import("react/jsx-runtime").JSX.Element;
|
|
13
16
|
//# sourceMappingURL=login_client_wrapper.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login_client_wrapper.d.ts","sourceRoot":"","sources":["../../src/server_pages/login_client_wrapper.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"login_client_wrapper.d.ts","sourceRoot":"","sources":["../../src/server_pages/login_client_wrapper.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAGrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,WAAW,EAAE,UAAU,GAAG,UAAU,GAAG,sBAAsB,GAAG,OAAO,CAAC,GAAG;IACpH,SAAS,EAAE,MAAM,GAAG,eAAe,CAAC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,0BAA0B;IAC1B,KAAK,CAAC,EAAE,iBAAiB,CAAC;CAC3B,CAAC;AAGF;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,SAAS,EACT,SAAS,EACT,sBAAsB,EACtB,aAAa,EACb,cAAc,EACd,sBAAsB,EACtB,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAClB,KAAK,GACN,EAAE,uBAAuB,2CA2CzB"}
|
|
@@ -12,7 +12,7 @@ import { create_app_logger } from "../lib/app_logger";
|
|
|
12
12
|
* Client wrapper for LoginLayout
|
|
13
13
|
* Initializes hazo_connect data client on client side and passes config from server
|
|
14
14
|
*/
|
|
15
|
-
export function LoginClientWrapper({ image_src, image_alt, image_background_color, redirectRoute, successMessage, alreadyLoggedInMessage, showLogoutButton, showReturnHomeButton, returnHomeButtonLabel, returnHomePath, forgotPasswordPath, forgotPasswordLabel, createAccountPath, createAccountLabel, }) {
|
|
15
|
+
export function LoginClientWrapper({ image_src, image_alt, image_background_color, redirectRoute, successMessage, alreadyLoggedInMessage, showLogoutButton, showReturnHomeButton, returnHomeButtonLabel, returnHomePath, forgotPasswordPath, forgotPasswordLabel, createAccountPath, createAccountLabel, oauth, }) {
|
|
16
16
|
const [dataClient, setDataClient] = useState(null);
|
|
17
17
|
useEffect(() => {
|
|
18
18
|
// Initialize hazo_connect on client side
|
|
@@ -25,5 +25,5 @@ export function LoginClientWrapper({ image_src, image_alt, image_background_colo
|
|
|
25
25
|
return (_jsx("div", { className: "cls_login_page_loading flex items-center justify-center min-h-screen", children: _jsx("div", { className: "text-slate-600 animate-pulse", children: "Loading..." }) }));
|
|
26
26
|
}
|
|
27
27
|
const logger = create_app_logger();
|
|
28
|
-
return (_jsx(LoginLayout, { image_src: image_src, image_alt: image_alt, image_background_color: image_background_color, data_client: dataClient, logger: logger, redirectRoute: redirectRoute, successMessage: successMessage, alreadyLoggedInMessage: alreadyLoggedInMessage, showLogoutButton: showLogoutButton, showReturnHomeButton: showReturnHomeButton, returnHomeButtonLabel: returnHomeButtonLabel, returnHomePath: returnHomePath, forgot_password_path: forgotPasswordPath, forgot_password_label: forgotPasswordLabel, create_account_path: createAccountPath, create_account_label: createAccountLabel }));
|
|
28
|
+
return (_jsx(LoginLayout, { image_src: image_src, image_alt: image_alt, image_background_color: image_background_color, data_client: dataClient, logger: logger, redirectRoute: redirectRoute, successMessage: successMessage, alreadyLoggedInMessage: alreadyLoggedInMessage, showLogoutButton: showLogoutButton, showReturnHomeButton: showReturnHomeButton, returnHomeButtonLabel: returnHomeButtonLabel, returnHomePath: returnHomePath, forgot_password_path: forgotPasswordPath, forgot_password_label: forgotPasswordLabel, create_account_path: createAccountPath, create_account_label: createAccountLabel, oauth: oauth }));
|
|
29
29
|
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hazo_auth",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.3.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
|
-
"hazo_auth": "./
|
|
8
|
+
"hazo_auth": "./bin/hazo_auth.mjs"
|
|
9
9
|
},
|
|
10
10
|
"exports": {
|
|
11
11
|
".": {
|
|
@@ -119,6 +119,8 @@
|
|
|
119
119
|
},
|
|
120
120
|
"files": [
|
|
121
121
|
"dist/**/*",
|
|
122
|
+
"bin/**/*",
|
|
123
|
+
"cli-src/**/*",
|
|
122
124
|
"public/profile_pictures/library/**/*",
|
|
123
125
|
"hazo_auth_config.example.ini",
|
|
124
126
|
"hazo_notify_config.example.ini",
|
|
@@ -183,12 +185,14 @@
|
|
|
183
185
|
"morgan": "^1.10.1",
|
|
184
186
|
"multer": "^2.0.2",
|
|
185
187
|
"next": "^16.0.7",
|
|
188
|
+
"next-auth": "^4.24.13",
|
|
186
189
|
"next-themes": "^0.4.6",
|
|
187
190
|
"react": "^18.3.1",
|
|
188
191
|
"react-dom": "^18.3.1",
|
|
189
192
|
"sonner": "^2.0.7",
|
|
190
193
|
"tailwind-merge": "^3.4.0",
|
|
191
194
|
"tailwindcss-animate": "^1.0.7",
|
|
195
|
+
"tsx": "^4.20.6",
|
|
192
196
|
"zod": "^4.1.12"
|
|
193
197
|
},
|
|
194
198
|
"devDependencies": {
|