Files
platform/gateway/database.py
Yusuf Suleman 79d2c3b4b6 fix: remove all default credentials (#2)
- Gateway: admin user seeded from ADMIN_USERNAME/ADMIN_PASSWORD env vars
  (no more hardcoded admin/admin). Warns if not set.
- Trips: USERNAME/PASSWORD env vars no longer default to admin/admin.
  Warns if not set.
- Fitness: user seed requires USER{n}_USERNAME/PASSWORD env vars.
  No more "changeme" fallback. Skips seed if not set.
- /api/auth/register remains disabled (403)

Closes #2
2026-03-29 09:10:44 -05:00

142 lines
5.4 KiB
Python

"""
Platform Gateway — Database initialization and access.
"""
import sqlite3
import bcrypt
from config import (
DB_PATH, TRIPS_URL, FITNESS_URL, INVENTORY_URL,
MINIFLUX_URL, SHELFMARK_URL, SPOTIZERR_URL, BUDGET_URL,
)
def get_db():
conn = sqlite3.connect(str(DB_PATH))
conn.row_factory = sqlite3.Row
conn.execute("PRAGMA foreign_keys = ON")
conn.execute("PRAGMA journal_mode = WAL")
return conn
def init_db():
conn = get_db()
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
display_name TEXT NOT NULL DEFAULT '',
created_at TEXT DEFAULT CURRENT_TIMESTAMP
)''')
c.execute('''CREATE TABLE IF NOT EXISTS sessions (
token TEXT PRIMARY KEY,
user_id INTEGER NOT NULL,
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
expires_at TEXT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
)''')
c.execute('''CREATE TABLE IF NOT EXISTS service_connections (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
service TEXT NOT NULL,
auth_type TEXT NOT NULL DEFAULT 'bearer',
auth_token TEXT NOT NULL,
metadata TEXT DEFAULT '{}',
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
UNIQUE(user_id, service),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
)''')
c.execute('''CREATE TABLE IF NOT EXISTS apps (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
icon TEXT DEFAULT '',
route_prefix TEXT NOT NULL,
proxy_target TEXT NOT NULL,
sort_order INTEGER DEFAULT 0,
enabled INTEGER DEFAULT 1,
dashboard_widget TEXT DEFAULT NULL
)''')
c.execute('''CREATE TABLE IF NOT EXISTS pinned_items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
service TEXT NOT NULL DEFAULT 'inventory',
item_id TEXT NOT NULL,
item_name TEXT NOT NULL DEFAULT '',
pinned_at TEXT DEFAULT CURRENT_TIMESTAMP,
UNIQUE(user_id, service, item_id),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
)''')
conn.commit()
# Seed default apps
existing = c.execute("SELECT COUNT(*) FROM apps").fetchone()[0]
if existing == 0:
c.execute("INSERT INTO apps VALUES ('trips', 'Trips', 'map', '/trips', ?, 1, 1, 'upcoming_trips')", (TRIPS_URL,))
c.execute("INSERT INTO apps VALUES ('fitness', 'Fitness', 'bar-chart', '/fitness', ?, 2, 1, 'daily_calories')", (FITNESS_URL,))
c.execute("INSERT INTO apps VALUES ('inventory', 'Inventory', 'package', '/inventory', ?, 3, 1, 'items_issues')", (INVENTORY_URL,))
conn.commit()
else:
# Ensure inventory app exists (migration for existing DBs)
inv = c.execute("SELECT id FROM apps WHERE id = 'inventory'").fetchone()
if not inv:
c.execute("INSERT INTO apps VALUES ('inventory', 'Inventory', 'package', '/inventory', ?, 3, 1, 'items_issues')", (INVENTORY_URL,))
conn.commit()
print("[Gateway] Added inventory app")
# Ensure reader app exists
rdr = c.execute("SELECT id FROM apps WHERE id = 'reader'").fetchone()
if not rdr:
c.execute("INSERT INTO apps VALUES ('reader', 'Reader', 'rss', '/reader', ?, 4, 1, 'unread_count')", (MINIFLUX_URL,))
conn.commit()
print("[Gateway] Added reader app")
# Ensure books app exists (now media)
books = c.execute("SELECT id FROM apps WHERE id = 'books'").fetchone()
if not books:
c.execute("INSERT INTO apps VALUES ('books', 'Media', 'book', '/media', ?, 5, 1, NULL)", (SHELFMARK_URL,))
conn.commit()
print("[Gateway] Added media app")
else:
c.execute("UPDATE apps SET name = 'Media', route_prefix = '/media' WHERE id = 'books'")
conn.commit()
# Ensure music (spotizerr) app exists
music = c.execute("SELECT id FROM apps WHERE id = 'music'").fetchone()
if not music:
c.execute("INSERT INTO apps VALUES ('music', 'Music', 'music', '/music', ?, 6, 1, NULL)", (SPOTIZERR_URL,))
conn.commit()
print("[Gateway] Added music app")
# Ensure budget app exists
budget = c.execute("SELECT id FROM apps WHERE id = 'budget'").fetchone()
if not budget:
c.execute("INSERT OR IGNORE INTO apps VALUES ('budget', 'Budget', 'dollar-sign', '/budget', ?, 7, 1, 'budget_summary')", (BUDGET_URL,))
conn.commit()
print("[Gateway] Added budget app")
# Seed admin user from env vars if no users exist
import os
user_count = c.execute("SELECT COUNT(*) FROM users").fetchone()[0]
if user_count == 0:
admin_user = os.environ.get("ADMIN_USERNAME")
admin_pass = os.environ.get("ADMIN_PASSWORD")
admin_name = os.environ.get("ADMIN_DISPLAY_NAME", "Admin")
if not admin_user or not admin_pass:
print("[Gateway] WARNING: No users exist and ADMIN_USERNAME/ADMIN_PASSWORD not set. Create a user manually.")
else:
pw_hash = bcrypt.hashpw(admin_pass.encode(), bcrypt.gensalt()).decode()
c.execute("INSERT INTO users (username, password_hash, display_name) VALUES (?, ?, ?)",
(admin_user, pw_hash, admin_name))
conn.commit()
print(f"[Gateway] Created admin user: {admin_user}")
conn.close()