fix(snappymail): set admin password via Python+PHP directly in application.ini
djmaze/snappymail does not reliably apply SNAPPYMAIL_ADMIN_PASSWORD. Instead: read current hash from application.ini, verify it against vault password using password_verify() in container PHP, update only if wrong. Idempotent — no restart if password is already correct. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
1b3f3e62b9
commit
e09e2fe04a
1 changed files with 61 additions and 4 deletions
|
|
@ -147,11 +147,68 @@
|
|||
state: present
|
||||
pull: missing
|
||||
|
||||
# ── SnappyMail: force restart so entrypoint applies SNAPPYMAIL_ADMIN_PASSWORD ──
|
||||
# The env var is processed by the container entrypoint on every start.
|
||||
# Explicit restart ensures the password is always written to config correctly.
|
||||
- name: Restart SnappyMail to apply admin password from env
|
||||
# ── SnappyMail admin password — write bcrypt hash directly to application.ini ──
|
||||
# djmaze/snappymail does not reliably apply SNAPPYMAIL_ADMIN_PASSWORD env var;
|
||||
# instead we verify and update the hash in the config file on every deploy.
|
||||
- name: Ensure SnappyMail admin password is set correctly
|
||||
ansible.builtin.shell: |
|
||||
python3 << 'PYEOF'
|
||||
import subprocess, re, sys
|
||||
|
||||
config_path = "{{ tools_root }}/snappymail/data/_data_/_default_/configs/application.ini"
|
||||
password = "{{ snappymail_admin_password }}"
|
||||
|
||||
try:
|
||||
with open(config_path) as f:
|
||||
content = f.read()
|
||||
except FileNotFoundError:
|
||||
print("CONFIG_NOT_FOUND")
|
||||
sys.exit(1)
|
||||
|
||||
# Extract current hash (bcrypt hashes start with $2y$)
|
||||
m = re.search(r'^admin_password\s*=\s*"?(\$2y\$[^"\n]+)', content, re.M)
|
||||
current_hash = m.group(1).strip() if m else ""
|
||||
|
||||
if current_hash:
|
||||
r = subprocess.run(
|
||||
["docker", "exec", "snappymail", "php", "-r",
|
||||
f"echo password_verify('{password}', '{current_hash}') ? 'yes' : 'no';"],
|
||||
capture_output=True, text=True
|
||||
)
|
||||
if r.stdout.strip() == "yes":
|
||||
print("ALREADY_SET")
|
||||
sys.exit(0)
|
||||
|
||||
# Generate a new bcrypt hash using PHP inside the container
|
||||
r = subprocess.run(
|
||||
["docker", "exec", "snappymail", "php", "-r",
|
||||
f"echo password_hash('{password}', PASSWORD_BCRYPT);"],
|
||||
capture_output=True, text=True
|
||||
)
|
||||
new_hash = r.stdout.strip()
|
||||
if not new_hash.startswith("$2y$"):
|
||||
print(f"HASH_ERROR: {r.stderr}")
|
||||
sys.exit(1)
|
||||
|
||||
new_content = re.sub(
|
||||
r'^admin_password\s*=.*$',
|
||||
f'admin_password = "{new_hash}"',
|
||||
content, flags=re.M
|
||||
)
|
||||
with open(config_path, "w") as f:
|
||||
f.write(new_content)
|
||||
print("UPDATED")
|
||||
PYEOF
|
||||
register: snappymail_pw_result
|
||||
changed_when: "'UPDATED' in snappymail_pw_result.stdout"
|
||||
failed_when: >
|
||||
snappymail_pw_result.rc != 0 or
|
||||
'CONFIG_NOT_FOUND' in snappymail_pw_result.stdout or
|
||||
'HASH_ERROR' in snappymail_pw_result.stdout
|
||||
|
||||
- name: Restart SnappyMail after password update
|
||||
ansible.builtin.command: docker restart snappymail
|
||||
when: snappymail_pw_result.changed
|
||||
changed_when: true
|
||||
|
||||
# ── Mail accounts (idempotent: check host-side config file) ──────────────────
|
||||
|
|
|
|||
Loading…
Reference in a new issue