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,254 @@
|
|
|
1
|
+
// file_description: init command for hazo_auth
|
|
2
|
+
// Creates directories and copies config files to consuming projects
|
|
3
|
+
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
import * as fs from "fs";
|
|
6
|
+
import * as path from "path";
|
|
7
|
+
|
|
8
|
+
// section: esm_shim
|
|
9
|
+
// ESM-compatible __dirname shim
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = path.dirname(__filename);
|
|
12
|
+
|
|
13
|
+
// section: types
|
|
14
|
+
type InitResult = {
|
|
15
|
+
directories_created: string[];
|
|
16
|
+
files_copied: string[];
|
|
17
|
+
skipped: string[];
|
|
18
|
+
errors: string[];
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// section: constants
|
|
22
|
+
const REQUIRED_DIRECTORIES = [
|
|
23
|
+
"public/profile_pictures/library",
|
|
24
|
+
"public/profile_pictures/uploads",
|
|
25
|
+
"data",
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
const CONFIG_FILES = [
|
|
29
|
+
{ source: "hazo_auth_config.example.ini", target: "hazo_auth_config.ini" },
|
|
30
|
+
{ source: "hazo_notify_config.example.ini", target: "hazo_notify_config.ini" },
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
// section: helpers
|
|
34
|
+
function get_project_root(): string {
|
|
35
|
+
return process.cwd();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function get_package_root(): string {
|
|
39
|
+
// When running from node_modules, we need to find the hazo_auth package root
|
|
40
|
+
// When running in development, use the current directory
|
|
41
|
+
|
|
42
|
+
// Check if we're in node_modules
|
|
43
|
+
const parts = __dirname.split(path.sep);
|
|
44
|
+
const node_modules_index = parts.lastIndexOf("node_modules");
|
|
45
|
+
|
|
46
|
+
if (node_modules_index !== -1) {
|
|
47
|
+
// We're in node_modules/hazo_auth/dist/cli
|
|
48
|
+
return parts.slice(0, node_modules_index + 2).join(path.sep);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Development mode - go up from src/cli or dist/cli
|
|
52
|
+
return path.resolve(__dirname, "..", "..");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function ensure_dir(dir_path: string): boolean {
|
|
56
|
+
if (!fs.existsSync(dir_path)) {
|
|
57
|
+
fs.mkdirSync(dir_path, { recursive: true });
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function copy_file_if_not_exists(source: string, target: string): "created" | "skipped" | "error" {
|
|
64
|
+
if (fs.existsSync(target)) {
|
|
65
|
+
return "skipped";
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!fs.existsSync(source)) {
|
|
69
|
+
return "error";
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
fs.copyFileSync(source, target);
|
|
74
|
+
return "created";
|
|
75
|
+
} catch {
|
|
76
|
+
return "error";
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function copy_directory(source: string, target: string): number {
|
|
81
|
+
let copied = 0;
|
|
82
|
+
|
|
83
|
+
if (!fs.existsSync(source)) {
|
|
84
|
+
return 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
ensure_dir(target);
|
|
88
|
+
|
|
89
|
+
const items = fs.readdirSync(source);
|
|
90
|
+
|
|
91
|
+
for (const item of items) {
|
|
92
|
+
const source_path = path.join(source, item);
|
|
93
|
+
const target_path = path.join(target, item);
|
|
94
|
+
|
|
95
|
+
const stat = fs.statSync(source_path);
|
|
96
|
+
|
|
97
|
+
if (stat.isDirectory()) {
|
|
98
|
+
copied += copy_directory(source_path, target_path);
|
|
99
|
+
} else if (!fs.existsSync(target_path)) {
|
|
100
|
+
fs.copyFileSync(source_path, target_path);
|
|
101
|
+
copied++;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return copied;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function create_gitkeep(dir_path: string): void {
|
|
109
|
+
const gitkeep_path = path.join(dir_path, ".gitkeep");
|
|
110
|
+
if (!fs.existsSync(gitkeep_path)) {
|
|
111
|
+
const files = fs.readdirSync(dir_path);
|
|
112
|
+
if (files.length === 0) {
|
|
113
|
+
fs.writeFileSync(gitkeep_path, "# This file keeps the empty directory in git\n");
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function create_env_template(project_root: string): boolean {
|
|
119
|
+
const env_example_path = path.join(project_root, ".env.local.example");
|
|
120
|
+
|
|
121
|
+
if (fs.existsSync(env_example_path)) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const content = `# hazo_auth environment variables
|
|
126
|
+
# Copy this file to .env.local and fill in the values
|
|
127
|
+
|
|
128
|
+
# Required for email functionality (email verification, password reset)
|
|
129
|
+
ZEPTOMAIL_API_KEY=your_zeptomail_api_key_here
|
|
130
|
+
|
|
131
|
+
# Optional: Database path (defaults to data/hazo_auth.sqlite)
|
|
132
|
+
# HAZO_AUTH_DB_PATH=./data/hazo_auth.sqlite
|
|
133
|
+
`;
|
|
134
|
+
|
|
135
|
+
fs.writeFileSync(env_example_path, content);
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// section: main
|
|
140
|
+
export function handle_init(): void {
|
|
141
|
+
const project_root = get_project_root();
|
|
142
|
+
const package_root = get_package_root();
|
|
143
|
+
|
|
144
|
+
console.log("\n\x1b[1m🐸 hazo_auth Initialization\x1b[0m");
|
|
145
|
+
console.log("=".repeat(50));
|
|
146
|
+
console.log(`Project root: ${project_root}`);
|
|
147
|
+
console.log(`Package root: ${package_root}\n`);
|
|
148
|
+
|
|
149
|
+
const result: InitResult = {
|
|
150
|
+
directories_created: [],
|
|
151
|
+
files_copied: [],
|
|
152
|
+
skipped: [],
|
|
153
|
+
errors: [],
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
// Step 1: Create directories
|
|
157
|
+
console.log("\x1b[1m📁 Creating directories...\x1b[0m\n");
|
|
158
|
+
|
|
159
|
+
for (const dir of REQUIRED_DIRECTORIES) {
|
|
160
|
+
const full_path = path.join(project_root, dir);
|
|
161
|
+
|
|
162
|
+
if (ensure_dir(full_path)) {
|
|
163
|
+
console.log(`\x1b[32m[CREATE]\x1b[0m ${dir}/`);
|
|
164
|
+
result.directories_created.push(dir);
|
|
165
|
+
} else {
|
|
166
|
+
console.log(`\x1b[33m[EXISTS]\x1b[0m ${dir}/`);
|
|
167
|
+
result.skipped.push(dir);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Step 2: Copy config files
|
|
172
|
+
console.log("\n\x1b[1m📄 Copying config files...\x1b[0m\n");
|
|
173
|
+
|
|
174
|
+
for (const config of CONFIG_FILES) {
|
|
175
|
+
const source_path = path.join(package_root, config.source);
|
|
176
|
+
const target_path = path.join(project_root, config.target);
|
|
177
|
+
|
|
178
|
+
const status = copy_file_if_not_exists(source_path, target_path);
|
|
179
|
+
|
|
180
|
+
if (status === "created") {
|
|
181
|
+
console.log(`\x1b[32m[CREATE]\x1b[0m ${config.target}`);
|
|
182
|
+
result.files_copied.push(config.target);
|
|
183
|
+
} else if (status === "skipped") {
|
|
184
|
+
console.log(`\x1b[33m[EXISTS]\x1b[0m ${config.target}`);
|
|
185
|
+
result.skipped.push(config.target);
|
|
186
|
+
} else {
|
|
187
|
+
console.log(`\x1b[31m[ERROR]\x1b[0m ${config.target} - source not found: ${source_path}`);
|
|
188
|
+
result.errors.push(config.target);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Step 3: Copy profile picture library
|
|
193
|
+
console.log("\n\x1b[1m🖼️ Copying profile picture library...\x1b[0m\n");
|
|
194
|
+
|
|
195
|
+
const library_source = path.join(package_root, "public", "profile_pictures", "library");
|
|
196
|
+
const library_target = path.join(project_root, "public", "profile_pictures", "library");
|
|
197
|
+
|
|
198
|
+
if (fs.existsSync(library_source)) {
|
|
199
|
+
const copied_count = copy_directory(library_source, library_target);
|
|
200
|
+
|
|
201
|
+
if (copied_count > 0) {
|
|
202
|
+
console.log(`\x1b[32m[COPY]\x1b[0m ${copied_count} library images`);
|
|
203
|
+
result.files_copied.push(`${copied_count} library images`);
|
|
204
|
+
} else {
|
|
205
|
+
console.log(`\x1b[33m[EXISTS]\x1b[0m Library images already present`);
|
|
206
|
+
result.skipped.push("library images");
|
|
207
|
+
}
|
|
208
|
+
} else {
|
|
209
|
+
console.log(`\x1b[33m[SKIP]\x1b[0m Library not found at: ${library_source}`);
|
|
210
|
+
result.skipped.push("library images (source not found)");
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Step 4: Create .gitkeep files for empty directories
|
|
214
|
+
console.log("\n\x1b[1m📌 Creating .gitkeep files...\x1b[0m\n");
|
|
215
|
+
|
|
216
|
+
const empty_dirs = ["public/profile_pictures/uploads", "data"];
|
|
217
|
+
|
|
218
|
+
for (const dir of empty_dirs) {
|
|
219
|
+
const full_path = path.join(project_root, dir);
|
|
220
|
+
if (fs.existsSync(full_path)) {
|
|
221
|
+
create_gitkeep(full_path);
|
|
222
|
+
console.log(`\x1b[32m[CREATE]\x1b[0m ${dir}/.gitkeep`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Step 5: Create .env.local.example template
|
|
227
|
+
console.log("\n\x1b[1m🔑 Creating environment template...\x1b[0m\n");
|
|
228
|
+
|
|
229
|
+
if (create_env_template(project_root)) {
|
|
230
|
+
console.log(`\x1b[32m[CREATE]\x1b[0m .env.local.example`);
|
|
231
|
+
result.files_copied.push(".env.local.example");
|
|
232
|
+
} else {
|
|
233
|
+
console.log(`\x1b[33m[EXISTS]\x1b[0m .env.local.example`);
|
|
234
|
+
result.skipped.push(".env.local.example");
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Summary
|
|
238
|
+
console.log("\n" + "=".repeat(50));
|
|
239
|
+
console.log("\x1b[1mSummary:\x1b[0m");
|
|
240
|
+
console.log(` \x1b[32m✓ Created:\x1b[0m ${result.directories_created.length} directories, ${result.files_copied.length} files`);
|
|
241
|
+
console.log(` \x1b[33m⊘ Skipped:\x1b[0m ${result.skipped.length} items`);
|
|
242
|
+
|
|
243
|
+
if (result.errors.length > 0) {
|
|
244
|
+
console.log(` \x1b[31m✗ Errors:\x1b[0m ${result.errors.length}`);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
console.log("\n\x1b[32m🦊 Initialization complete!\x1b[0m");
|
|
248
|
+
console.log("\nNext steps:");
|
|
249
|
+
console.log(" 1. Edit \x1b[36mhazo_auth_config.ini\x1b[0m with your settings");
|
|
250
|
+
console.log(" 2. Copy \x1b[36m.env.local.example\x1b[0m to \x1b[36m.env.local\x1b[0m and add your API keys");
|
|
251
|
+
console.log(" 3. Run \x1b[36mnpx hazo_auth generate-routes --pages\x1b[0m to generate routes and pages");
|
|
252
|
+
console.log(" 4. Run \x1b[36mnpx hazo_auth validate\x1b[0m to check your setup");
|
|
253
|
+
console.log();
|
|
254
|
+
}
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
// file_description: CLI command to initialize users, roles, and permissions from configuration
|
|
2
|
+
// section: imports
|
|
3
|
+
import { get_hazo_connect_instance } from "../lib/hazo_connect_instance.server.js";
|
|
4
|
+
import { createCrudService } from "hazo_connect/server";
|
|
5
|
+
import { get_user_management_config } from "../lib/user_management_config.server.js";
|
|
6
|
+
import { get_config_value } from "../lib/config/config_loader.server.js";
|
|
7
|
+
import { create_app_logger } from "../lib/app_logger.js";
|
|
8
|
+
|
|
9
|
+
// section: types
|
|
10
|
+
type InitSummary = {
|
|
11
|
+
permissions: {
|
|
12
|
+
inserted: string[];
|
|
13
|
+
existing: string[];
|
|
14
|
+
};
|
|
15
|
+
role: {
|
|
16
|
+
inserted: boolean;
|
|
17
|
+
existing: boolean;
|
|
18
|
+
role_id: string | null;
|
|
19
|
+
};
|
|
20
|
+
role_permissions: {
|
|
21
|
+
inserted: number;
|
|
22
|
+
existing: number;
|
|
23
|
+
};
|
|
24
|
+
user_role: {
|
|
25
|
+
inserted: boolean;
|
|
26
|
+
existing: boolean;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// section: helpers
|
|
31
|
+
/**
|
|
32
|
+
* Prints a summary of what was inserted vs what already existed
|
|
33
|
+
*/
|
|
34
|
+
function print_summary(summary: InitSummary): void {
|
|
35
|
+
console.log("=".repeat(60));
|
|
36
|
+
console.log("INITIALIZATION SUMMARY");
|
|
37
|
+
console.log("=".repeat(60));
|
|
38
|
+
console.log();
|
|
39
|
+
|
|
40
|
+
// Permissions summary
|
|
41
|
+
console.log("Permissions:");
|
|
42
|
+
if (summary.permissions.inserted.length > 0) {
|
|
43
|
+
console.log(` ✓ Inserted (${summary.permissions.inserted.length}):`);
|
|
44
|
+
summary.permissions.inserted.forEach((name) => console.log(` - ${name}`));
|
|
45
|
+
}
|
|
46
|
+
if (summary.permissions.existing.length > 0) {
|
|
47
|
+
console.log(` ⊙ Already existed (${summary.permissions.existing.length}):`);
|
|
48
|
+
summary.permissions.existing.forEach((name) => console.log(` - ${name}`));
|
|
49
|
+
}
|
|
50
|
+
console.log();
|
|
51
|
+
|
|
52
|
+
// Role summary
|
|
53
|
+
console.log("Role:");
|
|
54
|
+
if (summary.role.inserted) {
|
|
55
|
+
console.log(` ✓ Inserted: default_super_user_role (ID: ${summary.role.role_id})`);
|
|
56
|
+
}
|
|
57
|
+
if (summary.role.existing) {
|
|
58
|
+
console.log(` ⊙ Already existed: default_super_user_role (ID: ${summary.role.role_id})`);
|
|
59
|
+
}
|
|
60
|
+
console.log();
|
|
61
|
+
|
|
62
|
+
// Role permissions summary
|
|
63
|
+
console.log("Role-Permission Assignments:");
|
|
64
|
+
if (summary.role_permissions.inserted > 0) {
|
|
65
|
+
console.log(` ✓ Inserted: ${summary.role_permissions.inserted} assignment(s)`);
|
|
66
|
+
}
|
|
67
|
+
if (summary.role_permissions.existing > 0) {
|
|
68
|
+
console.log(` ⊙ Already existed: ${summary.role_permissions.existing} assignment(s)`);
|
|
69
|
+
}
|
|
70
|
+
console.log();
|
|
71
|
+
|
|
72
|
+
// User role summary
|
|
73
|
+
console.log("User-Role Assignment:");
|
|
74
|
+
if (summary.user_role.inserted) {
|
|
75
|
+
console.log(` ✓ Inserted: Super user role assigned to user`);
|
|
76
|
+
}
|
|
77
|
+
if (summary.user_role.existing) {
|
|
78
|
+
console.log(` ⊙ Already existed: User already has super user role`);
|
|
79
|
+
}
|
|
80
|
+
console.log();
|
|
81
|
+
|
|
82
|
+
console.log("=".repeat(60));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// section: types_options
|
|
86
|
+
export type InitUsersOptions = {
|
|
87
|
+
/** Email address of the user to assign super user role (overrides config) */
|
|
88
|
+
email?: string;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// section: main_function
|
|
92
|
+
/**
|
|
93
|
+
* Initializes users, roles, and permissions from configuration
|
|
94
|
+
* This function reads from hazo_auth_config.ini and sets up:
|
|
95
|
+
* 1. Permissions from [hazo_auth__user_management] application_permission_list_defaults
|
|
96
|
+
* 2. A default_super_user_role with all permissions
|
|
97
|
+
* 3. Assigns the role to user from --email parameter or [hazo_auth__initial_setup] default_super_user_email
|
|
98
|
+
*/
|
|
99
|
+
export async function handle_init_users(options: InitUsersOptions = {}): Promise<void> {
|
|
100
|
+
const logger = create_app_logger();
|
|
101
|
+
const summary: InitSummary = {
|
|
102
|
+
permissions: {
|
|
103
|
+
inserted: [],
|
|
104
|
+
existing: [],
|
|
105
|
+
},
|
|
106
|
+
role: {
|
|
107
|
+
inserted: false,
|
|
108
|
+
existing: false,
|
|
109
|
+
role_id: null,
|
|
110
|
+
},
|
|
111
|
+
role_permissions: {
|
|
112
|
+
inserted: 0,
|
|
113
|
+
existing: 0,
|
|
114
|
+
},
|
|
115
|
+
user_role: {
|
|
116
|
+
inserted: false,
|
|
117
|
+
existing: false,
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
console.log("\n🐸 hazo_auth init-users\n");
|
|
123
|
+
console.log("Initializing users, roles, and permissions from configuration...\n");
|
|
124
|
+
|
|
125
|
+
// Get hazo_connect instance
|
|
126
|
+
const hazoConnect = get_hazo_connect_instance();
|
|
127
|
+
const permissions_service = createCrudService(hazoConnect, "hazo_permissions");
|
|
128
|
+
const roles_service = createCrudService(hazoConnect, "hazo_roles");
|
|
129
|
+
const role_permissions_service = createCrudService(hazoConnect, "hazo_role_permissions");
|
|
130
|
+
const users_service = createCrudService(hazoConnect, "hazo_users");
|
|
131
|
+
const user_roles_service = createCrudService(hazoConnect, "hazo_user_roles");
|
|
132
|
+
|
|
133
|
+
// 1. Get permissions from config
|
|
134
|
+
const config = get_user_management_config();
|
|
135
|
+
const permission_names = config.application_permission_list_defaults || [];
|
|
136
|
+
|
|
137
|
+
if (permission_names.length === 0) {
|
|
138
|
+
console.log("⚠ No permissions found in configuration.");
|
|
139
|
+
console.log(" Add permissions to [hazo_auth__user_management] application_permission_list_defaults\n");
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
console.log(`Found ${permission_names.length} permission(s) in configuration:`);
|
|
144
|
+
permission_names.forEach((name) => console.log(` - ${name}`));
|
|
145
|
+
console.log();
|
|
146
|
+
|
|
147
|
+
// 2. Add permissions to hazo_permissions table
|
|
148
|
+
const permission_id_map: Record<string, string> = {};
|
|
149
|
+
const now = new Date().toISOString();
|
|
150
|
+
|
|
151
|
+
for (const permission_name of permission_names) {
|
|
152
|
+
const trimmed_name = permission_name.trim();
|
|
153
|
+
if (!trimmed_name) continue;
|
|
154
|
+
|
|
155
|
+
// Check if permission already exists
|
|
156
|
+
const existing_permissions = await permissions_service.findBy({
|
|
157
|
+
permission_name: trimmed_name,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
if (Array.isArray(existing_permissions) && existing_permissions.length > 0) {
|
|
161
|
+
const existing_permission = existing_permissions[0];
|
|
162
|
+
const perm_id = existing_permission.id as string;
|
|
163
|
+
permission_id_map[trimmed_name] = perm_id;
|
|
164
|
+
summary.permissions.existing.push(trimmed_name);
|
|
165
|
+
console.log(`✓ Permission already exists: ${trimmed_name} (ID: ${perm_id})`);
|
|
166
|
+
} else {
|
|
167
|
+
// Insert new permission
|
|
168
|
+
const new_permission = await permissions_service.insert({
|
|
169
|
+
permission_name: trimmed_name,
|
|
170
|
+
description: `Permission for ${trimmed_name}`,
|
|
171
|
+
created_at: now,
|
|
172
|
+
changed_at: now,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const perm_id = Array.isArray(new_permission)
|
|
176
|
+
? (new_permission[0] as { id: string }).id
|
|
177
|
+
: (new_permission as { id: string }).id;
|
|
178
|
+
permission_id_map[trimmed_name] = perm_id;
|
|
179
|
+
summary.permissions.inserted.push(trimmed_name);
|
|
180
|
+
console.log(`✓ Inserted permission: ${trimmed_name} (ID: ${perm_id})`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
console.log();
|
|
185
|
+
|
|
186
|
+
// 3. Create or get default_super_user_role
|
|
187
|
+
const role_name = "default_super_user_role";
|
|
188
|
+
const existing_roles = await roles_service.findBy({
|
|
189
|
+
role_name,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
let role_id: string;
|
|
193
|
+
if (Array.isArray(existing_roles) && existing_roles.length > 0) {
|
|
194
|
+
role_id = existing_roles[0].id as string;
|
|
195
|
+
summary.role.existing = true;
|
|
196
|
+
summary.role.role_id = role_id;
|
|
197
|
+
console.log(`✓ Role already exists: ${role_name} (ID: ${role_id})`);
|
|
198
|
+
} else {
|
|
199
|
+
const new_role = await roles_service.insert({
|
|
200
|
+
role_name,
|
|
201
|
+
created_at: now,
|
|
202
|
+
changed_at: now,
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
role_id = Array.isArray(new_role)
|
|
206
|
+
? (new_role[0] as { id: string }).id
|
|
207
|
+
: (new_role as { id: string }).id;
|
|
208
|
+
summary.role.inserted = true;
|
|
209
|
+
summary.role.role_id = role_id;
|
|
210
|
+
console.log(`✓ Created role: ${role_name} (ID: ${role_id})`);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
console.log();
|
|
214
|
+
|
|
215
|
+
// 4. Assign all permissions to the role
|
|
216
|
+
const permission_ids = Object.values(permission_id_map);
|
|
217
|
+
|
|
218
|
+
for (const permission_id of permission_ids) {
|
|
219
|
+
// Check if role-permission assignment already exists
|
|
220
|
+
const existing_assignments = await role_permissions_service.findBy({
|
|
221
|
+
role_id,
|
|
222
|
+
permission_id,
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
if (Array.isArray(existing_assignments) && existing_assignments.length > 0) {
|
|
226
|
+
summary.role_permissions.existing++;
|
|
227
|
+
const perm_name = Object.keys(permission_id_map).find(
|
|
228
|
+
(key) => permission_id_map[key] === permission_id,
|
|
229
|
+
);
|
|
230
|
+
console.log(`✓ Role-permission already exists: ${role_name} -> ${perm_name}`);
|
|
231
|
+
} else {
|
|
232
|
+
await role_permissions_service.insert({
|
|
233
|
+
role_id,
|
|
234
|
+
permission_id,
|
|
235
|
+
created_at: now,
|
|
236
|
+
changed_at: now,
|
|
237
|
+
});
|
|
238
|
+
summary.role_permissions.inserted++;
|
|
239
|
+
const perm_name = Object.keys(permission_id_map).find(
|
|
240
|
+
(key) => permission_id_map[key] === permission_id,
|
|
241
|
+
);
|
|
242
|
+
console.log(`✓ Assigned permission to role: ${role_name} -> ${perm_name}`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
console.log();
|
|
247
|
+
|
|
248
|
+
// 5. Get super user email from options or config
|
|
249
|
+
const super_user_email = options.email?.trim() || get_config_value(
|
|
250
|
+
"hazo_auth__initial_setup",
|
|
251
|
+
"default_super_user_email",
|
|
252
|
+
"",
|
|
253
|
+
).trim();
|
|
254
|
+
|
|
255
|
+
if (!super_user_email) {
|
|
256
|
+
console.log("⚠ No super user email provided.");
|
|
257
|
+
console.log(" Either use --email=user@example.com parameter");
|
|
258
|
+
console.log(" Or add [hazo_auth__initial_setup] default_super_user_email to config\n");
|
|
259
|
+
print_summary(summary);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (options.email) {
|
|
264
|
+
console.log(`Using email from --email parameter: ${super_user_email}`);
|
|
265
|
+
} else {
|
|
266
|
+
console.log(`Using email from config: ${super_user_email}`);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
console.log(`Looking up user with email: ${super_user_email}`);
|
|
270
|
+
|
|
271
|
+
// 6. Find user by email
|
|
272
|
+
const users = await users_service.findBy({
|
|
273
|
+
email_address: super_user_email,
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
if (!Array.isArray(users) || users.length === 0) {
|
|
277
|
+
console.log(`✗ User not found with email: ${super_user_email}`);
|
|
278
|
+
console.log(" Please ensure the user exists in the database before running this script.\n");
|
|
279
|
+
print_summary(summary);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const user = users[0];
|
|
284
|
+
const user_id = user.id as string;
|
|
285
|
+
console.log(`✓ Found user: ${super_user_email} (ID: ${user_id})`);
|
|
286
|
+
console.log();
|
|
287
|
+
|
|
288
|
+
// 7. Assign role to user
|
|
289
|
+
const existing_user_roles = await user_roles_service.findBy({
|
|
290
|
+
user_id,
|
|
291
|
+
role_id,
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
if (Array.isArray(existing_user_roles) && existing_user_roles.length > 0) {
|
|
295
|
+
summary.user_role.existing = true;
|
|
296
|
+
console.log(`✓ User already has role assigned: ${user_id} -> ${role_name}`);
|
|
297
|
+
} else {
|
|
298
|
+
await user_roles_service.insert({
|
|
299
|
+
user_id,
|
|
300
|
+
role_id,
|
|
301
|
+
created_at: now,
|
|
302
|
+
changed_at: now,
|
|
303
|
+
});
|
|
304
|
+
summary.user_role.inserted = true;
|
|
305
|
+
console.log(`✓ Assigned role to user: ${user_id} -> ${role_name}`);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
console.log();
|
|
309
|
+
|
|
310
|
+
// 8. Print summary
|
|
311
|
+
print_summary(summary);
|
|
312
|
+
|
|
313
|
+
logger.info("init_users_completed", {
|
|
314
|
+
filename: "init_users.ts",
|
|
315
|
+
line_number: 0,
|
|
316
|
+
summary,
|
|
317
|
+
});
|
|
318
|
+
} catch (error) {
|
|
319
|
+
const error_message = error instanceof Error ? error.message : "Unknown error";
|
|
320
|
+
const error_stack = error instanceof Error ? error.stack : undefined;
|
|
321
|
+
|
|
322
|
+
console.error("\n✗ Error initializing users:");
|
|
323
|
+
console.error(` ${error_message}`);
|
|
324
|
+
if (error_stack) {
|
|
325
|
+
console.error("\nStack trace:");
|
|
326
|
+
console.error(error_stack);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
logger.error("init_users_failed", {
|
|
330
|
+
filename: "init_users.ts",
|
|
331
|
+
line_number: 0,
|
|
332
|
+
error_message,
|
|
333
|
+
error_stack,
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
process.exit(1);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// section: help
|
|
341
|
+
/**
|
|
342
|
+
* Shows help for the init-users command
|
|
343
|
+
*/
|
|
344
|
+
export function show_init_users_help(): void {
|
|
345
|
+
console.log(`
|
|
346
|
+
hazo_auth init-users
|
|
347
|
+
|
|
348
|
+
Initialize users, roles, and permissions from configuration.
|
|
349
|
+
|
|
350
|
+
This command reads from hazo_auth_config.ini and:
|
|
351
|
+
1. Creates permissions from [hazo_auth__user_management] application_permission_list_defaults
|
|
352
|
+
2. Creates a 'default_super_user_role' role
|
|
353
|
+
3. Assigns all permissions to the super user role
|
|
354
|
+
4. Finds user by email (from --email parameter or config)
|
|
355
|
+
5. Assigns the super user role to that user
|
|
356
|
+
|
|
357
|
+
Options:
|
|
358
|
+
--email=<email> Email address of the user to assign super user role
|
|
359
|
+
(overrides [hazo_auth__initial_setup] default_super_user_email)
|
|
360
|
+
--help, -h Show this help message
|
|
361
|
+
|
|
362
|
+
Configuration required in hazo_auth_config.ini:
|
|
363
|
+
|
|
364
|
+
[hazo_auth__user_management]
|
|
365
|
+
application_permission_list_defaults = admin_user_management,admin_role_management,admin_permission_management
|
|
366
|
+
|
|
367
|
+
[hazo_auth__initial_setup]
|
|
368
|
+
default_super_user_email = admin@example.com (optional if using --email)
|
|
369
|
+
|
|
370
|
+
Note: The user must already exist in the database (registered) before running this command.
|
|
371
|
+
|
|
372
|
+
Usage:
|
|
373
|
+
npx hazo_auth init-users
|
|
374
|
+
npx hazo_auth init-users --email=admin@example.com
|
|
375
|
+
`);
|
|
376
|
+
}
|