From 70fd20cef52fdf5ef38afbce28f0bf34f5cf432f Mon Sep 17 00:00:00 2001 From: Slavi Pantaleev Date: Mon, 3 Jun 2024 21:06:19 +0300 Subject: [PATCH] Add support for WeChat bridging This is based on the PR (https://github.com/spantaleev/matrix-docker-ansible-deploy/pull/3241) by Tobias Diez (https://github.com/tobiasdiez). I've refactored some parts, made it more configurable, polished it up, and it's integrated into the playbook now. Both the WeChat bridge and WeChat agent appear to be working. The WeChat bridge joins rooms and responds as expected. That said, end-to-end testing (actually bridging to a WeChat account) has not been done yet. Fixes https://github.com/spantaleev/matrix-docker-ansible-deploy/issues/701 Fixes https://github.com/spantaleev/matrix-docker-ansible-deploy/issues/3092 This is sponsored https://etke.cc/ work related to https://gitlab.com/etke.cc/ansible/-/issues/2 Squashed commit of the following: commit fdd37f02472a0b83d61b4fac80650442f90e7629 Author: Slavi Pantaleev Date: Mon Jun 3 21:05:53 2024 +0300 Add documentation for WeChat bridge commit 8426fc8b95bb160ea7f9659bd45bc59cf1326614 Author: Slavi Pantaleev Date: Mon Jun 3 20:59:42 2024 +0300 Rename directory for matrix_wechat_agent_container_src_files_path commit da200df82bbc9153d307095dd90e4769c400ea1e Author: Slavi Pantaleev Date: Mon Jun 3 20:58:26 2024 +0300 Make WeChat listen_secret configurable and auto-configured via matrix_homeserver_generic_secret_key commit 4022cb1355828ac16af7d9228cb1066962bb35f5 Author: Slavi Pantaleev Date: Mon Jun 3 20:54:56 2024 +0300 Refactor install.yml for WeChat a bit (using blocks, etc.) commit d07a39b4c4f6b93d04204e13e384086d5a242d52 Author: Slavi Pantaleev Date: Mon Jun 3 20:52:35 2024 +0300 Rename WeChat Agent configuration file This makes it more clear that it belongs to the agent. Otherwise, `config.yaml` and `configure.yaml` make you wonder. commit ccca72f8d1e602f7c42f4bd552193afa153c9b9d Author: Slavi Pantaleev Date: Mon Jun 3 20:49:06 2024 +0300 Move WeChat agent configuration to a template commit a4047d94d8877b4095712dfc76ac3082a1edca28 Author: Slavi Pantaleev Date: Mon Jun 3 20:47:17 2024 +0300 Mount WeChat config as readonly and instruct bridge to not update it commit bc0e89f345bf14bbdbfd574bb60d93918c2ac053 Author: Slavi Pantaleev Date: Mon Jun 3 20:46:33 2024 +0300 Sync WeChat config with upstream Brings up-to-date with: https://github.com/duo/matrix-wechat/commits/0.2.4/example-config.yaml commit a46f5b9cbc8bf16042685a18c77d25a606bc8232 Author: Slavi Pantaleev Date: Mon Jun 3 19:48:17 2024 +0300 Rename some files commit 3877679040cffc4ca6cccfa21a7335f8f796f06e Author: Slavi Pantaleev Date: Mon Jun 3 19:47:10 2024 +0300 Update WeChat logging config This brings it up-to-date with what mautrix-go uses. Otherwise, on startup we see: > Migrating legacy log config .. and it gets migrated to what we've done here. commit e3e95ab234651867c7a975a08455549b31db4172 Author: Slavi Pantaleev Date: Mon Jun 3 19:43:37 2024 +0300 Make sure matrix-wechat-agent runs as 1000:1000 It needs to write stuff to `/home/user/.vnc`. `/home/user` is owned by `user:group` (`1000:1000`), so it cannot run any other way. Previously, if the `matrix` user was uid=1000 by chance, it would work, but that's pure luck. commit 4d5748ae9b84c81d6b48b0a41b790339d9ac4724 Author: Slavi Pantaleev Date: Mon Jun 3 18:57:09 2024 +0300 Pin wechat and wechat-agent versions commit 40d40009f19ebceed4126146cbb510a2c95af671 Author: Slavi Pantaleev Date: Mon Jun 3 18:53:58 2024 +0300 docker_image -> container_image for WeChat bridge commit cc33aff592541913070d13288d17b04ed6243176 Author: Slavi Pantaleev Date: Mon Jun 3 18:00:25 2024 +0300 docker_src -> container_src in WeChat bridge commit 42e6ae9a6483c8ca6d53b8052058d41d90d93797 Author: Slavi Pantaleev Date: Mon Jun 3 17:54:24 2024 +0300 matrix_go_wechat_ -> matrix_wechat_ The bridge is written in Go, but does not include Go anywhere in its name. As such, it's mostly useless to use `matrix_go_wechat` as the prefix. commit d6662a69d1916d215d5184320c36d2ef73afd3e9 Author: Tobias Diez Date: Mon Mar 25 10:55:16 2024 +0800 Add wechat bridge --- docs/configuring-playbook-bridge-wechat.md | 17 ++ docs/configuring-playbook.md | 2 + group_vars/matrix_servers | 65 +++++ .../matrix-bridge-wechat/defaults/main.yml | 152 ++++++++++ .../matrix-bridge-wechat/tasks/install.yml | 129 +++++++++ .../matrix-bridge-wechat/tasks/main.yml | 20 ++ .../matrix-bridge-wechat/tasks/uninstall.yml | 39 +++ .../tasks/validate_config.yml | 19 ++ .../templates/agent-config.yaml.j2 | 13 + .../templates/config.yaml.j2 | 265 ++++++++++++++++++ .../systemd/matrix-wechat-agent.service.j2 | 49 ++++ .../systemd/matrix-wechat.service.j2 | 47 ++++ setup.yml | 1 + 13 files changed, 818 insertions(+) create mode 100644 docs/configuring-playbook-bridge-wechat.md create mode 100644 roles/custom/matrix-bridge-wechat/defaults/main.yml create mode 100644 roles/custom/matrix-bridge-wechat/tasks/install.yml create mode 100644 roles/custom/matrix-bridge-wechat/tasks/main.yml create mode 100644 roles/custom/matrix-bridge-wechat/tasks/uninstall.yml create mode 100644 roles/custom/matrix-bridge-wechat/tasks/validate_config.yml create mode 100644 roles/custom/matrix-bridge-wechat/templates/agent-config.yaml.j2 create mode 100644 roles/custom/matrix-bridge-wechat/templates/config.yaml.j2 create mode 100644 roles/custom/matrix-bridge-wechat/templates/systemd/matrix-wechat-agent.service.j2 create mode 100644 roles/custom/matrix-bridge-wechat/templates/systemd/matrix-wechat.service.j2 diff --git a/docs/configuring-playbook-bridge-wechat.md b/docs/configuring-playbook-bridge-wechat.md new file mode 100644 index 000000000..fe4a3b6b2 --- /dev/null +++ b/docs/configuring-playbook-bridge-wechat.md @@ -0,0 +1,17 @@ +# Setting up the WeChat Bridge (optional) + +The playbook can install and configure the [matrix-wechat](https://github.com/duo/matrix-wechat) bridge for you (for bridging to the [WeChat](https://www.wechat.com/) network). + +See the project page to learn what it does and why it might be useful to you. + +To enable the bridge, use the following playbook configuration and re-run the playbook's [installation](./installing.md) procedure: + +```yaml +matrix_wechat_enabled: true +``` + +## Usage + +Once the bridge is installed, start a chat with `@wechatbot:YOUR_DOMAIN` (where `YOUR_DOMAIN` is your base domain, not the `matrix.` domain). + +Send `help` to the bot to see the available commands. diff --git a/docs/configuring-playbook.md b/docs/configuring-playbook.md index 86139e1a4..708367083 100644 --- a/docs/configuring-playbook.md +++ b/docs/configuring-playbook.md @@ -178,6 +178,8 @@ When you're done with all the configuration you'd like to do, continue with [Ins - [Setting up Heisenbridge bouncer-style IRC bridging](configuring-playbook-bridge-heisenbridge.md) (optional) +- [Setting up WeChat bridging](configuring-playbook-bridge-wechat.md) (optional) + ### Bots diff --git a/group_vars/matrix_servers b/group_vars/matrix_servers index 3030110e2..a93926366 100755 --- a/group_vars/matrix_servers +++ b/group_vars/matrix_servers @@ -93,6 +93,8 @@ matrix_homeserver_container_extra_arguments_auto: | + (['--mount type=bind,src=' + matrix_go_skype_bridge_config_path + '/registration.yaml,dst=/matrix-go-skype-bridge-registration.yaml,ro'] if matrix_go_skype_bridge_enabled else []) + + (['--mount type=bind,src=' + matrix_wechat_config_path + '/registration.yaml,dst=/matrix-wechat-registration.yaml,ro'] if matrix_wechat_enabled else []) + + (['--mount type=bind,src=' + matrix_heisenbridge_base_path + '/registration.yaml,dst=/heisenbridge-registration.yaml,ro'] if matrix_heisenbridge_enabled else []) + (['--mount type=bind,src=' + matrix_hookshot_base_path + '/registration.yml,dst=/hookshot-registration.yml,ro'] if matrix_hookshot_enabled else []) @@ -162,6 +164,8 @@ matrix_homeserver_app_service_config_files_auto: | + (['/matrix-go-skype-bridge-registration.yaml'] if matrix_go_skype_bridge_enabled else []) + + (['/matrix-wechat-registration.yaml'] if matrix_wechat_enabled else []) + + (['/heisenbridge-registration.yaml'] if matrix_heisenbridge_enabled else []) + (['/hookshot-registration.yml'] if matrix_hookshot_enabled else []) @@ -298,6 +302,10 @@ devture_systemd_service_manager_services_list_auto: | + ([{'name': 'matrix-go-skype-bridge.service', 'priority': 2000, 'groups': ['matrix', 'bridges', 'go-skype']}] if matrix_go_skype_bridge_enabled else []) + + ([{'name': 'matrix-wechat.service', 'priority': 2000, 'groups': ['matrix', 'bridges', 'wechat']}] if matrix_wechat_enabled else []) + + + ([{'name': 'matrix-wechat-agent.service', 'priority': 2000, 'groups': ['matrix', 'bridges', 'wechat']}] if matrix_wechat_enabled else []) + + ([{'name': 'matrix-heisenbridge.service', 'priority': 2000, 'groups': ['matrix', 'bridges', 'heisenbridge']}] if matrix_heisenbridge_enabled else []) + ([{'name': 'matrix-hookshot.service', 'priority': 2000, 'groups': ['matrix', 'bridges', 'hookshot', 'bridge-hookshot']}] if matrix_hookshot_enabled else []) @@ -1713,6 +1721,57 @@ matrix_mautrix_wsproxy_syncproxy_database_password: "{{ '%s' | format(matrix_hom # ###################################################################### +###################################################################### +# +# matrix-bridge-wechat +# +###################################################################### + +# We don't enable bridges by default. +matrix_wechat_enabled: false + +matrix_wechat_systemd_required_services_list_auto: | + {{ + matrix_addons_homeserver_systemd_services_list + + + ([devture_postgres_identifier ~ '.service'] if (devture_postgres_enabled and matrix_wechat_database_hostname == devture_postgres_connection_hostname) else []) + }} + +matrix_wechat_container_image_self_build: "{{ matrix_architecture not in ['amd64', 'arm64'] }}" + +matrix_wechat_agent_container_image_self_build: "{{ matrix_architecture not in ['amd64'] }}" + +matrix_wechat_container_network: "{{ matrix_addons_container_network }}" + +matrix_wechat_container_additional_networks_auto: |- + {{ + ( + ([] if matrix_addons_homeserver_container_network == '' else [matrix_addons_homeserver_container_network]) + + + ([devture_postgres_container_network] if (devture_postgres_enabled and matrix_wechat_database_hostname == devture_postgres_connection_hostname and matrix_wechat_container_network != devture_postgres_container_network) else []) + ) | unique + }} + +matrix_wechat_appservice_token: "{{ '%s' | format(matrix_homeserver_generic_secret_key) | password_hash('sha512', 'wechat.as.token', rounds=655555) | to_uuid }}" + +matrix_wechat_homeserver_address: "{{ matrix_addons_homeserver_client_api_url }}" +matrix_wechat_homeserver_token: "{{ '%s' | format(matrix_homeserver_generic_secret_key) | password_hash('sha512', 'wechat.hs.token', rounds=655555) | to_uuid }}" + +matrix_wechat_login_shared_secret: "{{ matrix_synapse_ext_password_provider_shared_secret_auth_shared_secret if matrix_synapse_ext_password_provider_shared_secret_auth_enabled else '' }}" + +matrix_wechat_bridge_listen_secret: "{{ '%s' | format(matrix_homeserver_generic_secret_key) | password_hash('sha512', 'wechat.lstn', rounds=655555) | to_uuid }}" + +# Postgres is the default, except if not using internal Postgres server +matrix_wechat_database_engine: "{{ 'postgres' if devture_postgres_enabled else 'sqlite' }}" +matrix_wechat_database_hostname: "{{ devture_postgres_connection_hostname if devture_postgres_enabled else '' }}" +matrix_wechat_database_password: "{{ '%s' | format(matrix_homeserver_generic_secret_key) | password_hash('sha512', 'gowechat.db', rounds=655555) | to_uuid }}" + +###################################################################### +# +# /matrix-bridge-wechat +# +###################################################################### + ###################################################################### # # matrix-bridge-mautrix-whatsapp @@ -3694,6 +3753,12 @@ devture_postgres_managed_databases_auto: | 'password': matrix_go_skype_bridge_database_password, }] if (matrix_go_skype_bridge_enabled and matrix_go_skype_bridge_database_engine == 'postgres' and matrix_go_skype_bridge_database_hostname == devture_postgres_connection_hostname) else []) + + ([{ + 'name': matrix_wechat_database_name, + 'username': matrix_wechat_database_username, + 'password': matrix_wechat_database_password, + }] if (matrix_wechat_enabled and matrix_wechat_database_engine == 'postgres' and matrix_wechat_database_hostname == devture_postgres_connection_hostname) else []) + + ([{ 'name': matrix_mautrix_facebook_database_name, 'username': matrix_mautrix_facebook_database_username, diff --git a/roles/custom/matrix-bridge-wechat/defaults/main.yml b/roles/custom/matrix-bridge-wechat/defaults/main.yml new file mode 100644 index 000000000..acd65f407 --- /dev/null +++ b/roles/custom/matrix-bridge-wechat/defaults/main.yml @@ -0,0 +1,152 @@ +--- + +# WeChat Bridge is a Matrix <-> WeChat bridge +# Project source code URL: https://github.com/duo/matrix-wechat + +matrix_wechat_enabled: true + +# renovate: datasource=docker depName=lxduo/matrix-wechat +matrix_wechat_version: 0.2.4 +matrix_wechat_container_image: "{{ matrix_wechat_container_image_name_prefix }}lxduo/matrix-wechat:{{ matrix_wechat_version }}" +matrix_wechat_container_image_name_prefix: "{{ 'localhost/' if matrix_wechat_container_image_self_build else matrix_container_global_registry_prefix }}" +matrix_wechat_container_image_force_pull: "{{ matrix_wechat_container_image.endswith(':latest') }}" + +matrix_wechat_container_image_self_build: false +matrix_wechat_container_image_self_build_repo: "https://github.com/duo/matrix-wechat.git" +matrix_wechat_container_image_self_build_branch: "{{ 'master' if matrix_wechat_version == 'latest' else matrix_wechat_version }}" + +# renovate: datasource=docker depName=lxduo/matrix-wechat-agent +matrix_wechat_agent_version: 0.0.1 +matrix_wechat_agent_container_image: "{{ matrix_wechat_agent_container_image_name_prefix }}lxduo/matrix-wechat-agent:{{ matrix_wechat_agent_version }}" +matrix_wechat_agent_container_image_name_prefix: "{{ 'localhost/' if matrix_wechat_agent_container_image_self_build else matrix_container_global_registry_prefix }}" +matrix_wechat_agent_container_image_force_pull: "{{ matrix_wechat_agent_container_image.endswith(':latest') }}" + +# The agent needs to write to /home/user/.vnc. +# `/home/user` is owned by `user:group` (`1000:1000`), so it needs to run with that user/group. +matrix_wechat_agent_container_user_uid: 1000 +matrix_wechat_agent_container_user_gid: 1000 + +matrix_wechat_agent_container_image_self_build: false +matrix_wechat_agent_container_image_self_build_repo: "https://github.com/duo/matrix-wechat-agent.git" +matrix_wechat_agent_container_image_self_build_branch: "{{ 'master' if matrix_wechat_agent_version == 'latest' else matrix_wechat_agent_version }}" + +matrix_wechat_base_path: "{{ matrix_base_data_path }}/wechat" +matrix_wechat_config_path: "{{ matrix_wechat_base_path }}/config" +matrix_wechat_data_path: "{{ matrix_wechat_base_path }}/data" +matrix_wechat_container_src_files_path: "{{ matrix_wechat_base_path }}/container-src" +matrix_wechat_agent_container_src_files_path: "{{ matrix_wechat_base_path }}/agent-container-src" + +matrix_wechat_homeserver_address: "" +matrix_wechat_homeserver_domain: "{{ matrix_domain }}" +matrix_wechat_appservice_address: 'http://matrix-wechat:8080' + +matrix_wechat_container_network: "" + +matrix_wechat_container_additional_networks: "{{ matrix_wechat_container_additional_networks_auto + matrix_wechat_container_additional_networks_custom }}" +matrix_wechat_container_additional_networks_auto: [] +matrix_wechat_container_additional_networks_custom: [] + +# A list of extra arguments to pass to the container +matrix_wechat_container_extra_arguments: [] + +# List of systemd services that matrix-wechat.service depends on. +matrix_wechat_systemd_required_services_list: "{{ matrix_wechat_systemd_required_services_list_default + matrix_wechat_systemd_required_services_list_auto + matrix_wechat_systemd_required_services_list_custom }}" +matrix_wechat_systemd_required_services_list_default: ['docker.service'] +matrix_wechat_systemd_required_services_list_auto: [] +matrix_wechat_systemd_required_services_list_custom: [] + +# List of systemd services that matrix-wechat.service wants +matrix_wechat_systemd_wanted_services_list: [] + +matrix_wechat_appservice_token: '' +matrix_wechat_homeserver_token: '' + +matrix_wechat_appservice_bot_username: wechatbot + +matrix_wechat_command_prefix: "!wechat" + +# Whether or not created rooms should have federation enabled. +# If false, created portal rooms will never be federated. +matrix_wechat_federate_rooms: true + +# Database-related configuration fields. +matrix_wechat_database_engine: 'postgres' +matrix_wechat_database_username: 'matrix_wechat' +matrix_wechat_database_password: 'some-password' +matrix_wechat_database_hostname: '' +matrix_wechat_database_port: 5432 +matrix_wechat_database_name: 'matrix_wechat' +matrix_wechat_database_sslmode: disable +matrix_wechat_database_connection_string: 'postgresql://{{ matrix_wechat_database_username }}:{{ matrix_wechat_database_password }}@{{ matrix_wechat_database_hostname }}:{{ matrix_wechat_database_port }}/{{ matrix_wechat_database_name }}?sslmode={{ matrix_wechat_database_sslmode }}' + +matrix_wechat_bridge_listen_secret: '' + +# Can be set to enable automatic double-puppeting via Shared Secret Auth (https://github.com/devture/matrix-synapse-shared-secret-auth). +matrix_wechat_login_shared_secret: '' +matrix_wechat_login_shared_secret_map: + "{{ {matrix_wechat_homeserver_domain: matrix_wechat_login_shared_secret} if matrix_wechat_login_shared_secret else {} }}" + +# Servers to always allow double puppeting from +matrix_wechat_double_puppet_server_map: + "{{ matrix_wechat_homeserver_domain: matrix_wechat_homeserver_address }}" + +# Enable End-to-bridge encryption +matrix_wechat_encryption_allow: "{{ matrix_bridges_encryption_enabled }}" +matrix_wechat_encryption_default: "{{ matrix_wechat_encryption_allow }}" + +# Minimum severity of journal log messages. +# Options: debug, info, warn, error, fatal +matrix_wechat_log_level: 'warn' + +matrix_wechat_permissions: | + {{ + {matrix_wechat_homeserver_domain: 'user'} + | combine({matrix_admin: 'admin'} if matrix_admin else {}) + }} + +# Default Wechat 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_wechat_configuration_extension_yaml`) +# or completely replace this variable with your own template. +matrix_wechat_configuration_yaml: "{{ lookup('template', 'templates/config.yaml.j2') }}" + +matrix_wechat_configuration_extension_yaml: | + # Your custom YAML configuration goes here. + # This configuration extends the default starting configuration (`matrix_wechat_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_wechat_configuration_yaml`. + +matrix_wechat_configuration_extension: "{{ matrix_wechat_configuration_extension_yaml | from_yaml if matrix_wechat_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_wechat_configuration_yaml`. +matrix_wechat_configuration: "{{ matrix_wechat_configuration_yaml | from_yaml | combine(matrix_wechat_configuration_extension, recursive=True) }}" + +matrix_wechat_registration_yaml: | + id: wechat + url: {{ matrix_wechat_appservice_address }} + as_token: "{{ matrix_wechat_appservice_token }}" + hs_token: "{{ matrix_wechat_homeserver_token }}" + # See https://github.com/mautrix/signal/issues/43 + sender_localpart: _bot_{{ matrix_wechat_appservice_bot_username }} + rate_limited: false + namespaces: + users: + - regex: '^@_wechat_(.*):{{ matrix_wechat_homeserver_domain | regex_escape }}$' + exclusive: true + - exclusive: true + regex: '^@{{ matrix_wechat_appservice_bot_username | regex_escape }}:{{ matrix_wechat_homeserver_domain | regex_escape }}$' + de.sorunome.msc2409.push_ephemeral: true + +matrix_wechat_registration: "{{ matrix_wechat_registration_yaml | from_yaml }}" + + +matrix_wechat_agent_service_secret: "{{ matrix_wechat_bridge_listen_secret }}" + +matrix_wechat_agent_configuration_yaml: "{{ lookup('template', 'templates/agent-config.yaml.j2') }}" + +matrix_wechat_agent_configuration: "{{ matrix_wechat_agent_configuration_yaml | from_yaml }}" diff --git a/roles/custom/matrix-bridge-wechat/tasks/install.yml b/roles/custom/matrix-bridge-wechat/tasks/install.yml new file mode 100644 index 000000000..8a2d0694b --- /dev/null +++ b/roles/custom/matrix-bridge-wechat/tasks/install.yml @@ -0,0 +1,129 @@ +--- + +- name: Ensure WeChat Bridge paths exists + ansible.builtin.file: + path: "{{ item.path }}" + state: directory + mode: 0750 + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_groupname }}" + with_items: + - {path: "{{ matrix_wechat_base_path }}", when: true} + - {path: "{{ matrix_wechat_config_path }}", when: true} + - {path: "{{ matrix_wechat_data_path }}", when: true} + - {path: "{{ matrix_wechat_container_src_files_path }}", when: "{{ matrix_wechat_container_image_self_build }}"} + - {path: "{{ matrix_wechat_agent_container_src_files_path }}", when: "{{ matrix_wechat_agent_container_image_self_build }}"} + when: item.when | bool + +- name: Ensure WeChat Bridge image is pulled + community.docker.docker_image: + name: "{{ matrix_wechat_container_image }}" + source: "{{ 'pull' if ansible_version.major > 2 or ansible_version.minor > 7 else omit }}" + force_source: "{{ matrix_wechat_container_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_wechat_container_image_force_pull }}" + when: not matrix_wechat_container_image_self_build + register: result + retries: "{{ devture_playbook_help_container_retries_count }}" + delay: "{{ devture_playbook_help_container_retries_delay }}" + until: result is not failed + +- when: matrix_wechat_container_image_self_build | bool + block: + - name: Ensure WeChat Bridge repository is present on self-build + ansible.builtin.git: + repo: "{{ matrix_wechat_container_image_self_build_repo }}" + dest: "{{ matrix_wechat_container_src_files_path }}" + version: "{{ matrix_wechat_container_image_self_build_branch }}" + force: "yes" + become: true + become_user: "{{ matrix_user_username }}" + register: matrix_wechat_git_pull_results + + - name: Ensure WeChat Bridge container image is built + community.docker.docker_image: + name: "{{ matrix_wechat_container_image }}" + source: build + force_source: "{{ matrix_wechat_git_pull_results.changed 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_wechat_git_pull_results.changed }}" + build: + dockerfile: Dockerfile + path: "{{ matrix_wechat_container_src_files_path }}" + pull: true + +- name: Ensure WeChat Agent image is pulled + community.docker.docker_image: + name: "{{ matrix_wechat_agent_container_image }}" + source: "{{ 'pull' if ansible_version.major > 2 or ansible_version.minor > 7 else omit }}" + force_source: "{{ matrix_wechat_agent_container_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_wechat_agent_container_image_force_pull }}" + when: not matrix_wechat_agent_container_image_self_build + register: result + retries: "{{ devture_playbook_help_container_retries_count }}" + delay: "{{ devture_playbook_help_container_retries_delay }}" + until: result is not failed + +- when: matrix_wechat_agent_container_image_self_build | bool + block: + - name: Ensure WeChat Agent repository is present on self-build + ansible.builtin.git: + repo: "{{ matrix_wechat_agent_container_image_self_build_repo }}" + dest: "{{ matrix_wechat_agent_container_src_files_path }}" + version: "{{ matrix_wechat_agent_container_image_self_build_branch }}" + force: "yes" + become: true + become_user: "{{ matrix_user_username }}" + register: matrix_wechat_agent_git_pull_results + + - name: Ensure WeChat Agent container image is built + community.docker.docker_image: + name: "{{ matrix_wechat_agent_container_image }}" + source: build + force_source: "{{ matrix_wechat_agent_git_pull_results.changed 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_wechat_agent_git_pull_results.changed }}" + build: + dockerfile: Dockerfile + path: "{{ matrix_wechat_agent_container_src_files_path }}" + pull: true + +- name: Ensure WeChat configuration installed + ansible.builtin.copy: + content: "{{ matrix_wechat_configuration | to_nice_yaml(indent=2, width=999999) }}" + dest: "{{ matrix_wechat_config_path }}/config.yaml" + mode: 0644 + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_groupname }}" + +- name: Ensure WeChat registration.yaml installed + ansible.builtin.copy: + content: "{{ matrix_wechat_registration | to_nice_yaml(indent=2, width=999999) }}" + dest: "{{ matrix_wechat_config_path }}/registration.yaml" + mode: 0644 + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_groupname }}" + +- name: Ensure Wechat Agent configuration installed + ansible.builtin.copy: + content: "{{ matrix_wechat_agent_configuration | to_nice_yaml(indent=2, width=999999) }}" + dest: "{{ matrix_wechat_config_path }}/agent-config.yaml" + mode: 0644 + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_groupname }}" + +- name: Ensure matrix-wechat container network is created + community.general.docker_network: + name: "{{ matrix_wechat_container_network }}" + driver: bridge + +- name: Ensure matrix-wechat.service installed + ansible.builtin.template: + src: "{{ role_path }}/templates/systemd/matrix-wechat.service.j2" + dest: "{{ devture_systemd_docker_base_systemd_path }}/matrix-wechat.service" + mode: 0644 + register: matrix_wechat_systemd_service_result + +- name: Ensure matrix-wechat-agent.service installed + ansible.builtin.template: + src: "{{ role_path }}/templates/systemd/matrix-wechat-agent.service.j2" + dest: "{{ devture_systemd_docker_base_systemd_path }}/matrix-wechat-agent.service" + mode: 0644 + register: matrix_wechat_agent_systemd_service_result diff --git a/roles/custom/matrix-bridge-wechat/tasks/main.yml b/roles/custom/matrix-bridge-wechat/tasks/main.yml new file mode 100644 index 000000000..effcd7d5e --- /dev/null +++ b/roles/custom/matrix-bridge-wechat/tasks/main.yml @@ -0,0 +1,20 @@ +--- + +- tags: + - setup-all + - setup-wechat + - install-all + - install-wechat + block: + - when: matrix_wechat_enabled | bool + ansible.builtin.include_tasks: "{{ role_path }}/tasks/validate_config.yml" + + - when: matrix_wechat_enabled | bool + ansible.builtin.include_tasks: "{{ role_path }}/tasks/install.yml" + +- tags: + - setup-all + - setup-wechat + block: + - when: not matrix_wechat_enabled | bool + ansible.builtin.include_tasks: "{{ role_path }}/tasks/uninstall.yml" diff --git a/roles/custom/matrix-bridge-wechat/tasks/uninstall.yml b/roles/custom/matrix-bridge-wechat/tasks/uninstall.yml new file mode 100644 index 000000000..cf19203fa --- /dev/null +++ b/roles/custom/matrix-bridge-wechat/tasks/uninstall.yml @@ -0,0 +1,39 @@ +--- + +- name: Check existence of matrix-wechat service + ansible.builtin.stat: + path: "/etc/systemd/system/matrix-wechat.service" + register: matrix_wechat_service_stat + +- when: matrix_wechat_service_stat.stat.exists | bool + block: + - name: Ensure matrix-wechat is stopped + ansible.builtin.service: + name: matrix-wechat + state: stopped + enabled: false + daemon_reload: true + + - name: Ensure matrix-wechat.service doesn't exist + ansible.builtin.file: + path: "/etc/systemd/system/matrix-wechat.service" + state: absent + +- name: Check existence of matrix-wechat-agent service + ansible.builtin.stat: + path: "/etc/systemd/system/matrix-wechat-agent.service" + register: matrix_wechat_agent_service_stat + +- when: matrix_wechat_agent_service_stat.stat.exists | bool + block: + - name: Ensure matrix-wechat-agent is stopped + ansible.builtin.service: + name: matrix-wechat-agent + state: stopped + enabled: false + daemon_reload: true + + - name: Ensure matrix-wechat-agent.service doesn't exist + ansible.builtin.file: + path: "/etc/systemd/system/matrix-wechat-agent.service" + state: absent diff --git a/roles/custom/matrix-bridge-wechat/tasks/validate_config.yml b/roles/custom/matrix-bridge-wechat/tasks/validate_config.yml new file mode 100644 index 000000000..49159be21 --- /dev/null +++ b/roles/custom/matrix-bridge-wechat/tasks/validate_config.yml @@ -0,0 +1,19 @@ +--- + +- name: Fail if required WeChat settings not defined + ansible.builtin.fail: + msg: >- + You need to define a required configuration setting (`{{ item.name }}`). + when: "item.when | bool and vars[item.name] == ''" + with_items: + - {'name': 'matrix_wechat_appservice_token', when: true} + - {'name': 'matrix_wechat_homeserver_address', when: true} + - {'name': 'matrix_wechat_homeserver_token', when: true} + - {'name': 'matrix_wechat_database_hostname', when: "{{ matrix_wechat_database_engine == 'postgres' }}"} + - {'name': 'matrix_wechat_container_network', when: true} + - {'name': 'matrix_wechat_bridge_listen_secret', when: true} + +- name: Fail if WeChat enabled on ARM64 (not supported by the wechat agent, even with self-building) + when: matrix_architecture not in ['amd64'] + ansible.builtin.fail: + msg: "The WeChat Agent does not support the '{{ matrix_architecture }}' architecture yet. Its Dockerfile downloads amd64 binaries and does not work on arm64." diff --git a/roles/custom/matrix-bridge-wechat/templates/agent-config.yaml.j2 b/roles/custom/matrix-bridge-wechat/templates/agent-config.yaml.j2 new file mode 100644 index 000000000..19c1d1ad9 --- /dev/null +++ b/roles/custom/matrix-bridge-wechat/templates/agent-config.yaml.j2 @@ -0,0 +1,13 @@ +wechat: + version: 3.8.1.26 + listen_port: 22222 + init_timeout: 10s + request_timeout: 30s + +service: + addr: ws://matrix-wechat:20002 + secret: {{ matrix_wechat_bridge_listen_secret | to_json }} + ping_interval: 30s + +log: + level: info diff --git a/roles/custom/matrix-bridge-wechat/templates/config.yaml.j2 b/roles/custom/matrix-bridge-wechat/templates/config.yaml.j2 new file mode 100644 index 000000000..3a5091894 --- /dev/null +++ b/roles/custom/matrix-bridge-wechat/templates/config.yaml.j2 @@ -0,0 +1,265 @@ +#jinja2: lstrip_blocks: "True" +# Homeserver details. +homeserver: + # The address that this appservice can use to connect to the homeserver. + address: {{ matrix_wechat_homeserver_address | to_json }} + # The domain of the homeserver (for MXIDs, etc). + domain: {{ matrix_wechat_homeserver_domain | to_json }} + + # What software is the homeserver running? + # Standard Matrix homeservers like Synapse, Dendrite and Conduit should just use "standard" here. + software: standard + # The URL to push real-time bridge status to. + # If set, the bridge will make POST requests to this URL whenever a user's connection state changes. + # The bridge will use the appservice as_token to authorize requests. + status_endpoint: null + # Endpoint for reporting per-message status. + message_send_checkpoint_endpoint: null + # Does the homeserver support https://github.com/matrix-org/matrix-spec-proposals/pull/2246? + async_media: false + + # Should the bridge use a websocket for connecting to the homeserver? + # The server side is currently not documented anywhere and is only implemented by mautrix-wsproxy, + # mautrix-asmux (deprecated), and hungryserv (proprietary). + websocket: false + # How often should the websocket be pinged? Pinging will be disabled if this is zero. + ping_interval_seconds: 0 + +# 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_wechat_appservice_address | to_json }} + + # The hostname and port where this appservice should listen. + hostname: 0.0.0.0 + port: 8080 + + # Database config. + database: + # The database type. "sqlite3" and "postgres" are supported. + type: postgres + # The database URI. + # SQLite: File name is enough. https://github.com/mattn/go-sqlite3#connection-string + # Postgres: Connection string. For example, postgres://user:password@host/database?sslmode=disable + # To connect via Unix socket, use something like postgres:///dbname?host=/var/run/postgresql + uri: {{ matrix_wechat_database_connection_string | to_json }} + # Maximum number of connections. Mostly relevant for Postgres. + max_open_conns: 20 + max_idle_conns: 2 + # Maximum connection idle time and lifetime before they're closed. Disabled if null. + # Parsed with https://pkg.go.dev/time#ParseDuration + max_conn_idle_time: null + max_conn_lifetime: null + + # The unique ID of this appservice. + id: wechat + # Appservice bot details. + bot: + # Username of the appservice bot. + username: {{ matrix_wechat_appservice_bot_username | to_json }} + # Display name and avatar for bot. Set to "remove" to remove display name/avatar, leave empty + # to leave display name/avatar as-is. + displayname: WeChat bridge bot + avatar: mxc://matrix.org/rddVQBTjOOmNkNLXWfYJNfPW + + # Whether or not to receive ephemeral events via appservice transactions. + # Requires MSC2409 support (i.e. Synapse 1.22+). + ephemeral_events: true + + # Should incoming events be handled asynchronously? + # This may be necessary for large public instances with lots of messages going through. + # However, messages will not be guaranteed to be bridged in the same order they were sent in. + async_transactions: false + + # Authentication tokens for AS <-> HS communication. Autogenerated; do not modify. + as_token: {{ matrix_wechat_appservice_token | to_json }} + hs_token: {{ matrix_wechat_homeserver_token | to_json }} + +# Bridge config +bridge: + # Localpart template of MXIDs for WeChat users. + # {% raw %}{{.}}{% endraw %} is replaced with the uin of the WeChat user. + username_template: {% raw %}_wechat_{{.}}{% endraw %} + # Displayname template for WeChat users. + displayname_template: "{% raw %}{{if .Name}}{{.Name}}{{else}}{{.Uin}}{{end}} (WeChat){% endraw %}" + # WeChat listen address (for agent connection) + listen_address: "0.0.0.0:20002" + listen_secret: {{ matrix_wechat_bridge_listen_secret | to_json }} + # Should the bridge create a space for each logged-in user and add bridged rooms to it? + # Users who logged in before turning this on should run `!wa sync space` to create and fill the space for the first time. + personal_filtering_spaces: false + # Whether the bridge should send the message status as a custom com.beeper.message_send_status event. + message_status_events: false + # Whether the bridge should send error notices via m.notice events when a message fails to bridge. + message_error_notices: true + portal_message_buffer: 128 + # Enable redaction + allow_redaction: false + # Should puppet avatars be fetched from the server even if an avatar is already set? + user_avatar_sync: true + # Should the bridge update the m.direct account data event when double puppeting is enabled. + # Note that updating the m.direct event is not atomic (except with mautrix-asmux) + # and is therefore prone to race conditions. + sync_direct_chat_list: false + # When double puppeting is enabled, users can use `!wa toggle` to change whether + # presence is bridged. These settings set the default values. + # Existing users won't be affected when these are changed. + default_bridge_presence: false + # Send the presence as "available" to WeChat when users start typing on a portal. + # This works as a workaround for homeservers that do not support presence, and allows + # users to see when the WeChat user on the other side is typing during a conversation. + send_presence_on_typing: false + # Servers to always allow double puppeting from + double_puppet_server_map: + "{{ matrix_wechat_homeserver_domain }}": {{ matrix_wechat_homeserver_address }} + # Allow using double puppeting from any server with a valid client .well-known file. + double_puppet_allow_discovery: false + # Shared secrets for https://github.com/devture/matrix-synapse-shared-secret-auth + # + # If set, double puppeting will be enabled automatically for local users + # instead of users having to find an access token and run `login-matrix` + # manually. + login_shared_secret_map: {{ matrix_wechat_login_shared_secret_map | to_json }} + # Whether to explicitly set the avatar and room name for private chat portal rooms. + # If set to `default`, this will be enabled in encrypted rooms and disabled in unencrypted rooms. + # If set to `always`, all DM rooms will have explicit names and avatars set. + # If set to `never`, DM rooms will never have names and avatars set. + private_chat_portal_meta: default + # Should group members be synced in parallel? This makes member sync faster + parallel_member_sync: false + # Set this to true to tell the bridge to re-send m.bridge events to all rooms on the next run. + # This field will automatically be changed back to false after it, except if the config file is not writable. + resend_bridge_info: false + # When using double puppeting, should muted chats be muted in Matrix? + mute_bridging: false + # Allow invite permission for user. User can invite any bots to room with WeChat + # users (private chat and groups) + allow_user_invite: false + # Whether or not created rooms should have federation enabled. + # If false, created portal rooms will never be federated. + federate_rooms: true + # Should the bridge never send alerts to the bridge management room? + # These are mostly things like the user being logged out. + disable_bridge_alerts: false + # Maximum time for handling Matrix events. Duration strings formatted for https://pkg.go.dev/time#ParseDuration + # Null means there's no enforced timeout. + message_handling_timeout: + # Send an error message after this timeout, but keep waiting for the response until the deadline. + # This is counted from the origin_server_ts, so the warning time is consistent regardless of the source of delay. + # If the message is older than this when it reaches the bridge, the message won't be handled at all. + error_after: null + # Drop messages after this timeout. They may still go through if the message got sent to the servers. + # This is counted from the time the bridge starts handling the message. + deadline: 120s + + # The prefix for commands. Only required in non-management rooms. + command_prefix: {{ matrix_wechat_command_prefix | to_json }} + + # Messages sent upon joining a management room. + # Markdown is supported. The defaults are listed below. + management_room_text: + # Sent when joining a room. + welcome: "Hello, I'm a WeChat bridge bot." + # Sent when joining a management room and the user is already logged in. + welcome_connected: "Use `help` for help." + # Sent when joining a management room and the user is not logged in. + welcome_unconnected: "Use `help` for help or `login` to log in." + # Optional extra text sent when joining a management room. + additional_help: "" + + # End-to-bridge encryption support options. + # + # See https://docs.mau.fi/bridges/general/end-to-bridge-encryption.html for more info. + encryption: + # Allow encryption, work in group chat rooms with e2ee enabled + allow: {{ matrix_wechat_encryption_allow | to_json }} + # Default to encryption, force-enable encryption in all portals the bridge creates + # This will cause the bridge bot to be in private chats for the encryption to work properly. + default: {{ matrix_wechat_encryption_default | to_json }} + # Whether to use MSC2409/MSC3202 instead of /sync long polling for receiving encryption-related data. + appservice: false + # Require encryption, drop any unencrypted messages. + require: false + # Enable key sharing? If enabled, key requests for rooms where users are in will be fulfilled. + # You must use a client that supports requesting keys from other users to use this feature. + allow_key_sharing: false + # Should users mentions be in the event wire content to enable the server to send push notifications? + plaintext_mentions: false + # Options for deleting megolm sessions from the bridge. + delete_keys: + # Beeper-specific: delete outbound sessions when hungryserv confirms + # that the user has uploaded the key to key backup. + delete_outbound_on_ack: false + # Don't store outbound sessions in the inbound table. + dont_store_outbound: false + # Ratchet megolm sessions forward after decrypting messages. + ratchet_on_decrypt: false + # Delete fully used keys (index >= max_messages) after decrypting messages. + delete_fully_used_on_decrypt: false + # Delete previous megolm sessions from same device when receiving a new one. + delete_prev_on_new_session: false + # Delete megolm sessions received from a device when the device is deleted. + delete_on_device_delete: false + # Periodically delete megolm sessions when 2x max_age has passed since receiving the session. + periodically_delete_expired: false + # Delete inbound megolm sessions that don't have the received_at field used for + # automatic ratcheting and expired session deletion. This is meant as a migration + # to delete old keys prior to the bridge update. + delete_outdated_inbound: false + # What level of device verification should be required from users? + # + # Valid levels: + # unverified - Send keys to all device in the room. + # cross-signed-untrusted - Require valid cross-signing, but trust all cross-signing keys. + # cross-signed-tofu - Require valid cross-signing, trust cross-signing keys on first use (and reject changes). + # cross-signed-verified - Require valid cross-signing, plus a valid user signature from the bridge bot. + # Note that creating user signatures from the bridge bot is not currently possible. + # verified - Require manual per-device verification + # (currently only possible by modifying the `trust` column in the `crypto_device` database table). + verification_levels: + # Minimum level for which the bridge should send keys to when bridging messages from WeChat to Matrix. + receive: unverified + # Minimum level that the bridge should accept for incoming Matrix messages. + send: unverified + # Minimum level that the bridge should require for accepting key requests. + share: cross-signed-tofu + # Options for Megolm room key rotation. These options allow you to + # configure the m.room.encryption event content. See: + # https://spec.matrix.org/v1.3/client-server-api/#mroomencryption for + # more information about that event. + rotation: + # Enable custom Megolm room key rotation settings. Note that these + # settings will only apply to rooms created after this option is + # set. + enable_custom: false + # The maximum number of milliseconds a session should be used + # before changing it. The Matrix spec recommends 604800000 (a week) + # as the default. + milliseconds: 604800000 + # The maximum number of messages that should be sent with a given a + # session before changing it. The Matrix spec recommends 100 as the + # default. + messages: 100 + + # Disable rotating keys when a user's devices change? + # You should not enable this option unless you understand all the implications. + disable_device_change_key_rotation: false + + + # Permissions for using the bridge. + # Permitted values: + # user - Access to use the bridge to chat with a WeChat account. + # admin - User level and some additional administration tools + # Permitted keys: + # * - All Matrix users + # domain - All users on that homeserver + # mxid - Specific user + permissions: {{ matrix_wechat_permissions | to_json }} + +# Logging config. See https://github.com/tulir/zeroconfig for details. +logging: + min_level: {{ matrix_wechat_log_level }} + writers: + - type: stdout + format: pretty-colored diff --git a/roles/custom/matrix-bridge-wechat/templates/systemd/matrix-wechat-agent.service.j2 b/roles/custom/matrix-bridge-wechat/templates/systemd/matrix-wechat-agent.service.j2 new file mode 100644 index 000000000..8e5ea5239 --- /dev/null +++ b/roles/custom/matrix-bridge-wechat/templates/systemd/matrix-wechat-agent.service.j2 @@ -0,0 +1,49 @@ +#jinja2: lstrip_blocks: "True" +[Unit] +Description=Matrix WeChat Agent +{% for service in matrix_wechat_systemd_required_services_list %} +Requires={{ service }} +After={{ service }} +{% endfor %} +{% for service in matrix_wechat_systemd_wanted_services_list %} +Wants={{ service }} +{% endfor %} +DefaultDependencies=no + +[Service] +Type=simple +Environment="HOME={{ devture_systemd_docker_base_systemd_unit_home_path }}" +ExecStartPre=-{{ devture_systemd_docker_base_host_command_sh }} -c '{{ devture_systemd_docker_base_host_command_docker }} stop --time={{ devture_systemd_docker_base_container_stop_grace_time_seconds }} matrix-wechat-agent 2>/dev/null || true' +ExecStartPre=-{{ devture_systemd_docker_base_host_command_sh }} -c '{{ devture_systemd_docker_base_host_command_docker }} rm matrix-wechat-agent 2>/dev/null || true' + +{# + The agent needs to write to /home/user/.vnc. + `/home/user` is owned by `user:group` (`1000:1000`), so it needs to run with that user/group. +#} +ExecStartPre={{ devture_systemd_docker_base_host_command_docker }} create \ + --rm \ + --name=matrix-wechat-agent \ + --log-driver=none \ + --user={{ matrix_wechat_agent_container_user_uid }}:{{ matrix_wechat_agent_container_user_gid }} \ + --cap-drop=ALL \ + --network={{ matrix_wechat_container_network }} \ + --mount type=bind,src={{ matrix_wechat_config_path }}/agent-config.yaml,dst=/home/user/matrix-wechat-agent/configure.yaml,ro \ + {% for arg in matrix_wechat_container_extra_arguments %} + {{ arg }} \ + {% endfor %} + {{ matrix_wechat_agent_container_image }} + +{% for network in matrix_wechat_container_additional_networks %} +ExecStartPre={{ devture_systemd_docker_base_host_command_docker }} network connect {{ network }} matrix-wechat-agent +{% endfor %} + +ExecStart={{ devture_systemd_docker_base_host_command_docker }} start --attach matrix-wechat-agent + +ExecStop=-{{ devture_systemd_docker_base_host_command_sh }} -c '{{ devture_systemd_docker_base_host_command_docker }} stop --time={{ devture_systemd_docker_base_container_stop_grace_time_seconds }} matrix-wechat-agent 2>/dev/null || true' +ExecStop=-{{ devture_systemd_docker_base_host_command_sh }} -c '{{ devture_systemd_docker_base_host_command_docker }} rm matrix-wechat-agent 2>/dev/null || true' +Restart=always +RestartSec=30 +SyslogIdentifier=matrix-wechat-agent + +[Install] +WantedBy=multi-user.target diff --git a/roles/custom/matrix-bridge-wechat/templates/systemd/matrix-wechat.service.j2 b/roles/custom/matrix-bridge-wechat/templates/systemd/matrix-wechat.service.j2 new file mode 100644 index 000000000..96f87e9bb --- /dev/null +++ b/roles/custom/matrix-bridge-wechat/templates/systemd/matrix-wechat.service.j2 @@ -0,0 +1,47 @@ +#jinja2: lstrip_blocks: "True" +[Unit] +Description=Matrix WeChat Bridge +{% for service in matrix_wechat_systemd_required_services_list %} +Requires={{ service }} +After={{ service }} +{% endfor %} +{% for service in matrix_wechat_systemd_wanted_services_list %} +Wants={{ service }} +{% endfor %} +DefaultDependencies=no + +[Service] +Type=simple +Environment="HOME={{ devture_systemd_docker_base_systemd_unit_home_path }}" +ExecStartPre=-{{ devture_systemd_docker_base_host_command_sh }} -c '{{ devture_systemd_docker_base_host_command_docker }} stop --time={{ devture_systemd_docker_base_container_stop_grace_time_seconds }} matrix-wechat 2>/dev/null || true' +ExecStartPre=-{{ devture_systemd_docker_base_host_command_sh }} -c '{{ devture_systemd_docker_base_host_command_docker }} rm matrix-wechat 2>/dev/null || true' + +ExecStartPre={{ devture_systemd_docker_base_host_command_docker }} create \ + --rm \ + --name=matrix-wechat \ + --log-driver=none \ + --user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ + --cap-drop=ALL \ + --network={{ matrix_wechat_container_network }} \ + --mount type=bind,src={{ matrix_wechat_config_path }},dst=/config,ro \ + --mount type=bind,src={{ matrix_wechat_data_path }},dst=/data \ + --workdir=/data \ + {% for arg in matrix_wechat_container_extra_arguments %} + {{ arg }} \ + {% endfor %} + {{ matrix_wechat_container_image }} \ + /usr/bin/matrix-wechat -c /config/config.yaml -r /config/registration.yaml --no-update +{% for network in matrix_wechat_container_additional_networks %} +ExecStartPre={{ devture_systemd_docker_base_host_command_docker }} network connect {{ network }} matrix-wechat +{% endfor %} + +ExecStart={{ devture_systemd_docker_base_host_command_docker }} start --attach matrix-wechat + +ExecStop=-{{ devture_systemd_docker_base_host_command_sh }} -c '{{ devture_systemd_docker_base_host_command_docker }} stop --time={{ devture_systemd_docker_base_container_stop_grace_time_seconds }} matrix-wechat 2>/dev/null || true' +ExecStop=-{{ devture_systemd_docker_base_host_command_sh }} -c '{{ devture_systemd_docker_base_host_command_docker }} rm matrix-wechat 2>/dev/null || true' +Restart=always +RestartSec=30 +SyslogIdentifier=matrix-wechat + +[Install] +WantedBy=multi-user.target diff --git a/setup.yml b/setup.yml index d93a71a2e..f284ec88c 100644 --- a/setup.yml +++ b/setup.yml @@ -58,6 +58,7 @@ - custom/matrix-bridge-appservice-kakaotalk - custom/matrix-bridge-beeper-linkedin - custom/matrix-bridge-go-skype-bridge + - custom/matrix-bridge-wechat - custom/matrix-bridge-mautrix-facebook - custom/matrix-bridge-mautrix-twitter - custom/matrix-bridge-mautrix-hangouts