diff --git a/work/notifications/README.md b/work/notifications/README.md index 36df7c8..20ba3a7 100644 --- a/work/notifications/README.md +++ b/work/notifications/README.md @@ -1,18 +1,11 @@ -# Notifications Work Area +# Notifications work area -This directory holds the public research notes for the `/notifications` -endpoint in relation to issue `#350`. +Research for `/notifications` and issue `#350`. -The protocol source of truth lives in: +Normative spec: `IETF-RFC.md`, `spec.yaml`. This directory is implementation notes and cross-stack notes under `research/`. -- `IETF-RFC.md` -- `spec.yaml` - -This place keeps only the research layer: - -- `research/` for implementation notes and cross-platform - observations - -Current documents: +Contents: - `research/README.md` +- `research/matrix-notification-types.md` (types + pinned code links) +- `research/examples/` (wire JSON in fenced blocks, `metadata.md`, `discrepancies.md`) diff --git a/work/notifications/research/README.md b/work/notifications/research/README.md index c3eebfd..b72dae8 100644 --- a/work/notifications/research/README.md +++ b/work/notifications/research/README.md @@ -1,19 +1,17 @@ -# Notifications Research +# Notifications research -This directory keeps the public research notes for `/notifications`. +Research notes for `/notifications`. -Current files: +- `matrix-notification-types.md` - types and where they live in code (pinned links) +- `examples/README.md` - layout of the example files +- `examples/metadata.md` - pinned commits (reva, Nextcloud, OCM-API spec cross-check) +- `examples/nextcloud-files.md`, `examples/nextcloud-talk.md`, `examples/nextcloud-calendar.md` - wire JSON + context +- `examples/reva-ocm-notifications.md` - reva `notify` bodies +- `examples/discrepancies.md` - spec vs code, and where stacks disagree +- `nextcloud-server.md`, `nextcloud-talk.md`, `ocis-reva.md`, `cernbox-reva.md`, `opencloud-reva.md` - per-platform notes -- `nextcloud-server.md` - File-oriented notes from the Nextcloud server inspection -- `nextcloud-talk.md` - Notes on `talk-room` and resource-event use of `/notifications` -- `ocis-reva.md` - Notes on the main non-Nextcloud contrast in this inspection -- `cernbox-reva.md` - Notes on route presence versus notification behavior -- `opencloud-reva.md` - Short notes on the current openCloud / reva notification path +Notes for ocis and owncloud/reva are in `ocis-reva.md`. Example JSON under +`examples/` uses cs3org/reva permalinks; `examples/metadata.md` explains how +that relates to owncloud/reva. -The platform files also keep a small list of the notification types -seen in code and the main send and receive paths for each stack. +Platform files list notification types and send/receive paths from code review. diff --git a/work/notifications/research/examples/README.md b/work/notifications/research/examples/README.md new file mode 100644 index 0000000..b360478 --- /dev/null +++ b/work/notifications/research/examples/README.md @@ -0,0 +1,22 @@ +# OCM notification examples (wire JSON) + +Each example is the HTTP JSON body for `/notifications`-style traffic: one object with `notificationType`, `resourceType`, `providerId`, and nested `notification`. Shapes come from the code paths named in each file; secrets are redacted. + +Provenance sits in the markdown (repo, file, method, which side sends). The fenced `json` blocks are the wire payload; metadata keys like `label` or `emission` never belong inside them. + +Commits and GitHub permalinks live in `metadata.md` (reva, Nextcloud, OCM-API spec cross-check). Links use `blob//path` so they do not break when `main` moves. + +Source first; tests where they exist (reva httptest) or the manual steps in `work/notifications/research/` otherwise. Placeholders are angle brackets or `REDACTED`. + +Files, Talk, Calendar, and reva `notify` at the pinned commit. More stacks can use the same layout. + +| File | What | +| ---- | ---- | +| `metadata.md` | Commits (reva, Nextcloud, OCM-API for spec links) | +| `nextcloud-files.md` | `resourceType` `file` | +| `nextcloud-talk.md` | `resourceType` `talk-room` | +| `nextcloud-calendar.md` | `resourceType` `calendar` | +| `reva-ocm-notifications.md` | reva `notify` output | +| `discrepancies.md` | Spec vs code; where stacks disagree | + +PR: rebase onto the target branch, run a secret scan on touched markdown, note any OpenAPI field-name mismatch beside the example. diff --git a/work/notifications/research/examples/discrepancies.md b/work/notifications/research/examples/discrepancies.md new file mode 100644 index 0000000..a253b03 --- /dev/null +++ b/work/notifications/research/examples/discrepancies.md @@ -0,0 +1,40 @@ +# Where spec text, code, and stacks disagree + +Permalinks are listed in [`metadata.md`](metadata.md) (OCM-API, reva, Nextcloud). + +I keep two things separate on purpose. [`ocis-reva.md`](../ocis-reva.md) describes owncloud/ocis and owncloud/reva at the commits I inspected: how the OCM service is wired, what the `/ocm/notifications` handler expects, and what still looked rough. The JSON examples in this folder use [cs3org/reva](https://github.com/cs3org/reva) permalinks because that is the tree the links in this repo point at. The same commit hash often appears on owncloud/reva when both forks carry the same revision. The split between these files is by topic (product wiring versus example JSON), not a claim about which fork is authoritative. + +## When servers do not match each other + +This section is informal notes from comparing implementations. It is not a complete interoperability matrix. + +- Reva `notify` emits `SHARE_CHANGE_PERMISSION`. Nextcloud Files uses `RESHARE_CHANGE_PERMISSION` on the file path ([`matrix-notification-types.md`](../matrix-notification-types.md) section 1). The OpenAPI [`notificationType` MAY list](https://github.com/cs3org/OCM-API/blob/2de5068e0b4755794b54670655d625bbd78615fc/spec.yaml#L768-L777) lists `RESHARE_CHANGE_PERMISSION`. Interoperation requires a mapping if peers compare `notificationType` as a plain string. +- Nextcloud Files uses `sharedSecret` heavily in outbound file traffic (matrix section 1). The oCIS / reva receive path in [`ocis-reva.md`](../ocis-reva.md) expects `grantee` and, for permission changes, `notification.protocol`. The remote has to send what the receiver implements, which is not always the same as the draft text. +- Nextcloud Files sends and receives many `notificationType` values. The reva `notify` switch I pinned only implements `SHARE_UNSHARED` and `SHARE_CHANGE_PERMISSION` ([`reva-ocm-notifications.md`](reva-ocm-notifications.md), matrix section 3). A type string that exists only on the Nextcloud side can fail on reva. +- On the Nextcloud Files receive path, `RESHARE_CHANGE_PERMISSION` calls `updateResharePermissions`, which throws (`HintException`, updating reshares not allowed) in the tree I read. Other layers may still report success. See matrix section 1.1 and [`nextcloud-server.md`](../nextcloud-server.md). +- [CERN / cs3org reva](../cernbox-reva.md) and [openCloud / reva](../opencloud-reva.md) were different in my pass: the route existed, but typed handling was minimal or absent. Check those files before assuming parity with Nextcloud or a full ocmd receiver. + +The per-codebase map lives in [`matrix-notification-types.md`](../matrix-notification-types.md) and the platform files under `research/`. + +## Reva `protocol` on notifications + +Share Creation defines `protocol` as one JSON **object**, not an array: + +- [`spec.yaml` `protocol`](https://github.com/cs3org/OCM-API/blob/2de5068e0b4755794b54670655d625bbd78615fc/spec.yaml#L555-L572) +- [`IETF-RFC.md` Share Creation](https://github.com/cs3org/OCM-API/blob/2de5068e0b4755794b54670655d625bbd78615fc/IETF-RFC.md#L873-L897) + +For permission-change notifications: + +- [`NewNotification`](https://github.com/cs3org/OCM-API/blob/2de5068e0b4755794b54670655d625bbd78615fc/spec.yaml#L761-L801) does not document `notification.protocol`. +- [`IETF-RFC.md` Share Updating](https://github.com/cs3org/OCM-API/blob/2de5068e0b4755794b54670655d625bbd78615fc/IETF-RFC.md#L1293-L1301): `RESHARE_CHANGE_PERMISSION` payload and side effects are out of scope. +- [`notificationType` MAY list](https://github.com/cs3org/OCM-API/blob/2de5068e0b4755794b54670655d625bbd78615fc/spec.yaml#L768-L777): `RESHARE_CHANGE_PERMISSION`; reva sends `SHARE_CHANGE_PERMISSION`. + +Reva fills `notification.protocol` with the same object encoding as Share Creation via [`protocols.go`](https://github.com/cs3org/reva/blob/823c2f1c2593ad310f49da2f68e35b757fb49e15/internal/http/services/ocmd/protocols.go) (reva pin in `metadata.md`). + +## Nextcloud envelope + +Nextcloud keeps the top-level fields stable (`notificationType`, `resourceType`, `providerId`, nested `notification`). Files and Talk diverge inside `notification`. The builder is [`CloudFederationNotification.php`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/lib/private/Federation/CloudFederationNotification.php) `setMessage`. + +## Talk `MESSAGE_POSTED` + +`messageData` / `unreadInfo` track the federated chat sync story; keys move with Spreed. I used [`BackendNotifier.php`](https://github.com/nextcloud/spreed/blob/76fd45d40827f76619942c9cd0a3323188dc6e42/lib/Federation/BackendNotifier.php) `sendMessageUpdate` at the Spreed pin. diff --git a/work/notifications/research/examples/metadata.md b/work/notifications/research/examples/metadata.md new file mode 100644 index 0000000..44fc552 --- /dev/null +++ b/work/notifications/research/examples/metadata.md @@ -0,0 +1,73 @@ +# Commits I pinned for these examples + +Label: `ocm-notifications-implementation-examples` + +Commits for the server, Spreed, and reva trees these notes came from. Use them when you diff the PHP or Go against the markdown and JSON in this folder. + +--- + +## Nextcloud server (Files + Calendar) + +| | | +| --- | --- | +| Repo | [nextcloud/server](https://github.com/nextcloud/server) | +| Branch | `master` | +| Commit | `f5faddaf31ebabd6f722e7b29f35d1f28c947259` | +| Version string (from `version.php` at the time) | `34.0.0 dev` | + +--- + +## Nextcloud Spreed (Talk) + +| | | +| --- | --- | +| Repo | [nextcloud/spreed](https://github.com/nextcloud/spreed) | +| Branch | `main` | +| Commit | `76fd45d40827f76619942c9cd0a3323188dc6e42` | + +--- + +## Reva (notify samples) + +The examples in this folder use [cs3org/reva](https://github.com/cs3org/reva) +for `blob/` links. [`ocis-reva.md`](../ocis-reva.md) is written against +[owncloud/reva](https://github.com/owncloud/reva) when the tree matched that +commit. The hash is the same in both places; only the GitHub org in the URL +changes. Line numbers can still drift between forks, so verify before you rely +on a permalink. + +The hash below exists on cs3org/reva; other forks may not match line-for-line. + +| | | +| --- | --- | +| Commit | `823c2f1c2593ad310f49da2f68e35b757fb49e15` | +| Branch | `main` | +| Open on GitHub | [cs3org/reva @ that commit](https://github.com/cs3org/reva/commit/823c2f1c2593ad310f49da2f68e35b757fb49e15) | + +--- + +## OCM-API (OpenAPI and IETF draft text) + +Cross-checks in `discrepancies.md` and `reva-ocm-notifications.md` use this tree. + +| | | +| --- | --- | +| Repo | [cs3org/OCM-API](https://github.com/cs3org/OCM-API) | +| Commit | `2de5068e0b4755794b54670655d625bbd78615fc` | +| Open on GitHub | [commit](https://github.com/cs3org/OCM-API/commit/2de5068e0b4755794b54670655d625bbd78615fc) | + +--- + +## Reva paths I keep pointing at + +Same commit as in the previous section. Permalinks all start from `https://github.com/cs3org/reva/blob/823c2f1c2593ad310f49da2f68e35b757fb49e15/`. + +| What | Path | +| ---- | ---- | +| Notify client tests | [`pkg/ocm/client/notify_payload_test.go`](https://github.com/cs3org/reva/blob/823c2f1c2593ad310f49da2f68e35b757fb49e15/pkg/ocm/client/notify_payload_test.go) | +| `notify` in the gRPC service | [`internal/grpc/services/ocmshareprovider/ocmshareprovider.go`](https://github.com/cs3org/reva/blob/823c2f1c2593ad310f49da2f68e35b757fb49e15/internal/grpc/services/ocmshareprovider/ocmshareprovider.go) (`notify`) | +| Protocol JSON shape | [`internal/http/services/ocmd/protocols.go`](https://github.com/cs3org/reva/blob/823c2f1c2593ad310f49da2f68e35b757fb49e15/internal/http/services/ocmd/protocols.go) | + +--- + +When you change a pin, update the permalinks in the same change. If you move the OCM-API pin, refresh every `blob/2de5068...` link under `work/notifications/research/examples/`. diff --git a/work/notifications/research/examples/nextcloud-calendar.md b/work/notifications/research/examples/nextcloud-calendar.md new file mode 100644 index 0000000..6ebfd48 --- /dev/null +++ b/work/notifications/research/examples/nextcloud-calendar.md @@ -0,0 +1,22 @@ +# Nextcloud Calendar: wire JSON for notifications + +Use the Nextcloud server commit from `metadata.md`. This file only documents one notification type. + +--- + +## SYNC_CALENDAR + +The notifier is [`CalendarFederationNotifier.php`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/apps/dav/lib/CalDAV/Federation/CalendarFederationNotifier.php) and the traffic is outbound. `providerId` is the fixed string `calendar` because that is what [`CalendarFederationProvider.php`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/apps/dav/lib/CalDAV/Federation/CalendarFederationProvider.php) exposes as `PROVIDER_ID`. + +```json +{ + "notificationType": "SYNC_CALENDAR", + "resourceType": "calendar", + "providerId": "calendar", + "notification": { + "sharedSecret": "", + "shareWith": "", + "calendarUrl": "https:///remote.php/dav/remote-calendars/<...>" + } +} +``` diff --git a/work/notifications/research/examples/nextcloud-files.md b/work/notifications/research/examples/nextcloud-files.md new file mode 100644 index 0000000..dfba6e2 --- /dev/null +++ b/work/notifications/research/examples/nextcloud-files.md @@ -0,0 +1,134 @@ +# Nextcloud Files: wire JSON for notifications + +The server commit and permalink base are in `metadata.md` under Nextcloud server. Above each fenced block I point to the PHP file; inside the fence is the POST body (`Content-Type: application/json`) and nothing else. + +Placeholders are angle brackets, not real credentials. + +--- + +## REQUEST_RESHARE + +Same server commit as in `metadata.md`. Built in [`Notifications.php`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/apps/federatedfilesharing/lib/Notifications.php), sent outbound to the remote peer. + +```json +{ + "notificationType": "REQUEST_RESHARE", + "resourceType": "file", + "providerId": "", + "notification": { + "sharedSecret": "", + "shareWith": "@", + "senderId": "", + "shareType": "user", + "message": "Ask owner to reshare the file" + } +} +``` + +--- + +## SHARE_UNSHARED (owner to recipient) + +Again [`Notifications.php`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/apps/federatedfilesharing/lib/Notifications.php), outbound. + +```json +{ + "notificationType": "SHARE_UNSHARED", + "resourceType": "file", + "providerId": "", + "notification": { + "sharedSecret": "", + "message": "file is no longer shared with you" + } +} +``` + +--- + +## RESHARE_UNDO + +Same [`Notifications.php`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/apps/federatedfilesharing/lib/Notifications.php), still outbound. + +```json +{ + "notificationType": "RESHARE_UNDO", + "resourceType": "file", + "providerId": "", + "notification": { + "sharedSecret": "", + "message": "reshare was revoked" + } +} +``` + +--- + +## SHARE_ACCEPTED (re-share chain toward owner) + +[`CloudFederationProviderFiles.php`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/apps/federatedfilesharing/lib/OCM/CloudFederationProviderFiles.php) emits this only in the re-share chain situations (owner vs sharedBy and the rest; read the file for the exact gate), and it is sent outbound like the other file notifications. + +```json +{ + "notificationType": "SHARE_ACCEPTED", + "resourceType": "file", + "providerId": "", + "notification": { + "sharedSecret": "", + "message": "Recipient accepted the re-share" + } +} +``` + +--- + +## SHARE_DECLINED (re-share chain toward owner) + +Same file and gating as the previous entry. [`CloudFederationProviderFiles.php`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/apps/federatedfilesharing/lib/OCM/CloudFederationProviderFiles.php). + +```json +{ + "notificationType": "SHARE_DECLINED", + "resourceType": "file", + "providerId": "", + "notification": { + "sharedSecret": "", + "message": "Recipient declined the re-share" + } +} +``` + +--- + +## SHARE_ACCEPTED (incoming external share) + +This one is built in [`External/Manager.php`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/apps/files_sharing/lib/External/Manager.php) and sent outbound. + +```json +{ + "notificationType": "SHARE_ACCEPTED", + "resourceType": "file", + "providerId": "", + "notification": { + "sharedSecret": "", + "message": "Recipient accept the share" + } +} +``` + +--- + +## SHARE_DECLINED (incoming external share) + +Same [`Manager.php`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/apps/files_sharing/lib/External/Manager.php) as the previous section, also outbound. + +```json +{ + "notificationType": "SHARE_DECLINED", + "resourceType": "file", + "providerId": "", + "notification": { + "sharedSecret": "", + "message": "Recipient declined the share" + } +} +``` diff --git a/work/notifications/research/examples/nextcloud-talk.md b/work/notifications/research/examples/nextcloud-talk.md new file mode 100644 index 0000000..f64a250 --- /dev/null +++ b/work/notifications/research/examples/nextcloud-talk.md @@ -0,0 +1,194 @@ +# Nextcloud Talk: wire JSON for notifications + +The Spreed commit I used is in `metadata.md` under Nextcloud Spreed. On the server side the envelope still goes through [`CloudFederationNotification`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/lib/private/Federation/CloudFederationNotification.php) at the server commit listed there. The fenced blocks are the JSON body as it goes on the wire. + +I traced the send path through [`BackendNotifier.php`](https://github.com/nextcloud/spreed/blob/76fd45d40827f76619942c9cd0a3323188dc6e42/lib/Federation/BackendNotifier.php); all of these are outbound toward the remote peer unless I say otherwise. + +--- + +## SHARE_ACCEPTED + +Outbound when the remote side accepts: `sendShareAccepted`. + +```json +{ + "notificationType": "SHARE_ACCEPTED", + "resourceType": "talk-room", + "providerId": "", + "notification": { + "remoteServerUrl": "", + "sharedSecret": "", + "message": "Recipient accepted the share", + "displayName": "", + "cloudId": "@" + } +} +``` + +--- + +## SHARE_DECLINED + +Outbound when the remote side declines: `sendShareDeclined`. + +```json +{ + "notificationType": "SHARE_DECLINED", + "resourceType": "talk-room", + "providerId": "", + "notification": { + "remoteServerUrl": "", + "sharedSecret": "", + "message": "Recipient declined the share" + } +} +``` + +--- + +## SHARE_UNSHARED + +Outbound unshare: `sendRemoteUnShare`. + +```json +{ + "notificationType": "SHARE_UNSHARED", + "resourceType": "talk-room", + "providerId": "", + "notification": { + "remoteServerUrl": "", + "sharedSecret": "", + "message": "This room has been unshared" + } +} +``` + +--- + +## PARTICIPANT_MODIFIED + +Participant field changes go through `sendParticipantModifiedUpdate`. + +```json +{ + "notificationType": "PARTICIPANT_MODIFIED", + "resourceType": "talk-room", + "providerId": "", + "notification": { + "remoteServerUrl": "", + "sharedSecret": "", + "remoteToken": "", + "changedProperty": "", + "newValue": "", + "oldValue": "" + } +} +``` + +--- + +## ROOM_MODIFIED (basic room property change) + +Plain room metadata changes use `sendRoomModifiedUpdate`. + +```json +{ + "notificationType": "ROOM_MODIFIED", + "resourceType": "talk-room", + "providerId": "", + "notification": { + "remoteServerUrl": "", + "sharedSecret": "", + "remoteToken": "", + "changedProperty": "", + "newValue": "", + "oldValue": "" + } +} +``` + +--- + +## ROOM_MODIFIED (call started variant) + +`sendCallStarted` covers the call-start variant of `ROOM_MODIFIED`. + +```json +{ + "notificationType": "ROOM_MODIFIED", + "resourceType": "talk-room", + "providerId": "", + "notification": { + "remoteServerUrl": "", + "sharedSecret": "", + "remoteToken": "", + "changedProperty": "", + "newValue": "", + "oldValue": null, + "callFlag": 0, + "details": {} + } +} +``` + +--- + +## ROOM_MODIFIED (lobby variant) + +`sendRoomModifiedLobbyUpdate` covers the lobby/timer branch of `ROOM_MODIFIED`. + +```json +{ + "notificationType": "ROOM_MODIFIED", + "resourceType": "talk-room", + "providerId": "", + "notification": { + "remoteServerUrl": "", + "sharedSecret": "", + "remoteToken": "", + "changedProperty": "", + "newValue": 0, + "oldValue": 0, + "dateTime": "", + "timerReached": false + } +} +``` + +--- + +## MESSAGE_POSTED + +[`MessageSentListener.php`](https://github.com/nextcloud/spreed/blob/76fd45d40827f76619942c9cd0a3323188dc6e42/lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php) ends up calling `sendMessageUpdate` on [`BackendNotifier.php`](https://github.com/nextcloud/spreed/blob/76fd45d40827f76619942c9cd0a3323188dc6e42/lib/Federation/BackendNotifier.php). The exact fields inside `messageData` and `unreadInfo` will move between Spreed releases; this block matches what I read at the pinned commit. + +```json +{ + "notificationType": "MESSAGE_POSTED", + "resourceType": "talk-room", + "providerId": "", + "notification": { + "remoteServerUrl": "", + "sharedSecret": "", + "remoteToken": "", + "messageData": { + "remoteMessageId": 0, + "actorType": "users", + "actorId": "", + "actorDisplayName": "", + "messageType": "comment", + "systemMessage": "", + "expirationDatetime": "", + "message": "", + "messageParameter": "[]", + "creationDatetime": "", + "metaData": "" + }, + "unreadInfo": { + "unreadMessages": 0, + "unreadMention": false, + "unreadMentionDirect": false, + "lastReadMessage": 0 + } + } +} +``` diff --git a/work/notifications/research/examples/reva-ocm-notifications.md b/work/notifications/research/examples/reva-ocm-notifications.md new file mode 100644 index 0000000..4302bbf --- /dev/null +++ b/work/notifications/research/examples/reva-ocm-notifications.md @@ -0,0 +1,68 @@ +# Reva: wire JSON from `notify` + +Commit is in `metadata.md` under reva. Permalinks use [cs3org/reva](https://github.com/cs3org/reva) at that hash (same tree I inspected). + +The `notify` switch in [`ocmshareprovider.go`](https://github.com/cs3org/reva/blob/823c2f1c2593ad310f49da2f68e35b757fb49e15/internal/grpc/services/ocmshareprovider/ocmshareprovider.go) emits the two cases below; other notification types hit the default branch and error out. I cross-checked the client side with [`notify_payload_test.go`](https://github.com/cs3org/reva/blob/823c2f1c2593ad310f49da2f68e35b757fb49e15/pkg/ocm/client/notify_payload_test.go). [`client.go`](https://github.com/cs3org/reva/blob/823c2f1c2593ad310f49da2f68e35b757fb49e15/pkg/ocm/client/client.go) sends them through `NotifyRemote` to `{remote_ocm_endpoint}/notifications`. For the Go structs, see [`payload.go`](https://github.com/cs3org/reva/blob/823c2f1c2593ad310f49da2f68e35b757fb49e15/pkg/ocm/client/payload.go). + +Each fenced `json` section is the raw HTTP body and nothing else. + +--- + +## SHARE_UNSHARED + +```json +{ + "notificationType": "SHARE_UNSHARED", + "resourceType": "file", + "providerId": "", + "notification": { + "grantee": "" + } +} +``` + +--- + +## SHARE_CHANGE_PERMISSION + +OCM-API pin for the links below is in [`metadata.md`](metadata.md). + +### Spec cross-check + +Share Creation defines `protocol` as one JSON object (`type: object`), not an array: + +- [`spec.yaml` `protocol`](https://github.com/cs3org/OCM-API/blob/2de5068e0b4755794b54670655d625bbd78615fc/spec.yaml#L555-L572) +- [`IETF-RFC.md` Share Creation](https://github.com/cs3org/OCM-API/blob/2de5068e0b4755794b54670655d625bbd78615fc/IETF-RFC.md#L873-L897) + +For `POST /notifications` I did not find a schema that lists inner keys on `notification`: + +- [`NewNotification`](https://github.com/cs3org/OCM-API/blob/2de5068e0b4755794b54670655d625bbd78615fc/spec.yaml#L761-L801) +- [`IETF-RFC.md` `/notifications` fields](https://github.com/cs3org/OCM-API/blob/2de5068e0b4755794b54670655d625bbd78615fc/IETF-RFC.md#L1059-L1070) +- [`IETF-RFC.md` Share Updating](https://github.com/cs3org/OCM-API/blob/2de5068e0b4755794b54670655d625bbd78615fc/IETF-RFC.md#L1293-L1301) leaves the `RESHARE_CHANGE_PERMISSION` payload out of scope +- [`notificationType` MAY list](https://github.com/cs3org/OCM-API/blob/2de5068e0b4755794b54670655d625bbd78615fc/spec.yaml#L768-L777) includes `RESHARE_CHANGE_PERMISSION`; the JSON below uses reva's `SHARE_CHANGE_PERMISSION` + +The remaining gap is the inner `notification` shape on this path and the type string, not whether `protocol` is an object. See [`discrepancies.md`](discrepancies.md). + +### Reva + +`notification.protocol` is produced by [`Protocols.MarshalJSON`](https://github.com/cs3org/reva/blob/823c2f1c2593ad310f49da2f68e35b757fb49e15/internal/http/services/ocmd/protocols.go), using the same object model as Share Creation `protocol`. + +```json +{ + "notificationType": "SHARE_CHANGE_PERMISSION", + "resourceType": "file", + "providerId": "", + "notification": { + "grantee": "", + "protocol": { + "name": "multi", + "options": {}, + "webdav": { + "sharedSecret": "", + "permissions": ["read", "write"], + "uri": "https://example.invalid/remote.php/dav/ocm/token" + } + } + } +} +``` diff --git a/work/notifications/research/matrix-notification-types.md b/work/notifications/research/matrix-notification-types.md new file mode 100644 index 0000000..e085302 --- /dev/null +++ b/work/notifications/research/matrix-notification-types.md @@ -0,0 +1,128 @@ +# Notification types matrix (what I saw in code) + +Source-level map of what shows up on the logical OCM notifications endpoint (`notificationType`, `resourceType`, `providerId`, nested `notification`). Normative text stays in `IETF-RFC.md` and `spec.yaml`. + +Commits and GitHub permalinks are in `research/examples/metadata.md` (Nextcloud server, Spreed, and [cs3org/reva](https://github.com/cs3org/reva) for the reva pin). + +For concrete JSON bodies, see `research/examples/nextcloud-files.md`, `nextcloud-talk.md`, `nextcloud-calendar.md`, `reva-ocm-notifications.md`. Tables here stay short; the examples carry the wire format. + +Placeholders in the tables are angle-bracket tokens, not real secrets. + +--- + +## 1. Nextcloud Files (`resourceType` `file`) + +### 1.1 Inbound `notificationReceived` + +Inbound handling is the switch in [`CloudFederationProviderFiles.php`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/apps/federatedfilesharing/lib/OCM/CloudFederationProviderFiles.php) `notificationReceived`. + + +| notificationType | Handler method | providerId semantics | +| ------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------ | +| SHARE_ACCEPTED | shareAccepted | Federated share id string `$id` (local id on receiver for `federatedShareProvider->getShareById($id)`) | +| SHARE_DECLINED | shareDeclined | Same | +| SHARE_UNSHARED | unshare | Same | +| REQUEST_RESHARE | reshareRequested | Same | +| RESHARE_UNDO | undoReshare | Same | +| RESHARE_CHANGE_PERMISSION | updateResharePermissions | Same (handler throws `HintException`: updating reshares not allowed in inspected code path) | + + +### 1.2 Outbound (emitted via OCM) + +| notificationType | Primary source file | Inner `notification` keys (summary) | +| ---------------- | ----------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | +| REQUEST_RESHARE | [`Notifications.php`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/apps/federatedfilesharing/lib/Notifications.php) | sharedSecret, shareWith, senderId, shareType, message | +| SHARE_UNSHARED | same | sharedSecret, message | +| RESHARE_UNDO | same | sharedSecret, message | +| SHARE_ACCEPTED | [`CloudFederationProviderFiles.php`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/apps/federatedfilesharing/lib/OCM/CloudFederationProviderFiles.php) (re-share chain to owner remote) | sharedSecret, message | +| SHARE_DECLINED | same | sharedSecret, message | +| SHARE_ACCEPTED | [`Manager.php`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/apps/files_sharing/lib/External/Manager.php) (incoming external share accept) | sharedSecret, message | +| SHARE_DECLINED | same | sharedSecret, message | + + +Outbound `providerId` for Files: remote share identifier (`remoteId` / `getRemoteId` depending on path). + +Envelope for senders: [`CloudFederationNotification.php`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/lib/private/Federation/CloudFederationNotification.php) method `setMessage`. + +### 1.3 User OCS triggers (not OCM JSON; they cause outbound notifications) + +Routes: [`routes.php`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/apps/files_sharing/appinfo/routes.php). Controller: [`RemoteController.php`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/apps/files_sharing/lib/Controller/RemoteController.php). + +--- + +## 2. Nextcloud Talk (`resourceType` `talk-room`) + +Constants: [`FederationManager.php`](https://github.com/nextcloud/spreed/blob/76fd45d40827f76619942c9cd0a3323188dc6e42/lib/Federation/FederationManager.php). + +Outbound: [`BackendNotifier.php`](https://github.com/nextcloud/spreed/blob/76fd45d40827f76619942c9cd0a3323188dc6e42/lib/Federation/BackendNotifier.php) (via `sendUpdateToRemote` -> `sendCloudNotification`). + +Inbound: [`CloudFederationProviderTalk.php`](https://github.com/nextcloud/spreed/blob/76fd45d40827f76619942c9cd0a3323188dc6e42/lib/Federation/CloudFederationProviderTalk.php) method `notificationReceived` (`providerId` numeric string cast to int for local attendee id). + + +| notificationType | Outbound methods (same file) | providerId | Inner keys (summary) | +| -------------------- | ----------------------------------------------------------------------------------- | ------------------ | ------------------------------------------------------------------------------- | +| SHARE_ACCEPTED | sendShareAccepted | remote attendee id | remoteServerUrl, sharedSecret, message, displayName, cloudId | +| SHARE_DECLINED | sendShareDeclined | remote attendee id | remoteServerUrl, sharedSecret, message | +| SHARE_UNSHARED | sendRemoteUnShare | local attendee id | remoteServerUrl, sharedSecret, message | +| PARTICIPANT_MODIFIED | sendParticipantModifiedUpdate | local attendee id | remoteServerUrl, sharedSecret, remoteToken, changedProperty, newValue, oldValue | +| ROOM_MODIFIED | sendRoomModifiedUpdate, sendCallStarted, sendCallEnded, sendRoomModifiedLobbyUpdate | local attendee id | Variants add callFlag, details, dateTime, timerReached | +| MESSAGE_POSTED | sendMessageUpdate | local attendee id | remoteServerUrl, sharedSecret, remoteToken, messageData, unreadInfo | + + +`MESSAGE_POSTED` path: [`MessageSentListener.php`](https://github.com/nextcloud/spreed/blob/76fd45d40827f76619942c9cd0a3323188dc6e42/lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php) -> `sendMessageUpdate`. + +--- + +## 3. Reva `notify` line (`resourceType` `file`) + +The table below is the pinned cs3org/reva tree. For how ocis wraps that service +and what the HTTP handler expects, see [`ocis-reva.md`](ocis-reva.md). + +Structs: [`payload.go`](https://github.com/cs3org/reva/blob/823c2f1c2593ad310f49da2f68e35b757fb49e15/pkg/ocm/client/payload.go). + +Runtime send: [`ocmshareprovider.go`](https://github.com/cs3org/reva/blob/823c2f1c2593ad310f49da2f68e35b757fb49e15/internal/grpc/services/ocmshareprovider/ocmshareprovider.go) function `notify`. + + +| notificationType | Sent by notify switch | Inner notification object | +| ----------------------- | --------------------- | -------------------------------------- | +| SHARE_UNSHARED | yes | grantee only (opaque user id) | +| SHARE_CHANGE_PERMISSION | yes | grantee + protocol (from getProtocols) | + + +Other `notificationType` strings: default branch in inspected `notify` returns error (see tests in [`pkg/ocm/client`](https://github.com/cs3org/reva/blob/823c2f1c2593ad310f49da2f68e35b757fb49e15/pkg/ocm/client/notify_payload_test.go)). + +HTTP: [`client.go`](https://github.com/cs3org/reva/blob/823c2f1c2593ad310f49da2f68e35b757fb49e15/pkg/ocm/client/client.go) `NotifyRemote` -> `POST` `{endpoint}/notifications`. + +Pins: `metadata.md` (reva and OCM-API commits). + +Permission-change: reva sends `SHARE_CHANGE_PERMISSION` and sets `notification.protocol` via [`protocols.go`](https://github.com/cs3org/reva/blob/823c2f1c2593ad310f49da2f68e35b757fb49e15/internal/http/services/ocmd/protocols.go) `Protocols.MarshalJSON`, same object model as Share Creation [`protocol`](https://github.com/cs3org/OCM-API/blob/2de5068e0b4755794b54670655d625bbd78615fc/spec.yaml#L555-L572). + +OpenAPI [`notificationType` MAY list](https://github.com/cs3org/OCM-API/blob/2de5068e0b4755794b54670655d625bbd78615fc/spec.yaml#L768-L777) and IETF [Share Updating](https://github.com/cs3org/OCM-API/blob/2de5068e0b4755794b54670655d625bbd78615fc/IETF-RFC.md#L1293-L1301) use `RESHARE_CHANGE_PERMISSION`. `NewNotification` does not document inner `notification` keys. See `research/examples/discrepancies.md`. + +--- + +## 4. Calendar (`resourceType` `calendar`) add-on + +Outbound: [`CalendarFederationNotifier.php`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/apps/dav/lib/CalDAV/Federation/CalendarFederationNotifier.php) method `notifySyncCalendar`. + +- notificationType: `SYNC_CALENDAR` (constant `NOTIFICATION_SYNC_CALENDAR`). +- providerId: literal string `calendar` (`CalendarFederationProvider::PROVIDER_ID` in [`CalendarFederationProvider.php`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/apps/dav/lib/CalDAV/Federation/CalendarFederationProvider.php)). +- Inner keys: sharedSecret, shareWith, calendarUrl. + +Inbound: [`CalendarFederationProvider.php`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/apps/dav/lib/CalDAV/Federation/CalendarFederationProvider.php) method `notificationReceived`. + +--- + +## 5. Signing (high level) + +Inbound: [`RequestHandlerController.php`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php) method `receiveNotification` uses signed request validation when signing is not disabled via app config. + +Outbound: [`OCMDiscoveryService.php`](https://github.com/nextcloud/server/blob/f5faddaf31ebabd6f722e7b29f35d1f28c947259/lib/private/OCM/OCMDiscoveryService.php) `requestRemoteOcmEndpoint` (signing on outgoing requests; JSON body shape unchanged vs unsigned path). + +--- + +## 6. Caveats + +- Files `RESHARE_CHANGE_PERMISSION`: receive path throws before useful work; no working permission update in the code I read. +- Talk: needs real federation to exercise; I did not capture every type on the wire. +- Calendar: `providerId` is the fixed string `calendar`, not a numeric share id like Files. diff --git a/work/notifications/research/ocis-reva.md b/work/notifications/research/ocis-reva.md index 48bbdd5..3f220d6 100644 --- a/work/notifications/research/ocis-reva.md +++ b/work/notifications/research/ocis-reva.md @@ -1,5 +1,13 @@ # oCIS And reva Research +I inspected owncloud/ocis and owncloud/reva at the commits below. This note +covers the oCIS side: how the OCM service is wired in, what the +`/ocm/notifications` handler checks, and what the outbound client sends. The +raw JSON samples are in `research/examples/reva-ocm-notifications.md`, with +cs3org/reva permalinks at the same commit as in this repo. That file follows the +cs3org URLs so the links stay consistent with the rest of the examples folder. +If you need to compare trees across forks, see [`examples/metadata.md`](examples/metadata.md). + Inspected repos: - `https://github.com/owncloud/ocis` @@ -31,8 +39,11 @@ The binding model is also different. Instead of leaning on it expects `providerId`, `grantee`, and, for permission changes, `protocol`. This is one visible cross-server difference in the current inspection. -The naming split is real too. ownCloud / reva uses `SHARE_CHANGE_PERMISSION`, -while Nextcloud still exposes `RESHARE_CHANGE_PERMISSION`. +There is also a naming split: ownCloud / reva uses `SHARE_CHANGE_PERMISSION`, +while Nextcloud still exposes `RESHARE_CHANGE_PERMISSION`. The MAY list in +[`spec.yaml`](https://github.com/cs3org/OCM-API/blob/2de5068e0b4755794b54670655d625bbd78615fc/spec.yaml#L768-L777) +at the OCM-API pin in `research/examples/metadata.md` uses the `RESHARE_*` +spelling. ## Notification Types And Code Paths