Skip to content

Conversation

gkc
Copy link
Contributor

@gkc gkc commented Mar 2, 2025

Closes #1777

Currently end-users have to fully manage all of their profiles. We want to enable policy owners / administrators to have their policy management atSign “push” profiles to their end-users so that those profiles are visible and available for use (or removed, and unavailable for use) in near-real-time.

This PR currently only contains an initial spike. It illustrates the basic functionality but has the following limitations:
(1) It would permit 'spam' - i.e. any atSign could push profiles to any user
(2) It does not allow the end-user to remove or update these managed profiles as they wish, while still allowing for profiles to be deleted via the policy management atSign sending a deleteProfile event

Ongoing design discussion is here

- What I did

  • Modified the app so it dynamically updates its profiles list as another atSign shares / un-shares a profile
  • Created a very basic programme (npp_push) with hard-coded values to share and then un-share a profile

- How I did it

  • See commits, and comments on the Files Changed tab

- How to verify it

  • Run the desktop app from this branch
  • Modify packages/sshnoports/bin/npp_push.dart changing atSigns etc, then execute dart bin/npp_push.dart <profile name>

@@ -129,6 +131,9 @@ class _OnboardingButtonState extends State<OnboardingButton> {
}

Future<void> onboard({required String atsign, required String rootDomain, bool isFromInitState = false}) async {
SyncServiceImpl.queueSize = 1;
SyncServiceImpl.syncRequestThreshold = 1;
SyncServiceImpl.syncRequestTriggerInSeconds = 1;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

When we get a statsNotification that commitId has increased, we want to have the sync execute as soon as possible.

Dependence on sync for dynamic addition / removal of profiles is unlikely be part of the eventual solution.

await initializeContactsService(rootDomain: rootDomain);
AtClientManager.getInstance().atClient.syncService.addProgressListener(ProfileProgressListener());
AtClientManager.getInstance().atClient.syncService.sync();
atClient.syncService.addProgressListener(ProfileProgressListener(atClient));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

refactor to inject the atClient into the ProfileProgressListener

@@ -8,8 +8,11 @@ import 'package:npt_flutter/util/uuid.dart';

class ProfileRepository {
final Map<String, Profile> _profileCache = {};
final Map<String, String?> _profileSharedByMap = {};
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In this spike we need a way to keep track of who shared the profile so that when we actually fetch the profile from the datastore we can pass the correct sharedBy

if (ix >= 0) {
final uuid = key.key.substring(0, ix);
final sharedBy = key.sharedBy;
_profileSharedByMap[uuid] = sharedBy;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

keep track of the sharedBy

import 'package:npt_flutter/features/profile_list/bloc/profile_list_bloc.dart';
import 'package:npt_flutter/util/uuid.dart';

import '../../profile_list/cubit/sync_cubit.dart';

class ProfileProgressListener extends SyncProgressListener {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The spike approach was to subscribe to notifications auto-generated as a result of another atSign sharing or unsharing a profile. Receiving an update triggers a sync the results of which are later handled by the onSyncProgressEvent function below; receiving a delete removes the cached: profile and triggers a ProfileListLoadEvent for the ProfileListBlock

final profileListBlock =
App.navState.currentContext!.read<ProfileListBloc>();

bool profileSynced() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Check if this syncProgressEvent contained updates / deletes of any profiles


if (syncProgress.syncStatus == SyncStatus.success &&
(profileListBlock.state is ProfileListLoaded &&
profileListBlock.state is ProfileListLoaded &&
(profileSynced() ||
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Now triggering the ProfileListLoadEvent not just on the initial sync of the app, but on subsequent syncs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

feat: "Managed" profiles for NoPorts Desktop app
1 participant