diff --git a/.claude/JOURNAL.md b/.claude/JOURNAL.md index 1ac9286..388d83d 100644 --- a/.claude/JOURNAL.md +++ b/.claude/JOURNAL.md @@ -147,3 +147,6 @@ This journal tracks substantive work on documents, diagrams, and documentation c 48. **Task - Settings dictionary YAML**: Externalized settings metadata to config/settings_dictionary.yml
**Result**: Created settings_dictionary.yml with categories as top-level keys (JupyterHub Core, Docker Spawner, GPU, Services, Idle Culler, Branding), each containing list of settings with name, description, default, and optional empty_display. Updated SettingsPageHandler to load from YAML instead of hardcoded values. Added pyyaml to Dockerfile pip install. Dockerfile now copies settings_dictionary.yml to /srv/jupyterhub/ + +49. **Task - xkcdpass password generation**: Replaced custom word list with xkcdpass library for auto-generated passwords
+ **Result**: Moved settings_dictionary.yml to services/jupyterhub/conf/ for proper image baking. Replaced hardcoded word list with xkcdpass library for memorable password generation. Added configurable env vars: JUPYTERHUB_AUTOGENERATED_PASSWORD_WORDS (default 4) and JUPYTERHUB_AUTOGENERATED_PASSWORD_DELIMITER (default "-"). Added xkcdpass to Dockerfile pip install. Fixed ENABLE_SIGNUP to JUPYTERHUB_SIGNUP_ENABLED in Dockerfile defaults diff --git a/config/jupyterhub_config.py b/config/jupyterhub_config.py index 4b05dc0..337421b 100644 --- a/config/jupyterhub_config.py +++ b/config/jupyterhub_config.py @@ -88,11 +88,11 @@ def sync_nativeauth_on_rename(target, value, oldvalue, initiator): @event.listens_for(orm.User, 'after_insert') def create_nativeauth_on_user_insert(mapper, connection, target): """Auto-create NativeAuthenticator UserInfo when a new User is created via admin panel. - Generates a memorable password and auto-approves the user.""" + Generates a memorable password using xkcdpass and auto-approves the user.""" username = target.name try: import bcrypt - import random + from xkcdpass import xkcd_password as xp from sqlalchemy import text # Check if UserInfo already exists (user might have signed up normally) @@ -104,11 +104,12 @@ def create_nativeauth_on_user_insert(mapper, connection, target): print(f"[NativeAuth Auto-Create] UserInfo already exists for: {username}") return - # Generate memorable 3-word password - words = ['apple', 'beach', 'cloud', 'dance', 'eagle', 'flame', 'grape', 'happy', - 'ivory', 'jolly', 'karma', 'lemon', 'mango', 'noble', 'ocean', 'piano', - 'quest', 'river', 'storm', 'tiger', 'urban', 'vivid', 'water', 'zebra'] - password = '-'.join(random.sample(words, 3)) + # Generate memorable password using xkcdpass (configurable via env) + num_words = int(os.environ.get('JUPYTERHUB_AUTOGENERATED_PASSWORD_WORDS', 4)) + delimiter = os.environ.get('JUPYTERHUB_AUTOGENERATED_PASSWORD_DELIMITER', '-') + wordfile = xp.locate_wordfile() + words = xp.generate_wordlist(wordfile=wordfile, min_length=4, max_length=6) + password = xp.generate_xkcdpassword(words, numwords=num_words, delimiter=delimiter) # Hash password with bcrypt hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()) diff --git a/services/jupyterhub/Dockerfile.jupyterhub b/services/jupyterhub/Dockerfile.jupyterhub index 1ae0d8b..c8f80de 100644 --- a/services/jupyterhub/Dockerfile.jupyterhub +++ b/services/jupyterhub/Dockerfile.jupyterhub @@ -42,9 +42,9 @@ COPY --chmod=600 services/jupyterhub/templates/certs /mnt/certs COPY --chmod=644 services/jupyterhub/templates_enhanced/*.html /srv/jupyterhub/templates/ COPY --chmod=644 services/jupyterhub/templates_enhanced/static/custom.css /tmp/custom.css COPY --chmod=644 config/jupyterhub_config.py /srv/jupyterhub/jupyterhub_config.py -COPY --chmod=644 config/settings_dictionary.yml /srv/jupyterhub/settings_dictionary.yml +COPY --chmod=644 services/jupyterhub/conf/settings_dictionary.yml /srv/jupyterhub/settings_dictionary.yml -## install dockerspawner, nativeauthenticator, idle-culler, pyyaml +## install dockerspawner, nativeauthenticator, idle-culler, pyyaml, xkcdpass RUN <<-EOF echo "installing core jupyterhub python packages" pip install -U --no-cache-dir \ @@ -52,7 +52,8 @@ RUN <<-EOF dockerspawner \ jupyterhub-nativeauthenticator \ jupyterhub-idle-culler \ - pyyaml + pyyaml \ + xkcdpass EOF ## copy custom.css to JupyterHub's static directory @@ -62,7 +63,9 @@ RUN <<-EOF EOF ## default environment variables -ENV ENABLE_SIGNUP=1 +ENV JUPYTERHUB_SIGNUP_ENABLED=1 +ENV JUPYTERHUB_AUTOGENERATED_PASSWORD_WORDS=4 +ENV JUPYTERHUB_AUTOGENERATED_PASSWORD_DELIMITER="-" ENV STELLARS_JUPYTERHUB_VERSION=${VERSION} ENV JUPYTERHUB_CUSTOM_LOGO_URI="" diff --git a/config/settings_dictionary.yml b/services/jupyterhub/conf/settings_dictionary.yml similarity index 88% rename from config/settings_dictionary.yml rename to services/jupyterhub/conf/settings_dictionary.yml index aed5b2f..b33b9e1 100644 --- a/config/settings_dictionary.yml +++ b/services/jupyterhub/conf/settings_dictionary.yml @@ -20,6 +20,14 @@ JupyterHub Core: description: SSL/TLS (0=disabled, 1=enabled) default: "1" + - name: JUPYTERHUB_AUTOGENERATED_PASSWORD_WORDS + description: Number of words in auto-generated passwords + default: "4" + + - name: JUPYTERHUB_AUTOGENERATED_PASSWORD_DELIMITER + description: Delimiter between words in auto-generated passwords + default: "-" + Docker Spawner: - name: JUPYTERHUB_NOTEBOOK_IMAGE description: User container image