diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 17adc0012..2c409cf60 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -3,8 +3,9 @@ name: Build on: push: branches: - - main + - main_tchap - "release/**" + - "test/**" tags: - "v*" @@ -22,9 +23,9 @@ env: CARGO_NET_GIT_FETCH_WITH_CLI: "true" SCCACHE_GHA_ENABLED: "true" RUSTC_WRAPPER: "sccache" - IMAGE: ghcr.io/element-hq/matrix-authentication-service - IMAGE_SYN2MAS: ghcr.io/element-hq/matrix-authentication-service/syn2mas - BUILDCACHE: ghcr.io/element-hq/matrix-authentication-service/buildcache + IMAGE: ghcr.io/tchapgouv/matrix-authentication-service + IMAGE_SYN2MAS: ghcr.io/tchapgouv/matrix-authentication-service/syn2mas + BUILDCACHE: ghcr.io/tchapgouv/matrix-authentication-service/buildcache DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index jobs: @@ -313,7 +314,7 @@ jobs: # Only sign on tags and on commits on main branch if: | github.event_name != 'pull_request' - && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') + && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main_tchap') env: REGULAR_DIGEST: ${{ steps.output.outputs.metadata && fromJSON(steps.output.outputs.metadata).regular.digest }} @@ -329,7 +330,7 @@ jobs: syn2mas: name: Release syn2mas on NPM runs-on: ubuntu-24.04 - if: github.event_name != 'pull_request' + if: 'false' permissions: contents: read @@ -422,7 +423,7 @@ jobs: unstable: name: Update the unstable release - if: github.ref == 'refs/heads/main' + if: github.ref == 'refs/heads/main_tchap' runs-on: ubuntu-24.04 needs: diff --git a/policies/register/identity.rego b/policies/register/identity.rego new file mode 100644 index 000000000..4fcfdac67 --- /dev/null +++ b/policies/register/identity.rego @@ -0,0 +1,17 @@ +package identity + +headers = { + "Content-Type": "application/json", + "Accept": "application/json" +} + +url = sprintf("%s?medium=%s&address=%s", [data.external_service.url, "email", input.email]) + + +get_identity_info = http.send( + { + "method": "get", + "url": url, + "headers": headers + } +) \ No newline at end of file diff --git a/policies/register/register.rego b/policies/register/register.rego index 6a36f9611..3b51f6001 100644 --- a/policies/register/register.rego +++ b/policies/register/register.rego @@ -4,9 +4,13 @@ package register import rego.v1 +import data.identity import data.common import data.email as email_policy +import future.keywords.contains +import future.keywords.if +import future.keywords.in default allow := false @@ -92,3 +96,69 @@ violation contains object.union({"field": "email"}, v) if { # Get the violation object from the email policy some v in email_policy.violation } + + +# Violation for email on wrong homeserver +violation contains { + "field": "email", + "code": "email-wrong-homeserver", + "msg": "email is registered on a different homeserver" +} if { + # Check if email is present + input.email + + # Check if external service configuration exists + data.external_service + + # Get API response + identity_info_json := identity.get_identity_info + + # Check if "hs" is present in the response + "hs" in identity_info_json + + # Check if the hs does NOT match the server_name + identity_info_json.hs != data.server_name +} + +# Violation for email requiring invitation +violation contains { + "field": "email", + "code": "email-invitation-required", + "msg": "invitation required for this email" +} if { + # Check if email is present + input.email + + # Check if external service configuration exists + data.external_service + + # Get API response + identity_info_json := identity.get_identity_info + + # Check if "hs" is present and matches server_name + "hs" in identity_info_json + identity_info_json.hs == data.server_name + + # Check if requires_invite is true and invited is false + identity_info_json.requires_invite == true + identity_info_json.invited == false +} + +# Violation for email with missing hs field +violation contains { + "field": "email", + "code": "email-invalid-response", + "msg": "invalid response from identity server" +} if { + # Check if email is present + input.email + + # Check if external service configuration exists + data.external_service + + # Get API response + identity_info_json := identity.get_identity_info + + # Check if "hs" is NOT present in the response + not "hs" in identity_info_json +} diff --git a/policies/register/register_test.rego b/policies/register/register_test.rego index 040cdcc5d..235845377 100644 --- a/policies/register/register_test.rego +++ b/policies/register/register_test.rego @@ -2,6 +2,8 @@ package register_test import data.register import rego.v1 +import future.keywords.if +import future.keywords.in mock_registration := { "registration_method": "password", @@ -111,3 +113,51 @@ test_ip_ban if { } with data.requester.banned_user_agents.substrings as ["Evil"] } + +# Test external service allowing registration +test_external_service_allowed if { + # Create a test input with only the necessary fields + test_input := { + "username": "hello", + "email": "hello@example.com", + "registration_method": "password", + } + + register.allow with input as test_input + with as { + "url": "https://matrix.agent.agriculture.tchap.gouv.fr/_matrix/identity/api/v1/info" + } + with data.server_name as "matrix.org" +} + +mock_http_missing_hs_response(request) = response if { + response := { + "status_code": 200, + "body": { + "invited": true, + "requires_invite": false + } + } +} + +mock_http_wrong_hs_response(request) = response if { + response := { + "status_code": 200, + "body": { + "hs": "wrong.org", + "invited": true, + "requires_invite": false + } + } +} + +mock_http_requires_invite_response(request) = response if { + response := { + "status_code": 200, + "body": { + "hs": "matrix.org", + "invited": false, + "requires_invite": true + } + } +}