admin passwordHash import support
This commit is contained in:
parent
8f540164df
commit
d767346345
2 changed files with 35 additions and 7 deletions
19
README.md
19
README.md
|
|
@ -336,7 +336,7 @@ Secrets/credentials in the config file can reference environment variables using
|
|||
|
||||
##### Admin Setup (Automated)
|
||||
|
||||
- **Example:**
|
||||
- **Example (new instance):**
|
||||
```json
|
||||
{
|
||||
"admin": {
|
||||
|
|
@ -346,11 +346,26 @@ Secrets/credentials in the config file can reference environment variables using
|
|||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **Example (migration from another instance):**
|
||||
```json
|
||||
{
|
||||
"admin": {
|
||||
"username": "admin",
|
||||
"passwordHash": "$argon2id$v=19$m=19456,t=2,p=1$...",
|
||||
"recoveryKey": "${RECOVERY_KEY}"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- **Fields:**
|
||||
- `username`: Admin username to create on first startup
|
||||
- `password`: Admin password (can use `${ENV_VAR}`)
|
||||
- `password`: Admin password for new instances (can use `${ENV_VAR}`)
|
||||
- `passwordHash`: Pre-hashed password for migration (exported from another instance)
|
||||
- `recoveryKey`: Optional recovery key (can use `${ENV_VAR}`) - if provided, the UI prompt to download recovery key will be skipped
|
||||
|
||||
> **Note:** Use either `password` OR `passwordHash`, not both. The `passwordHash` option is useful when migrating from another Zerobyte instance using an exported config with `includePasswordHash=true`.
|
||||
|
||||
**On first startup, Zerobyte will automatically create the admin user from the config file.**
|
||||
|
||||
> **⚠️ About the Recovery Key**
|
||||
|
|
|
|||
|
|
@ -176,17 +176,30 @@ export const startup = async () => {
|
|||
|
||||
try {
|
||||
const { authService } = await import("../auth/auth.service");
|
||||
if (configFileAdmin && configFileAdmin.username && configFileAdmin.password) {
|
||||
if (configFileAdmin && configFileAdmin.username && (configFileAdmin.password || configFileAdmin.passwordHash)) {
|
||||
const hasUsers = await authService.hasUsers();
|
||||
if (!hasUsers) {
|
||||
const { user } = await authService.register(configFileAdmin.username, configFileAdmin.password);
|
||||
logger.info(`Admin user '${configFileAdmin.username}' created from config.`);
|
||||
let userId: number;
|
||||
if (configFileAdmin.passwordHash) {
|
||||
// Import with existing password hash (migration from another instance)
|
||||
const [user] = await db.insert(usersTable).values({
|
||||
username: configFileAdmin.username,
|
||||
passwordHash: configFileAdmin.passwordHash,
|
||||
}).returning();
|
||||
userId = user.id;
|
||||
logger.info(`Admin user '${configFileAdmin.username}' imported with password hash from config.`);
|
||||
} else {
|
||||
// Create new user with plaintext password
|
||||
const { user } = await authService.register(configFileAdmin.username, configFileAdmin.password);
|
||||
userId = user.id;
|
||||
logger.info(`Admin user '${configFileAdmin.username}' created from config.`);
|
||||
}
|
||||
if (configFileAdmin.recoveryKey) {
|
||||
await db.update(usersTable).set({ hasDownloadedResticPassword: true }).where(eq(usersTable.id, user.id));
|
||||
await db.update(usersTable).set({ hasDownloadedResticPassword: true }).where(eq(usersTable.id, userId));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.warn("Admin config missing required fields (username, password). Skipping automated admin setup.");
|
||||
logger.warn("Admin config missing required fields (username, password or passwordHash). Skipping automated admin setup.");
|
||||
}
|
||||
} catch (err) {
|
||||
const e = err instanceof Error ? err : new Error(String(err));
|
||||
|
|
|
|||
Loading…
Reference in a new issue