hazo_auth 4.2.0 → 4.4.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/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 +117 -0
- package/cli-src/lib/auth/auth_utils.server.ts +196 -0
- package/cli-src/lib/auth/dev_lock_validator.edge.ts +171 -0
- package/cli-src/lib/auth/hazo_get_auth.server.ts +583 -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/org_cache.ts +148 -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 +92 -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 +243 -0
- package/cli-src/lib/dev_lock_config.server.ts +148 -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/multi_tenancy_config.server.ts +94 -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/org_service.ts +965 -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 +178 -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/cli-src/server/types/app_types.ts +74 -0
- package/cli-src/server/types/express.d.ts +16 -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/dev_lock/index.d.ts +29 -0
- package/dist/components/layouts/dev_lock/index.d.ts.map +1 -0
- package/dist/components/layouts/dev_lock/index.js +60 -0
- package/dist/components/layouts/index.d.ts +2 -0
- package/dist/components/layouts/index.d.ts.map +1 -1
- package/dist/components/layouts/index.js +1 -0
- package/dist/components/layouts/org_management/index.d.ts +26 -0
- package/dist/components/layouts/org_management/index.d.ts.map +1 -0
- package/dist/components/layouts/org_management/index.js +75 -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/user_management/components/org_hierarchy_tab.d.ts +13 -0
- package/dist/components/layouts/user_management/components/org_hierarchy_tab.d.ts.map +1 -0
- package/dist/components/layouts/user_management/components/org_hierarchy_tab.js +276 -0
- package/dist/components/layouts/user_management/index.d.ts +3 -1
- package/dist/components/layouts/user_management/index.d.ts.map +1 -1
- package/dist/components/layouts/user_management/index.js +10 -4
- package/dist/lib/auth/auth_types.d.ts +6 -0
- package/dist/lib/auth/auth_types.d.ts.map +1 -1
- package/dist/lib/auth/dev_lock_validator.edge.d.ts +38 -0
- package/dist/lib/auth/dev_lock_validator.edge.d.ts.map +1 -0
- package/dist/lib/auth/dev_lock_validator.edge.js +122 -0
- package/dist/lib/auth/hazo_get_auth.server.d.ts.map +1 -1
- package/dist/lib/auth/hazo_get_auth.server.js +61 -1
- package/dist/lib/auth/org_cache.d.ts +65 -0
- package/dist/lib/auth/org_cache.d.ts.map +1 -0
- package/dist/lib/auth/org_cache.js +103 -0
- package/dist/lib/config/default_config.d.ts +76 -0
- package/dist/lib/config/default_config.d.ts.map +1 -1
- package/dist/lib/config/default_config.js +42 -0
- package/dist/lib/dev_lock_config.server.d.ts +41 -0
- package/dist/lib/dev_lock_config.server.d.ts.map +1 -0
- package/dist/lib/dev_lock_config.server.js +50 -0
- package/dist/lib/multi_tenancy_config.server.d.ts +30 -0
- package/dist/lib/multi_tenancy_config.server.d.ts.map +1 -0
- package/dist/lib/multi_tenancy_config.server.js +41 -0
- package/dist/lib/services/org_service.d.ts +191 -0
- package/dist/lib/services/org_service.d.ts.map +1 -0
- package/dist/lib/services/org_service.js +746 -0
- package/dist/lib/utils/password_validator.d.ts +7 -1
- package/dist/lib/utils/password_validator.d.ts.map +1 -1
- package/dist/page_components/dev_lock.d.ts +11 -0
- package/dist/page_components/dev_lock.d.ts.map +1 -0
- package/dist/page_components/dev_lock.js +17 -0
- package/dist/page_components/index.d.ts +1 -0
- package/dist/page_components/index.d.ts.map +1 -1
- package/dist/page_components/index.js +1 -0
- package/dist/page_components/org_management.d.ts +27 -0
- package/dist/page_components/org_management.d.ts.map +1 -0
- package/dist/page_components/org_management.js +18 -0
- package/hazo_auth_config.example.ini +30 -0
- package/package.json +27 -3
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// file_description: load ui shell layout settings from hazo_auth_config.ini
|
|
2
|
+
// section: imports
|
|
3
|
+
import { get_config_value } from "./config/config_loader.server.js";
|
|
4
|
+
|
|
5
|
+
// section: types
|
|
6
|
+
export type UiShellLayoutMode = "test_sidebar" | "standalone";
|
|
7
|
+
|
|
8
|
+
export type UiShellConfig = {
|
|
9
|
+
layout_mode: UiShellLayoutMode;
|
|
10
|
+
standalone_heading: string;
|
|
11
|
+
standalone_description: string;
|
|
12
|
+
standalone_wrapper_class: string;
|
|
13
|
+
standalone_content_class: string;
|
|
14
|
+
standalone_show_heading: boolean;
|
|
15
|
+
standalone_show_description: boolean;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// section: helpers
|
|
19
|
+
/**
|
|
20
|
+
* Reads ui shell configuration controlling whether pages use the sidebar test shell
|
|
21
|
+
* or a clean standalone wrapper that inherits consumer project styling.
|
|
22
|
+
*/
|
|
23
|
+
export function get_ui_shell_config(): UiShellConfig {
|
|
24
|
+
const section = "hazo_auth__ui_shell";
|
|
25
|
+
|
|
26
|
+
const layoutModeValue = get_config_value(section, "layout_mode", "test_sidebar").toLowerCase();
|
|
27
|
+
const layout_mode: UiShellLayoutMode =
|
|
28
|
+
layoutModeValue === "standalone" ? "standalone" : "test_sidebar";
|
|
29
|
+
|
|
30
|
+
const standalone_heading = get_config_value(
|
|
31
|
+
section,
|
|
32
|
+
"standalone_heading",
|
|
33
|
+
"Welcome to hazo auth"
|
|
34
|
+
);
|
|
35
|
+
const standalone_description = get_config_value(
|
|
36
|
+
section,
|
|
37
|
+
"standalone_description",
|
|
38
|
+
"Reuse the packaged authentication flows while inheriting your existing app shell styles."
|
|
39
|
+
);
|
|
40
|
+
const standalone_wrapper_class = get_config_value(
|
|
41
|
+
section,
|
|
42
|
+
"standalone_wrapper_class",
|
|
43
|
+
"cls_standalone_shell flex min-h-screen w-full items-center justify-center bg-background px-4 py-10"
|
|
44
|
+
);
|
|
45
|
+
const standalone_content_class = get_config_value(
|
|
46
|
+
section,
|
|
47
|
+
"standalone_content_class",
|
|
48
|
+
"cls_standalone_shell_content w-full max-w-5xl shadow-xl rounded-2xl border bg-card"
|
|
49
|
+
);
|
|
50
|
+
const standalone_show_heading = get_config_value(
|
|
51
|
+
section,
|
|
52
|
+
"standalone_show_heading",
|
|
53
|
+
"true"
|
|
54
|
+
).toLowerCase() === "true";
|
|
55
|
+
const standalone_show_description = get_config_value(
|
|
56
|
+
section,
|
|
57
|
+
"standalone_show_description",
|
|
58
|
+
"true"
|
|
59
|
+
).toLowerCase() === "true";
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
layout_mode,
|
|
63
|
+
standalone_heading,
|
|
64
|
+
standalone_description,
|
|
65
|
+
standalone_wrapper_class,
|
|
66
|
+
standalone_content_class,
|
|
67
|
+
standalone_show_heading,
|
|
68
|
+
standalone_show_description,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// file_description: server-only helper to read UI size configuration from hazo_auth_config.ini
|
|
2
|
+
// section: imports
|
|
3
|
+
import { get_config_number } from "./config/config_loader.server.js";
|
|
4
|
+
|
|
5
|
+
// section: types
|
|
6
|
+
export type UISizesConfig = {
|
|
7
|
+
gravatar_size: number;
|
|
8
|
+
profile_picture_size: number;
|
|
9
|
+
tooltip_icon_size_default: number;
|
|
10
|
+
tooltip_icon_size_small: number;
|
|
11
|
+
library_photo_grid_columns: number;
|
|
12
|
+
library_photo_preview_size: number;
|
|
13
|
+
image_compression_max_dimension: number;
|
|
14
|
+
upload_file_hard_limit_bytes: number;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// section: helpers
|
|
18
|
+
/**
|
|
19
|
+
* Reads UI size configuration from hazo_auth_config.ini file
|
|
20
|
+
* Falls back to defaults if hazo_auth_config.ini is not found or section is missing
|
|
21
|
+
* @returns UI sizes configuration options
|
|
22
|
+
*/
|
|
23
|
+
export function get_ui_sizes_config(): UISizesConfig {
|
|
24
|
+
const section = "hazo_auth__ui_sizes";
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
gravatar_size: get_config_number(section, "gravatar_size", 200),
|
|
28
|
+
profile_picture_size: get_config_number(section, "profile_picture_size", 200),
|
|
29
|
+
tooltip_icon_size_default: get_config_number(section, "tooltip_icon_size_default", 16),
|
|
30
|
+
tooltip_icon_size_small: get_config_number(section, "tooltip_icon_size_small", 14),
|
|
31
|
+
library_photo_grid_columns: get_config_number(section, "library_photo_grid_columns", 4),
|
|
32
|
+
library_photo_preview_size: get_config_number(section, "library_photo_preview_size", 200),
|
|
33
|
+
image_compression_max_dimension: get_config_number(section, "image_compression_max_dimension", 200),
|
|
34
|
+
upload_file_hard_limit_bytes: get_config_number(section, "upload_file_hard_limit_bytes", 10485760), // 10MB
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// file_description: server-only helper to read shared user fields configuration from hazo_auth_config.ini
|
|
2
|
+
// section: imports
|
|
3
|
+
import { get_config_boolean } from "./config/config_loader.server.js";
|
|
4
|
+
|
|
5
|
+
// section: types
|
|
6
|
+
export type UserFieldsConfig = {
|
|
7
|
+
show_name_field: boolean;
|
|
8
|
+
show_email_field: boolean;
|
|
9
|
+
show_password_field: boolean;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// section: helpers
|
|
13
|
+
/**
|
|
14
|
+
* Reads shared user fields configuration from hazo_auth_config.ini file
|
|
15
|
+
* Falls back to defaults if hazo_auth_config.ini is not found or section is missing
|
|
16
|
+
* This configuration is used by register and my_settings layouts
|
|
17
|
+
* @returns User fields configuration options
|
|
18
|
+
*/
|
|
19
|
+
export function get_user_fields_config(): UserFieldsConfig {
|
|
20
|
+
// Read field visibility with defaults (all true by default)
|
|
21
|
+
const show_name_field = get_config_boolean("hazo_auth__user_fields", "show_name_field", true);
|
|
22
|
+
const show_email_field = get_config_boolean("hazo_auth__user_fields", "show_email_field", true);
|
|
23
|
+
const show_password_field = get_config_boolean("hazo_auth__user_fields", "show_password_field", true);
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
show_name_field,
|
|
27
|
+
show_email_field,
|
|
28
|
+
show_password_field,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// file_description: server-only helper to read user management configuration from hazo_auth_config.ini
|
|
2
|
+
// section: imports
|
|
3
|
+
import { get_config_value, get_config_array, read_config_section } from "./config/config_loader.server.js";
|
|
4
|
+
|
|
5
|
+
// section: types
|
|
6
|
+
export type UserManagementConfig = {
|
|
7
|
+
application_permission_list_defaults: string[];
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// section: helpers
|
|
11
|
+
/**
|
|
12
|
+
* Reads user management configuration from hazo_auth_config.ini file
|
|
13
|
+
* Falls back to defaults if hazo_auth_config.ini is not found or section is missing
|
|
14
|
+
* @returns User management configuration options
|
|
15
|
+
*/
|
|
16
|
+
export function get_user_management_config(): UserManagementConfig {
|
|
17
|
+
// Try to read from hazo_auth__user_management section first
|
|
18
|
+
const user_management_section = read_config_section("hazo_auth__user_management");
|
|
19
|
+
const permissions_section = read_config_section("permissions");
|
|
20
|
+
|
|
21
|
+
// Try application_permission_list_defaults from user_management section
|
|
22
|
+
let permission_list: string[] = [];
|
|
23
|
+
|
|
24
|
+
if (user_management_section?.application_permission_list_defaults) {
|
|
25
|
+
permission_list = get_config_array(
|
|
26
|
+
"hazo_auth__user_management",
|
|
27
|
+
"application_permission_list_defaults",
|
|
28
|
+
[]
|
|
29
|
+
);
|
|
30
|
+
} else if (permissions_section?.list) {
|
|
31
|
+
// Fallback to permissions section list key
|
|
32
|
+
permission_list = get_config_array("permissions", "list", []);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
application_permission_list_defaults: permission_list,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// file_description: server-only helper to read user profiles cache configuration from hazo_auth_config.ini
|
|
2
|
+
// section: imports
|
|
3
|
+
import {
|
|
4
|
+
get_config_number,
|
|
5
|
+
} from "./config/config_loader.server.js";
|
|
6
|
+
|
|
7
|
+
// section: types
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* User profiles cache configuration options
|
|
11
|
+
*/
|
|
12
|
+
export type UserProfilesCacheConfig = {
|
|
13
|
+
cache_enabled: boolean;
|
|
14
|
+
cache_max_entries: number;
|
|
15
|
+
cache_ttl_minutes: number;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// section: helpers
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Reads user profiles cache configuration from hazo_auth_config.ini file
|
|
22
|
+
* Falls back to defaults if hazo_auth_config.ini is not found or section is missing
|
|
23
|
+
* @returns User profiles cache configuration options
|
|
24
|
+
*/
|
|
25
|
+
export function get_user_profiles_cache_config(): UserProfilesCacheConfig {
|
|
26
|
+
const section_name = "hazo_auth__user_profiles";
|
|
27
|
+
|
|
28
|
+
// Cache settings
|
|
29
|
+
// cache_enabled: 0 = disabled, 1 = enabled (default: 1)
|
|
30
|
+
const cache_enabled_num = get_config_number(
|
|
31
|
+
section_name,
|
|
32
|
+
"cache_enabled",
|
|
33
|
+
1,
|
|
34
|
+
);
|
|
35
|
+
const cache_enabled = cache_enabled_num === 1;
|
|
36
|
+
|
|
37
|
+
const cache_max_entries = get_config_number(
|
|
38
|
+
section_name,
|
|
39
|
+
"cache_max_entries",
|
|
40
|
+
5000, // Default: 5000 entries
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const cache_ttl_minutes = get_config_number(
|
|
44
|
+
section_name,
|
|
45
|
+
"cache_ttl_minutes",
|
|
46
|
+
5, // Default: 5 minutes
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
cache_enabled,
|
|
51
|
+
cache_max_entries,
|
|
52
|
+
cache_ttl_minutes,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// file_description: shared helper functions for API routes to get filename and line number
|
|
2
|
+
// section: helpers
|
|
3
|
+
/**
|
|
4
|
+
* Gets the filename from the call stack
|
|
5
|
+
* This is a simplified version that extracts the filename from the error stack
|
|
6
|
+
* @returns Filename or "route.ts" as default
|
|
7
|
+
*/
|
|
8
|
+
export function get_filename(): string {
|
|
9
|
+
try {
|
|
10
|
+
const stack = new Error().stack;
|
|
11
|
+
if (!stack) {
|
|
12
|
+
return "route.ts";
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Parse stack trace to find the caller's file
|
|
16
|
+
const lines = stack.split("\n");
|
|
17
|
+
// Skip Error line and get_filename line, get the actual caller
|
|
18
|
+
for (let i = 2; i < lines.length; i++) {
|
|
19
|
+
const line = lines[i];
|
|
20
|
+
// Match file paths in stack trace (e.g., "at /path/to/file.ts:123:45")
|
|
21
|
+
const match = line.match(/([^/\\]+\.tsx?):(\d+):(\d+)/);
|
|
22
|
+
if (match) {
|
|
23
|
+
return match[1];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return "route.ts";
|
|
27
|
+
} catch {
|
|
28
|
+
return "route.ts";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Gets the line number from the call stack
|
|
34
|
+
* This is a simplified version that extracts the line number from the error stack
|
|
35
|
+
* @returns Line number or 0
|
|
36
|
+
*/
|
|
37
|
+
export function get_line_number(): number {
|
|
38
|
+
try {
|
|
39
|
+
const stack = new Error().stack;
|
|
40
|
+
if (!stack) {
|
|
41
|
+
return 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Parse stack trace to find the caller's line number
|
|
45
|
+
const lines = stack.split("\n");
|
|
46
|
+
// Skip Error line and get_line_number line, get the actual caller
|
|
47
|
+
for (let i = 2; i < lines.length; i++) {
|
|
48
|
+
const line = lines[i];
|
|
49
|
+
// Match line numbers in stack trace (e.g., "at /path/to/file.ts:123:45")
|
|
50
|
+
const match = line.match(/([^/\\]+\.tsx?):(\d+):(\d+)/);
|
|
51
|
+
if (match) {
|
|
52
|
+
return parseInt(match[2], 10) || 0;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return 0;
|
|
56
|
+
} catch {
|
|
57
|
+
return 0;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// file_description: utility functions for sanitizing error messages for user display
|
|
2
|
+
// section: imports
|
|
3
|
+
import { create_app_logger } from "../app_logger.js";
|
|
4
|
+
|
|
5
|
+
// section: constants
|
|
6
|
+
const USER_FRIENDLY_ERROR_MESSAGE = "We are facing some issues in our system, please try again later.";
|
|
7
|
+
|
|
8
|
+
// section: types
|
|
9
|
+
export type ErrorSanitizationOptions = {
|
|
10
|
+
logToConsole?: boolean;
|
|
11
|
+
logToLogger?: boolean;
|
|
12
|
+
logger?: ReturnType<typeof create_app_logger>;
|
|
13
|
+
context?: Record<string, unknown>;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// section: helpers
|
|
17
|
+
/**
|
|
18
|
+
* Sanitizes error messages for user display
|
|
19
|
+
* Replaces technical error messages with user-friendly ones
|
|
20
|
+
* @param error - The error object or message
|
|
21
|
+
* @param options - Options for logging and context
|
|
22
|
+
* @returns User-friendly error message
|
|
23
|
+
*/
|
|
24
|
+
export function sanitize_error_for_user(
|
|
25
|
+
error: unknown,
|
|
26
|
+
options: ErrorSanitizationOptions = {}
|
|
27
|
+
): string {
|
|
28
|
+
const { logToConsole = true, logToLogger = true, logger, context = {} } = options;
|
|
29
|
+
|
|
30
|
+
// Extract detailed error message
|
|
31
|
+
const detailed_error_message =
|
|
32
|
+
error instanceof Error ? error.message : String(error);
|
|
33
|
+
const error_stack = error instanceof Error ? error.stack : undefined;
|
|
34
|
+
|
|
35
|
+
// Log detailed error to console
|
|
36
|
+
if (logToConsole) {
|
|
37
|
+
console.error("Detailed error:", {
|
|
38
|
+
message: detailed_error_message,
|
|
39
|
+
stack: error_stack,
|
|
40
|
+
...context,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Log detailed error to logger if provided
|
|
45
|
+
if (logToLogger && logger) {
|
|
46
|
+
logger.error("error_occurred", {
|
|
47
|
+
filename: context.filename as string || "unknown",
|
|
48
|
+
line_number: context.line_number as number || 0,
|
|
49
|
+
error_message: detailed_error_message,
|
|
50
|
+
error_stack,
|
|
51
|
+
...context,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Check if error is a PostgREST or database-related error
|
|
56
|
+
const is_database_error =
|
|
57
|
+
detailed_error_message.includes("PostgREST") ||
|
|
58
|
+
detailed_error_message.includes("403 Forbidden") ||
|
|
59
|
+
detailed_error_message.includes("404 Not Found") ||
|
|
60
|
+
detailed_error_message.includes("500 Internal Server Error") ||
|
|
61
|
+
detailed_error_message.includes("database") ||
|
|
62
|
+
detailed_error_message.includes("connection") ||
|
|
63
|
+
detailed_error_message.includes("timeout");
|
|
64
|
+
|
|
65
|
+
// Return user-friendly message for database/API errors
|
|
66
|
+
if (is_database_error) {
|
|
67
|
+
return USER_FRIENDLY_ERROR_MESSAGE;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// For other errors, return the original message (could be user-friendly already)
|
|
71
|
+
// But still log the detailed error
|
|
72
|
+
return detailed_error_message;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// file_description: server-side password validation utility
|
|
2
|
+
// section: types
|
|
3
|
+
export type PasswordRequirementOptions = {
|
|
4
|
+
minimum_length: number;
|
|
5
|
+
require_uppercase: boolean;
|
|
6
|
+
require_lowercase: boolean;
|
|
7
|
+
require_number: boolean;
|
|
8
|
+
require_special: boolean;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type PasswordValidationResult = {
|
|
12
|
+
valid: boolean;
|
|
13
|
+
errors: string[];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// section: helpers
|
|
17
|
+
/**
|
|
18
|
+
* Validates a password against specified requirements (server-side version)
|
|
19
|
+
* @param password - The password to validate
|
|
20
|
+
* @param requirements - Password requirement options
|
|
21
|
+
* @returns Validation result with valid flag and error messages
|
|
22
|
+
*/
|
|
23
|
+
export function validate_password(
|
|
24
|
+
password: string,
|
|
25
|
+
requirements: PasswordRequirementOptions
|
|
26
|
+
): PasswordValidationResult {
|
|
27
|
+
const errors: string[] = [];
|
|
28
|
+
|
|
29
|
+
if (!password || password.trim().length === 0) {
|
|
30
|
+
return {
|
|
31
|
+
valid: false,
|
|
32
|
+
errors: ["Password is required"],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (password.length < requirements.minimum_length) {
|
|
37
|
+
errors.push(
|
|
38
|
+
`Password must be at least ${requirements.minimum_length} characters`
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (requirements.require_uppercase && !/[A-Z]/.test(password)) {
|
|
43
|
+
errors.push("Password must include at least one uppercase letter");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (requirements.require_lowercase && !/[a-z]/.test(password)) {
|
|
47
|
+
errors.push("Password must include at least one lowercase letter");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (requirements.require_number && !/\d/.test(password)) {
|
|
51
|
+
errors.push("Password must include at least one number");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (
|
|
55
|
+
requirements.require_special &&
|
|
56
|
+
!/[!@#$%^&*(),.?":{}|<>\-_+=\[\];'/\\]/.test(password)
|
|
57
|
+
) {
|
|
58
|
+
errors.push("Password must include at least one special character");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
valid: errors.length === 0,
|
|
63
|
+
errors,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// file_description: provide shared utility helpers for the hazo_auth project
|
|
2
|
+
import { clsx, type ClassValue } from "clsx";
|
|
3
|
+
import { twMerge } from "tailwind-merge";
|
|
4
|
+
|
|
5
|
+
// section: tailwind_merge_helper
|
|
6
|
+
export function merge_class_names(...inputs: ClassValue[]) {
|
|
7
|
+
return twMerge(clsx(inputs));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// section: shadcn_compatibility_helper
|
|
11
|
+
export const cn = (...inputs: ClassValue[]) => merge_class_names(...inputs);
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// file_description: expose the logging facade used across the hazo_auth backend
|
|
2
|
+
// section: imports
|
|
3
|
+
import type { logger_method, logger_service } from "../types/app_types";
|
|
4
|
+
|
|
5
|
+
// section: helper_functions
|
|
6
|
+
const create_console_logger = (namespace: string): logger_service => {
|
|
7
|
+
const write = (level: string, message: string, data?: Record<string, unknown>) => {
|
|
8
|
+
const timestamp = new Date().toISOString();
|
|
9
|
+
// eslint-disable-next-line no-console
|
|
10
|
+
console.log(
|
|
11
|
+
JSON.stringify({
|
|
12
|
+
namespace,
|
|
13
|
+
level,
|
|
14
|
+
message,
|
|
15
|
+
data,
|
|
16
|
+
timestamp,
|
|
17
|
+
})
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
debug: (message, data) => write("debug", message, data),
|
|
23
|
+
info: (message, data) => write("info", message, data),
|
|
24
|
+
warn: (message, data) => write("warn", message, data),
|
|
25
|
+
error: (message, data) => write("error", message, data),
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// section: factory
|
|
30
|
+
export const create_logger_service = (
|
|
31
|
+
namespace: string,
|
|
32
|
+
external_logger?: Partial<logger_service>
|
|
33
|
+
): logger_service => {
|
|
34
|
+
const console_logger = create_console_logger(namespace);
|
|
35
|
+
|
|
36
|
+
const safe_bind = (
|
|
37
|
+
level: keyof logger_service,
|
|
38
|
+
fallback: logger_method
|
|
39
|
+
): logger_method => {
|
|
40
|
+
const candidate = external_logger?.[level];
|
|
41
|
+
if (typeof candidate === "function") {
|
|
42
|
+
return (message, data) => candidate(message, data);
|
|
43
|
+
}
|
|
44
|
+
return fallback;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
type logger_method = (message: string, data?: Record<string, unknown>) => void;
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
debug: safe_bind("debug", console_logger.debug),
|
|
51
|
+
info: safe_bind("info", console_logger.info),
|
|
52
|
+
warn: safe_bind("warn", console_logger.warn),
|
|
53
|
+
error: safe_bind("error", console_logger.error),
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// file_description: define shared application level types for the hazo_auth server
|
|
2
|
+
// section: request_context_types
|
|
3
|
+
import type { Request } from "express";
|
|
4
|
+
|
|
5
|
+
// section: logger_interface_definition
|
|
6
|
+
export type logger_method = (
|
|
7
|
+
message: string,
|
|
8
|
+
data?: Record<string, unknown>
|
|
9
|
+
) => void;
|
|
10
|
+
|
|
11
|
+
export type logger_service = {
|
|
12
|
+
debug: logger_method;
|
|
13
|
+
info: logger_method;
|
|
14
|
+
warn: logger_method;
|
|
15
|
+
error: logger_method;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// section: configuration_types
|
|
19
|
+
export type emailer_client = {
|
|
20
|
+
send_message: (
|
|
21
|
+
payload: Record<string, unknown>
|
|
22
|
+
) => Promise<{ success: boolean }>;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type handlebars_templates = Record<string, string>;
|
|
26
|
+
|
|
27
|
+
export type password_policy = {
|
|
28
|
+
min_length: number;
|
|
29
|
+
requires_uppercase: boolean;
|
|
30
|
+
requires_lowercase: boolean;
|
|
31
|
+
requires_number: boolean;
|
|
32
|
+
requires_symbol: boolean;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type token_settings = {
|
|
36
|
+
access_token_ttl_seconds: number;
|
|
37
|
+
refresh_token_ttl_seconds: number;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export type rate_limit_settings = {
|
|
41
|
+
max_attempts: number;
|
|
42
|
+
window_minutes: number;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type captcha_settings =
|
|
46
|
+
| {
|
|
47
|
+
provider: "recaptcha_v2" | "recaptcha_v3" | "hcaptcha";
|
|
48
|
+
secret_key: string;
|
|
49
|
+
}
|
|
50
|
+
| undefined;
|
|
51
|
+
|
|
52
|
+
export type runtime_configuration = {
|
|
53
|
+
permission_names: string[];
|
|
54
|
+
logger: logger_service;
|
|
55
|
+
emailer: emailer_client;
|
|
56
|
+
templates: handlebars_templates;
|
|
57
|
+
labels: Record<string, string>;
|
|
58
|
+
styles: Record<string, string>;
|
|
59
|
+
password_policy: password_policy;
|
|
60
|
+
token_settings: token_settings;
|
|
61
|
+
rate_limit: rate_limit_settings;
|
|
62
|
+
captcha: captcha_settings;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export type app_context = {
|
|
66
|
+
config: runtime_configuration;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// section: typed_request_wrapper
|
|
70
|
+
export type context_request<T = unknown> = Request & {
|
|
71
|
+
body: T;
|
|
72
|
+
context: app_context;
|
|
73
|
+
};
|
|
74
|
+
|
package/dist/cli/index.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { run_validation } from "./validate.js";
|
|
6
6
|
import { generate_routes } from "./generate.js";
|
|
7
7
|
import { handle_init } from "./init.js";
|
|
8
|
+
import { handle_init_users, show_init_users_help } from "./init_users.js";
|
|
8
9
|
// section: constants
|
|
9
10
|
const VERSION = "1.6.0";
|
|
10
11
|
const HELP_TEXT = `
|
|
@@ -14,6 +15,7 @@ Usage: hazo_auth <command> [options]
|
|
|
14
15
|
|
|
15
16
|
Commands:
|
|
16
17
|
init Initialize hazo_auth in your project (creates directories, copies config)
|
|
18
|
+
init-users Initialize permissions, roles, and super user from config
|
|
17
19
|
validate Check your hazo_auth setup and configuration
|
|
18
20
|
generate-routes Generate API route files and pages in your project
|
|
19
21
|
|
|
@@ -23,6 +25,7 @@ Options:
|
|
|
23
25
|
|
|
24
26
|
Examples:
|
|
25
27
|
npx hazo_auth init
|
|
28
|
+
npx hazo_auth init-users
|
|
26
29
|
npx hazo_auth validate
|
|
27
30
|
npx hazo_auth generate-routes
|
|
28
31
|
npx hazo_auth generate-routes --pages
|
|
@@ -139,6 +142,21 @@ Actions:
|
|
|
139
142
|
}
|
|
140
143
|
handle_init();
|
|
141
144
|
break;
|
|
145
|
+
case "init-users": {
|
|
146
|
+
if (help) {
|
|
147
|
+
show_init_users_help();
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
// Parse --email option
|
|
151
|
+
let email;
|
|
152
|
+
for (const arg of args) {
|
|
153
|
+
if (arg.startsWith("--email=")) {
|
|
154
|
+
email = arg.replace("--email=", "");
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
await handle_init_users({ email });
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
142
160
|
case "validate":
|
|
143
161
|
if (help) {
|
|
144
162
|
console.log(`
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type InitUsersOptions = {
|
|
2
|
+
/** Email address of the user to assign super user role (overrides config) */
|
|
3
|
+
email?: string;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* Initializes users, roles, and permissions from configuration
|
|
7
|
+
* This function reads from hazo_auth_config.ini and sets up:
|
|
8
|
+
* 1. Permissions from [hazo_auth__user_management] application_permission_list_defaults
|
|
9
|
+
* 2. A default_super_user_role with all permissions
|
|
10
|
+
* 3. Assigns the role to user from --email parameter or [hazo_auth__initial_setup] default_super_user_email
|
|
11
|
+
*/
|
|
12
|
+
export declare function handle_init_users(options?: InitUsersOptions): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Shows help for the init-users command
|
|
15
|
+
*/
|
|
16
|
+
export declare function show_init_users_help(): void;
|
|
17
|
+
//# sourceMappingURL=init_users.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init_users.d.ts","sourceRoot":"","sources":["../../src/cli/init_users.ts"],"names":[],"mappings":"AAqFA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAGF;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+OrF;AAGD;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAgC3C"}
|