hazo_auth 7.0.1 → 8.0.1
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 +96 -319
- package/SETUP_CHECKLIST.md +59 -248
- package/cli-src/cli/generate.ts +1 -10
- package/cli-src/cli/validate.ts +0 -4
- package/cli-src/lib/auth/auth_types.ts +15 -21
- package/cli-src/lib/auth/hazo_get_auth.server.ts +19 -0
- package/cli-src/lib/auth/hazo_get_tenant_auth.server.ts +24 -25
- package/cli-src/lib/auth/index.ts +2 -2
- package/cli-src/lib/auth/nextauth_config.ts +27 -67
- package/cli-src/lib/auth/with_auth.server.ts +15 -15
- package/cli-src/lib/config/default_config.ts +8 -0
- package/cli-src/lib/cookies_config.server.ts +1 -1
- package/cli-src/lib/email_verification_config.server.ts +34 -0
- package/cli-src/lib/forgot_password_config.server.ts +34 -0
- package/cli-src/lib/legal/legal_docs_config.server.ts +61 -0
- package/cli-src/lib/legal/legal_docs_reader.server.ts +36 -0
- package/cli-src/lib/legal/legal_docs_service.ts +196 -0
- package/cli-src/lib/legal/legal_docs_types.ts +31 -0
- package/cli-src/lib/login_config.server.ts +29 -14
- package/cli-src/lib/my_settings_config.server.ts +3 -0
- package/cli-src/lib/oauth_config.server.ts +31 -57
- package/cli-src/lib/register_config.server.ts +35 -11
- package/cli-src/lib/reset_password_config.server.ts +31 -0
- package/cli-src/lib/services/email_template_manifest.ts +0 -17
- package/cli-src/lib/services/index.ts +2 -8
- package/cli-src/lib/services/oauth_service.ts +74 -128
- package/cli-src/lib/services/otp_service.ts +7 -2
- package/cli-src/lib/services/registration_service.ts +16 -1
- package/cli-src/lib/services/session_token_service.ts +0 -2
- package/config/hazo_auth_config.example.ini +41 -76
- package/dist/cli/generate.d.ts.map +1 -1
- package/dist/cli/generate.js +1 -10
- package/dist/cli/validate.d.ts.map +1 -1
- package/dist/cli/validate.js +0 -4
- package/dist/client.d.ts +1 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +3 -1
- package/dist/components/layouts/create_firm/index.d.ts +8 -4
- package/dist/components/layouts/create_firm/index.d.ts.map +1 -1
- package/dist/components/layouts/create_firm/index.js +3 -3
- package/dist/components/layouts/email_verification/index.d.ts +5 -4
- package/dist/components/layouts/email_verification/index.d.ts.map +1 -1
- package/dist/components/layouts/email_verification/index.js +4 -4
- package/dist/components/layouts/forgot_password/index.d.ts +5 -4
- package/dist/components/layouts/forgot_password/index.d.ts.map +1 -1
- package/dist/components/layouts/forgot_password/index.js +2 -2
- package/dist/components/layouts/index.d.ts +1 -0
- package/dist/components/layouts/index.d.ts.map +1 -1
- package/dist/components/layouts/index.js +2 -0
- package/dist/components/layouts/legal/index.d.ts +5 -0
- package/dist/components/layouts/legal/index.d.ts.map +1 -0
- package/dist/components/layouts/legal/index.js +4 -0
- package/dist/components/layouts/legal/legal_acceptance_gate.d.ts +7 -0
- package/dist/components/layouts/legal/legal_acceptance_gate.d.ts.map +1 -0
- package/dist/components/layouts/legal/legal_acceptance_gate.js +84 -0
- package/dist/components/layouts/legal/legal_doc_checkbox_list.d.ts +9 -0
- package/dist/components/layouts/legal/legal_doc_checkbox_list.d.ts.map +1 -0
- package/dist/components/layouts/legal/legal_doc_checkbox_list.js +11 -0
- package/dist/components/layouts/legal/legal_doc_combined_view.d.ts +9 -0
- package/dist/components/layouts/legal/legal_doc_combined_view.d.ts.map +1 -0
- package/dist/components/layouts/legal/legal_doc_combined_view.js +11 -0
- package/dist/components/layouts/legal/legal_doc_drawer.d.ts +8 -0
- package/dist/components/layouts/legal/legal_doc_drawer.d.ts.map +1 -0
- package/dist/components/layouts/legal/legal_doc_drawer.js +55 -0
- package/dist/components/layouts/login/index.d.ts +13 -19
- package/dist/components/layouts/login/index.d.ts.map +1 -1
- package/dist/components/layouts/login/index.js +8 -11
- package/dist/components/layouts/otp/index.d.ts +5 -1
- package/dist/components/layouts/otp/index.d.ts.map +1 -1
- package/dist/components/layouts/otp/index.js +2 -2
- package/dist/components/layouts/register/hooks/use_register_form.d.ts +5 -1
- package/dist/components/layouts/register/hooks/use_register_form.d.ts.map +1 -1
- package/dist/components/layouts/register/hooks/use_register_form.js +25 -10
- package/dist/components/layouts/register/index.d.ts +11 -11
- package/dist/components/layouts/register/index.d.ts.map +1 -1
- package/dist/components/layouts/register/index.js +26 -7
- package/dist/components/layouts/reset_password/index.d.ts +5 -4
- package/dist/components/layouts/reset_password/index.d.ts.map +1 -1
- package/dist/components/layouts/reset_password/index.js +5 -5
- package/dist/components/layouts/shared/components/already_logged_in_guard.d.ts +5 -3
- package/dist/components/layouts/shared/components/already_logged_in_guard.d.ts.map +1 -1
- package/dist/components/layouts/shared/components/already_logged_in_guard.js +2 -2
- package/dist/components/layouts/shared/components/facebook_sign_in_button.d.ts +2 -6
- package/dist/components/layouts/shared/components/facebook_sign_in_button.d.ts.map +1 -1
- package/dist/components/layouts/shared/components/facebook_sign_in_button.js +11 -13
- package/dist/components/layouts/shared/components/sidebar_layout_wrapper.d.ts.map +1 -1
- package/dist/components/layouts/shared/components/sidebar_layout_wrapper.js +3 -8
- package/dist/components/layouts/shared/components/two_column_auth_layout.d.ts +6 -3
- package/dist/components/layouts/shared/components/two_column_auth_layout.d.ts.map +1 -1
- package/dist/components/layouts/shared/components/two_column_auth_layout.js +5 -8
- package/dist/components/layouts/shared/index.d.ts +2 -0
- package/dist/components/layouts/shared/index.d.ts.map +1 -1
- package/dist/components/layouts/shared/index.js +1 -0
- package/dist/components/layouts/user_management/index.d.ts.map +1 -1
- package/dist/components/layouts/user_management/index.js +84 -9
- package/dist/components/ui/button.d.ts +1 -1
- package/dist/components/ui/input-otp.d.ts +2 -2
- package/dist/components/ui/sheet.d.ts +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/lib/auth/auth_types.d.ts +14 -13
- package/dist/lib/auth/auth_types.d.ts.map +1 -1
- package/dist/lib/auth/auth_types.js +0 -10
- package/dist/lib/auth/hazo_get_auth.server.d.ts.map +1 -1
- package/dist/lib/auth/hazo_get_auth.server.js +19 -0
- package/dist/lib/auth/hazo_get_tenant_auth.server.d.ts +7 -8
- package/dist/lib/auth/hazo_get_tenant_auth.server.d.ts.map +1 -1
- package/dist/lib/auth/hazo_get_tenant_auth.server.js +22 -23
- package/dist/lib/auth/index.d.ts +2 -2
- package/dist/lib/auth/index.d.ts.map +1 -1
- package/dist/lib/auth/nextauth_config.d.ts +0 -10
- package/dist/lib/auth/nextauth_config.d.ts.map +1 -1
- package/dist/lib/auth/nextauth_config.js +23 -52
- package/dist/lib/auth/with_auth.server.d.ts +13 -13
- package/dist/lib/auth/with_auth.server.d.ts.map +1 -1
- package/dist/lib/auth/with_auth.server.js +2 -2
- package/dist/lib/config/default_config.d.ts +16 -0
- package/dist/lib/config/default_config.d.ts.map +1 -1
- package/dist/lib/config/default_config.js +8 -0
- package/dist/lib/cookies_config.server.d.ts +1 -1
- package/dist/lib/cookies_config.server.js +1 -1
- package/dist/lib/email_verification_config.server.d.ts +3 -0
- package/dist/lib/email_verification_config.server.d.ts.map +1 -1
- package/dist/lib/email_verification_config.server.js +15 -0
- package/dist/lib/forgot_password_config.server.d.ts +3 -0
- package/dist/lib/forgot_password_config.server.d.ts.map +1 -1
- package/dist/lib/forgot_password_config.server.js +15 -0
- package/dist/lib/legal/legal_docs_config.server.d.ts +22 -0
- package/dist/lib/legal/legal_docs_config.server.d.ts.map +1 -0
- package/dist/lib/legal/legal_docs_config.server.js +52 -0
- package/dist/lib/legal/legal_docs_reader.server.d.ts +15 -0
- package/dist/lib/legal/legal_docs_reader.server.d.ts.map +1 -0
- package/dist/lib/legal/legal_docs_reader.server.js +24 -0
- package/dist/lib/legal/legal_docs_service.d.ts +49 -0
- package/dist/lib/legal/legal_docs_service.d.ts.map +1 -0
- package/dist/lib/legal/legal_docs_service.js +140 -0
- package/dist/lib/legal/legal_docs_types.d.ts +25 -0
- package/dist/lib/legal/legal_docs_types.d.ts.map +1 -0
- package/dist/lib/legal/legal_docs_types.js +2 -0
- package/dist/lib/login_config.server.d.ts +3 -6
- package/dist/lib/login_config.server.d.ts.map +1 -1
- package/dist/lib/login_config.server.js +11 -7
- package/dist/lib/my_settings_config.server.d.ts +1 -0
- package/dist/lib/my_settings_config.server.d.ts.map +1 -1
- package/dist/lib/my_settings_config.server.js +2 -0
- package/dist/lib/oauth_config.server.d.ts +8 -17
- package/dist/lib/oauth_config.server.d.ts.map +1 -1
- package/dist/lib/oauth_config.server.js +10 -25
- package/dist/lib/register_config.server.d.ts +5 -2
- package/dist/lib/register_config.server.d.ts.map +1 -1
- package/dist/lib/register_config.server.js +15 -4
- package/dist/lib/reset_password_config.server.d.ts +3 -0
- package/dist/lib/reset_password_config.server.d.ts.map +1 -1
- package/dist/lib/reset_password_config.server.js +13 -0
- package/dist/lib/services/email_template_manifest.d.ts.map +1 -1
- package/dist/lib/services/email_template_manifest.js +0 -17
- package/dist/lib/services/index.d.ts +0 -2
- package/dist/lib/services/index.d.ts.map +1 -1
- package/dist/lib/services/index.js +0 -1
- package/dist/lib/services/oauth_service.d.ts +11 -22
- package/dist/lib/services/oauth_service.d.ts.map +1 -1
- package/dist/lib/services/oauth_service.js +63 -96
- package/dist/lib/services/otp_service.d.ts +1 -1
- package/dist/lib/services/otp_service.d.ts.map +1 -1
- package/dist/lib/services/otp_service.js +6 -1
- package/dist/lib/services/registration_service.d.ts +5 -0
- package/dist/lib/services/registration_service.d.ts.map +1 -1
- package/dist/lib/services/registration_service.js +6 -0
- package/dist/lib/services/session_token_service.d.ts +0 -2
- package/dist/lib/services/session_token_service.d.ts.map +1 -1
- package/dist/lib/services/session_token_service.js +0 -2
- package/dist/page_components/create_firm.d.ts +1 -13
- package/dist/page_components/create_firm.d.ts.map +1 -1
- package/dist/page_components/create_firm.js +6 -10
- package/dist/page_components/forgot_password.d.ts +4 -1
- package/dist/page_components/forgot_password.d.ts.map +1 -1
- package/dist/page_components/forgot_password.js +6 -2
- package/dist/page_components/index.d.ts +0 -5
- package/dist/page_components/index.d.ts.map +1 -1
- package/dist/page_components/index.js +0 -5
- package/dist/page_components/login.d.ts +4 -1
- package/dist/page_components/login.d.ts.map +1 -1
- package/dist/page_components/login.js +6 -2
- package/dist/page_components/register.d.ts +4 -1
- package/dist/page_components/register.d.ts.map +1 -1
- package/dist/page_components/register.js +6 -2
- package/dist/page_components/reset_password.d.ts +4 -1
- package/dist/page_components/reset_password.d.ts.map +1 -1
- package/dist/page_components/reset_password.js +6 -2
- package/dist/page_components/verify_email.d.ts +4 -1
- package/dist/page_components/verify_email.d.ts.map +1 -1
- package/dist/page_components/verify_email.js +6 -2
- package/dist/server/routes/assets.d.ts +8 -0
- package/dist/server/routes/assets.d.ts.map +1 -0
- package/dist/server/routes/assets.js +38 -0
- package/dist/server/routes/consent_me.d.ts +4 -0
- package/dist/server/routes/consent_me.d.ts.map +1 -0
- package/dist/server/routes/consent_me.js +15 -0
- package/dist/server/routes/index.d.ts +9 -4
- package/dist/server/routes/index.d.ts.map +1 -1
- package/dist/server/routes/index.js +13 -5
- package/dist/server/routes/legal_docs_accept.d.ts +3 -0
- package/dist/server/routes/legal_docs_accept.d.ts.map +1 -0
- package/dist/server/routes/legal_docs_accept.js +43 -0
- package/dist/server/routes/legal_docs_get.d.ts +3 -0
- package/dist/server/routes/legal_docs_get.d.ts.map +1 -0
- package/dist/server/routes/legal_docs_get.js +49 -0
- package/dist/server/routes/legal_docs_publish.d.ts +3 -0
- package/dist/server/routes/legal_docs_publish.d.ts.map +1 -0
- package/dist/server/routes/legal_docs_publish.js +35 -0
- package/dist/server/routes/me.d.ts.map +1 -1
- package/dist/server/routes/me.js +1 -43
- package/dist/server/routes/oauth_facebook_callback.d.ts +1 -1
- package/dist/server/routes/oauth_facebook_callback.d.ts.map +1 -1
- package/dist/server/routes/oauth_facebook_callback.js +8 -1
- package/dist/server/routes/oauth_google_callback.js +1 -1
- package/dist/server/routes/otp/verify.js +2 -2
- package/dist/server/routes/register.d.ts.map +1 -1
- package/dist/server/routes/register.js +26 -0
- package/dist/server/routes/strings_defaults.d.ts +4 -0
- package/dist/server/routes/strings_defaults.d.ts.map +1 -0
- package/dist/server/routes/strings_defaults.js +7 -0
- package/dist/server/routes/user_management_users.d.ts +11 -0
- package/dist/server/routes/user_management_users.d.ts.map +1 -1
- package/dist/server/routes/user_management_users.js +94 -0
- package/dist/server-lib.d.ts +0 -3
- package/dist/server-lib.d.ts.map +1 -1
- package/dist/server-lib.js +0 -2
- package/dist/server_pages/forgot_password.d.ts +18 -14
- package/dist/server_pages/forgot_password.d.ts.map +1 -1
- package/dist/server_pages/forgot_password.js +14 -12
- package/dist/server_pages/forgot_password_client_wrapper.d.ts +8 -7
- package/dist/server_pages/forgot_password_client_wrapper.d.ts.map +1 -1
- package/dist/server_pages/forgot_password_client_wrapper.js +2 -2
- package/dist/server_pages/index.d.ts +2 -0
- package/dist/server_pages/index.d.ts.map +1 -1
- package/dist/server_pages/index.js +1 -0
- package/dist/server_pages/login.d.ts +22 -23
- package/dist/server_pages/login.d.ts.map +1 -1
- package/dist/server_pages/login.js +27 -14
- package/dist/server_pages/login_client_wrapper.d.ts +9 -10
- package/dist/server_pages/login_client_wrapper.d.ts.map +1 -1
- package/dist/server_pages/login_client_wrapper.js +2 -2
- package/dist/server_pages/my_settings.d.ts +1 -3
- package/dist/server_pages/my_settings.d.ts.map +1 -1
- package/dist/server_pages/my_settings.js +2 -9
- package/dist/server_pages/register.d.ts +17 -20
- package/dist/server_pages/register.d.ts.map +1 -1
- package/dist/server_pages/register.js +20 -15
- package/dist/server_pages/register_client_wrapper.d.ts +8 -10
- package/dist/server_pages/register_client_wrapper.d.ts.map +1 -1
- package/dist/server_pages/register_client_wrapper.js +2 -2
- package/dist/server_pages/reset_password.d.ts +16 -11
- package/dist/server_pages/reset_password.d.ts.map +1 -1
- package/dist/server_pages/reset_password.js +14 -10
- package/dist/server_pages/reset_password_client_wrapper.d.ts +8 -7
- package/dist/server_pages/reset_password_client_wrapper.d.ts.map +1 -1
- package/dist/server_pages/reset_password_client_wrapper.js +2 -2
- package/dist/server_pages/verify_email.d.ts +18 -12
- package/dist/server_pages/verify_email.d.ts.map +1 -1
- package/dist/server_pages/verify_email.js +13 -11
- package/dist/server_pages/verify_email_client_wrapper.d.ts +8 -7
- package/dist/server_pages/verify_email_client_wrapper.d.ts.map +1 -1
- package/dist/server_pages/verify_email_client_wrapper.js +2 -2
- package/dist/strings.d.ts +2 -0
- package/dist/strings.d.ts.map +1 -0
- package/dist/strings.js +3 -0
- package/dist/themes/index.d.ts +0 -1
- package/dist/themes/index.d.ts.map +1 -1
- package/dist/themes/index.js +1 -1
- package/package.json +30 -61
- package/dist/themes/preset_indigo_sunset.d.ts +0 -3
- package/dist/themes/preset_indigo_sunset.d.ts.map +0 -1
- package/dist/themes/preset_indigo_sunset.js +0 -20
|
@@ -14,16 +14,9 @@ const SECTION_NAME = "hazo_auth__oauth";
|
|
|
14
14
|
*/
|
|
15
15
|
export function get_oauth_config() {
|
|
16
16
|
const enable_google = get_config_boolean(SECTION_NAME, "enable_google", DEFAULT_OAUTH.enable_google);
|
|
17
|
-
const enable_facebook = get_config_boolean(SECTION_NAME, "enable_facebook", false);
|
|
18
17
|
const enable_email_password = get_config_boolean(SECTION_NAME, "enable_email_password", DEFAULT_OAUTH.enable_email_password);
|
|
19
|
-
// Generic key (backward compat)
|
|
20
18
|
const auto_link_unverified_accounts = get_config_boolean(SECTION_NAME, "auto_link_unverified_accounts", DEFAULT_OAUTH.auto_link_unverified_accounts);
|
|
21
|
-
// Per-provider Google key (falls back to generic)
|
|
22
|
-
const auto_link_unverified_accounts_google = get_config_boolean(SECTION_NAME, "auto_link_unverified_accounts_google", auto_link_unverified_accounts);
|
|
23
|
-
// Per-provider Facebook key (defaults to false — don't auto-link Facebook unverified)
|
|
24
|
-
const auto_link_unverified_accounts_facebook = get_config_boolean(SECTION_NAME, "auto_link_unverified_accounts_facebook", false);
|
|
25
19
|
const google_button_text = get_config_value(SECTION_NAME, "google_button_text", DEFAULT_OAUTH.google_button_text);
|
|
26
|
-
const facebook_button_text = get_config_value(SECTION_NAME, "facebook_button_text", "Continue with Facebook");
|
|
27
20
|
const oauth_divider_text = get_config_value(SECTION_NAME, "oauth_divider_text", DEFAULT_OAUTH.oauth_divider_text);
|
|
28
21
|
const sign_in_page = get_config_value(SECTION_NAME, "sign_in_page", DEFAULT_OAUTH.sign_in_page);
|
|
29
22
|
const error_page = get_config_value(SECTION_NAME, "error_page", DEFAULT_OAUTH.error_page);
|
|
@@ -31,17 +24,17 @@ export function get_oauth_config() {
|
|
|
31
24
|
const default_redirect = get_config_value(SECTION_NAME, "default_redirect", DEFAULT_OAUTH.default_redirect);
|
|
32
25
|
const skip_invitation_check = get_config_boolean(SECTION_NAME, "skip_invitation_check", DEFAULT_OAUTH.skip_invitation_check);
|
|
33
26
|
const no_scope_redirect = get_config_value(SECTION_NAME, "no_scope_redirect", DEFAULT_OAUTH.no_scope_redirect);
|
|
34
|
-
const
|
|
35
|
-
const
|
|
27
|
+
const enable_facebook_oauth = get_config_boolean(SECTION_NAME, "enable_facebook_oauth", false);
|
|
28
|
+
const facebook_app_id = process.env.HAZO_AUTH_FACEBOOK_APP_ID ||
|
|
29
|
+
get_config_value(SECTION_NAME, "facebook_app_id", "");
|
|
30
|
+
const facebook_app_secret = process.env.HAZO_AUTH_FACEBOOK_APP_SECRET ||
|
|
31
|
+
get_config_value(SECTION_NAME, "facebook_app_secret", "");
|
|
32
|
+
const facebook_button_text = get_config_value(SECTION_NAME, "facebook_button_text", "Continue with Facebook");
|
|
36
33
|
return {
|
|
37
34
|
enable_google,
|
|
38
|
-
enable_facebook,
|
|
39
35
|
enable_email_password,
|
|
40
36
|
auto_link_unverified_accounts,
|
|
41
|
-
auto_link_unverified_accounts_google,
|
|
42
|
-
auto_link_unverified_accounts_facebook,
|
|
43
37
|
google_button_text,
|
|
44
|
-
facebook_button_text,
|
|
45
38
|
oauth_divider_text,
|
|
46
39
|
sign_in_page,
|
|
47
40
|
error_page,
|
|
@@ -49,8 +42,10 @@ export function get_oauth_config() {
|
|
|
49
42
|
default_redirect,
|
|
50
43
|
skip_invitation_check,
|
|
51
44
|
no_scope_redirect,
|
|
52
|
-
|
|
53
|
-
|
|
45
|
+
enable_facebook_oauth,
|
|
46
|
+
facebook_app_id,
|
|
47
|
+
facebook_app_secret,
|
|
48
|
+
facebook_button_text,
|
|
54
49
|
};
|
|
55
50
|
}
|
|
56
51
|
/**
|
|
@@ -67,13 +62,3 @@ export function is_google_oauth_enabled() {
|
|
|
67
62
|
export function is_email_password_enabled() {
|
|
68
63
|
return get_config_boolean(SECTION_NAME, "enable_email_password", DEFAULT_OAUTH.enable_email_password);
|
|
69
64
|
}
|
|
70
|
-
/**
|
|
71
|
-
* Helper to check if Facebook OAuth is enabled and credentials are present
|
|
72
|
-
* @returns true if Facebook OAuth is enabled and env vars are set
|
|
73
|
-
*/
|
|
74
|
-
export function is_facebook_oauth_enabled() {
|
|
75
|
-
const enabled = get_config_boolean(SECTION_NAME, "enable_facebook", false);
|
|
76
|
-
if (!enabled)
|
|
77
|
-
return false;
|
|
78
|
-
return !!(process.env.HAZO_AUTH_FACEBOOK_APP_ID && process.env.HAZO_AUTH_FACEBOOK_APP_SECRET);
|
|
79
|
-
}
|
|
@@ -15,14 +15,17 @@ export type RegisterConfig = {
|
|
|
15
15
|
returnHomePath: string;
|
|
16
16
|
signInPath: string;
|
|
17
17
|
signInLabel: string;
|
|
18
|
+
imageSrc: string;
|
|
19
|
+
imageAlt: string;
|
|
20
|
+
imageBackgroundColor: string;
|
|
18
21
|
/** OAuth configuration */
|
|
19
22
|
oauth: {
|
|
20
23
|
enable_google: boolean;
|
|
21
|
-
enable_facebook: boolean;
|
|
22
24
|
enable_email_password: boolean;
|
|
23
25
|
google_button_text: string;
|
|
24
|
-
facebook_button_text: string;
|
|
25
26
|
oauth_divider_text: string;
|
|
27
|
+
enable_facebook_oauth: boolean;
|
|
28
|
+
facebook_button_text: string;
|
|
26
29
|
};
|
|
27
30
|
};
|
|
28
31
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register_config.server.d.ts","sourceRoot":"","sources":["../../src/lib/register_config.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"register_config.server.d.ts","sourceRoot":"","sources":["../../src/lib/register_config.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAerB,MAAM,MAAM,cAAc,GAAG;IAC3B,aAAa,EAAE,OAAO,CAAC;IACvB,oBAAoB,EAAE;QACpB,cAAc,EAAE,MAAM,CAAC;QACvB,iBAAiB,EAAE,OAAO,CAAC;QAC3B,iBAAiB,EAAE,OAAO,CAAC;QAC3B,cAAc,EAAE,OAAO,CAAC;QACxB,eAAe,EAAE,OAAO,CAAC;KAC1B,CAAC;IACF,sBAAsB,EAAE,MAAM,CAAC;IAC/B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,0BAA0B;IAC1B,KAAK,EAAE;QACL,aAAa,EAAE,OAAO,CAAC;QACvB,qBAAqB,EAAE,OAAO,CAAC;QAC/B,kBAAkB,EAAE,MAAM,CAAC;QAC3B,kBAAkB,EAAE,MAAM,CAAC;QAC3B,qBAAqB,EAAE,OAAO,CAAC;QAC/B,oBAAoB,EAAE,MAAM,CAAC;KAC9B,CAAC;CACH,CAAC;AAGF;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,cAAc,CAgFpD"}
|
|
@@ -7,6 +7,10 @@ import { get_password_requirements_config } from "./password_requirements_config
|
|
|
7
7
|
import { get_already_logged_in_config } from "./already_logged_in_config.server.js";
|
|
8
8
|
import { get_user_fields_config } from "./user_fields_config.server.js";
|
|
9
9
|
import { get_oauth_config } from "./oauth_config.server.js";
|
|
10
|
+
// Default image path - consuming apps should either:
|
|
11
|
+
// 1. Configure their own image_src in hazo_auth_config.ini
|
|
12
|
+
// 2. Copy the default images from node_modules/hazo_auth/public/hazo_auth/images/ to their public folder
|
|
13
|
+
const DEFAULT_REGISTER_IMAGE_PATH = "/hazo_auth/images/register_default.jpg";
|
|
10
14
|
// section: helpers
|
|
11
15
|
/**
|
|
12
16
|
* Reads register layout configuration from hazo_auth_config.ini file
|
|
@@ -28,12 +32,16 @@ export function get_register_config() {
|
|
|
28
32
|
// Read sign in link configuration
|
|
29
33
|
const signInPath = get_config_value("hazo_auth__register_layout", "sign_in_path", "/hazo_auth/login");
|
|
30
34
|
const signInLabel = get_config_value("hazo_auth__register_layout", "sign_in_label", "Sign in");
|
|
35
|
+
// Read image configuration
|
|
36
|
+
// If not set in config, falls back to default path-based image
|
|
37
|
+
// Consuming apps should copy images to public/hazo_auth/images/ or configure their own image_src
|
|
38
|
+
const imageSrc = get_config_value("hazo_auth__register_layout", "image_src", DEFAULT_REGISTER_IMAGE_PATH);
|
|
39
|
+
const imageAlt = get_config_value("hazo_auth__register_layout", "image_alt", "Modern building representing user registration");
|
|
40
|
+
const imageBackgroundColor = get_config_value("hazo_auth__register_layout", "image_background_color", "#e2e8f0");
|
|
31
41
|
// Get OAuth configuration (shared with login)
|
|
32
42
|
const oauthConfig = get_oauth_config();
|
|
33
43
|
// For the register page, default button text to "Sign up with Google" unless overridden
|
|
34
44
|
const registerGoogleButtonText = get_config_value("hazo_auth__oauth", "google_button_text_register", "Sign up with Google");
|
|
35
|
-
// For the register page, default Facebook button text to "Sign up with Facebook" unless overridden
|
|
36
|
-
const registerFacebookButtonText = get_config_value("hazo_auth__oauth", "facebook_button_text_register", "Sign up with Facebook");
|
|
37
45
|
return {
|
|
38
46
|
showNameField,
|
|
39
47
|
passwordRequirements,
|
|
@@ -44,13 +52,16 @@ export function get_register_config() {
|
|
|
44
52
|
returnHomePath: alreadyLoggedInConfig.returnHomePath,
|
|
45
53
|
signInPath,
|
|
46
54
|
signInLabel,
|
|
55
|
+
imageSrc,
|
|
56
|
+
imageAlt,
|
|
57
|
+
imageBackgroundColor,
|
|
47
58
|
oauth: {
|
|
48
59
|
enable_google: oauthConfig.enable_google,
|
|
49
|
-
enable_facebook: oauthConfig.enable_facebook,
|
|
50
60
|
enable_email_password: oauthConfig.enable_email_password,
|
|
51
61
|
google_button_text: registerGoogleButtonText,
|
|
52
|
-
facebook_button_text: registerFacebookButtonText,
|
|
53
62
|
oauth_divider_text: oauthConfig.oauth_divider_text,
|
|
63
|
+
enable_facebook_oauth: oauthConfig.enable_facebook_oauth,
|
|
64
|
+
facebook_button_text: oauthConfig.facebook_button_text,
|
|
54
65
|
},
|
|
55
66
|
};
|
|
56
67
|
}
|
|
@@ -16,6 +16,9 @@ export type ResetPasswordConfig = {
|
|
|
16
16
|
require_number: boolean;
|
|
17
17
|
require_special: boolean;
|
|
18
18
|
};
|
|
19
|
+
imageSrc: string;
|
|
20
|
+
imageAlt: string;
|
|
21
|
+
imageBackgroundColor: string;
|
|
19
22
|
};
|
|
20
23
|
/**
|
|
21
24
|
* Reads reset password layout configuration from hazo_auth_config.ini file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reset_password_config.server.d.ts","sourceRoot":"","sources":["../../src/lib/reset_password_config.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"reset_password_config.server.d.ts","sourceRoot":"","sources":["../../src/lib/reset_password_config.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAarB,MAAM,MAAM,mBAAmB,GAAG;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE;QACpB,cAAc,EAAE,MAAM,CAAC;QACvB,iBAAiB,EAAE,OAAO,CAAC;QAC3B,iBAAiB,EAAE,OAAO,CAAC;QAC3B,cAAc,EAAE,OAAO,CAAC;QACxB,eAAe,EAAE,OAAO,CAAC;KAC1B,CAAC;IACF,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,MAAM,CAAC;CAC9B,CAAC;AAGF;;;;GAIG;AACH,wBAAgB,yBAAyB,IAAI,mBAAmB,CAgE/D"}
|
|
@@ -5,6 +5,10 @@ import "server-only";
|
|
|
5
5
|
import { get_config_value } from "./config/config_loader.server.js";
|
|
6
6
|
import { get_already_logged_in_config } from "./already_logged_in_config.server.js";
|
|
7
7
|
import { get_password_requirements_config } from "./password_requirements_config.server.js";
|
|
8
|
+
// Default image path - consuming apps should either:
|
|
9
|
+
// 1. Configure their own image_src in hazo_auth_config.ini
|
|
10
|
+
// 2. Copy the default images from node_modules/hazo_auth/public/hazo_auth/images/ to their public folder
|
|
11
|
+
const DEFAULT_RESET_PASSWORD_IMAGE_PATH = "/hazo_auth/images/reset_password_default.jpg";
|
|
8
12
|
// section: helpers
|
|
9
13
|
/**
|
|
10
14
|
* Reads reset password layout configuration from hazo_auth_config.ini file
|
|
@@ -25,6 +29,12 @@ export function get_reset_password_config() {
|
|
|
25
29
|
const forgotPasswordPath = get_config_value(section, "forgot_password_path", "/hazo_auth/forgot_password");
|
|
26
30
|
// Get shared password requirements
|
|
27
31
|
const passwordRequirements = get_password_requirements_config();
|
|
32
|
+
// Read image configuration
|
|
33
|
+
// If not set in config, falls back to default path-based image
|
|
34
|
+
// Consuming apps should copy images to public/hazo_auth/images/ or configure their own image_src
|
|
35
|
+
const imageSrc = get_config_value(section, "image_src", DEFAULT_RESET_PASSWORD_IMAGE_PATH);
|
|
36
|
+
const imageAlt = get_config_value(section, "image_alt", "Reset password illustration");
|
|
37
|
+
const imageBackgroundColor = get_config_value(section, "image_background_color", "#f1f5f9");
|
|
28
38
|
return {
|
|
29
39
|
errorMessage,
|
|
30
40
|
successMessage,
|
|
@@ -36,5 +46,8 @@ export function get_reset_password_config() {
|
|
|
36
46
|
returnHomeButtonLabel: alreadyLoggedInConfig.returnHomeButtonLabel,
|
|
37
47
|
returnHomePath: alreadyLoggedInConfig.returnHomePath,
|
|
38
48
|
passwordRequirements,
|
|
49
|
+
imageSrc,
|
|
50
|
+
imageAlt,
|
|
51
|
+
imageBackgroundColor,
|
|
39
52
|
};
|
|
40
53
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email_template_manifest.d.ts","sourceRoot":"","sources":["../../../src/lib/services/email_template_manifest.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAMrB,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAiB3E;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,EAAE,sBAAsB,
|
|
1
|
+
{"version":3,"file":"email_template_manifest.d.ts","sourceRoot":"","sources":["../../../src/lib/services/email_template_manifest.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAMrB,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAiB3E;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,EAAE,sBAAsB,EAuE/D,CAAC"}
|
|
@@ -92,21 +92,4 @@ export const hazo_auth_template_manifest = [
|
|
|
92
92
|
},
|
|
93
93
|
],
|
|
94
94
|
},
|
|
95
|
-
{
|
|
96
|
-
template_name: "otp_signin_code",
|
|
97
|
-
template_label: "OTP sign-in code",
|
|
98
|
-
category: SYSTEM_CATEGORY,
|
|
99
|
-
html: read_template("otp_signin_code", "html"),
|
|
100
|
-
text: read_template("otp_signin_code", "txt"),
|
|
101
|
-
variables: [
|
|
102
|
-
{
|
|
103
|
-
variable_name: "otp_code",
|
|
104
|
-
variable_description: "6-digit OTP code for email sign-in (v6.1.0+)",
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
variable_name: "expires_in_minutes",
|
|
108
|
-
variable_description: "Number of minutes until the OTP code expires",
|
|
109
|
-
},
|
|
110
|
-
],
|
|
111
|
-
},
|
|
112
95
|
];
|
|
@@ -18,6 +18,4 @@ export * from "./scope_service.js";
|
|
|
18
18
|
export * from "./user_scope_service.js";
|
|
19
19
|
export * from "./oauth_service.js";
|
|
20
20
|
export * from "./branding_service.js";
|
|
21
|
-
export { request_email_otp, verify_email_otp, generate_otp_code, hash_otp_code, verify_otp_code, } from "./otp_service.js";
|
|
22
|
-
export type { RequestEmailOTPResult, VerifyEmailOTPResult } from "./otp_service";
|
|
23
21
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/services/index.ts"],"names":[],"mappings":"AAEA,cAAc,iBAAiB,CAAC;AAChC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,kCAAkC,CAAC;AACjD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iCAAiC,CAAC;AAChD,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/services/index.ts"],"names":[],"mappings":"AAEA,cAAc,iBAAiB,CAAC;AAChC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,kCAAkC,CAAC;AACjD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iCAAiC,CAAC;AAChD,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC;AAChC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC"}
|
|
@@ -20,4 +20,3 @@ export * from "./scope_service.js";
|
|
|
20
20
|
export * from "./user_scope_service.js";
|
|
21
21
|
export * from "./oauth_service.js";
|
|
22
22
|
export * from "./branding_service.js";
|
|
23
|
-
export { request_email_otp, verify_email_otp, generate_otp_code, hash_otp_code, verify_otp_code, } from "./otp_service.js";
|
|
@@ -11,6 +11,14 @@ export type GoogleOAuthData = {
|
|
|
11
11
|
/** Whether Google has verified this email */
|
|
12
12
|
email_verified: boolean;
|
|
13
13
|
};
|
|
14
|
+
export type FacebookOAuthData = {
|
|
15
|
+
facebook_id: string;
|
|
16
|
+
email: string;
|
|
17
|
+
name?: string;
|
|
18
|
+
profile_picture_url?: string;
|
|
19
|
+
/** Facebook does not always verify emails — only link when hazo user is verified */
|
|
20
|
+
email_verified: boolean;
|
|
21
|
+
};
|
|
14
22
|
export type OAuthLoginResult = {
|
|
15
23
|
success: boolean;
|
|
16
24
|
user_id?: string;
|
|
@@ -24,16 +32,6 @@ export type OAuthLoginResult = {
|
|
|
24
32
|
name?: string;
|
|
25
33
|
error?: string;
|
|
26
34
|
};
|
|
27
|
-
export type FacebookOAuthData = {
|
|
28
|
-
/** Facebook's unique user ID */
|
|
29
|
-
facebook_id: string;
|
|
30
|
-
/** User's email address from Facebook (may be null if user denied email permission) */
|
|
31
|
-
email: string | null;
|
|
32
|
-
/** User's full name from Facebook profile */
|
|
33
|
-
name?: string;
|
|
34
|
-
/** User's profile picture URL from Facebook */
|
|
35
|
-
profile_picture_url?: string;
|
|
36
|
-
};
|
|
37
35
|
export type LinkGoogleResult = {
|
|
38
36
|
success: boolean;
|
|
39
37
|
error?: string;
|
|
@@ -56,19 +54,10 @@ export type AuthProvidersResult = {
|
|
|
56
54
|
*/
|
|
57
55
|
export declare function handle_google_oauth_login(adapter: HazoConnectAdapter, data: GoogleOAuthData): Promise<OAuthLoginResult>;
|
|
58
56
|
/**
|
|
59
|
-
* Handles Facebook OAuth login
|
|
60
|
-
*
|
|
61
|
-
* 2. Check if user exists with email -> link Facebook account (respects auto_link_unverified)
|
|
62
|
-
* 3. Create new user with Facebook data (email_verified always false — never trust Facebook)
|
|
63
|
-
*
|
|
64
|
-
* @param adapter - The hazo_connect adapter instance
|
|
65
|
-
* @param data - Facebook OAuth user data
|
|
66
|
-
* @param opts - Options (auto_link_unverified: whether to link unverified accounts)
|
|
67
|
-
* @returns OAuth login result with user_id and status flags
|
|
57
|
+
* Handles Facebook OAuth login: find-by-facebook_id → find-by-email+link → create new.
|
|
58
|
+
* Mirrors handle_google_oauth_login exactly. Uses auto_link_unverified_accounts gate.
|
|
68
59
|
*/
|
|
69
|
-
export declare function handle_facebook_oauth_login(adapter: HazoConnectAdapter, data: FacebookOAuthData
|
|
70
|
-
auto_link_unverified?: boolean;
|
|
71
|
-
}): Promise<OAuthLoginResult>;
|
|
60
|
+
export declare function handle_facebook_oauth_login(adapter: HazoConnectAdapter, data: FacebookOAuthData): Promise<OAuthLoginResult>;
|
|
72
61
|
/**
|
|
73
62
|
* Links a Google account to an existing user
|
|
74
63
|
* @param adapter - The hazo_connect adapter instance
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/oauth_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AASvD,MAAM,MAAM,eAAe,GAAG;IAC5B,mDAAmD;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,6CAA6C;IAC7C,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"oauth_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/oauth_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AASvD,MAAM,MAAM,eAAe,GAAG;IAC5B,mDAAmD;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,6CAA6C;IAC7C,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oFAAoF;IACpF,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uDAAuD;IACvD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAGF;;;;;;;;;GASG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,gBAAgB,CAAC,CAiL3B;AAED;;;GAGG;AACH,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,gBAAgB,CAAC,CA6H3B;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,gBAAgB,CAAC,CAgE3B;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,OAAO,CAAC,CAclB;AAED;;;;;GAKG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,kBAAkB,EAC3B,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,OAAO,CAAC,CAclB;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,mBAAmB,CAAC,CA2C9B;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA0D/C"}
|
|
@@ -168,33 +168,23 @@ export async function handle_google_oauth_login(adapter, data) {
|
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
/**
|
|
171
|
-
* Handles Facebook OAuth login
|
|
172
|
-
*
|
|
173
|
-
* 2. Check if user exists with email -> link Facebook account (respects auto_link_unverified)
|
|
174
|
-
* 3. Create new user with Facebook data (email_verified always false — never trust Facebook)
|
|
175
|
-
*
|
|
176
|
-
* @param adapter - The hazo_connect adapter instance
|
|
177
|
-
* @param data - Facebook OAuth user data
|
|
178
|
-
* @param opts - Options (auto_link_unverified: whether to link unverified accounts)
|
|
179
|
-
* @returns OAuth login result with user_id and status flags
|
|
171
|
+
* Handles Facebook OAuth login: find-by-facebook_id → find-by-email+link → create new.
|
|
172
|
+
* Mirrors handle_google_oauth_login exactly. Uses auto_link_unverified_accounts gate.
|
|
180
173
|
*/
|
|
181
|
-
export async function handle_facebook_oauth_login(adapter, data
|
|
174
|
+
export async function handle_facebook_oauth_login(adapter, data) {
|
|
182
175
|
const logger = create_app_logger();
|
|
183
176
|
try {
|
|
184
|
-
const { facebook_id, email, name, profile_picture_url } = data;
|
|
177
|
+
const { facebook_id, email, name, profile_picture_url, email_verified } = data;
|
|
178
|
+
const oauth_config = get_oauth_config();
|
|
185
179
|
const users_service = createCrudService(adapter, "hazo_users");
|
|
186
180
|
const now = new Date().toISOString();
|
|
187
|
-
// Step 1:
|
|
188
|
-
const
|
|
189
|
-
if (Array.isArray(
|
|
190
|
-
const user =
|
|
191
|
-
await users_service.updateById(user.id, {
|
|
192
|
-
|
|
193
|
-
changed_at: now,
|
|
194
|
-
});
|
|
195
|
-
logger.info("oauth_service_facebook_login_existing_facebook_user", {
|
|
181
|
+
// Step 1: existing user with this facebook_id
|
|
182
|
+
const users_by_fb_id = await users_service.findBy({ facebook_id });
|
|
183
|
+
if (Array.isArray(users_by_fb_id) && users_by_fb_id.length > 0) {
|
|
184
|
+
const user = users_by_fb_id[0];
|
|
185
|
+
await users_service.updateById(user.id, { last_logon: now, changed_at: now });
|
|
186
|
+
logger.info("oauth_service_facebook_login_existing_fb_user", {
|
|
196
187
|
filename: "oauth_service.ts",
|
|
197
|
-
line_number: get_line_number(),
|
|
198
188
|
user_id: user.id,
|
|
199
189
|
email: user.email_address,
|
|
200
190
|
});
|
|
@@ -207,91 +197,76 @@ export async function handle_facebook_oauth_login(adapter, data, opts) {
|
|
|
207
197
|
name: user.name,
|
|
208
198
|
};
|
|
209
199
|
}
|
|
210
|
-
// Step 2:
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if (!user_email_verified) {
|
|
217
|
-
if (!(opts === null || opts === void 0 ? void 0 : opts.auto_link_unverified)) {
|
|
218
|
-
return {
|
|
219
|
-
success: false,
|
|
220
|
-
error: "link_blocked_unverified",
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
// auto_link_unverified=true: link but do NOT change email_verified status
|
|
224
|
-
}
|
|
225
|
-
// Link Facebook account to existing user
|
|
226
|
-
const current_auth_providers = user.auth_providers || "email";
|
|
227
|
-
const new_auth_providers = current_auth_providers.includes("facebook")
|
|
228
|
-
? current_auth_providers
|
|
229
|
-
: `${current_auth_providers},facebook`;
|
|
230
|
-
const update_data = {
|
|
231
|
-
facebook_id,
|
|
232
|
-
auth_providers: new_auth_providers,
|
|
233
|
-
last_logon: now,
|
|
234
|
-
changed_at: now,
|
|
235
|
-
};
|
|
236
|
-
// Update name if not set and Facebook provides one
|
|
237
|
-
if (!user.name && name) {
|
|
238
|
-
update_data.name = name;
|
|
239
|
-
}
|
|
240
|
-
// Update profile picture if not set and Facebook provides one
|
|
241
|
-
if (!user.profile_picture_url && profile_picture_url) {
|
|
242
|
-
update_data.profile_picture_url = profile_picture_url;
|
|
243
|
-
update_data.profile_source = "custom";
|
|
244
|
-
}
|
|
245
|
-
await users_service.updateById(user.id, update_data);
|
|
246
|
-
logger.info("oauth_service_facebook_linked_to_existing", {
|
|
247
|
-
filename: "oauth_service.ts",
|
|
248
|
-
line_number: get_line_number(),
|
|
249
|
-
user_id: user.id,
|
|
250
|
-
email,
|
|
251
|
-
was_unverified: !user_email_verified,
|
|
252
|
-
});
|
|
200
|
+
// Step 2: existing user with matching email
|
|
201
|
+
const users_by_email = await users_service.findBy({ email_address: email });
|
|
202
|
+
if (Array.isArray(users_by_email) && users_by_email.length > 0) {
|
|
203
|
+
const user = users_by_email[0];
|
|
204
|
+
const user_email_verified = user.email_verified;
|
|
205
|
+
if (!user_email_verified && !oauth_config.auto_link_unverified_accounts) {
|
|
253
206
|
return {
|
|
254
|
-
success:
|
|
255
|
-
|
|
256
|
-
is_new_user: false,
|
|
257
|
-
was_linked: true,
|
|
258
|
-
email: user.email_address,
|
|
259
|
-
name: update_data.name || user.name,
|
|
207
|
+
success: false,
|
|
208
|
+
error: "An account with this email exists but is not verified. Please verify your email first.",
|
|
260
209
|
};
|
|
261
210
|
}
|
|
211
|
+
const current_auth_providers = user.auth_providers || "email";
|
|
212
|
+
const new_auth_providers = current_auth_providers.includes("facebook")
|
|
213
|
+
? current_auth_providers
|
|
214
|
+
: `${current_auth_providers},facebook`;
|
|
215
|
+
const update_data = {
|
|
216
|
+
facebook_id,
|
|
217
|
+
auth_providers: new_auth_providers,
|
|
218
|
+
last_logon: now,
|
|
219
|
+
changed_at: now,
|
|
220
|
+
};
|
|
221
|
+
if (!user_email_verified && email_verified) {
|
|
222
|
+
update_data.email_verified = true;
|
|
223
|
+
}
|
|
224
|
+
if (!user.name && name)
|
|
225
|
+
update_data.name = name;
|
|
226
|
+
if (!user.profile_picture_url && profile_picture_url) {
|
|
227
|
+
update_data.profile_picture_url = profile_picture_url;
|
|
228
|
+
update_data.profile_source = "custom";
|
|
229
|
+
}
|
|
230
|
+
await users_service.updateById(user.id, update_data);
|
|
231
|
+
logger.info("oauth_service_facebook_linked_to_existing", {
|
|
232
|
+
filename: "oauth_service.ts",
|
|
233
|
+
user_id: user.id,
|
|
234
|
+
email,
|
|
235
|
+
was_unverified: !user_email_verified,
|
|
236
|
+
});
|
|
237
|
+
return {
|
|
238
|
+
success: true,
|
|
239
|
+
user_id: user.id,
|
|
240
|
+
is_new_user: false,
|
|
241
|
+
was_linked: true,
|
|
242
|
+
email: user.email_address,
|
|
243
|
+
name: user.name,
|
|
244
|
+
};
|
|
262
245
|
}
|
|
263
|
-
// Step 3:
|
|
246
|
+
// Step 3: create new user
|
|
264
247
|
const user_id = randomUUID();
|
|
265
248
|
const insert_data = {
|
|
266
249
|
id: user_id,
|
|
267
250
|
email_address: email,
|
|
268
|
-
password_hash: "", // Empty string for Facebook-only users
|
|
269
|
-
email_verified: false, // Never trust Facebook's email_verified claim
|
|
270
|
-
status: "ACTIVE",
|
|
271
|
-
login_attempts: 0,
|
|
272
251
|
facebook_id,
|
|
273
252
|
auth_providers: "facebook",
|
|
253
|
+
email_verified: email_verified,
|
|
254
|
+
last_logon: now,
|
|
274
255
|
created_at: now,
|
|
275
256
|
changed_at: now,
|
|
276
|
-
last_logon: now,
|
|
277
257
|
};
|
|
278
|
-
if (name)
|
|
258
|
+
if (name)
|
|
279
259
|
insert_data.name = name;
|
|
280
|
-
}
|
|
281
260
|
if (profile_picture_url) {
|
|
282
261
|
insert_data.profile_picture_url = profile_picture_url;
|
|
283
262
|
insert_data.profile_source = "custom";
|
|
284
263
|
}
|
|
285
|
-
const
|
|
286
|
-
if (!Array.isArray(
|
|
287
|
-
return {
|
|
288
|
-
success: false,
|
|
289
|
-
error: "Failed to create user account",
|
|
290
|
-
};
|
|
264
|
+
const inserted = await users_service.insert(insert_data);
|
|
265
|
+
if (!Array.isArray(inserted) || inserted.length === 0) {
|
|
266
|
+
return { success: false, error: "Failed to create user account" };
|
|
291
267
|
}
|
|
292
268
|
logger.info("oauth_service_facebook_new_user_created", {
|
|
293
269
|
filename: "oauth_service.ts",
|
|
294
|
-
line_number: get_line_number(),
|
|
295
270
|
user_id,
|
|
296
271
|
email,
|
|
297
272
|
});
|
|
@@ -300,7 +275,7 @@ export async function handle_facebook_oauth_login(adapter, data, opts) {
|
|
|
300
275
|
user_id,
|
|
301
276
|
is_new_user: true,
|
|
302
277
|
was_linked: false,
|
|
303
|
-
email
|
|
278
|
+
email,
|
|
304
279
|
name,
|
|
305
280
|
};
|
|
306
281
|
}
|
|
@@ -309,17 +284,9 @@ export async function handle_facebook_oauth_login(adapter, data, opts) {
|
|
|
309
284
|
logToConsole: true,
|
|
310
285
|
logToLogger: true,
|
|
311
286
|
logger,
|
|
312
|
-
context: {
|
|
313
|
-
filename: "oauth_service.ts",
|
|
314
|
-
line_number: get_line_number(),
|
|
315
|
-
email: data.email,
|
|
316
|
-
operation: "handle_facebook_oauth_login",
|
|
317
|
-
},
|
|
287
|
+
context: { filename: "oauth_service.ts", email: data.email, operation: "handle_facebook_oauth_login" },
|
|
318
288
|
});
|
|
319
|
-
return {
|
|
320
|
-
success: false,
|
|
321
|
-
error: user_friendly_error,
|
|
322
|
-
};
|
|
289
|
+
return { success: false, error: user_friendly_error };
|
|
323
290
|
}
|
|
324
291
|
}
|
|
325
292
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"otp_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/otp_service.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;AAUrB;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAG1C;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAEjE;AAED,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAMtF;AAID,MAAM,MAAM,qBAAqB,GAC7B;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,cAAc,CAAC;IAAC,mBAAmB,EAAE,MAAM,CAAA;CAAE,CAAC;AAItE;;;;;;;;;;;GAWG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;CACZ,GAAG,OAAO,CAAC,qBAAqB,CAAC,
|
|
1
|
+
{"version":3,"file":"otp_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/otp_service.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;AAUrB;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAG1C;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAEjE;AAED,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAMtF;AAID,MAAM,MAAM,qBAAqB,GAC7B;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,cAAc,CAAC;IAAC,mBAAmB,EAAE,MAAM,CAAA;CAAE,CAAC;AAItE;;;;;;;;;;;GAWG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;CACZ,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAmHjC;AAID,MAAM,MAAM,oBAAoB,GAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GACnE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,oBAAoB,GAAG,SAAS,CAAA;CAAE,CAAC;AAE3D,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAsHhC"}
|
|
@@ -111,6 +111,11 @@ export async function request_email_otp(args) {
|
|
|
111
111
|
expires_at,
|
|
112
112
|
attempt_count: 0,
|
|
113
113
|
requester_ip: ip,
|
|
114
|
+
// Explicitly pass created_at in JS ISO format ("2024-01-01T00:00:00.000Z") rather
|
|
115
|
+
// than relying on SQLite's DEFAULT (datetime('now') = "2024-01-01 00:00:00").
|
|
116
|
+
// The space-separated SQLite format compares as less-than the T-separated JS ISO
|
|
117
|
+
// threshold used in rate-limit WHERE clauses, causing the counter to always read 0.
|
|
118
|
+
created_at: new Date().toISOString(),
|
|
114
119
|
});
|
|
115
120
|
// 7. Dispatch email — fire-and-forget; errors are logged but do not surface to caller
|
|
116
121
|
try {
|
|
@@ -155,7 +160,7 @@ export async function verify_email_otp(args) {
|
|
|
155
160
|
// 2. Check expiry
|
|
156
161
|
const expires_at_ms = Date.parse(String(row.expires_at));
|
|
157
162
|
if (Number.isNaN(expires_at_ms) || expires_at_ms < Date.now()) {
|
|
158
|
-
return { ok: false, error: "
|
|
163
|
+
return { ok: false, error: "expired" };
|
|
159
164
|
}
|
|
160
165
|
// 3. argon2 verify
|
|
161
166
|
const is_valid = await verify_otp_code(String(row.otp_hash), code);
|
|
@@ -4,6 +4,11 @@ export type RegistrationData = {
|
|
|
4
4
|
password: string;
|
|
5
5
|
name?: string;
|
|
6
6
|
url_on_logon?: string;
|
|
7
|
+
legal_accepted?: Record<string, {
|
|
8
|
+
hash: string;
|
|
9
|
+
}>;
|
|
10
|
+
ip?: string | null;
|
|
11
|
+
user_agent?: string | null;
|
|
7
12
|
};
|
|
8
13
|
export type RegistrationResult = {
|
|
9
14
|
success: boolean;
|
|
@@ -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;
|
|
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;AAmBvD,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;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClD,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,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,CAmK7B"}
|
|
@@ -10,6 +10,7 @@ import { send_template_email } from "./email_service.js";
|
|
|
10
10
|
import { sanitize_error_for_user } from "../utils/error_sanitizer.js";
|
|
11
11
|
import { get_line_number } from "../utils/api_route_helpers.js";
|
|
12
12
|
import { is_user_types_enabled, get_default_user_type, } from "../user_types_config.server.js";
|
|
13
|
+
import { write_legal_acceptance } from "../legal/legal_docs_service.js";
|
|
13
14
|
// section: helpers
|
|
14
15
|
/**
|
|
15
16
|
* Registers a new user in the database using hazo_connect
|
|
@@ -18,6 +19,7 @@ import { is_user_types_enabled, get_default_user_type, } from "../user_types_con
|
|
|
18
19
|
* @returns Registration result with success status and user_id or error
|
|
19
20
|
*/
|
|
20
21
|
export async function register_user(adapter, data) {
|
|
22
|
+
var _a, _b;
|
|
21
23
|
try {
|
|
22
24
|
const { email, password, name, url_on_logon } = data;
|
|
23
25
|
// Create CRUD service for hazo_users table
|
|
@@ -130,6 +132,10 @@ export async function register_user(adapter, data) {
|
|
|
130
132
|
});
|
|
131
133
|
}
|
|
132
134
|
}
|
|
135
|
+
// Write legal acceptance records if provided
|
|
136
|
+
if (data.legal_accepted && Object.keys(data.legal_accepted).length > 0) {
|
|
137
|
+
await write_legal_acceptance(adapter, user_id, data.legal_accepted, (_a = data.ip) !== null && _a !== void 0 ? _a : null, (_b = data.user_agent) !== null && _b !== void 0 ? _b : null);
|
|
138
|
+
}
|
|
133
139
|
return {
|
|
134
140
|
success: true,
|
|
135
141
|
user_id,
|
|
@@ -16,8 +16,6 @@ export type ValidateSessionTokenResult = {
|
|
|
16
16
|
* Token includes user_id, email, issued at time, and expiration
|
|
17
17
|
* @param user_id - User ID
|
|
18
18
|
* @param email - User email address
|
|
19
|
-
* @param managed_by_user_id - Optional: ID of the managing user (for impersonation)
|
|
20
|
-
* @param ttl_seconds - Optional: token lifetime in seconds (default: 30 days). Use 604800 for 7-day OTP sessions.
|
|
21
19
|
* @returns JWT token string
|
|
22
20
|
*/
|
|
23
21
|
export declare function create_session_token(user_id: string, email: string, managed_by_user_id?: string, ttl_seconds?: number): Promise<string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session_token_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/session_token_service.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AAuCF
|
|
1
|
+
{"version":3,"file":"session_token_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/session_token_service.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AAuCF;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,kBAAkB,CAAC,EAAE,MAAM,EAC3B,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,CA4CjB;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,0BAA0B,CAAC,CAkDrC"}
|