hazo_auth 1.0.5 → 1.2.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 +341 -0
- package/hazo_auth_config.example.ini +41 -0
- package/instrumentation.ts +2 -2
- package/package.json +2 -1
- package/scripts/init_users.ts +378 -0
- package/src/app/api/hazo_auth/login/route.ts +27 -1
- package/src/app/api/hazo_auth/register/route.ts +13 -10
- package/src/app/hazo_auth/forgot_password/page.tsx +3 -3
- package/src/app/hazo_auth/login/login_page_client.tsx +15 -0
- package/src/app/hazo_auth/login/page.tsx +16 -4
- package/src/app/hazo_auth/my_settings/page.tsx +3 -3
- package/src/app/hazo_auth/register/page.tsx +14 -4
- package/src/app/hazo_auth/register/register_page_client.tsx +9 -0
- package/src/app/hazo_auth/reset_password/page.tsx +3 -3
- package/src/app/hazo_auth/user_management/page.tsx +3 -3
- package/src/app/hazo_auth/verify_email/page.tsx +3 -3
- package/src/components/layouts/login/hooks/use_login_form.ts +13 -8
- package/src/components/layouts/login/index.tsx +28 -0
- package/src/components/layouts/register/hooks/use_register_form.ts +4 -1
- package/src/components/layouts/register/index.tsx +18 -0
- package/src/components/layouts/shared/components/auth_page_shell.tsx +36 -0
- package/src/components/layouts/shared/components/standalone_layout_wrapper.tsx +53 -0
- package/src/lib/config/config_loader.server.ts +20 -5
- package/src/lib/login_config.server.ts +25 -0
- package/src/lib/register_config.server.ts +17 -1
- package/src/lib/services/login_service.ts +19 -3
- package/src/lib/services/registration_service.ts +25 -4
- package/src/lib/services/user_profiles_service.ts +143 -0
- package/src/lib/services/user_update_service.ts +16 -3
- package/src/lib/ui_shell_config.server.ts +73 -0
- package/src/lib/utils/error_sanitizer.ts +75 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
// file_description: script to initialize users, roles, and permissions from configuration
|
|
2
|
+
// Run with: npx tsx scripts/init_users.ts init_users
|
|
3
|
+
// section: imports
|
|
4
|
+
import { get_hazo_connect_instance } from "../src/lib/hazo_connect_instance.server";
|
|
5
|
+
import { createCrudService } from "hazo_connect/server";
|
|
6
|
+
import { get_user_management_config } from "../src/lib/user_management_config.server";
|
|
7
|
+
import { get_config_value } from "../src/lib/config/config_loader.server";
|
|
8
|
+
import { create_app_logger } from "../src/lib/app_logger";
|
|
9
|
+
|
|
10
|
+
// section: types
|
|
11
|
+
type InitSummary = {
|
|
12
|
+
permissions: {
|
|
13
|
+
inserted: string[];
|
|
14
|
+
existing: string[];
|
|
15
|
+
};
|
|
16
|
+
role: {
|
|
17
|
+
inserted: boolean;
|
|
18
|
+
existing: boolean;
|
|
19
|
+
role_id: number | null;
|
|
20
|
+
};
|
|
21
|
+
role_permissions: {
|
|
22
|
+
inserted: number;
|
|
23
|
+
existing: number;
|
|
24
|
+
};
|
|
25
|
+
user_role: {
|
|
26
|
+
inserted: boolean;
|
|
27
|
+
existing: boolean;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// section: helpers
|
|
32
|
+
/**
|
|
33
|
+
* Displays help information for available commands
|
|
34
|
+
*/
|
|
35
|
+
function show_help(): void {
|
|
36
|
+
console.log(`
|
|
37
|
+
hazo_auth CLI - User and Permission Management
|
|
38
|
+
|
|
39
|
+
Usage: npx tsx scripts/init_users.ts <command>
|
|
40
|
+
|
|
41
|
+
Available Commands:
|
|
42
|
+
init_users Initialize users, roles, and permissions from configuration
|
|
43
|
+
- Reads permissions from hazo_auth_config.ini [hazo_auth__user_management] application_permission_list_defaults
|
|
44
|
+
- Creates default_super_user_role in hazo_roles
|
|
45
|
+
- Assigns all permissions to the super user role
|
|
46
|
+
- Finds user by email from hazo_auth_config.ini [hazo_auth__initial_setup] default_super_user_email
|
|
47
|
+
- Assigns super user role to the user
|
|
48
|
+
- Provides summary of what was inserted vs what already existed
|
|
49
|
+
|
|
50
|
+
help Show this help message
|
|
51
|
+
|
|
52
|
+
Configuration:
|
|
53
|
+
Add the following to hazo_auth_config.ini:
|
|
54
|
+
|
|
55
|
+
[hazo_auth__user_management]
|
|
56
|
+
application_permission_list_defaults = admin_user_management,admin_role_management,admin_permission_management
|
|
57
|
+
|
|
58
|
+
[hazo_auth__initial_setup]
|
|
59
|
+
default_super_user_email = admin@example.com
|
|
60
|
+
|
|
61
|
+
Examples:
|
|
62
|
+
npx tsx scripts/init_users.ts init_users
|
|
63
|
+
npx tsx scripts/init_users.ts help
|
|
64
|
+
`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Initializes users, roles, and permissions from configuration
|
|
69
|
+
*/
|
|
70
|
+
async function init_users(): Promise<void> {
|
|
71
|
+
const logger = create_app_logger();
|
|
72
|
+
const summary: InitSummary = {
|
|
73
|
+
permissions: {
|
|
74
|
+
inserted: [],
|
|
75
|
+
existing: [],
|
|
76
|
+
},
|
|
77
|
+
role: {
|
|
78
|
+
inserted: false,
|
|
79
|
+
existing: false,
|
|
80
|
+
role_id: null,
|
|
81
|
+
},
|
|
82
|
+
role_permissions: {
|
|
83
|
+
inserted: 0,
|
|
84
|
+
existing: 0,
|
|
85
|
+
},
|
|
86
|
+
user_role: {
|
|
87
|
+
inserted: false,
|
|
88
|
+
existing: false,
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
console.log("Initializing users, roles, and permissions from configuration...\n");
|
|
94
|
+
|
|
95
|
+
// Get hazo_connect instance
|
|
96
|
+
const hazoConnect = get_hazo_connect_instance();
|
|
97
|
+
const permissions_service = createCrudService(hazoConnect, "hazo_permissions");
|
|
98
|
+
const roles_service = createCrudService(hazoConnect, "hazo_roles");
|
|
99
|
+
const role_permissions_service = createCrudService(hazoConnect, "hazo_role_permissions");
|
|
100
|
+
const users_service = createCrudService(hazoConnect, "hazo_users");
|
|
101
|
+
const user_roles_service = createCrudService(hazoConnect, "hazo_user_roles");
|
|
102
|
+
|
|
103
|
+
// 1. Get permissions from config
|
|
104
|
+
const config = get_user_management_config();
|
|
105
|
+
const permission_names = config.application_permission_list_defaults || [];
|
|
106
|
+
|
|
107
|
+
if (permission_names.length === 0) {
|
|
108
|
+
console.log("⚠ No permissions found in configuration.");
|
|
109
|
+
console.log(" Add permissions to [hazo_auth__user_management] application_permission_list_defaults\n");
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
console.log(`Found ${permission_names.length} permission(s) in configuration:`);
|
|
114
|
+
permission_names.forEach((name) => console.log(` - ${name}`));
|
|
115
|
+
console.log();
|
|
116
|
+
|
|
117
|
+
// 2. Add permissions to hazo_permissions table
|
|
118
|
+
const permission_id_map: Record<string, number> = {};
|
|
119
|
+
const now = new Date().toISOString();
|
|
120
|
+
|
|
121
|
+
for (const permission_name of permission_names) {
|
|
122
|
+
const trimmed_name = permission_name.trim();
|
|
123
|
+
if (!trimmed_name) continue;
|
|
124
|
+
|
|
125
|
+
// Check if permission already exists
|
|
126
|
+
const existing_permissions = await permissions_service.findBy({
|
|
127
|
+
permission_name: trimmed_name,
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
if (Array.isArray(existing_permissions) && existing_permissions.length > 0) {
|
|
131
|
+
const existing_permission = existing_permissions[0];
|
|
132
|
+
const perm_id = existing_permission.id as number;
|
|
133
|
+
permission_id_map[trimmed_name] = perm_id;
|
|
134
|
+
summary.permissions.existing.push(trimmed_name);
|
|
135
|
+
console.log(`✓ Permission already exists: ${trimmed_name} (ID: ${perm_id})`);
|
|
136
|
+
} else {
|
|
137
|
+
// Insert new permission
|
|
138
|
+
const new_permission = await permissions_service.insert({
|
|
139
|
+
permission_name: trimmed_name,
|
|
140
|
+
description: `Permission for ${trimmed_name}`,
|
|
141
|
+
created_at: now,
|
|
142
|
+
changed_at: now,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const perm_id = Array.isArray(new_permission)
|
|
146
|
+
? (new_permission[0] as { id: number }).id
|
|
147
|
+
: (new_permission as { id: number }).id;
|
|
148
|
+
permission_id_map[trimmed_name] = perm_id;
|
|
149
|
+
summary.permissions.inserted.push(trimmed_name);
|
|
150
|
+
console.log(`✓ Inserted permission: ${trimmed_name} (ID: ${perm_id})`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
console.log();
|
|
155
|
+
|
|
156
|
+
// 3. Create or get default_super_user_role
|
|
157
|
+
const role_name = "default_super_user_role";
|
|
158
|
+
const existing_roles = await roles_service.findBy({
|
|
159
|
+
role_name,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
let role_id: number;
|
|
163
|
+
if (Array.isArray(existing_roles) && existing_roles.length > 0) {
|
|
164
|
+
role_id = existing_roles[0].id as number;
|
|
165
|
+
summary.role.existing = true;
|
|
166
|
+
summary.role.role_id = role_id;
|
|
167
|
+
console.log(`✓ Role already exists: ${role_name} (ID: ${role_id})`);
|
|
168
|
+
} else {
|
|
169
|
+
const new_role = await roles_service.insert({
|
|
170
|
+
role_name,
|
|
171
|
+
created_at: now,
|
|
172
|
+
changed_at: now,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
role_id = Array.isArray(new_role)
|
|
176
|
+
? (new_role[0] as { id: number }).id
|
|
177
|
+
: (new_role as { id: number }).id;
|
|
178
|
+
summary.role.inserted = true;
|
|
179
|
+
summary.role.role_id = role_id;
|
|
180
|
+
console.log(`✓ Created role: ${role_name} (ID: ${role_id})`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
console.log();
|
|
184
|
+
|
|
185
|
+
// 4. Assign all permissions to the role
|
|
186
|
+
const permission_ids = Object.values(permission_id_map);
|
|
187
|
+
|
|
188
|
+
for (const permission_id of permission_ids) {
|
|
189
|
+
// Check if role-permission assignment already exists
|
|
190
|
+
const existing_assignments = await role_permissions_service.findBy({
|
|
191
|
+
role_id,
|
|
192
|
+
permission_id,
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
if (Array.isArray(existing_assignments) && existing_assignments.length > 0) {
|
|
196
|
+
summary.role_permissions.existing++;
|
|
197
|
+
const perm_name = Object.keys(permission_id_map).find(
|
|
198
|
+
(key) => permission_id_map[key] === permission_id,
|
|
199
|
+
);
|
|
200
|
+
console.log(`✓ Role-permission already exists: ${role_name} -> ${perm_name}`);
|
|
201
|
+
} else {
|
|
202
|
+
await role_permissions_service.insert({
|
|
203
|
+
role_id,
|
|
204
|
+
permission_id,
|
|
205
|
+
created_at: now,
|
|
206
|
+
changed_at: now,
|
|
207
|
+
});
|
|
208
|
+
summary.role_permissions.inserted++;
|
|
209
|
+
const perm_name = Object.keys(permission_id_map).find(
|
|
210
|
+
(key) => permission_id_map[key] === permission_id,
|
|
211
|
+
);
|
|
212
|
+
console.log(`✓ Assigned permission to role: ${role_name} -> ${perm_name}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
console.log();
|
|
217
|
+
|
|
218
|
+
// 5. Get super user email from config
|
|
219
|
+
const super_user_email = get_config_value(
|
|
220
|
+
"hazo_auth__initial_setup",
|
|
221
|
+
"default_super_user_email",
|
|
222
|
+
"",
|
|
223
|
+
).trim();
|
|
224
|
+
|
|
225
|
+
if (!super_user_email) {
|
|
226
|
+
console.log("⚠ No super user email found in configuration.");
|
|
227
|
+
console.log(" Add [hazo_auth__initial_setup] default_super_user_email to config\n");
|
|
228
|
+
print_summary(summary);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
console.log(`Looking up user with email: ${super_user_email}`);
|
|
233
|
+
|
|
234
|
+
// 6. Find user by email
|
|
235
|
+
const users = await users_service.findBy({
|
|
236
|
+
email_address: super_user_email,
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
if (!Array.isArray(users) || users.length === 0) {
|
|
240
|
+
console.log(`✗ User not found with email: ${super_user_email}`);
|
|
241
|
+
console.log(" Please ensure the user exists in the database before running this script.\n");
|
|
242
|
+
print_summary(summary);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const user = users[0];
|
|
247
|
+
const user_id = user.id as string;
|
|
248
|
+
console.log(`✓ Found user: ${super_user_email} (ID: ${user_id})`);
|
|
249
|
+
console.log();
|
|
250
|
+
|
|
251
|
+
// 7. Assign role to user
|
|
252
|
+
const existing_user_roles = await user_roles_service.findBy({
|
|
253
|
+
user_id,
|
|
254
|
+
role_id,
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
if (Array.isArray(existing_user_roles) && existing_user_roles.length > 0) {
|
|
258
|
+
summary.user_role.existing = true;
|
|
259
|
+
console.log(`✓ User already has role assigned: ${user_id} -> ${role_name}`);
|
|
260
|
+
} else {
|
|
261
|
+
await user_roles_service.insert({
|
|
262
|
+
user_id,
|
|
263
|
+
role_id,
|
|
264
|
+
created_at: now,
|
|
265
|
+
changed_at: now,
|
|
266
|
+
});
|
|
267
|
+
summary.user_role.inserted = true;
|
|
268
|
+
console.log(`✓ Assigned role to user: ${user_id} -> ${role_name}`);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
console.log();
|
|
272
|
+
|
|
273
|
+
// 8. Print summary
|
|
274
|
+
print_summary(summary);
|
|
275
|
+
|
|
276
|
+
logger.info("init_users_completed", {
|
|
277
|
+
filename: "init_users.ts",
|
|
278
|
+
line_number: 0,
|
|
279
|
+
summary,
|
|
280
|
+
});
|
|
281
|
+
} catch (error) {
|
|
282
|
+
const error_message = error instanceof Error ? error.message : "Unknown error";
|
|
283
|
+
const error_stack = error instanceof Error ? error.stack : undefined;
|
|
284
|
+
|
|
285
|
+
console.error("\n✗ Error initializing users:");
|
|
286
|
+
console.error(` ${error_message}`);
|
|
287
|
+
if (error_stack) {
|
|
288
|
+
console.error("\nStack trace:");
|
|
289
|
+
console.error(error_stack);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const logger = create_app_logger();
|
|
293
|
+
logger.error("init_users_failed", {
|
|
294
|
+
filename: "init_users.ts",
|
|
295
|
+
line_number: 0,
|
|
296
|
+
error_message,
|
|
297
|
+
error_stack,
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
process.exit(1);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Prints a summary of what was inserted vs what already existed
|
|
306
|
+
*/
|
|
307
|
+
function print_summary(summary: InitSummary): void {
|
|
308
|
+
console.log("=".repeat(60));
|
|
309
|
+
console.log("INITIALIZATION SUMMARY");
|
|
310
|
+
console.log("=".repeat(60));
|
|
311
|
+
console.log();
|
|
312
|
+
|
|
313
|
+
// Permissions summary
|
|
314
|
+
console.log("Permissions:");
|
|
315
|
+
if (summary.permissions.inserted.length > 0) {
|
|
316
|
+
console.log(` ✓ Inserted (${summary.permissions.inserted.length}):`);
|
|
317
|
+
summary.permissions.inserted.forEach((name) => console.log(` - ${name}`));
|
|
318
|
+
}
|
|
319
|
+
if (summary.permissions.existing.length > 0) {
|
|
320
|
+
console.log(` ⊙ Already existed (${summary.permissions.existing.length}):`);
|
|
321
|
+
summary.permissions.existing.forEach((name) => console.log(` - ${name}`));
|
|
322
|
+
}
|
|
323
|
+
console.log();
|
|
324
|
+
|
|
325
|
+
// Role summary
|
|
326
|
+
console.log("Role:");
|
|
327
|
+
if (summary.role.inserted) {
|
|
328
|
+
console.log(` ✓ Inserted: default_super_user_role (ID: ${summary.role.role_id})`);
|
|
329
|
+
}
|
|
330
|
+
if (summary.role.existing) {
|
|
331
|
+
console.log(` ⊙ Already existed: default_super_user_role (ID: ${summary.role.role_id})`);
|
|
332
|
+
}
|
|
333
|
+
console.log();
|
|
334
|
+
|
|
335
|
+
// Role permissions summary
|
|
336
|
+
console.log("Role-Permission Assignments:");
|
|
337
|
+
if (summary.role_permissions.inserted > 0) {
|
|
338
|
+
console.log(` ✓ Inserted: ${summary.role_permissions.inserted} assignment(s)`);
|
|
339
|
+
}
|
|
340
|
+
if (summary.role_permissions.existing > 0) {
|
|
341
|
+
console.log(` ⊙ Already existed: ${summary.role_permissions.existing} assignment(s)`);
|
|
342
|
+
}
|
|
343
|
+
console.log();
|
|
344
|
+
|
|
345
|
+
// User role summary
|
|
346
|
+
console.log("User-Role Assignment:");
|
|
347
|
+
if (summary.user_role.inserted) {
|
|
348
|
+
console.log(` ✓ Inserted: Super user role assigned to user`);
|
|
349
|
+
}
|
|
350
|
+
if (summary.user_role.existing) {
|
|
351
|
+
console.log(` ⊙ Already existed: User already has super user role`);
|
|
352
|
+
}
|
|
353
|
+
console.log();
|
|
354
|
+
|
|
355
|
+
console.log("=".repeat(60));
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// section: main
|
|
359
|
+
function main(): void {
|
|
360
|
+
const command = process.argv[2];
|
|
361
|
+
|
|
362
|
+
if (!command || command === "help" || command === "--help" || command === "-h") {
|
|
363
|
+
show_help();
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (command === "init_users") {
|
|
368
|
+
void init_users();
|
|
369
|
+
} else {
|
|
370
|
+
console.error(`Unknown command: ${command}\n`);
|
|
371
|
+
show_help();
|
|
372
|
+
process.exit(1);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
main();
|
|
377
|
+
|
|
378
|
+
|
|
@@ -6,6 +6,7 @@ import { create_app_logger } from "../../../../lib/app_logger";
|
|
|
6
6
|
import { authenticate_user } from "../../../../lib/services/login_service";
|
|
7
7
|
import { createCrudService } from "hazo_connect/server";
|
|
8
8
|
import { get_filename, get_line_number } from "../../../../lib/utils/api_route_helpers";
|
|
9
|
+
import { get_login_config } from "../../../../lib/login_config.server";
|
|
9
10
|
|
|
10
11
|
// section: api_handler
|
|
11
12
|
export async function POST(request: NextRequest) {
|
|
@@ -13,7 +14,7 @@ export async function POST(request: NextRequest) {
|
|
|
13
14
|
|
|
14
15
|
try {
|
|
15
16
|
const body = await request.json();
|
|
16
|
-
const { email, password } = body;
|
|
17
|
+
const { email, password, url_on_logon } = body;
|
|
17
18
|
|
|
18
19
|
// Validate input
|
|
19
20
|
if (!email || !password) {
|
|
@@ -106,6 +107,30 @@ export async function POST(request: NextRequest) {
|
|
|
106
107
|
const user = users && users.length > 0 ? users[0] : null;
|
|
107
108
|
const user_name = user?.name as string | undefined;
|
|
108
109
|
|
|
110
|
+
// Determine redirect URL priority:
|
|
111
|
+
// 1. url_on_logon from request body (if valid)
|
|
112
|
+
// 2. stored_url_on_logon from database (if available)
|
|
113
|
+
// 3. redirect_route_on_successful_login from config
|
|
114
|
+
// 4. Default to "/"
|
|
115
|
+
|
|
116
|
+
let redirectUrl = "/";
|
|
117
|
+
|
|
118
|
+
// Check priority 1: Request body
|
|
119
|
+
if (url_on_logon && typeof url_on_logon === "string" && url_on_logon.startsWith("/") && !url_on_logon.startsWith("//")) {
|
|
120
|
+
redirectUrl = url_on_logon;
|
|
121
|
+
}
|
|
122
|
+
// Check priority 2: Stored URL from DB
|
|
123
|
+
else if (result.stored_url_on_logon && typeof result.stored_url_on_logon === "string") {
|
|
124
|
+
redirectUrl = result.stored_url_on_logon;
|
|
125
|
+
}
|
|
126
|
+
// Check priority 3: Config
|
|
127
|
+
else {
|
|
128
|
+
const loginConfig = get_login_config();
|
|
129
|
+
if (loginConfig.redirectRoute) {
|
|
130
|
+
redirectUrl = loginConfig.redirectRoute;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
109
134
|
// Create response with cookies
|
|
110
135
|
const response = NextResponse.json(
|
|
111
136
|
{
|
|
@@ -114,6 +139,7 @@ export async function POST(request: NextRequest) {
|
|
|
114
139
|
user_id: user_id,
|
|
115
140
|
email,
|
|
116
141
|
name: user_name,
|
|
142
|
+
redirectUrl,
|
|
117
143
|
},
|
|
118
144
|
{ status: 200 }
|
|
119
145
|
);
|
|
@@ -5,6 +5,7 @@ import { get_hazo_connect_instance } from "../../../../lib/hazo_connect_instance
|
|
|
5
5
|
import { create_app_logger } from "../../../../lib/app_logger";
|
|
6
6
|
import { register_user } from "../../../../lib/services/registration_service";
|
|
7
7
|
import { get_filename, get_line_number } from "../../../../lib/utils/api_route_helpers";
|
|
8
|
+
import { sanitize_error_for_user } from "../../../../lib/utils/error_sanitizer";
|
|
8
9
|
|
|
9
10
|
// section: api_handler
|
|
10
11
|
export async function POST(request: NextRequest) {
|
|
@@ -12,7 +13,7 @@ export async function POST(request: NextRequest) {
|
|
|
12
13
|
|
|
13
14
|
try {
|
|
14
15
|
const body = await request.json();
|
|
15
|
-
const { name, email, password } = body;
|
|
16
|
+
const { name, email, password, url_on_logon } = body;
|
|
16
17
|
|
|
17
18
|
// Validate input
|
|
18
19
|
if (!email || !password) {
|
|
@@ -52,6 +53,7 @@ export async function POST(request: NextRequest) {
|
|
|
52
53
|
email,
|
|
53
54
|
password,
|
|
54
55
|
name,
|
|
56
|
+
url_on_logon,
|
|
55
57
|
});
|
|
56
58
|
|
|
57
59
|
if (!result.success) {
|
|
@@ -87,18 +89,19 @@ export async function POST(request: NextRequest) {
|
|
|
87
89
|
{ status: 201 }
|
|
88
90
|
);
|
|
89
91
|
} catch (error) {
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
92
|
+
const user_friendly_error = sanitize_error_for_user(error, {
|
|
93
|
+
logToConsole: true,
|
|
94
|
+
logToLogger: true,
|
|
95
|
+
logger,
|
|
96
|
+
context: {
|
|
97
|
+
filename: get_filename(),
|
|
98
|
+
line_number: get_line_number(),
|
|
99
|
+
operation: "register_api_route",
|
|
100
|
+
},
|
|
98
101
|
});
|
|
99
102
|
|
|
100
103
|
return NextResponse.json(
|
|
101
|
-
{ error:
|
|
104
|
+
{ error: user_friendly_error },
|
|
102
105
|
{ status: 500 }
|
|
103
106
|
);
|
|
104
107
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// file_description: render the forgot password page shell and mount the forgot password layout component within sidebar
|
|
2
2
|
// section: imports
|
|
3
|
-
import {
|
|
3
|
+
import { AuthPageShell } from "../../../components/layouts/shared/components/auth_page_shell";
|
|
4
4
|
import { ForgotPasswordPageClient } from "./forgot_password_page_client";
|
|
5
5
|
import { get_forgot_password_config } from "../../../lib/forgot_password_config.server";
|
|
6
6
|
|
|
@@ -10,7 +10,7 @@ export default function forgot_password_page() {
|
|
|
10
10
|
const forgotPasswordConfig = get_forgot_password_config();
|
|
11
11
|
|
|
12
12
|
return (
|
|
13
|
-
<
|
|
13
|
+
<AuthPageShell>
|
|
14
14
|
<ForgotPasswordPageClient
|
|
15
15
|
alreadyLoggedInMessage={forgotPasswordConfig.alreadyLoggedInMessage}
|
|
16
16
|
showLogoutButton={forgotPasswordConfig.showLogoutButton}
|
|
@@ -18,7 +18,7 @@ export default function forgot_password_page() {
|
|
|
18
18
|
returnHomeButtonLabel={forgotPasswordConfig.returnHomeButtonLabel}
|
|
19
19
|
returnHomePath={forgotPasswordConfig.returnHomePath}
|
|
20
20
|
/>
|
|
21
|
-
</
|
|
21
|
+
</AuthPageShell>
|
|
22
22
|
);
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -19,6 +19,11 @@ type LoginPageClientProps = {
|
|
|
19
19
|
showReturnHomeButton?: boolean;
|
|
20
20
|
returnHomeButtonLabel?: string;
|
|
21
21
|
returnHomePath?: string;
|
|
22
|
+
forgotPasswordPath?: string;
|
|
23
|
+
forgotPasswordLabel?: string;
|
|
24
|
+
createAccountPath?: string;
|
|
25
|
+
createAccountLabel?: string;
|
|
26
|
+
urlOnLogon?: string;
|
|
22
27
|
};
|
|
23
28
|
|
|
24
29
|
// section: component
|
|
@@ -30,6 +35,11 @@ export function LoginPageClient({
|
|
|
30
35
|
showReturnHomeButton,
|
|
31
36
|
returnHomeButtonLabel,
|
|
32
37
|
returnHomePath,
|
|
38
|
+
forgotPasswordPath,
|
|
39
|
+
forgotPasswordLabel,
|
|
40
|
+
createAccountPath,
|
|
41
|
+
createAccountLabel,
|
|
42
|
+
urlOnLogon,
|
|
33
43
|
}: LoginPageClientProps) {
|
|
34
44
|
const [dataClient, setDataClient] = useState<LayoutDataClient<unknown> | null>(null);
|
|
35
45
|
const [logger, setLogger] = useState<ReturnType<typeof create_app_logger> | null>(null);
|
|
@@ -65,6 +75,11 @@ export function LoginPageClient({
|
|
|
65
75
|
showReturnHomeButton={showReturnHomeButton}
|
|
66
76
|
returnHomeButtonLabel={returnHomeButtonLabel}
|
|
67
77
|
returnHomePath={returnHomePath}
|
|
78
|
+
forgot_password_path={forgotPasswordPath}
|
|
79
|
+
forgot_password_label={forgotPasswordLabel}
|
|
80
|
+
create_account_path={createAccountPath}
|
|
81
|
+
create_account_label={createAccountLabel}
|
|
82
|
+
urlOnLogon={urlOnLogon}
|
|
68
83
|
/>
|
|
69
84
|
);
|
|
70
85
|
}
|
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
// file_description: render the login page shell and mount the login layout component within sidebar
|
|
2
2
|
// section: imports
|
|
3
|
-
import {
|
|
3
|
+
import { AuthPageShell } from "../../../components/layouts/shared/components/auth_page_shell";
|
|
4
4
|
import { LoginPageClient } from "./login_page_client";
|
|
5
5
|
import { get_login_config } from "../../../lib/login_config.server";
|
|
6
6
|
|
|
7
7
|
// section: component
|
|
8
|
-
export default function login_page(
|
|
8
|
+
export default function login_page({
|
|
9
|
+
searchParams,
|
|
10
|
+
}: {
|
|
11
|
+
searchParams: { [key: string]: string | string[] | undefined };
|
|
12
|
+
}) {
|
|
9
13
|
// Read login configuration from hazo_auth_config.ini (server-side)
|
|
10
14
|
const loginConfig = get_login_config();
|
|
11
15
|
|
|
16
|
+
// Get url_on_logon from query params (if any)
|
|
17
|
+
const urlOnLogon = typeof searchParams.url_on_logon === "string" ? searchParams.url_on_logon : undefined;
|
|
18
|
+
|
|
12
19
|
return (
|
|
13
|
-
<
|
|
20
|
+
<AuthPageShell>
|
|
14
21
|
<LoginPageClient
|
|
15
22
|
redirectRoute={loginConfig.redirectRoute}
|
|
16
23
|
successMessage={loginConfig.successMessage}
|
|
@@ -19,8 +26,13 @@ export default function login_page() {
|
|
|
19
26
|
showReturnHomeButton={loginConfig.showReturnHomeButton}
|
|
20
27
|
returnHomeButtonLabel={loginConfig.returnHomeButtonLabel}
|
|
21
28
|
returnHomePath={loginConfig.returnHomePath}
|
|
29
|
+
forgotPasswordPath={loginConfig.forgotPasswordPath}
|
|
30
|
+
forgotPasswordLabel={loginConfig.forgotPasswordLabel}
|
|
31
|
+
createAccountPath={loginConfig.createAccountPath}
|
|
32
|
+
createAccountLabel={loginConfig.createAccountLabel}
|
|
33
|
+
urlOnLogon={urlOnLogon}
|
|
22
34
|
/>
|
|
23
|
-
</
|
|
35
|
+
</AuthPageShell>
|
|
24
36
|
);
|
|
25
37
|
}
|
|
26
38
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// file_description: render the my settings page shell and mount the my settings layout component within sidebar
|
|
2
2
|
// section: imports
|
|
3
|
-
import {
|
|
3
|
+
import { AuthPageShell } from "../../../components/layouts/shared/components/auth_page_shell";
|
|
4
4
|
import { MySettingsPageClient } from "./my_settings_page_client";
|
|
5
5
|
import { get_my_settings_config } from "../../../lib/my_settings_config.server";
|
|
6
6
|
|
|
@@ -10,7 +10,7 @@ export default function my_settings_page() {
|
|
|
10
10
|
const mySettingsConfig = get_my_settings_config();
|
|
11
11
|
|
|
12
12
|
return (
|
|
13
|
-
<
|
|
13
|
+
<AuthPageShell>
|
|
14
14
|
<MySettingsPageClient
|
|
15
15
|
userFields={mySettingsConfig.userFields}
|
|
16
16
|
passwordRequirements={mySettingsConfig.passwordRequirements}
|
|
@@ -34,7 +34,7 @@ export default function my_settings_page() {
|
|
|
34
34
|
uiSizes={mySettingsConfig.uiSizes}
|
|
35
35
|
fileTypes={mySettingsConfig.fileTypes}
|
|
36
36
|
/>
|
|
37
|
-
</
|
|
37
|
+
</AuthPageShell>
|
|
38
38
|
);
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
// file_description: render the register page shell and mount the register layout component within sidebar
|
|
2
2
|
// section: imports
|
|
3
|
-
import {
|
|
3
|
+
import { AuthPageShell } from "../../../components/layouts/shared/components/auth_page_shell";
|
|
4
4
|
import { RegisterPageClient } from "./register_page_client";
|
|
5
5
|
import { get_register_config } from "../../../lib/register_config.server";
|
|
6
6
|
|
|
7
7
|
// section: component
|
|
8
|
-
export default function register_page(
|
|
8
|
+
export default function register_page({
|
|
9
|
+
searchParams,
|
|
10
|
+
}: {
|
|
11
|
+
searchParams: { [key: string]: string | string[] | undefined };
|
|
12
|
+
}) {
|
|
9
13
|
// Read register configuration from hazo_auth_config.ini (server-side)
|
|
10
14
|
const registerConfig = get_register_config();
|
|
11
15
|
|
|
16
|
+
// Get url_on_logon from query params (if any)
|
|
17
|
+
const urlOnLogon = typeof searchParams.url_on_logon === "string" ? searchParams.url_on_logon : undefined;
|
|
18
|
+
|
|
12
19
|
return (
|
|
13
|
-
<
|
|
20
|
+
<AuthPageShell>
|
|
14
21
|
<RegisterPageClient
|
|
15
22
|
showNameField={registerConfig.showNameField}
|
|
16
23
|
passwordRequirements={registerConfig.passwordRequirements}
|
|
@@ -19,8 +26,11 @@ export default function register_page() {
|
|
|
19
26
|
showReturnHomeButton={registerConfig.showReturnHomeButton}
|
|
20
27
|
returnHomeButtonLabel={registerConfig.returnHomeButtonLabel}
|
|
21
28
|
returnHomePath={registerConfig.returnHomePath}
|
|
29
|
+
signInPath={registerConfig.signInPath}
|
|
30
|
+
signInLabel={registerConfig.signInLabel}
|
|
31
|
+
urlOnLogon={urlOnLogon}
|
|
22
32
|
/>
|
|
23
|
-
</
|
|
33
|
+
</AuthPageShell>
|
|
24
34
|
);
|
|
25
35
|
}
|
|
26
36
|
|
|
@@ -24,6 +24,9 @@ type RegisterPageClientProps = {
|
|
|
24
24
|
showReturnHomeButton?: boolean;
|
|
25
25
|
returnHomeButtonLabel?: string;
|
|
26
26
|
returnHomePath?: string;
|
|
27
|
+
signInPath?: string;
|
|
28
|
+
signInLabel?: string;
|
|
29
|
+
urlOnLogon?: string;
|
|
27
30
|
};
|
|
28
31
|
|
|
29
32
|
// section: component
|
|
@@ -35,6 +38,9 @@ export function RegisterPageClient({
|
|
|
35
38
|
showReturnHomeButton,
|
|
36
39
|
returnHomeButtonLabel,
|
|
37
40
|
returnHomePath,
|
|
41
|
+
signInPath,
|
|
42
|
+
signInLabel,
|
|
43
|
+
urlOnLogon,
|
|
38
44
|
}: RegisterPageClientProps) {
|
|
39
45
|
const [dataClient, setDataClient] = useState<LayoutDataClient<unknown> | null>(null);
|
|
40
46
|
|
|
@@ -66,6 +72,9 @@ export function RegisterPageClient({
|
|
|
66
72
|
showReturnHomeButton={showReturnHomeButton}
|
|
67
73
|
returnHomeButtonLabel={returnHomeButtonLabel}
|
|
68
74
|
returnHomePath={returnHomePath}
|
|
75
|
+
signInPath={signInPath}
|
|
76
|
+
signInLabel={signInLabel}
|
|
77
|
+
urlOnLogon={urlOnLogon}
|
|
69
78
|
/>
|
|
70
79
|
);
|
|
71
80
|
}
|