#!/bin/bash # Bookstack stores users in MySQL/SQLite via Laravel/Eloquent. We use # `php artisan tinker` to call the same User model the web UI does, so # password hashing + role assignment match exactly what Bookstack expects. _bookstackArtisan() { local container="bookstack" local php_body="$1" shift sudo docker exec -i -w /app/www "$@" "$container" php artisan tinker --execute="$php_body" 2>&1 } authAdapter_bookstack_setPassword() { local email="$1" password="$2" [[ -z "$email" ]] && { isError "Email is required."; return 1; } [[ -z "$password" ]] && password=$(generateRandomPassword) local out out=$(_bookstackArtisan ' $u = \BookStack\Users\Models\User::where("email", getenv("EZ_EMAIL"))->first(); if (!$u) { echo "EZ_USER_NOT_FOUND"; exit; } $u->password = bcrypt(getenv("EZ_PASS")); $u->save(); echo "EZ_RESET_OK:" . $u->name; ' -e "EZ_EMAIL=$email" -e "EZ_PASS=$password") if echo "$out" | grep -q EZ_USER_NOT_FOUND; then isError "No Bookstack user with email '$email'."; return 1 fi if ! echo "$out" | grep -q EZ_RESET_OK; then isError "Bookstack reset failed: $out"; return 1 fi if [[ "$email" == "${CFG_BOOKSTACK_ADMIN_USER:-}" ]]; then authPersistCfg bookstack ADMIN_PASSWORD "$password" fi isSuccessful "Bookstack password set for $email — New password: $password" } authAdapter_bookstack_createUser() { local email="$1" password="$2" name="$3" isAdmin="$4" [[ -z "$email" ]] && { isError "Email is required."; return 1; } [[ -z "$name" ]] && name="${email%@*}" [[ -z "$password" ]] && password=$(generateRandomPassword) local roleSlug="public" [[ "$isAdmin" == "true" ]] && roleSlug="admin" local out out=$(_bookstackArtisan ' if (\BookStack\Users\Models\User::where("email", getenv("EZ_EMAIL"))->exists()) { echo "EZ_USER_EXISTS"; exit; } $u = new \BookStack\Users\Models\User(); $u->name = getenv("EZ_NAME"); $u->email = getenv("EZ_EMAIL"); $u->password = bcrypt(getenv("EZ_PASS")); $u->email_confirmed = true; $base = preg_replace("/[^a-z0-9]+/", "-", strtolower($u->name ?: explode("@", $u->email)[0])); $base = trim($base, "-"); if ($base === "") $base = "user"; $slug = $base; $i = 1; while (\BookStack\Users\Models\User::where("slug", $slug)->exists()) { $i++; $slug = $base . "-" . $i; } $u->slug = $slug; $u->save(); $role = \BookStack\Users\Models\Role::where("system_name", getenv("EZ_ROLE"))->first(); if ($role) $u->attachRole($role); echo "EZ_USER_CREATED:" . $u->id; ' -e "EZ_EMAIL=$email" -e "EZ_NAME=$name" -e "EZ_PASS=$password" -e "EZ_ROLE=$roleSlug") if echo "$out" | grep -q EZ_USER_EXISTS; then isError "User '$email' already exists."; return 1; fi if ! echo "$out" | grep -q EZ_USER_CREATED; then isError "Bookstack create failed: $out"; return 1; fi if [[ "$isAdmin" == "true" && -z "${CFG_BOOKSTACK_ADMIN_USER:-}" ]]; then authPersistCfg bookstack ADMIN_USER "$email" authPersistCfg bookstack ADMIN_PASSWORD "$password" fi isSuccessful "Bookstack user created — Email: $email — Password: $password" } authAdapter_bookstack_listUsers() { _bookstackArtisan ' foreach (\BookStack\Users\Models\User::all() as $u) { $roles = $u->roles->pluck("display_name")->join(","); echo "EZ_USER\t" . $u->email . "\t" . $u->name . "\t" . ($roles ?: "—") . "\n"; } ' } authAdapter_bookstack_deleteUser() { local email="$1" [[ -z "$email" ]] && { isError "Email is required."; return 1; } local out out=$(_bookstackArtisan ' $u = \BookStack\Users\Models\User::where("email", getenv("EZ_EMAIL"))->first(); if (!$u) { echo "EZ_USER_NOT_FOUND"; exit; } $u->delete(); echo "EZ_USER_DELETED"; ' -e "EZ_EMAIL=$email") echo "$out" | grep -q EZ_USER_NOT_FOUND && { isError "No Bookstack user with email '$email'."; return 1; } echo "$out" | grep -q EZ_USER_DELETED || { isError "Bookstack delete failed: $out"; return 1; } isSuccessful "Bookstack user '$email' deleted." } authAdapter_bookstack_setAdmin() { local email="$1" isAdmin="$2" [[ -z "$email" ]] && { isError "Email is required."; return 1; } local target="${isAdmin}"; [[ "$target" != "true" ]] && target="false" local out out=$(_bookstackArtisan ' $u = \BookStack\Users\Models\User::where("email", getenv("EZ_EMAIL"))->first(); if (!$u) { echo "EZ_USER_NOT_FOUND"; exit; } $admin = \BookStack\Users\Models\Role::where("system_name", "admin")->first(); if (!$admin) { echo "EZ_ROLE_NOT_FOUND"; exit; } if (getenv("EZ_TARGET") === "true") { $u->attachRole($admin); } else { $u->detachRole($admin); } echo "EZ_OK"; ' -e "EZ_EMAIL=$email" -e "EZ_TARGET=$target") echo "$out" | grep -q EZ_USER_NOT_FOUND && { isError "No Bookstack user '$email'."; return 1; } echo "$out" | grep -q EZ_OK || { isError "Bookstack role change failed: $out"; return 1; } isSuccessful "Bookstack user '$email' admin → $target." }