Skip to content

collaboration @user mentions review #3128

Closed

Description

@rhafer

Issues with the /collaboration/notify endpoint

We introduced a new public endpoint here that is un-documented and completely unspecified. I guess this should be reworked into something on the graph service.

Do we really need the functionality to bulk-notifiy a list of users? This provides quite some potential for abuse. If this was just a single request per notified user it should be far easier to impose rate-limits and other protection.

1. unused type field

The type field is validated as required but never read. It isn't put on the event or used for branching. The API contract forces clients to send a field that has no effect. It's documented nowhere what this field is supposed to be.

2. Requester's access to fileID is never checked, allows to send spoofed mentions

The only file-access check is that each mentioned user can Stat the file. Nothing verifies the executant has any relationship to fileID. Any user who knows/guesses a valid fileID and the userIDs of people who do have access can generate a real notification:

" mentioned you in Q3-Financials.docx" with a working resourceLink to the actual file.

This also means that the handler can be abused to figure out stuff like, "does user xyz have access to file abc". This could be a possible information disclosure issue.

3. No bound on userIDs, no dedup

userIDs is caller-controlled and iterated with no length cap, each iteration doing a gRPC Authenticate + Stat. A single request can fan out into a large number of gateway calls. There's also no dedup: repeating the same userID produces duplicate entries in event.UserIDs, and the downstream handleResourceMention builds recipients from that list without dedup, so a user can be emailed N times from one request. This allows to flood users with notifications.

4. A single failed recipient lookup or stat request aborts the whole notification - service.go:115-145

If any one mentioned user fails machine auth or lacks Stat access to the file, the handler returns 500 and no event is published for anyone.

5. All errors are mapped to status code 500

6 . Minor issues

  • HandleNotification() in service.go:

    • storagespace.ParseID(data.FileID) is called in every loop iteration, could be done outside, same is true for setting event.Ref
    • authResponse.Status.Code / statResponse.Status.Code should be GetStatus().GetCode() to avoid potential nil pointer panics
  • handleResourceMention in services/notification/pkg/service/resource.go:

    • logs "could not select next gateway client" for an error from GetServiceUserContextWithContext`.

Activity

  1. butonic commented on Aug 12, 2026

    @butonic
    Member

    In msgraph there are endpoints like /me/messages and /chats/{id}/messages or /teams/{id}/channels/{id}/messages they do not fit our mention only usecase.

    I found the correct endpoint: #3128 (comment)

    Never mind the below.

    I would propose a POST /notifications/mention endpoint that does not exist. Sthe like:

    POST /notifications/mention
    Content-Type: application/json
    Authorization: Bearer <token>
    
    {
      "resource": {
        "type": "document",
        "id": "a1b2c3d4-...-resourceid",
        "name": "Projektplan_2026.docx",
        "path": "/Projekte/OpenCloud/Projektplan_2026.docx",
        "url": "https://cloud.opencloud.test/f/a1b2c3d4"
      },
      "mentionedBy": {
        "id": "u-1001",
        "displayName": "Jörn Friedrich Dreyer",
        "email": "joern@example.org"
      },
      "mentioned": [
        {
          "id": "u-1042",
          "displayName": "Anna Schmidt",
          "email": "anna@example.org"
        }
      ],
      "createdDateTime": "2026-08-12T09:41:00Z"
    }

    with a response like

    201 Created
    Content-Type: application/json
    
    {
      "id": "notif-7f3e9c2a",
      "status": "queued",
      "deliveredVia": ["email", "inApp"],
      "recipients": [
        {
          "id": "u-1042",
          "channel": "email",
          "status": "queued"
        },
        {
          "id": "u-1042",
          "channel": "inApp",
          "status": "delivered"
        }
      ],
      "createdDateTime": "2026-08-12T09:41:00Z"
    }

    Although I don't think we should expose the delivery status.

  2. self-assigned this
    on Aug 12, 2026
  3. moved this from Qualification to In Progress in OpenCloud Team Boardon Aug 12, 2026
  4. butonic commented on Aug 14, 2026

    @butonic
    Member

    Sorry, I finally found the right endpoint: https://learn.microsoft.com/en-us/graph/api/userteamwork-sendactivitynotification?view=graph-rest-1.0&tabs=http

    POST https://cloud.opencloud.test/graph/v1.0/users/{userId}/teamwork/sendActivityNotification
    Content-Type: application/json
    
    {
        "topic": {
            "source": "entityUrl",
            "value": "https://cloud.opencloud.test/f/a1b2c3d4"
        },
        "activityType": "mentioned",
    }
    • The sender is identified by the auth token
    • The recipient is identified by the {userId} in the url
    • The resource is identified by the url in the value

    That being said, while source can also be text the value would then be unstructured text. With entityUrl it MUST be a url.
    We can use that to point to a resource, however then we would have to parse it on the serverside to find out the actual filename so we can render a template like "{actor} mentioned you in {entity}". The ms graph API allows sending templateParameters in the request because it expects trusted clients. DO NOT ALLOW THAT! It would allow end users to impersonate other people or change the name of the file. In our case the browser directly makes the request.

    The activityType=mentioned might be too unspecific. We actually want to say someone mentioned you in a file ... or rather a collabora session. So maybe activityType=webofficeMentioned.

    I don't like it ... 👀

    There is also the teamsAppId which we could use to distinguish which app mentioned the user: Collabora / EURO-Office or just the files app. Or the Maps app? The entityUrl value could then point to an app specific endpoint:

    But then we still have to check the url on the server side. I would prefer if we build a URL on the server side and do not trust a URL sent by the browser.

    I think with teamsAppId={some uuid for the app} + activityType=mention + topic.source=text + topic.value={cutom string} we can make this safe. For collabora we set topic.value={resourceid}. This allows us to stat the resource, check permissions and build the correct notification.

    The only question I have is: should the recipient open the resource directly in weboffice if he clicks it? With a fallback to the Files app if the other user already left the document? (This is another reason why a session URL in the topic.value might be bad: if the session is gone the user would get an error)

    Yeah ... so, I think that covers it:

    POST https://cloud.opencloud.test/graph/v1.0/users/{userId}/teamwork/sendActivityNotification
    Content-Type: application/json
    
    {
        "topic": {
            "source": "text",
            "value": "d21381aa-01dc-45cb-a5b8-e6880c47c954$5fd14bf4-64ef-4592-aa34-07d74b376def!7c7e4d1a-5073-48d7-b093-3024dc5938b6"
        },
        "teamsAppId": "{some app uuid}"
        "activityType": "mentioned",
    }

    Im inclined to also allow a simple string like weboffice or maps in the teamsAppId, but I would prefer uuids. They can be registered dynamically on the server side and are easier to maintain than dozens of apps called 'notes'.

    Further reading:

  5. fschade commented on Aug 14, 2026

    @fschade
    Member

    @butonic, done, thanks for the hint, just for reference, theres also a bulk api available, i think its fine for now, but maybe we can make use out of it too!

    https://learn.microsoft.com/en-us/graph/api/teamwork-sendactivitynotificationtorecipients?view=graph-rest-1.0&tabs=http

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions