Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ WHISPARR_API_KEY=
# Session settings (JWT expiration, idle timeout) are configured via the
# Security tab in the Settings UI. These values are stored in the database.

# Admin Password Reset (emergency reset if you forget your password)
# Set to "true" and restart the container to reset the admin account.
# This allows you to re-run the setup flow at /setup.
# All other data (logs, issues, settings) is preserved.
# IMPORTANT: Remove this env var after resetting to prevent repeated resets!
# ADMIN_PASSWORD_RESET=true

# =============================================================================
# HEALTH CHECK (optional)
# =============================================================================
Expand Down
10 changes: 10 additions & 0 deletions .env.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ PROWLARR_API_KEY={{ op://Development/Logarr-Dev/PROWLARR_API_KEY }}
WHISPARR_URL={{ op://Development/Logarr-Dev/WHISPARR_URL }}
WHISPARR_API_KEY={{ op://Development/Logarr-Dev/WHISPARR_API_KEY }}

# =============================================================================
# SECURITY & AUTHENTICATION
# =============================================================================
# Admin Password Reset (emergency reset if you forget your password)
# Set to "true" and restart the container to reset the admin account.
# This allows you to re-run the setup flow at /setup.
# All other data (logs, issues, settings) is preserved.
# IMPORTANT: Remove this env var after resetting to prevent repeated resets!
# ADMIN_PASSWORD_RESET=true

# =============================================================================
# LOG FILE PATHS (optional - for file-based log ingestion)
# These are HOST paths used in development (native) mode.
Expand Down
2 changes: 1 addition & 1 deletion apps/backend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@logarr/backend",
"version": "0.5.5",
"version": "0.6.0",
"private": true,
"description": "Logarr NestJS backend API",
"scripts": {
Expand Down
3 changes: 3 additions & 0 deletions apps/backend/src/config/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ const envSchema = z.object({
REDIS_URL: z.string(),
CORS_ORIGIN: z.string().min(1),
LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).optional(),
// Optional: If set to "true", resets admin account on startup (allows re-running /setup)
// After reset, this env var is ignored until removed and re-added
ADMIN_PASSWORD_RESET: z.enum(['true', 'false']).optional(),
});

export type Env = z.infer<typeof envSchema>;
Expand Down
20 changes: 20 additions & 0 deletions apps/backend/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Logger } from 'nestjs-pino';
import { AppModule } from './app.module';
import { validateEnv, type Env } from './config/env';
import { AuthService } from './modules/auth/auth.service';
import { SettingsService } from './modules/settings/settings.service';

// Cache validated env for use in bootstrap
let cachedEnv: Env;
Expand Down Expand Up @@ -54,6 +55,25 @@ async function bootstrap() {

const logger = app.get(Logger);
const authService = app.get(AuthService);
const settingsService = app.get(SettingsService);

// Check if admin password reset is requested via env var
if (env.ADMIN_PASSWORD_RESET === 'true') {
await settingsService.resetAdminAccount();
console.log('');
console.log('╔════════════════════════════════════════════════════════════╗');
console.log('║ ADMIN ACCOUNT RESET ║');
console.log('╠════════════════════════════════════════════════════════════╣');
console.log('║ Admin account has been reset. ║');
console.log('║ All other data (logs, issues, settings) is preserved. ║');
console.log('║ ║');
console.log('║ Navigate to /setup to create a new admin account. ║');
console.log('║ ║');
console.log('║ Remove ADMIN_PASSWORD_RESET=true from your env file ║');
console.log('║ to prevent this message on next restart. ║');
console.log('╚════════════════════════════════════════════════════════════╝');
console.log('');
}

// Check if setup is required and log the setup token
const setupStatus = await authService.getSetupStatus();
Expand Down
27 changes: 27 additions & 0 deletions apps/backend/src/modules/settings/settings.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -515,4 +515,31 @@ export class SettingsService {
async getAdminCreatedAt(): Promise<string | null> {
return this.getSetting<string | null>(SETTINGS_KEYS.SECURITY_ADMIN_CREATED_AT, null);
}

/**
* Reset admin account to allow re-setup via /setup endpoint.
* Clears the setup_completed flag and admin credentials while preserving all other data.
*/
async resetAdminAccount(): Promise<void> {
await this.db
.delete(schema.appSettings)
.where(
eq(
schema.appSettings.key,
SETTINGS_KEYS.SECURITY_SETUP_COMPLETED
)
);
// Also clear admin credentials so setup can create a fresh account
await this.db
.delete(schema.appSettings)
.where(
eq(schema.appSettings.key, SETTINGS_KEYS.SECURITY_ADMIN_USERNAME)
);
await this.db
.delete(schema.appSettings)
.where(
eq(schema.appSettings.key, SETTINGS_KEYS.SECURITY_ADMIN_PASSWORD_HASH)
);
this.logger.warn('Admin account reset - user must complete setup again');
}
}
2 changes: 1 addition & 1 deletion apps/frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "frontend",
"version": "0.5.5",
"version": "0.6.0",
"private": true,
"scripts": {
"dev": "next dev --turbopack",
Expand Down
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ services:
WHISPARR_LOGS_PATH_1: ${WHISPARR_LOGS_PATH_1:-}
WHISPARR_LOGS_PATH_2: ${WHISPARR_LOGS_PATH_2:-}
WHISPARR_LOGS_PATH_3: ${WHISPARR_LOGS_PATH_3:-}
# Admin password reset - set to 'true' to reset admin account on startup
ADMIN_PASSWORD_RESET: ${ADMIN_PASSWORD_RESET:-}
volumes:
# Media server log mounts (optional - set paths in .env for file-based log ingestion)
# In the Sources UI, configure paths as: /plex-logs, /jellyfin-logs, /emby-logs, etc.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "logarr",
"version": "0.5.5",
"version": "0.6.0",
"private": true,
"description": "Unified logging for your media stack",
"scripts": {
Expand Down
Loading