---
# Param: stalwart_bots - up to STALWART_JMAP_MAX_METHOD_CALLS bot entries of stalwart_accounts; each method call addresses one bot through its accountId.
- name: "π List the app passwords of the bots"
include_tasks: "{{ role_path }}/tasks/jmap_call.yml"
vars:
stalwart_jmap_body: >-
{%- set calls = [] -%}
{%- for bot in stalwart_bots -%}
{%- set _ = calls.append(['x:AppPassword/get', {'accountId': bot.id, 'ids': none}, bot.address]) -%}
{%- endfor -%}
{{ {'using': ['urn:ietf:params:jmap:core', 'urn:stalwart:jmap'], 'methodCalls': calls} | to_json }}
- name: "π Decide which bots need a new app password"
ansible.builtin.set_fact:
stalwart_app_password_plan: >-
{%- set listed = {} -%}
{%- for method, result, call in stalwart_jmap.methodResponses -%}
{%- set _ = listed.update({call: result.list}) -%}
{%- endfor -%}
{%- set plan = [] -%}
{%- for bot in stalwart_bots -%}
{%- set owned = listed[bot.address] | selectattr('description', 'equalto', STALWART_BOT_APP_PASSWORD_DESCRIPTION)
| map(attribute='id') | list -%}
{%- set retired = listed[bot.address] | selectattr('description', 'equalto', STALWART_BOT_APP_PASSWORD_RETIRED_DESCRIPTION)
| map(attribute='id') | list -%}
{%- set renew = (owned | length != 1) or (bot.stored | length == 0) or (bot.stored == bot.secret) -%}
{%- set _ = plan.append({'key': bot.key, 'address': bot.address, 'id': bot.id, 'owned': owned,
'renew': renew, 'drop': retired + (owned if renew else [])}) -%}
{%- endfor -%}
{{ plan }}
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
- name: "π Replace the app passwords of the bots that need a new one"
when: stalwart_app_password_plan | selectattr('renew') | list | length > 0
block:
- name: "π Mint the new app passwords"
include_tasks: "{{ role_path }}/tasks/jmap_call.yml"
vars:
stalwart_jmap_body: >-
{%- set calls = [] -%}
{%- for bot in stalwart_app_password_plan if bot.renew -%}
{%- set _ = calls.append(['x:AppPassword/set', {'accountId': bot.id,
'create': {'p': {'description': STALWART_BOT_APP_PASSWORD_DESCRIPTION}}}, bot.address]) -%}
{%- endfor -%}
{{ {'using': ['urn:ietf:params:jmap:core', 'urn:stalwart:jmap'], 'methodCalls': calls} | to_json }}
- name: "π Read the minted app passwords"
ansible.builtin.set_fact:
stalwart_app_password_minted: >-
{%- set results = {} -%}
{%- for method, result, call in stalwart_jmap.methodResponses -%}
{%- set _ = results.update({call: result}) -%}
{%- endfor -%}
{%- set minted = [] -%}
{%- for bot in stalwart_app_password_plan if bot.renew -%}
{%- set _ = minted.append({'key': bot.key, 'address': bot.address,
'secret': results[bot.address].created.p.secret}) -%}
{%- endfor -%}
{{ minted }}
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
- name: "πΎ Persist the new app passwords"
ansible.builtin.include_role:
name: sys-token-store
tasks_from: write_many.yml
vars:
sys_token_store_entries: >-
{%- set entries = [] -%}
{%- for minted in stalwart_app_password_minted -%}
{%- set _ = entries.append({'user_key': minted.key, 'app': application_id, 'token': minted.secret}) -%}
{%- endfor -%}
{{ entries }}
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
- name: "π·οΈ Retire the app passwords the new ones replace"
include_tasks: "{{ role_path }}/tasks/jmap_call.yml"
vars:
stalwart_jmap_body: >-
{%- set calls = [] -%}
{%- for bot in stalwart_app_password_plan if bot.renew and bot.owned | length > 0 -%}
{%- set _ = calls.append(['x:AppPassword/set', {'accountId': bot.id,
'update': dict(bot.owned | zip([{'description': STALWART_BOT_APP_PASSWORD_RETIRED_DESCRIPTION}] * (bot.owned | length)))},
bot.address]) -%}
{%- endfor -%}
{{ {'using': ['urn:ietf:params:jmap:core', 'urn:stalwart:jmap'], 'methodCalls': calls} | to_json }}
when: stalwart_app_password_plan | selectattr('renew') | selectattr('owned') | list | length > 0
- name: "π₯ Defer dropping the retired app passwords"
when: stalwart_app_password_plan | selectattr('drop') | list | length > 0
block:
- name: "π₯ Record the retired app passwords per bot"
ansible.builtin.set_fact:
stalwart_app_password_stale: >-
{%- set stale = {} -%}
{%- for bot in stalwart_app_password_plan if bot.drop | length > 0 -%}
{%- set _ = stale.update({bot.address: {'account': bot.id, 'ids': bot.drop}}) -%}
{%- endfor -%}
{{ stalwart_app_password_stale | combine(stale) }}
- name: "π₯ Queue the drop for the service-loader post-load flush"
include_role:
name: sys-service-loader
tasks_from: list_or_shoot.yml
vars:
list_or_shoot_roles:
- web-app-stalwart