diff --git a/group_vars/matrix_servers b/group_vars/matrix_servers index 503a45be..b08cdce5 100755 --- a/group_vars/matrix_servers +++ b/group_vars/matrix_servers @@ -123,6 +123,36 @@ matrix_mautrix_facebook_homeserver_token: "{{ matrix_synapse_macaroon_secret_key ###################################################################### +###################################################################### +# +# matrix-bridge-mautrix-hangouts +# +###################################################################### + +# We don't enable bridges by default. +matrix_mautrix_hangouts_enabled: false + +matrix_mautrix_hangouts_systemd_required_services_list: | + {{ + ['docker.service'] + + + (['matrix-synapse.service'] if matrix_synapse_enabled else []) + }} + +matrix_mautrix_hangouts_appservice_token: "{{ matrix_synapse_macaroon_secret_key | password_hash('sha512', 'ho.as.token') | to_uuid }}" + +matrix_mautrix_hangouts_homeserver_token: "{{ matrix_synapse_macaroon_secret_key | password_hash('sha512', 'ho.hs.token') | to_uuid }}" + +###################################################################### +# +# /matrix-bridge-mautrix-hangouts_ +# +###################################################################### + + + + + ###################################################################### # # matrix-bridge-mautrix-telegram diff --git a/roles/matrix-bridge-mautrix-hangouts/defaults/main.yml b/roles/matrix-bridge-mautrix-hangouts/defaults/main.yml new file mode 100644 index 00000000..9687a9ae --- /dev/null +++ b/roles/matrix-bridge-mautrix-hangouts/defaults/main.yml @@ -0,0 +1,179 @@ +# mautrix-hangouts is a Matrix <-> Hangouts bridge +# See: https://github.com/tulir/mautrix-hangouts + +matrix_mautrix_hangouts_enabled: true + +matrix_mautrix_hangouts_docker_image: "dock.mau.dev/tulir/mautrix-hangouts:latest" +matrix_mautrix_hangouts_docker_image_force_pull: "{{ matrix_mautrix_hangouts_docker_image.endswith(':latest') }}" + +matrix_mautrix_hangouts_base_path: "{{ matrix_base_data_path }}/mautrix-hangouts" +matrix_mautrix_hangouts_config_path: "{{ matrix_mautrix_hangouts_base_path }}/config" +matrix_mautrix_hangouts_data_path: "{{ matrix_mautrix_hangouts_base_path }}/data" + +matrix_mautrix_hangouts_homeserver_address: 'http://matrix-synapse:8008' +matrix_mautrix_hangouts_homeserver_domain: '{{ matrix_domain }}' +matrix_mautrix_hangouts_appservice_address: 'http://matrix-mautrix-hangouts:8080' + +# A list of extra arguments to pass to the container +matrix_mautrix_hangouts_container_extra_arguments: [] + +# List of systemd services that matrix-mautrix-hangouts.service depends on. +matrix_mautrix_hangouts_systemd_required_services_list: ['docker.service'] + +# List of systemd services that matrix-mautrix-hangouts.service wants +matrix_mautrix_hangouts_systemd_wanted_services_list: [] + +matrix_mautrix_hangouts_appservice_token: '' +matrix_mautrix_hangouts_homeserver_token: '' + +# Default mxisd configuration template which covers the generic use case. +# You can customize it by controlling the various variables inside it. +# +# For a more advanced customization, you can extend the default (see `matrix_mautrix_hangouts_configuration_extension_yaml`) +# or completely replace this variable with your own template. +matrix_mautrix_hangouts_configuration_yaml: | + #jinja2: lstrip_blocks: "True" + # Homeserver details + homeserver: + # The address that this appservice can use to connect to the homeserver. + address: {{ matrix_mautrix_hangouts_homeserver_address }} + # The domain of the homeserver (for MXIDs, etc). + domain: {{ matrix_mautrix_hangouts_homeserver_domain }} + # Whether or not to verify the SSL certificate of the homeserver. + # Only applies if address starts with https:// + verify_ssl: true + + # Application service host/registration related details + # Changing these values requires regeneration of the registration. + appservice: + # The address that the homeserver can use to connect to this appservice. + address: {{ matrix_mautrix_hangouts_appservice_address }} + + # The hostname and port where this appservice should listen. + hostname: 0.0.0.0 + port: 8080 + # The maximum body size of appservice API requests (from the homeserver) in mebibytes + # Usually 1 is enough, but on high-traffic bridges you might need to increase this to avoid 413s + max_body_size: 1 + + # The full URI to the database. SQLite and Postgres are fully supported. + # Other DBMSes supported by SQLAlchemy may or may not work. + # Format examples: + # SQLite: sqlite:///filename.db + # Postgres: postgres://username:password@hostname/dbname + database: sqlite:////data/mautrix-hangouts.db + + # The unique ID of this appservice. + id: hangouts + # Username of the appservice bot. + bot_username: hangoutsbot + # Display name and avatar for bot. Set to "remove" to remove display name/avatar, leave empty + # to leave display name/avatar as-is. + bot_displayname: Hangouts bridge bot + bot_avatar: mxc://maunium.net/ddtNPZSKMNqaUzqrHuWvUADv + + # Authentication tokens for AS <-> HS communication. + as_token: "{{ matrix_mautrix_hangouts_appservice_token }}" + hs_token: "{{ matrix_mautrix_hangouts_homeserver_token }}" + + # Bridge config + bridge: + # Localpart template of MXIDs for Hangouts users. + # {userid} is replaced with the user ID of the Hangouts user. + username_template: "hangouts_{userid}" + # Displayname template for Hangouts users. + # {displayname} is replaced with the display name of the Hangouts user + # as defined below in displayname_preference. + # Keys available for displayname_preference are also available here. + displayname_template: '{displayname} (HO)' + # Available keys: + # "name" (full name) + # "first_name" + # "last_name" + # "nickname" + # "own_nickname" (user-specific!) + displayname_preference: + - name + + # The prefix for commands. Only required in non-management rooms. + command_prefix: "!HO" + + # Number of chats to sync (and create portals for) on startup/login. + # Maximum 20, set 0 to disable automatic syncing. + initial_chat_sync: 10 + # Whether or not the Hangouts users of logged in Matrix users should be + # invited to private chats when the user sends a message from another client. + invite_own_puppet_to_pm: false + # Whether or not to use /sync to get presence, read receipts and typing notifications when using + # your own Matrix account as the Matrix puppet for your Hangouts account. + sync_with_custom_puppets: true + # Whether or not to bridge presence in both directions. Hangouts allows users not to broadcast + # presence, but then it won't send other users' presence to the client. + presence: true + + # Permissions for using the bridge. + # Permitted values: + # user - Use the bridge with puppeting. + # admin - Use and administrate the bridge. + # Permitted keys: + # * - All Matrix users + # domain - All users on that homeserver + # mxid - Specific user + permissions: + '{{ matrix_mautrix_hangouts_homeserver_domain }}': user + + # Python logging configuration. + # + # See section 16.7.2 of the Python documentation for more info: + # https://docs.python.org/3.6/library/logging.config.html#configuration-dictionary-schema + logging: + version: 1 + formatters: + colored: + (): mautrix_hangouts.util.ColorFormatter + format: "[%(asctime)s] [%(levelname)s@%(name)s] %(message)s" + normal: + format: "[%(asctime)s] [%(levelname)s@%(name)s] %(message)s" + handlers: + console: + class: logging.StreamHandler + formatter: colored + loggers: + mau: + level: DEBUG + hangouts: + level: DEBUG + aiohttp: + level: INFO + root: + level: DEBUG + handlers: [console] + +matrix_mautrix_hangouts_configuration_extension_yaml: | + # Your custom YAML configuration goes here. + # This configuration extends the default starting configuration (`matrix_mautrix_hangouts_configuration_yaml`). + # + # You can override individual variables from the default configuration, or introduce new ones. + # + # If you need something more special, you can take full control by + # completely redefining `matrix_mautrix_hangouts_configuration_yaml`. + +matrix_mautrix_hangouts_configuration_extension: "{{ matrix_mautrix_hangouts_configuration_extension_yaml|from_yaml if matrix_mautrix_hangouts_configuration_extension_yaml|from_yaml is mapping else {} }}" + +# Holds the final configuration (a combination of the default and its extension). +# You most likely don't need to touch this variable. Instead, see `matrix_mautrix_hangouts_configuration_yaml`. +matrix_mautrix_hangouts_configuration: "{{ matrix_mautrix_hangouts_configuration_yaml|from_yaml|combine(matrix_mautrix_hangouts_configuration_extension, recursive=True) }}" + +matrix_mautrix_hangouts_registration_yaml: | + id: hangouts + as_token: "{{ matrix_mautrix_hangouts_appservice_token }}" + hs_token: "{{ matrix_mautrix_hangouts_homeserver_token }}" + namespaces: + users: + - exclusive: true + regex: '^@hangouts_.+:{{ matrix_mautrix_hangouts_homeserver_domain|regex_escape }}$' + url: {{ matrix_mautrix_hangouts_appservice_address }} + sender_localpart: hangoutsbot + rate_limited: false + +matrix_mautrix_hangouts_registration: "{{ matrix_mautrix_hangouts_registration_yaml|from_yaml }}" diff --git a/roles/matrix-bridge-mautrix-hangouts/tasks/init.yml b/roles/matrix-bridge-mautrix-hangouts/tasks/init.yml new file mode 100644 index 00000000..9881398d --- /dev/null +++ b/roles/matrix-bridge-mautrix-hangouts/tasks/init.yml @@ -0,0 +1,16 @@ +- set_fact: + matrix_systemd_services_list: "{{ matrix_systemd_services_list + ['matrix-mautrix-hangouts'] }}" + when: matrix_mautrix_hangouts_enabled|bool + +# If the matrix-synapse role is not used, these variables may not exist. +- set_fact: + matrix_synapse_container_extra_arguments: > + {{ matrix_synapse_container_extra_arguments|default([]) }} + + + {{ ["--mount type=bind,src={{ matrix_mautrix_hangouts_config_path }}/registration.yaml,dst=/matrix-mautrix-hangouts-registration.yaml,ro"] }} + + matrix_synapse_app_service_config_files: > + {{ matrix_synapse_app_service_config_files|default([]) }} + + + {{ ["/matrix-mautrix-hangouts-registration.yaml"] }} + when: matrix_mautrix_hangouts_enabled|bool diff --git a/roles/matrix-bridge-mautrix-hangouts/tasks/main.yml b/roles/matrix-bridge-mautrix-hangouts/tasks/main.yml new file mode 100644 index 00000000..0df0d0e3 --- /dev/null +++ b/roles/matrix-bridge-mautrix-hangouts/tasks/main.yml @@ -0,0 +1,21 @@ +- import_tasks: "{{ role_path }}/tasks/init.yml" + tags: + - always + +- import_tasks: "{{ role_path }}/tasks/validate_config.yml" + when: "run_setup|bool and matrix_mautrix_hangouts_enabled|bool" + tags: + - setup-all + - setup-mautrix-hangouts + +- import_tasks: "{{ role_path }}/tasks/setup_install.yml" + when: "run_setup|bool and matrix_mautrix_hangouts_enabled|bool" + tags: + - setup-all + - setup-mautrix-hangouts + +- import_tasks: "{{ role_path }}/tasks/setup_uninstall.yml" + when: "run_setup|bool and not matrix_mautrix_hangouts_enabled|bool" + tags: + - setup-all + - setup-mautrix-hangouts diff --git a/roles/matrix-bridge-mautrix-hangouts/tasks/setup_install.yml b/roles/matrix-bridge-mautrix-hangouts/tasks/setup_install.yml new file mode 100644 index 00000000..7f325165 --- /dev/null +++ b/roles/matrix-bridge-mautrix-hangouts/tasks/setup_install.yml @@ -0,0 +1,73 @@ +--- + +# If the matrix-synapse role is not used, `matrix_synapse_role_executed` won't exist. +# We don't want to fail in such cases. +- name: Fail if matrix-synapse role already executed + fail: + msg: >- + The matrix-bridge-mautrix-hangouts role needs to execute before the matrix-synapse role. + when: "matrix_synapse_role_executed|default(False)" + +- name: Ensure Mautrix Hangouts image is pulled + docker_image: + name: "{{ matrix_mautrix_hangouts_docker_image }}" + source: "{{ 'pull' if ansible_version.major > 2 or ansible_version.minor > 7 else omit }}" + force_source: "{{ matrix_mautrix_hangouts_docker_image_force_pull if ansible_version.major > 2 or ansible_version.minor >= 8 else omit }}" + force: "{{ omit if ansible_version.major > 2 or ansible_version.minor >= 8 else matrix_mautrix_hangouts_docker_image_force_pull }}" + +- name: Ensure Mautrix Hangouts paths exist + file: + path: "{{ item }}" + state: directory + mode: 0750 + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_username }}" + with_items: + - "{{ matrix_mautrix_hangouts_base_path }}" + - "{{ matrix_mautrix_hangouts_config_path }}" + - "{{ matrix_mautrix_hangouts_data_path }}" + +- name: Check if an old database file already exists + stat: + path: "{{ matrix_mautrix_hangouts_base_path }}/mautrix-hangouts.db" + register: matrix_mautrix_hangouts_stat_database + +- name: (Data relocation) Ensure matrix-mautrix-hangouts.service is stopped + service: + name: matrix-mautrix-hangouts + state: stopped + daemon_reload: yes + failed_when: false + when: "matrix_mautrix_hangouts_stat_database.stat.exists" + +- name: (Data relocation) Move mautrix-hangouts database file to ./data directory + command: "mv {{ matrix_mautrix_hangouts_base_path }}/mautrix-hangouts.db {{ matrix_mautrix_hangouts_data_path }}/mautrix-hangouts.db" + when: "matrix_mautrix_hangouts_stat_database.stat.exists" + +- name: Ensure mautrix-hangouts config.yaml installed + copy: + content: "{{ matrix_mautrix_hangouts_configuration|to_nice_yaml }}" + dest: "{{ matrix_mautrix_hangouts_config_path }}/config.yaml" + mode: 0644 + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_username }}" + +- name: Ensure mautrix-hangouts registration.yaml installed + copy: + content: "{{ matrix_mautrix_hangouts_registration|to_nice_yaml }}" + dest: "{{ matrix_mautrix_hangouts_config_path }}/registration.yaml" + mode: 0644 + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_username }}" + +- name: Ensure matrix-mautrix-hangouts.service installed + template: + src: "{{ role_path }}/templates/systemd/matrix-mautrix-hangouts.service.j2" + dest: "/etc/systemd/system/matrix-mautrix-hangouts.service" + mode: 0644 + register: matrix_mautrix_hangouts_systemd_service_result + +- name: Ensure systemd reloaded after matrix-mautrix-hangouts.service installation + service: + daemon_reload: yes + when: "matrix_mautrix_hangouts_systemd_service_result.changed" diff --git a/roles/matrix-bridge-mautrix-hangouts/tasks/setup_uninstall.yml b/roles/matrix-bridge-mautrix-hangouts/tasks/setup_uninstall.yml new file mode 100644 index 00000000..ef33e238 --- /dev/null +++ b/roles/matrix-bridge-mautrix-hangouts/tasks/setup_uninstall.yml @@ -0,0 +1,24 @@ +--- + +- name: Check existence of matrix-mautrix-hangouts service + stat: + path: "/etc/systemd/system/matrix-mautrix-hangouts.service" + register: matrix_mautrix_hangouts_service_stat + +- name: Ensure matrix-mautrix-hangouts is stopped + service: + name: matrix-mautrix-hangouts + state: stopped + daemon_reload: yes + when: "matrix_mautrix_hangouts_service_stat.stat.exists" + +- name: Ensure matrix-mautrix-hangouts.service doesn't exist + file: + path: "/etc/systemd/system/matrix-mautrix-hangouts.service" + state: absent + when: "matrix_mautrix_hangouts_service_stat.stat.exists" + +- name: Ensure systemd reloaded after matrix-mautrix-hangouts.service removal + service: + daemon_reload: yes + when: "matrix_mautrix_hangouts_service_stat.stat.exists" diff --git a/roles/matrix-bridge-mautrix-hangouts/tasks/validate_config.yml b/roles/matrix-bridge-mautrix-hangouts/tasks/validate_config.yml new file mode 100644 index 00000000..312cfcc8 --- /dev/null +++ b/roles/matrix-bridge-mautrix-hangouts/tasks/validate_config.yml @@ -0,0 +1,10 @@ +--- + +- name: Fail if required settings not defined + fail: + msg: >- + You need to define a required configuration setting (`{{ item }}`). + when: "vars[item] == ''" + with_items: + - "matrix_mautrix_hangouts_appservice_token" + - "matrix_mautrix_hangouts_homeserver_token" diff --git a/roles/matrix-bridge-mautrix-hangouts/templates/systemd/matrix-mautrix-hangouts.service.j2 b/roles/matrix-bridge-mautrix-hangouts/templates/systemd/matrix-mautrix-hangouts.service.j2 new file mode 100644 index 00000000..e241db3d --- /dev/null +++ b/roles/matrix-bridge-mautrix-hangouts/templates/systemd/matrix-mautrix-hangouts.service.j2 @@ -0,0 +1,48 @@ +#jinja2: lstrip_blocks: "True" +[Unit] +Description=Matrix Mautrix Hangouts server +{% for service in matrix_mautrix_hangouts_systemd_required_services_list %} +Requires={{ service }} +After={{ service }} +{% endfor %} +{% for service in matrix_mautrix_hangouts_systemd_wanted_services_list %} +Wants={{ service }} +{% endfor %} + +[Service] +Type=simple +ExecStartPre=-/usr/bin/docker kill matrix-mautrix-hangouts +ExecStartPre=-/usr/bin/docker rm matrix-mautrix-hangouts +ExecStartPre=/usr/bin/docker run --rm --name matrix-mautrix-hangouts-db \ + --log-driver=none \ + --user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ + --cap-drop=ALL \ + -v {{ matrix_mautrix_hangouts_config_path }}:/config:z \ + -v {{ matrix_mautrix_hangouts_data_path }}:/data:z \ + {{ matrix_mautrix_hangouts_docker_image }} \ + alembic -x config=/config/config.yaml upgrade head + +# Intentional delay, so that the homeserver (we likely depend on) can manage to start. +ExecStartPre=/bin/sleep 5 + +ExecStart=/usr/bin/docker run --rm --name matrix-mautrix-hangouts \ + --log-driver=none \ + --user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ + --cap-drop=ALL \ + --network={{ matrix_docker_network }} \ + -v {{ matrix_mautrix_hangouts_config_path }}:/config:z \ + -v {{ matrix_mautrix_hangouts_data_path }}:/data:z \ + {% for arg in matrix_mautrix_hangouts_container_extra_arguments %} + {{ arg }} \ + {% endfor %} + {{ matrix_mautrix_hangouts_docker_image }} \ + python3 -m mautrix_hangouts -c /config/config.yaml + +ExecStop=-/usr/bin/docker kill matrix-mautrix-hangouts +ExecStop=-/usr/bin/docker rm matrix-mautrix-hangouts +Restart=always +RestartSec=30 +SyslogIdentifier=matrix-mautrix-hangouts + +[Install] +WantedBy=multi-user.target diff --git a/setup.yml b/setup.yml index 341840a2..5a8148d7 100755 --- a/setup.yml +++ b/setup.yml @@ -11,6 +11,7 @@ - matrix-bridge-appservice-discord - matrix-bridge-appservice-irc - matrix-bridge-mautrix-facebook + - matrix-bridge-mautrix-hangouts - matrix-bridge-mautrix-telegram - matrix-bridge-mautrix-whatsapp - matrix-synapse