-
Notifications
You must be signed in to change notification settings - Fork 60
Conversation
For the first implementation, I'd recommend starting with acquisition method 3: passing the requested permissions at initialization time, although I disagree with the third sub-bullet regarding whether the app should proceed or not. It shouldn't be an all-or-nothing decision at startup. See comments lower down for how I think this should work. Now would be a good time to think about how the permissions UI should work. I'd steer clear of popup dialogs. How about a new button on the control bar (near the host panel) that would open an SDK App Control Panel. The button would show a notification when one or more apps is requesting permissions. I'd include these additional permissions:
Consider making permissions tri-state: "Disallow", "Allow this time", "Allow always". On the control panel, the user should also be able to:
Thinking about how this works from the app's perspective: The app won't get its requested permissions right away, different permissions may come in at different times, and the user could revoke a permission at any time. I think this warrants a new callback on Context: App permissions should be persisted on the backend (so they follow the user from device to device). Permissions must be enforced on the client, not in the SDK. Otherwise anyone could modify the SDK to circumvent it. #Resolved |
I agree with mostly what Eric has said. The third acquiring option seems in line with the most ideal v1 solution and shouldn't necessarily be an all or nothing gate. Also the additional permissions proposed for "me", audio, and video also make a lot of sense. The three states of permission also seems in line with many other permissioning models out there. I think that the UI conversation is something that needs to be had at the Altspace level. Currently we have not enforced a specific UI or interaction model for MRE management, so I think this should be vetted with Altspace as the first shipped customer. As a client runtime for an SDK, I think that the specific UI/UX experience for managing MRE's is something that should exist outside of the SDK. We can certainly recommend ways to handle it and implement them in the Test Bed and potentially Altspace, but I want to encourage that we focus on how we present the collection of permissions from the client API surface as a clear deliverable for this feature, rather than on enforcing how this is handled in a host apps UI. #Resolved |
Though I do like the idea of a popup MRE panel like the host tools in Altspace for the specific UI case in Altspace. #Resolved |
@eanders-ms @tombuMS The "me" permission can already be implemented host-side since there are no MRE requirement that clients have to join as a user. Ditto the "video" permission since it goes through a non-default factory. I don't think I've seen any other cases of explicit permission being needed to play sound, though I agree that a master volume control host-side is desirable. I'd like to keep the discussion of UI implementations out of this review if possible, given that different hosts can implement it differently. Let's decide what the API surface should look like, then design a UI around that. As an app developer, IMO the more external async dependencies your app has, the harder it becomes to reason about. I don't like the idea of different permissions being granted at different times for the same user, seems like it would add a lot of complexity for using those gated features. My preference leans towards acquisition 3, failure mode 2: request all permissions during setup, and users grant permissions as a condition of joining. #Resolved |
I actually think that will work just fine. The |
Great work Steven, and great comments. I agree with most, but not all, of Eric's and Tom's comments.
#Resolved |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(see feedback above)
design/permissions.md
Outdated
* `string appOrigin` - The origin of the MRE requesting permission, as described above. | ||
* `string appDisplayName` - A human-readable identifier for the MRE server provided from the manifest. | ||
* `Permissions permissionsNeeded` - A bitfield of the permissions required to run the app. | ||
* `Permissions permissionsWanted` - A bitfield of permissions that the app can use, but are not needed to run. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is something being passed to a host app, we may want to consider passing this in a more friendly unpacked format, so that the host app can easily digest this for their UI. Otherwise the parsing of the bitfield in to actionable items and repacking has to happen as code written by each host app. If we send this as something already parsed and receive in the same unpacked manner, we can abstract away the need to deal with separating out actionable items from a bitfield. Maybe an array of Permissions enum value that can easily be iterated over to add prompts to an overall UI? #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact based on this proposal, the json will already contain an array of permission strings that could be passed along as is to this call to the host app. You could just wait until the permissions task has completed before you pack this in to a bitfield of approved permissions.
In reply to: 441643214 [](ancestors = 441643214)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good point: since we're sending the perms down as arrays, there's no point in repacking them. I like bitfields because of O(1) lookups, but for <32 items I suppose it doesn't matter.
In reply to: 441644095 [](ancestors = 441644095,441643214)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean still packing for lookups is fine, I was just suggesting doing that packing after the host app has gathered the approved permissions. #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm pretty sure C# lets you do foreach loops on bitfields of enums. It's cool like that. Might not matter, even for enumeration. I'll play with this come implementation time.
In reply to: 441733983 [](ancestors = 441733983)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit convoluted how you have to iterate over the values of the enum, but there is a way. It is still easier at this point since the message is carrying as an array of values to just pass that array in to the dialog and receive one back.
In reply to: 441766267 [](ancestors = 441766267,441733983)
design/permissions.md
Outdated
The default implementation of the permissions manager will also include the following virtual methods: | ||
|
||
* `void ReadFromStorage()` - Populate the in-memory permission database from offline storage. | ||
* `void WriteToStorage()` - Write the "remembered" portions of the in-memory permission database to offline storage. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this storage we would be providing and interfacing with in our runtime code, since this refers to a default permission manager? Does this mean that no permission manager is required to be supplied by the host app? #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The interface does not require any kind of persistent storage. But since most hosts will probably want it, the MRE namespace will also have an abstract base implementation that provides some stubs. Haven't worked out all the details here yet.
In reply to: 441648519 [](ancestors = 441648519)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. So the stubs are not for a default implementation of local storage then. They are just for optional hooks to the permission manager supplied by the host app? #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
requests `user-interaction`, that permission is associated with `ws://mres.altvr.com`, and all user decisions apply | ||
equally to new connections to the same server. These user decisions may or may not be persisted indefinitely by the host app. | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the host app should decide the scope here.
I'd also recommend rights to be managed by AppId over URL, if AppId is available
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you explain your reasoning for hosts making the scope determination? I can see the case for AppId over URL origin, because AppIds can uniquely identify an app and not just a server. I disagree, and think server trust is all that's required since there won't be origins with apps from multiple authors, and it's the author that the user is ultimately trusting.
In reply to: 441849523 [](ancestors = 441849523)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I should have worded that differently. I wanted to say that I don't think we should assume that scope goes beyond the single app, and the host app should ask the user if they would want to permit all apps, all apps by same developer, or a single app.
I, as a user, wouldn't want the assumption made about other apps for me. Just because I want to grant one app a specific permission, doesn't mean that all other apps that are deployed to the same root url should have the same permissions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So how do you define a single app, the full URL? Does it include query arguments? The more specific we get, the more nag screens the users are gonna be presented with. I think origin strikes a good balance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, a unique app to me is the full URL but excluding query arguments.
I think the best analogy is phone apps: If I install an app on my phone and I grant a permission, it shouldn't automatically grant permission to all other apps by that publisher. But if I launch the app with a different deep link, the permissions given to the app before still apply.
Agree that there will be more nag screens. To me that's up to the host app for how to manage. I imagine "yes/no once", "yes/no for this MRE always", "yes/no for all MREs always" would be required. It could be optional to add "yes/no for all MREs on this domain" (or "by this publisher" once MRE App registry is done), but I see that as lower priority
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🕐
*/ | ||
export enum Permissions { | ||
/** | ||
* Grants access to a persistent user identity across sessions. Needed for things like high scores lists or |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[](start = 99, length = 1)
comma
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This window is paginated, one page per MRE that requires permissions. The name of the app requesting permission, the | ||
server name it's hosted on, and a secure protocol indicator are all featured prominently. Each permission has a | ||
checkbox next to it: required permissions are checked and disabled, and optional permissions are checked or not based | ||
on app origin decision history and settings. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: indicate the number of pending requests in the tab label, like the friends requests UI does
"description": "An SPDX short license ID", | ||
"type": "string" | ||
}, | ||
"repositoryUri": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uri [](start = 13, length = 3)
Url, not Uri
"description": "A set of samples that exercise various features of the Mixed Reality Extensions SDK", | ||
"author": "Microsoft", | ||
"license": "MIT", | ||
"repositoryUri": "https://github.com/microsoft/mixed-reality-extension-sdk", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uri [](start = 12, length = 3)
Url #Resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No description provided.