Compare commits
No commits in common. "6f4958ba89b9d7b3160272a6c037aa6d4ee89352" and "63ad19eb128d1b5f5aee8c48503c8bf5e21e9f0f" have entirely different histories.
6f4958ba89
...
63ad19eb12
2 changed files with 2 additions and 67 deletions
15
app.py
15
app.py
|
|
@ -22,7 +22,7 @@ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||||
# Docker tab caches stale container IDs, so the footer is the reliable way
|
# Docker tab caches stale container IDs, so the footer is the reliable way
|
||||||
# to confirm a `docker compose up -d --build` actually took effect.
|
# to confirm a `docker compose up -d --build` actually took effect.
|
||||||
# Both are env-overridable if the deploy pipeline ever injects them.
|
# Both are env-overridable if the deploy pipeline ever injects them.
|
||||||
APP_VERSION = os.environ.get("APP_VERSION", "1.6.1")
|
APP_VERSION = os.environ.get("APP_VERSION", "1.6.0")
|
||||||
APP_VERSION_DATE = os.environ.get("APP_VERSION_DATE", "2026-08-27")
|
APP_VERSION_DATE = os.environ.get("APP_VERSION_DATE", "2026-08-27")
|
||||||
|
|
||||||
# Must point at a path that survives `docker compose up --build` — the
|
# Must point at a path that survives `docker compose up --build` — the
|
||||||
|
|
@ -45,19 +45,6 @@ def save_settings(data):
|
||||||
with open(SETTINGS_FILE, "w") as f:
|
with open(SETTINGS_FILE, "w") as f:
|
||||||
json.dump(existing, f, indent=2)
|
json.dump(existing, f, indent=2)
|
||||||
|
|
||||||
def delete_setting(key):
|
|
||||||
"""Remove a key outright. save_settings() only ever merges, so it can't
|
|
||||||
take something away — used to retire the plaintext shared password once
|
|
||||||
real accounts exist. Returns True if the key was there."""
|
|
||||||
settings = load_settings()
|
|
||||||
if key not in settings:
|
|
||||||
return False
|
|
||||||
del settings[key]
|
|
||||||
os.makedirs(os.path.dirname(SETTINGS_FILE) or ".", exist_ok=True)
|
|
||||||
with open(SETTINGS_FILE, "w") as f:
|
|
||||||
json.dump(settings, f, indent=2)
|
|
||||||
return True
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.secret_key = os.environ.get("SECRET_KEY") or secrets.token_hex(32)
|
app.secret_key = os.environ.get("SECRET_KEY") or secrets.token_hex(32)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,17 +12,10 @@ Run it inside the container, where Werkzeug and the real settings.json are:
|
||||||
docker exec -it arr-summary python3 manage_users.py add <username>
|
docker exec -it arr-summary python3 manage_users.py add <username>
|
||||||
docker exec -it arr-summary python3 manage_users.py passwd <username>
|
docker exec -it arr-summary python3 manage_users.py passwd <username>
|
||||||
docker exec -it arr-summary python3 manage_users.py remove <username>
|
docker exec -it arr-summary python3 manage_users.py remove <username>
|
||||||
docker exec -it arr-summary python3 manage_users.py retire-shared-password
|
|
||||||
|
|
||||||
The first `add` switches the dashboard from its single shared password to
|
The first `add` switches the dashboard from its single shared password to
|
||||||
per-user logins. Until then the old LOGIN_PASSWORD keeps working, so you
|
per-user logins. Until then the old LOGIN_PASSWORD keeps working, so you
|
||||||
can't lock yourself out by deploying this.
|
can't lock yourself out by deploying this.
|
||||||
|
|
||||||
Once accounts exist and you've confirmed they sign in,
|
|
||||||
`retire-shared-password` deletes the old plaintext login_password from
|
|
||||||
settings.json. It refuses to run while no accounts exist, because with
|
|
||||||
nothing configured at all the dashboard treats that as dev mode and lets
|
|
||||||
anyone in without a password.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
@ -31,10 +24,7 @@ import getpass
|
||||||
from app import (
|
from app import (
|
||||||
SETTINGS_FILE,
|
SETTINGS_FILE,
|
||||||
PASSWORD_HASH_METHOD,
|
PASSWORD_HASH_METHOD,
|
||||||
LOGIN_PASSWORD,
|
|
||||||
save_settings,
|
save_settings,
|
||||||
delete_setting,
|
|
||||||
load_settings,
|
|
||||||
load_users,
|
load_users,
|
||||||
generate_password_hash,
|
generate_password_hash,
|
||||||
)
|
)
|
||||||
|
|
@ -132,49 +122,7 @@ def cmd_remove(args):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def cmd_retire_shared_password(_args):
|
COMMANDS = {"list": cmd_list, "add": cmd_add, "passwd": cmd_passwd, "remove": cmd_remove}
|
||||||
"""Delete the plaintext login_password from settings.json.
|
|
||||||
|
|
||||||
Guarded, because removing it while nothing else is configured makes
|
|
||||||
get_active_password() empty — and the login route reads "no credentials
|
|
||||||
at all" as dev mode and lets anyone straight in.
|
|
||||||
"""
|
|
||||||
users = load_users()
|
|
||||||
if not users:
|
|
||||||
print("Refusing: no accounts exist yet, so the shared password is still",
|
|
||||||
file=sys.stderr)
|
|
||||||
print("the only way in. Run `add <username>` first and check you can",
|
|
||||||
file=sys.stderr)
|
|
||||||
print("sign in with it, then run this again.", file=sys.stderr)
|
|
||||||
return 1
|
|
||||||
|
|
||||||
if "login_password" not in load_settings():
|
|
||||||
print("Nothing to do — settings.json has no login_password.")
|
|
||||||
if LOGIN_PASSWORD:
|
|
||||||
print()
|
|
||||||
print("Note: LOGIN_PASSWORD is still set in the environment. It's")
|
|
||||||
print("ignored while accounts exist, but clear it from .env too if")
|
|
||||||
print("you want the old shared password gone entirely.")
|
|
||||||
return 0
|
|
||||||
|
|
||||||
delete_setting("login_password")
|
|
||||||
print(f"Removed the plaintext login_password from {SETTINGS_FILE}.")
|
|
||||||
print(f"{len(users)} account(s) remain in use: {', '.join(sorted(users))}")
|
|
||||||
if LOGIN_PASSWORD:
|
|
||||||
print()
|
|
||||||
print("LOGIN_PASSWORD is still set in the environment. It's ignored while")
|
|
||||||
print("accounts exist, but clear it from .env and restart to be rid of it.")
|
|
||||||
print("Don't clear it before you've confirmed the accounts work.")
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
COMMANDS = {
|
|
||||||
"list": cmd_list,
|
|
||||||
"add": cmd_add,
|
|
||||||
"passwd": cmd_passwd,
|
|
||||||
"remove": cmd_remove,
|
|
||||||
"retire-shared-password": cmd_retire_shared_password,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def main(argv):
|
def main(argv):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue