Skip to content

feat: exchange cloud ID#4417

Open
redblom wants to merge 1 commit into
nextcloud:mainfrom
sara-nl:invite-for-cloudid-exchange
Open

feat: exchange cloud ID#4417
redblom wants to merge 1 commit into
nextcloud:mainfrom
sara-nl:invite-for-cloudid-exchange

Conversation

@redblom
Copy link
Copy Markdown

@redblom redblom commented Apr 8, 2025

This is a work in progress
This PR implements #4416

About

The goal of this feature is to allow for easy remote contact information exchange (cloud ID, email, name) between 2 users from different instances/organizations based on an invitation request.
The feature is an implementation of the invitation workflow from the OCM specification (https://datatracker.ietf.org/doc/draft-ietf-ocm-open-cloud-mesh/)

A user (sender) creates the invitation. This invitation consists of an invite link and (encoded) invite code. The invitation is sent to another user (receiver) via email or through another channel, eg. chat.
After receiving the invitation, the receiver can accept the invitation by following the invite link or by pasting the (encoded) invite code into a manual accept form.
After accepting, the exchange of user information will take place resulting in the creation of both users in each other's contacts list.
Following the invite link in the email is the most convenient way to accept. It will redirect the receiver via a WAYF (Where Are You From) page immediately to an accept dialog.
Note: Manual acceptance of the invitation works with both the invite link and (encoded) invite code.

Screenshots

1_contacts-app-main-page-Mike Contacts page with new buttons 'Invite contact', 'Accept invite' and 'All invites'.

2_fill-in-invite-form Click 'Invite contact' and fill in form fields:
  • Invite label for reference in the Invites list (optional)
  • Recipient email (required)
  • Personal message that will be sent with the email (optional)
  • Check to send copy of the invite email to yourself (optional)
3_invite-sent-list 'All invites' button displays the invites sent.

3a_alt-way-to-share-invite It's also possible to share the invite by sending the invite link or code through an alternative channel (eg. chat).

4_invite-email-to-Pete This what the email to the receiver of the invite looks like.

5_copy-of-invite-email-to-Pete This is what the copy of the email to the sender of the invite looks like.

6_wayf-page Clicking on the invite link will direct the receiver to a WAYF (Where Are You From) page.
Here you choose your institute. You can also fill in your institute's provider address if you are not on the list. A discovery process will run to check whether your provider supports OCM.

7_login-after-wayf-page-select-Pete Login after selecting your institute.

8_accept-invite You will be redirected to an invite accept dialog.

9_invite-accepted-Pete On acceptance the contact information exchange will take place via the OCM `/invite-accepted` endpoint. This will lead to the creation of a new contact (the sender) on the receiver's end.

10_invite-accepted-Mike And on the sender end the receiver contact info will also be added.

11_alt-invite-without-email-Jimmie When the config setting `ocm_invites_optional_mail` is set to false, creating an invite will give you by default the option to share the invite through an alternative channel (eg. chat).

12_alt-invite-no-email-copy-code Copy the invite link or code and send it via your channel of choice.

12a_alt-invite-with-email You may still decide to send the invite via email by clicking the 'Send via email' button.

13_alt-manual-accept-invite-Dan The receiver of the invite can click 'Accept invite' and manually paste the invite link, code, or encoded invite code into the accept form.
And this will lead to the exchange of contact information via the OCM /invite-accepted endpoint.

14_alt-manual-invite-accepted-Dan After contact info exchange the sender will be added as a new contact on the receiver's end.

15_alt-manual-invite-accepted-Jimmie And the receiver will be added as a new contact on the sender's end.

@hamza221 hamza221 added enhancement New feature or request 2. developing Work in progress labels Apr 8, 2025
@hamza221 hamza221 marked this pull request as draft April 8, 2025 09:14
@redblom
Copy link
Copy Markdown
Author

redblom commented Apr 8, 2025

General layout plan:

  • dedicated button to send an invite to a remote user - below 'New contact' button
  • dedicated button on cloud ID component for existing remote contacts that have no cloud ID set
  • new sent invites will be displayed in the left panel - with a revoke option

Status:

  • invite accept dialog route implemented

@hamza221 hamza221 added this to the v7.1.0 milestone Apr 10, 2025
@redblom redblom force-pushed the invite-for-cloudid-exchange branch from ea81812 to 7c0eaa0 Compare April 10, 2025 20:45
@github-actions
Copy link
Copy Markdown

Hello there,
Thank you so much for taking the time and effort to create a pull request to our Nextcloud project.

We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process.

Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6

Thank you for contributing to Nextcloud and we hope to hear from you soon!

(If you believe you should not receive this message, you can add yourself to the blocklist.)

@ChristophWurst
Copy link
Copy Markdown
Member

Thanks for the contribution, @redblom!

The features relies on an implementation of the Invitation Workflow (see https://github.com/sara-nl/nc-collaboration).

Is there any way this could work without introducing an app dependency?

@hamza221 hamza221 modified the milestones: v7.1.0, v7.2.0 Apr 28, 2025
@redblom
Copy link
Copy Markdown
Author

redblom commented Apr 29, 2025

Thanks for the contribution, @redblom!

The features relies on an implementation of the Invitation Workflow (see https://github.com/sara-nl/nc-collaboration).

Is there any way this could work without introducing an app dependency?

Short answer: No, that is to say, the actual cloud ID exchange is not a responsibility of the contacts app but the contacts app (the cloud ID field) is a logical place where to have this option (as per earlier discussion with the Design Team).
The feature actually depends on the implementation of OCM /invite-accepted. This is currently in the process of being implemented for nextcloud server core (nextcloud/server#51113) so cloud ID exchange can become an integral part of nextcloud. Up until then there should be an app present implementing this.
The idea is to make the option not visible to the user when the platform can not do the actual cloud ID exchange (by configuration).
(so the best answer is: yes, when cloud ID exchange has become an integral part of nextcloud :)

@redblom redblom force-pushed the invite-for-cloudid-exchange branch 2 times, most recently from 0112a78 to e7c2604 Compare April 30, 2025 14:32
@ChristophWurst
Copy link
Copy Markdown
Member

Thanks for the clarification

@ChristophWurst ChristophWurst requested review from ArtificialOwl and removed request for GVodyanov, SebastianKrupinski and hamza221 May 15, 2025 12:09
@redblom redblom force-pushed the invite-for-cloudid-exchange branch 5 times, most recently from 76d6df3 to ca42433 Compare June 18, 2025 14:33
@redblom redblom force-pushed the invite-for-cloudid-exchange branch from ca42433 to 62ce0c2 Compare June 26, 2025 08:21
@redblom redblom closed this Jan 26, 2026
@redblom redblom force-pushed the invite-for-cloudid-exchange branch from d6a02e3 to 9b66ad3 Compare January 26, 2026 07:52
@redblom redblom reopened this Jan 26, 2026
@redblom
Copy link
Copy Markdown
Author

redblom commented Jan 26, 2026

@ArtificialOwl modified to work with Nextcloud 33 OCM endpoint request event.

@redblom redblom marked this pull request as draft January 27, 2026 08:46
@redblom
Copy link
Copy Markdown
Author

redblom commented Jan 27, 2026

List of modifications - basically moving everything around the invite-accepted capability to this app:

  • move implementation of invite-accepted capability to this app - done
  • move registering invite-accepted capability to this app - done
  • move setting/getting InviteAcceptDialog property to this app - done
  • rename lib/Migration/Version1016Date202502262004.php - done

@redblom redblom force-pushed the invite-for-cloudid-exchange branch from b840503 to a5432b0 Compare January 30, 2026 16:18
@redblom redblom marked this pull request as ready for review February 3, 2026 14:25
@redblom redblom marked this pull request as draft February 3, 2026 14:26
@redblom redblom force-pushed the invite-for-cloudid-exchange branch from a5432b0 to aed6433 Compare February 3, 2026 14:41
@redblom redblom marked this pull request as ready for review February 3, 2026 14:41
@redblom redblom force-pushed the invite-for-cloudid-exchange branch from aed6433 to 299aea5 Compare February 18, 2026 11:24
@redblom
Copy link
Copy Markdown
Author

redblom commented Feb 18, 2026

  • Ping me and I'll enable the workflows

@miaulalala - ping !

@redblom redblom force-pushed the invite-for-cloudid-exchange branch from 299aea5 to 3984fd6 Compare April 7, 2026 14:25
@redblom redblom closed this Apr 8, 2026
@redblom redblom force-pushed the invite-for-cloudid-exchange branch from 3984fd6 to a4ce368 Compare April 8, 2026 14:56
@redblom redblom reopened this Apr 8, 2026
@redblom
Copy link
Copy Markdown
Author

redblom commented Apr 9, 2026

@miaulalala - What's wrong with the sign-off, maybe co-author is not allowed ?

@miaulalala
Copy link
Copy Markdown
Contributor

@miaulalala - What's wrong with the sign-off, maybe co-author is not allowed ?

No that's not the issue, one setting has Anton P., the other Anton P (no dot) 😅

@redblom redblom force-pushed the invite-for-cloudid-exchange branch from 4e4bdca to e78bd65 Compare April 9, 2026 11:08
@redblom
Copy link
Copy Markdown
Author

redblom commented Apr 9, 2026

@miaulalala - What's wrong with the sign-off, maybe co-author is not allowed ?

No that's not the issue, one setting has Anton P., the other Anton P (no dot) 😅

Pfff 😳

Comment thread appinfo/routes.php Outdated
['name' => 'contacts#direct', 'url' => '/direct/contact/{contact}', 'verb' => 'GET'],
['name' => 'contacts#directcircle', 'url' => '/direct/circle/{singleId}', 'verb' => 'GET'],

['name' => 'federated_invites#get_invites', 'url' => '/ocm/invitations', 'verb' => 'GET'],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those can be replaced by the following attribute. See suggestion in FederatedInvitesController

	#[Route(type: Route::TYPE_FRONTPAGE, verb: 'GET', url: '/ocm/invitations')]

* @return JSONResponse
*/
#[NoAdminRequired]
public function getInvites(): JSONResponse {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public function getInvites(): JSONResponse {
#[Route(type: Route::TYPE_FRONTPAGE, verb: 'GET', url: '/ocm/invitations')]
public function getInvites(): JSONResponse {

* @return JSONResponse with data signature ['token' | 'message'] - the token of the deleted invitation or an error message in case of error
*/
#[NoAdminRequired]
public function deleteInvite(string $token): JSONResponse {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And so on

Suggested change
public function deleteInvite(string $token): JSONResponse {
#[Route(type: Route::TYPE_FRONTPAGE, verb: 'DELETE', url: '/ocm/invitations/{token}')]
public function deleteInvite(string $token): JSONResponse {

Comment thread lib/Command/DisableOcmInvites.php Outdated
return self::SUCCESS;
}

$this->appConfig->setValueBool('contacts', 'ocm_invites_enabled', false);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's introduce a lexicon in Contacts so that new settings are tracked.

Documentation: https://docs.nextcloud.com/server/latest/developer_manual/digging_deeper/config/lexicon.html
Example: https://github.com/nextcloud-gmbh/server/blob/04172b855de465bc661034b32724ca394ffee3fe/apps/settings/lib/ConfigLexicon.php#L22

Suggested change
$this->appConfig->setValueBool('contacts', 'ocm_invites_enabled', false);
$this->appConfig->setValueBool(App::ID, 'ocm_invites_enabled', false);

Comment thread lib/Command/DisableOcmInvites.php Outdated
}

$this->appConfig->setValueBool('contacts', 'ocm_invites_enabled', false);
$this->appConfig->deleteKey('core', ConfigLexicon::OCM_INVITE_ACCEPT_DIALOG);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a clean up of the old key? If so this should go into a repair step: https://docs.nextcloud.com/server/latest/developer_manual/digging_deeper/repair.html

Comment thread lib/Listener/OcmDiscoveryListener.php Outdated
public function handle(Event $event): void {
if ($event instanceof LocalOCMDiscoveryEvent) {
$event->addCapability('invite-accepted');
$inviteAcceptDialog = $this->appConfig->getValueString('core', ConfigLexicon::OCM_INVITE_ACCEPT_DIALOG);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't this be a Contacts app settings instead of consuming the private one?

Comment thread lib/Service/FederatedInvitesService.php Outdated
}

public function isOcmInvitesEnabled():bool {
return $this->appConfig->getValueBool(Application::APP_ID, 'ocm_invites_enabled', FederatedInvitesService::OCM_INVITES_ENABLED_BY_DEFAULT);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use a lexicon.

Comment thread lib/Service/SocialApiService.php Outdated
Comment on lines +256 to +267
$addressBook = null;
$addressBooks = $this->manager->getUserAddressBooks();
foreach ($addressBooks as $_addressBook) {
// TODO properly resolve the correct addressbook to add the contact to
// Resolve by uri seems a bit risky ... can we be sure the uri equals 'contacts' ?
// Perhaps add to the first 'non system' addressbook we find ?
// (although we still would like to add to the 'Contacts' addressbook I guess)
if ($_addressBook->getUri() === 'contacts') {
$addressBook = $_addressBook;
break;
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe @ChristophWurst can give us the better way of doing this

Comment thread lib/WayfProvider.php Outdated
* @return array an array containing all mesh providers
*/
public function getMeshProviders(): array {
$urls = preg_split('/\s+/', trim($this->appConfig->getValueString(Application::APP_ID, 'mesh_providers_service')));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lexicon

Comment thread lib/WayfProvider.php Outdated
* @return array an array containing all mesh providers
*/
public function getMeshProvidersFromCache(): array {
$data = $this->appConfig->getValueArray(Application::APP_ID, 'federations_cache', [], true);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lexicon

@miaulalala
Copy link
Copy Markdown
Contributor

@redblom - can you check on artonge's review comments please?

@redblom
Copy link
Copy Markdown
Author

redblom commented May 4, 2026

@redblom - can you check on artonge's review comments please?

👍 working on it.

@redblom redblom force-pushed the invite-for-cloudid-exchange branch 2 times, most recently from 55dafdf to e05f396 Compare May 8, 2026 18:44
…ion workflow

see https://github.com/cs3org/OCM-API/blob/v1.2.1/IETF-RFC.md

Features:
 - Button to invite remote users to exchange cloudIDs.
 - Button to manually accept invite to exchange cloudIDs.
 - WAYF page allowing the receiver of the invite to open and accept the invitation.
 - Listing of open invitations.
 - Option to resend, revoke open invitations.

Signed-off-by: Antoon P. <antoon.prins@surf.nl>
Co-authored-by: Micke Nordin <kano@sunet.se>
Co-authored-by: Mahdi Baghbani <mahdi-baghbani@azadehafzar.io>
@redblom
Copy link
Copy Markdown
Author

redblom commented May 12, 2026

@redblom - can you check on artonge's review comments please?

@miaulalala We've now covered them all we think.

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

Labels

3. to review Waiting for reviews enhancement New feature or request feedback-requested

Projects

Status: 🏗️ At engineering

Development

Successfully merging this pull request may close these issues.

8 participants