diff --git a/pkgs/by-name/ma/matrix-authentication-service/matrix-authentication-service_rego.patch b/pkgs/by-name/ma/matrix-authentication-service/matrix-authentication-service_rego.patch new file mode 100644 index 00000000000000..3bb4ec3d1d6ab2 --- /dev/null +++ b/pkgs/by-name/ma/matrix-authentication-service/matrix-authentication-service_rego.patch @@ -0,0 +1,802 @@ +diff --git a/policies/authorization_grant.rego b/policies/authorization_grant.rego +index 0ce1d63d..4cc87dce 100644 +--- a/policies/authorization_grant.rego ++++ b/policies/authorization_grant.rego +@@ -3,39 +3,39 @@ + # - input: schema["authorization_grant_input"] + package authorization_grant + +-import future.keywords.in ++import rego.v1 + + default allow := false + +-allow { ++allow if { + count(violation) == 0 + } + + # Users can request admin scopes if either: + # 1. They are in the admin_users list +-can_request_admin(user) { ++can_request_admin(user) if { + some admin_user in data.admin_users + user.username == admin_user + } + + # 2. They have the can_request_admin flag set to true +-can_request_admin(user) { ++can_request_admin(user) if { + user.can_request_admin + } + +-interactive_grant_type("authorization_code") = true ++interactive_grant_type("authorization_code") := true + +-interactive_grant_type("urn:ietf:params:oauth:grant-type:device_code") = true ++interactive_grant_type("urn:ietf:params:oauth:grant-type:device_code") := true + + # Special case to make empty scope work +-allowed_scope("") = true ++allowed_scope("") := true + +-allowed_scope("openid") = true ++allowed_scope("openid") := true + +-allowed_scope("email") = true ++allowed_scope("email") := true + + # This grants access to Synapse's admin API endpoints +-allowed_scope("urn:synapse:admin:*") { ++allowed_scope("urn:synapse:admin:*") if { + # Synapse doesn't support user-less tokens yet, so access to the admin API + # can only be used with an authorization_code grant or a device code grant + # as the user is present +@@ -44,39 +44,39 @@ allowed_scope("urn:synapse:admin:*") { + } + + # This grants access to the /graphql API endpoint +-allowed_scope("urn:mas:graphql:*") = true ++allowed_scope("urn:mas:graphql:*") := true + + # This makes it possible to query and do anything in the GraphQL API as an admin +-allowed_scope("urn:mas:admin") { ++allowed_scope("urn:mas:admin") if { + interactive_grant_type(input.grant_type) + can_request_admin(input.user) + } + + # This makes it possible to get the admin scope for clients that are allowed +-allowed_scope("urn:mas:admin") { ++allowed_scope("urn:mas:admin") if { + input.grant_type == "client_credentials" + some client in data.admin_clients + input.client.id == client + } + +-allowed_scope(scope) { ++allowed_scope(scope) if { + # Grant access to the C-S API only if there is a user + interactive_grant_type(input.grant_type) + regex.match("^urn:matrix:org.matrix.msc2967.client:device:[A-Za-z0-9._~!$&'()*+,;=:@/-]{10,}$", scope) + } + +-allowed_scope("urn:matrix:org.matrix.msc2967.client:api:*") { ++allowed_scope("urn:matrix:org.matrix.msc2967.client:api:*") if { + # Grant access to the C-S API only if there is a user + interactive_grant_type(input.grant_type) + } + +-violation[{"msg": msg}] { ++violation contains {"msg": msg} if { + some scope in split(input.scope, " ") + not allowed_scope(scope) + msg := sprintf("scope '%s' not allowed", [scope]) + } + +-violation[{"msg": "only one device scope is allowed at a time"}] { ++violation contains {"msg": "only one device scope is allowed at a time"} if { + scope_list := split(input.scope, " ") + count({key | scope_list[key]; startswith(scope_list[key], "urn:matrix:org.matrix.msc2967.client:device:")}) > 1 + } +diff --git a/policies/authorization_grant_test.rego b/policies/authorization_grant_test.rego +index fc30f353..286a644b 100644 +--- a/policies/authorization_grant_test.rego ++++ b/policies/authorization_grant_test.rego +@@ -1,10 +1,12 @@ + package authorization_grant + ++import rego.v1 ++ + user := {"username": "john"} + + client := {"client_id": "client"} + +-test_standard_scopes { ++test_standard_scopes if { + allow with input.user as user + with input.client as client + with input.scope as "" +@@ -32,7 +34,7 @@ test_standard_scopes { + with input.scope as "profile" + } + +-test_matrix_scopes { ++test_matrix_scopes if { + allow with input.user as user + with input.client as client + with input.grant_type as "authorization_code" +@@ -49,7 +51,7 @@ test_matrix_scopes { + with input.scope as "urn:matrix:org.matrix.msc2967.client:api:*" + } + +-test_device_scopes { ++test_device_scopes if { + allow with input.user as user + with input.client as client + with input.grant_type as "authorization_code" +@@ -84,7 +86,7 @@ test_device_scopes { + with input.scope as "urn:matrix:org.matrix.msc2967.client:device:AAbbCCdd01" + } + +-test_synapse_admin_scopes { ++test_synapse_admin_scopes if { + allow with input.user as user + with input.client as client + with data.admin_users as ["john"] +@@ -138,7 +140,7 @@ test_synapse_admin_scopes { + with input.scope as "urn:synapse:admin:*" + } + +-test_mas_scopes { ++test_mas_scopes if { + allow with input.user as user + with input.client as client + with input.scope as "urn:mas:graphql:*" +diff --git a/policies/client_registration.rego b/policies/client_registration.rego +index 0104979c..d842d592 100644 +--- a/policies/client_registration.rego ++++ b/policies/client_registration.rego +@@ -3,26 +3,26 @@ + # - input: schema["client_registration_input"] + package client_registration + +-import future.keywords.in ++import rego.v1 + + default allow := false + +-allow { ++allow if { + count(violation) == 0 + } + +-parse_uri(url) = obj { ++parse_uri(url) := obj if { + is_string(url) + [matches] := regex.find_all_string_submatch_n("^(?P[a-z][a-z0-9+.-]*):(?://(?P((?:(?:[a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])\\.)*(?:[a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])|127.0.0.1|0.0.0.0|\\[::1\\])(?::(?P[0-9]+))?))?(?P/[A-Za-z0-9/.-]*)$", url, 1) + obj := {"scheme": matches[1], "authority": matches[2], "host": matches[3], "port": matches[4], "path": matches[5]} + } + +-secure_url(x) { ++secure_url(x) if { + x + data.client_registration.allow_insecure_uris + } + +-secure_url(x) { ++secure_url(x) if { + url := parse_uri(x) + url.scheme == "https" + +@@ -36,14 +36,14 @@ secure_url(x) { + url.port == "" + } + +-host_matches_client_uri(x) { ++host_matches_client_uri(x) if { + x + + # Do not check we allow host mismatch + data.client_registration.allow_host_mismatch + } + +-host_matches_client_uri(x) { ++host_matches_client_uri(x) if { + x + + # Do not check if the client_uri is missing and we allow that +@@ -51,103 +51,103 @@ host_matches_client_uri(x) { + not data.client_metadata.client_uri + } + +-host_matches_client_uri(x) { ++host_matches_client_uri(x) if { + client_uri := parse_uri(input.client_metadata.client_uri) + uri := parse_uri(x) + is_subdomain(client_uri.host, uri.host) + } + +-violation[{"msg": "missing client_uri"}] { ++violation contains {"msg": "missing client_uri"} if { + not data.client_registration.allow_missing_client_uri + not input.client_metadata.client_uri + } + +-violation[{"msg": "invalid client_uri"}] { ++violation contains {"msg": "invalid client_uri"} if { + not secure_url(input.client_metadata.client_uri) + } + +-violation[{"msg": "invalid tos_uri"}] { ++violation contains {"msg": "invalid tos_uri"} if { + input.client_metadata.tos_uri + not secure_url(input.client_metadata.tos_uri) + } + +-violation[{"msg": "tos_uri not on the same host as the client_uri"}] { ++violation contains {"msg": "tos_uri not on the same host as the client_uri"} if { + input.client_metadata.tos_uri + not host_matches_client_uri(input.client_metadata.tos_uri) + } + +-violation[{"msg": "invalid policy_uri"}] { ++violation contains {"msg": "invalid policy_uri"} if { + input.client_metadata.policy_uri + not secure_url(input.client_metadata.policy_uri) + } + +-violation[{"msg": "policy_uri not on the same host as the client_uri"}] { ++violation contains {"msg": "policy_uri not on the same host as the client_uri"} if { + input.client_metadata.policy_uri + not host_matches_client_uri(input.client_metadata.policy_uri) + } + +-violation[{"msg": "invalid logo_uri"}] { ++violation contains {"msg": "invalid logo_uri"} if { + input.client_metadata.logo_uri + not secure_url(input.client_metadata.logo_uri) + } + +-violation[{"msg": "logo_uri not on the same host as the client_uri"}] { ++violation contains {"msg": "logo_uri not on the same host as the client_uri"} if { + input.client_metadata.logo_uri + not host_matches_client_uri(input.client_metadata.logo_uri) + } + +-violation[{"msg": "missing contacts"}] { ++violation contains {"msg": "missing contacts"} if { + not data.client_registration.allow_missing_contacts + not input.client_metadata.contacts + } + +-violation[{"msg": "invalid contacts"}] { ++violation contains {"msg": "invalid contacts"} if { + not is_array(input.client_metadata.contacts) + } + +-violation[{"msg": "empty contacts"}] { ++violation contains {"msg": "empty contacts"} if { + count(input.client_metadata.contacts) == 0 + } + + # If the grant_types is missing, we assume it is authorization_code +-uses_grant_type("authorization_code") { ++uses_grant_type("authorization_code") if { + not input.client_metadata.grant_types + } + + # Else, we check that the grant_types contains the given grant_type +-uses_grant_type(grant_type) { ++uses_grant_type(grant_type) if { + some gt in input.client_metadata.grant_types + gt == grant_type + } + + # Consider a client public if the authentication method is none +-is_public_client { ++is_public_client if { + input.client_metadata.token_endpoint_auth_method == "none" + } + +-requires_redirect_uris { ++requires_redirect_uris if { + uses_grant_type("authorization_code") + } + +-requires_redirect_uris { ++requires_redirect_uris if { + uses_grant_type("implicit") + } + +-violation[{"msg": "client_credentials grant_type requires some form of client authentication"}] { ++violation contains {"msg": "client_credentials grant_type requires some form of client authentication"} if { + uses_grant_type("client_credentials") + is_public_client + } + +-violation[{"msg": "missing redirect_uris"}] { ++violation contains {"msg": "missing redirect_uris"} if { + requires_redirect_uris + not input.client_metadata.redirect_uris + } + +-violation[{"msg": "invalid redirect_uris"}] { ++violation contains {"msg": "invalid redirect_uris"} if { + not is_array(input.client_metadata.redirect_uris) + } + +-violation[{"msg": "empty redirect_uris"}] { ++violation contains {"msg": "empty redirect_uris"} if { + requires_redirect_uris + count(input.client_metadata.redirect_uris) == 0 + } +@@ -156,7 +156,7 @@ violation[{"msg": "empty redirect_uris"}] { + # another host. + # This is used so a redirect_uri like 'com.example.app:/' works for + # a 'client_uri' of 'https://example.com/' +-reverse_dns_match(host, reverse_dns) { ++reverse_dns_match(host, reverse_dns) if { + is_string(host) + is_string(reverse_dns) + +@@ -171,7 +171,7 @@ reverse_dns_match(host, reverse_dns) { + } + + # Used to verify that all the various URIs are subdomains of the client_uri +-is_subdomain(host, subdomain) { ++is_subdomain(host, subdomain) if { + is_string(host) + is_string(subdomain) + +@@ -185,27 +185,27 @@ is_subdomain(host, subdomain) { + array.slice(subdomain_parts, 0, count(host_parts)) == host_parts + } + +-valid_native_redirector(x) { ++valid_native_redirector(x) if { + url := parse_uri(x) + is_localhost(url.host) + url.scheme == "http" + } + +-is_localhost(host) { ++is_localhost(host) if { + host == "localhost" + } + +-is_localhost(host) { ++is_localhost(host) if { + host == "127.0.0.1" + } + +-is_localhost(host) { ++is_localhost(host) if { + host == "[::1]" + } + + # Custom schemes should match the client_uri, reverse-dns style + # e.g. io.element.app:/ matches https://app.element.io/ +-valid_native_redirector(x) { ++valid_native_redirector(x) if { + url := parse_uri(x) + url.scheme != "http" + url.scheme != "https" +@@ -216,17 +216,17 @@ valid_native_redirector(x) { + reverse_dns_match(client_uri.host, url.scheme) + } + +-valid_redirect_uri(uri) { ++valid_redirect_uri(uri) if { + input.client_metadata.application_type == "native" + valid_native_redirector(uri) + } + +-valid_redirect_uri(uri) { ++valid_redirect_uri(uri) if { + secure_url(uri) + host_matches_client_uri(uri) + } + +-violation[{"msg": "invalid redirect_uri", "redirect_uri": redirect_uri}] { ++violation contains {"msg": "invalid redirect_uri", "redirect_uri": redirect_uri} if { + some redirect_uri in input.client_metadata.redirect_uris + not valid_redirect_uri(redirect_uri) + } +diff --git a/policies/client_registration_test.rego b/policies/client_registration_test.rego +index e7510f98..2e46004c 100644 +--- a/policies/client_registration_test.rego ++++ b/policies/client_registration_test.rego +@@ -1,6 +1,8 @@ + package client_registration + +-test_valid { ++import rego.v1 ++ ++test_valid if { + allow with input.client_metadata as { + "grant_types": ["authorization_code"], + "client_uri": "https://example.com/", +@@ -9,7 +11,7 @@ test_valid { + } + } + +-test_missing_client_uri { ++test_missing_client_uri if { + not allow with input.client_metadata as { + "grant_types": [], + "contacts": ["contact@example.com"], +@@ -22,7 +24,7 @@ test_missing_client_uri { + with data.client_registration.allow_missing_client_uri as true + } + +-test_insecure_client_uri { ++test_insecure_client_uri if { + not allow with input.client_metadata as { + "grant_types": [], + "client_uri": "http://example.com/", +@@ -30,7 +32,7 @@ test_insecure_client_uri { + } + } + +-test_tos_uri { ++test_tos_uri if { + allow with input.client_metadata as { + "grant_types": [], + "client_uri": "https://example.com/", +@@ -81,7 +83,7 @@ test_tos_uri { + with data.client_registration.allow_host_mismatch as true + } + +-test_logo_uri { ++test_logo_uri if { + allow with input.client_metadata as { + "grant_types": [], + "client_uri": "https://example.com/", +@@ -132,7 +134,7 @@ test_logo_uri { + with data.client_registration.allow_host_mismatch as true + } + +-test_policy_uri { ++test_policy_uri if { + allow with input.client_metadata as { + "grant_types": [], + "client_uri": "https://example.com/", +@@ -183,7 +185,7 @@ test_policy_uri { + with data.client_registration.allow_host_mismatch as true + } + +-test_redirect_uris { ++test_redirect_uris if { + # Missing redirect_uris + not allow with input.client_metadata as { + "client_uri": "https://example.com/", +@@ -226,7 +228,7 @@ test_redirect_uris { + } + } + +-test_web_redirect_uri { ++test_web_redirect_uri if { + allow with input.client_metadata as { + "application_type": "web", + "client_uri": "https://example.com/", +@@ -309,7 +311,7 @@ test_web_redirect_uri { + } + } + +-test_native_redirect_uri { ++test_native_redirect_uri if { + # This has all the redirect URIs types we're supporting for native apps + allow with input.client_metadata as { + "application_type": "native", +@@ -375,13 +377,13 @@ test_native_redirect_uri { + } + } + +-test_reverse_dns_match { ++test_reverse_dns_match if { + client_uri := parse_uri("https://element.io/") + redirect_uri := parse_uri("io.element.app:/callback") + reverse_dns_match(client_uri.host, redirect_uri.scheme) + } + +-test_contacts { ++test_contacts if { + # Missing contacts + not allow with input.client_metadata as { + "grant_types": [], +@@ -410,7 +412,7 @@ test_contacts { + } + } + +-test_client_credentials_grant { ++test_client_credentials_grant if { + # Allowed for confidential clients + allow with input.client_metadata as { + "grant_types": ["client_credentials"], +@@ -434,14 +436,14 @@ test_client_credentials_grant { + } + } + +-test_is_subdomain { ++test_is_subdomain if { + is_subdomain("example.com", "example.com") + is_subdomain("example.com", "app.example.com") + not is_subdomain("example.com", "example.org") + not is_subdomain("test.com", "example.com") + } + +-test_reverse_dns_match { ++test_reverse_dns_match if { + reverse_dns_match("example.com", "com.example") + reverse_dns_match("example.com", "com.example.app") + not reverse_dns_match("example.com", "org.example") +diff --git a/policies/email.rego b/policies/email.rego +index fecad108..83a00ea6 100644 +--- a/policies/email.rego ++++ b/policies/email.rego +@@ -3,32 +3,32 @@ + # - input: schema["email_input"] + package email + +-import future.keywords.in ++import rego.v1 + + default allow := false + +-allow { ++allow if { + count(violation) == 0 + } + + # Allow any domains if the data.allowed_domains array is not set +-email_domain_allowed { ++email_domain_allowed if { + not data.allowed_domains + } + + # Allow an email only if its domain is in the list of allowed domains +-email_domain_allowed { ++email_domain_allowed if { + [_, domain] := split(input.email, "@") + some allowed_domain in data.allowed_domains + glob.match(allowed_domain, ["."], domain) + } + +-violation[{"msg": "email domain is not allowed"}] { ++violation contains {"msg": "email domain is not allowed"} if { + not email_domain_allowed + } + + # Deny emails with their domain in the domains banlist +-violation[{"msg": "email domain is banned"}] { ++violation contains {"msg": "email domain is banned"} if { + [_, domain] := split(input.email, "@") + some banned_domain in data.banned_domains + glob.match(banned_domain, ["."], domain) +diff --git a/policies/email_test.rego b/policies/email_test.rego +index efda51bd..779594a4 100644 +--- a/policies/email_test.rego ++++ b/policies/email_test.rego +@@ -1,25 +1,27 @@ + package email + +-test_allow_all_domains { ++import rego.v1 ++ ++test_allow_all_domains if { + allow with input.email as "hello@staging.element.io" + } + +-test_allowed_domain { ++test_allowed_domain if { + allow with input.email as "hello@staging.element.io" + with data.allowed_domains as ["*.element.io"] + } + +-test_not_allowed_domain { ++test_not_allowed_domain if { + not allow with input.email as "hello@staging.element.io" + with data.allowed_domains as ["example.com"] + } + +-test_banned_domain { ++test_banned_domain if { + not allow with input.email as "hello@staging.element.io" + with data.banned_domains as ["*.element.io"] + } + +-test_banned_subdomain { ++test_banned_subdomain if { + not allow with input.email as "hello@staging.element.io" + with data.allowed_domains as ["*.element.io"] + with data.banned_domains as ["staging.element.io"] +diff --git a/policies/register.rego b/policies/register.rego +index 05193549..edcad662 100644 +--- a/policies/register.rego ++++ b/policies/register.rego +@@ -3,38 +3,38 @@ + # - input: schema["register_input"] + package register + +-import data.email as email_policy ++import rego.v1 + +-import future.keywords.in ++import data.email as email_policy + + default allow := false + +-allow { ++allow if { + count(violation) == 0 + } + +-violation[{"field": "username", "msg": "username too short"}] { ++violation contains {"field": "username", "msg": "username too short"} if { + count(input.username) <= 2 + } + +-violation[{"field": "username", "msg": "username too long"}] { ++violation contains {"field": "username", "msg": "username too long"} if { + count(input.username) > 64 + } + +-violation[{"field": "username", "msg": "username contains invalid characters"}] { ++violation contains {"field": "username", "msg": "username contains invalid characters"} if { + not regex.match("^[a-z0-9.=_/-]+$", input.username) + } + +-violation[{"msg": "unspecified registration method"}] { ++violation contains {"msg": "unspecified registration method"} if { + not input.registration_method + } + +-violation[{"msg": "unknown registration method"}] { ++violation contains {"msg": "unknown registration method"} if { + not input.registration_method in ["password", "upstream-oauth2"] + } + + # Check that we supplied an email for password registration +-violation[{"field": "email", "msg": "email required for password-based registration"}] { ++violation contains {"field": "email", "msg": "email required for password-based registration"} if { + input.registration_method == "password" + + not input.email +@@ -42,7 +42,7 @@ violation[{"field": "email", "msg": "email required for password-based registrat + + # Check if the email is valid using the email policy + # and add the email field to the violation object +-violation[object.union({"field": "email"}, v)] { ++violation contains object.union({"field": "email"}, v) if { + # Check if we have an email set in the input + input.email + +diff --git a/policies/register_test.rego b/policies/register_test.rego +index 4d8d5476..e5853a60 100644 +--- a/policies/register_test.rego ++++ b/policies/register_test.rego +@@ -1,52 +1,54 @@ + package register + ++import rego.v1 ++ + mock_registration := { + "registration_method": "password", + "username": "hello", + "email": "hello@staging.element.io", + } + +-test_allow_all_domains { ++test_allow_all_domains if { + allow with input as mock_registration + } + +-test_allowed_domain { ++test_allowed_domain if { + allow with input as mock_registration + with data.allowed_domains as ["*.element.io"] + } + +-test_not_allowed_domain { ++test_not_allowed_domain if { + not allow with input as mock_registration + with data.allowed_domains as ["example.com"] + } + +-test_banned_domain { ++test_banned_domain if { + not allow with input as mock_registration + with data.banned_domains as ["*.element.io"] + } + +-test_banned_subdomain { ++test_banned_subdomain if { + not allow with input as mock_registration + with data.allowed_domains as ["*.element.io"] + with data.banned_domains as ["staging.element.io"] + } + +-test_email_required { ++test_email_required if { + not allow with input as {"username": "hello", "registration_method": "password"} + } + +-test_no_email { ++test_no_email if { + allow with input as {"username": "hello", "registration_method": "upstream-oauth2"} + } + +-test_short_username { ++test_short_username if { + not allow with input as {"username": "a", "registration_method": "upstream-oauth2"} + } + +-test_long_username { ++test_long_username if { + not allow with input as {"username": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "registration_method": "upstream-oauth2"} + } + +-test_invalid_username { ++test_invalid_username if { + not allow with input as {"username": "hello world", "registration_method": "upstream-oauth2"} + } +diff --git a/policies/util/coveralls.rego b/policies/util/coveralls.rego +index 881c7f6f..5ff50129 100644 +--- a/policies/util/coveralls.rego ++++ b/policies/util/coveralls.rego +@@ -1,6 +1,6 @@ + package coveralls + +-import future.keywords ++import rego.v1 + + from_opa := {"source_files": coverage} + +@@ -9,7 +9,7 @@ coverage contains obj if { + obj := {"name": file, "coverage": to_lines(report)} + } + +-covered_map(report) = cm if { ++covered_map(report) := cm if { + covered := object.get(report, "covered", []) + cm := {line: 1 | + some item in covered +@@ -17,7 +17,7 @@ covered_map(report) = cm if { + } + } + +-not_covered_map(report) = ncm if { ++not_covered_map(report) := ncm if { + not_covered := object.get(report, "not_covered", []) + ncm := {line: 0 | + some item in not_covered +@@ -25,7 +25,7 @@ not_covered_map(report) = ncm if { + } + } + +-to_lines(report) = lines if { ++to_lines(report) := lines if { + cm := covered_map(report) + ncm := not_covered_map(report) + keys := sort([line | some line, _ in object.union(cm, ncm)]) +@@ -37,15 +37,15 @@ to_lines(report) = lines if { + ] + } + +-to_value(cm, _, line) = 1 if { ++to_value(cm, _, line) := 1 if { + cm[line] + } + +-to_value(_, ncm, line) = 0 if { ++to_value(_, ncm, line) := 0 if { + ncm[line] + } + +-to_value(cm, ncm, line) = null if { ++to_value(cm, ncm, line) := null if { + not cm[line] + not ncm[line] + } + diff --git a/pkgs/by-name/ma/matrix-authentication-service/package.nix b/pkgs/by-name/ma/matrix-authentication-service/package.nix index 233303caa62a30..ec5a914fdab9d4 100644 --- a/pkgs/by-name/ma/matrix-authentication-service/package.nix +++ b/pkgs/by-name/ma/matrix-authentication-service/package.nix @@ -92,6 +92,8 @@ rustPlatform.buildRustPackage rec { cp -r translations "$out/share/$pname/translations" ''; + patches = [ ./matrix-authentication-service_rego.patch ]; + meta = { description = "OAuth2.0 + OpenID Provider for Matrix Homeservers"; homepage = "https://github.com/element-hq/matrix-authentication-service";