Skip to content

Design Doc: Provider Contexts #2311

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
2 changes: 2 additions & 0 deletions designdocs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ To create a new design document, Please see the [Design Doc README](https://gith
- [PR](https://github.com/frequency-chain/frequency/pull/900)
- [Graph Sdk](./graph_sdk.md)
- [PR](https://github.com/frequency-chain/frequency/pull/1159)
- [Provider Contexts](./provider_contexts.md)
- [PR](https://github.com/frequency-chain/frequency/pull/2311)

## Basic Data Model

Expand Down
232 changes: 232 additions & 0 deletions designdocs/provider_contexts.md
Copy link
Collaborator

Choose a reason for hiding this comment

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

I detect some synergy here with the concept of namespaces, as discussed in #2312 . Provider/application registration and governance flow seems like an appropriate place to put that functionality...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Hmm... I'll have to think on this. It does feel like a future version of governance has a separate committee to handle this.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I do mention in my doc, that this kind of brings up the issue of whether we should "take the plunge" on at least a partial ENS implementation, which would handle the governance and ownership aspects of names/namespaces across all pallets/contracts.

Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
# Provider Contexts Design Doc

## Context and Scope

On Frequency, a Provider may either represent an application or a company.
This document will outline the changes that will allow a Provider to represent a company with one or multiple applications.
It also enables social wallet providers, custodial and non-custodial, to provide safe application information to their users.

This is an expansion of the [Registered Provider](https://github.com/frequency-chain/frequency/blob/main/designdocs/provider_registration.md) concepts.

Reference Document: [SIWF Specification](https://projectlibertylabs.github.io/siwf/v2/docs/)

### Why Is This Needed?

#### Concept of an Application Separate from a Provider

Many companies have a single major product, but some companies have multiple applications that serve different needs.
While each application could be a separate provider, this causes two issues: The sharing of capacity and the user permissions.

Having separate providers would require a single company to have separate Capacity staking for each application.
As each these applications are part of the same company, those applications should share Capacity as a single legal entity.

Separate providers per application would NOT align with the data security model of user-to-company that exists in the world today.
Provider-level delegations are better than introducing application-level delegations.
While user permissions are primarily write-based at this time, it is critical that users understand the delegation and their data is shared at a company level.


Finally, this structure does not prevent the setup of a 1:1 relationship between Application and Provider.
If a company wishes, they can create more than one Provider for the purposes of separation.
This may be desirable if there is a subsidiary company or other complex structures.

#### User Trust in Application Presentation

Users need to know what application they are logging into and trust that the displayed information is not a phishing attack.
Users have a reasonable expectation that the chain and wallet provide a level of protection against phishing attacks from Providers and Applications.

#### Easy Wallet Integration of Data

Wallets displaying login request information need to be able to easily obtain and verify the information they want to show the user.

## Proposal

Frequency should provide a safeguarded system of setting and updating Provider and Provider Application Contexts for wallets to display to users.

- [Storage and Structure of the Data](#data)
- [Mainnet Approval Flow](#governance)
- [Example of Wallet Usage via SIWF](#siwf)
- [Provider Dashboard Steps](#dashboard)

### **Storage and Structure of the Data** <a id='data'></a>

Currently, the `ProviderRegistryEntry` has only a `name` property, and no way to update said name.

Applications have two different pieces of default and (potentially) internationalized data:
- name
- logo/image

Limits
1. Provide a space to internationalize up to 150 localizations (Windows and macOS each have < 150).
2. Image MUST BE encoded (`png`)[https://www.w3.org/TR/png-3/] that is `250x100` (support for future sizes and light/dark should be considered).

The data structure must support both of these and internationalization.

Proposed are the following changes:

1. `ProviderRegistryEntry` struct be renamed `ApplicationRegistryEntry`
2. `ApplicationRegistryEntry` have the following properties:
```rust
pub struct ApplicationRegistryEntry<T, U>
where
T: Get<u32>,
U: Get<u32>,
{
pub default_name: BoundedVec<u8, T>,
pub localized_names: BTreeMap<Vec<u8>, BoundedVec<u8, T>>,
pub default_logo_250_100_png_bytes: BoundedVec<u8, U>,
pub localized_logo_250_100_png_bytes: BTreeMap<Vec<u8>, BoundedVec<u8, U>>,
}
```
3. The `ProviderToRegistryEntry` be updated to use `ApplicationRegistryEntry` so that the Provider has a "default" `ApplicationRegistryEntry`.
```rust
#[pallet::storage]
pub type ProviderToRegistryEntry<T: Config> = StorageMap<
_,
Twox64Concat,
ProviderId,
ApplicationRegistryEntry<T::MaxProviderNameSize, T::MaxProviderLogo250X100Size>,
OptionQuery,
>;
```
4. New `ProviderToApplicationRegistryEntry` storage be initialized:
```rust
// Alias for clarity
type ApplicationIdentifier<T: Config> = BoundedVec<u8, T::MaxProviderNameSize>

#[pallet::storage]
pub type ProviderToApplicationRegistryEntry<T: Config> = StorageDoubleMap<
_,
Twox64Concat,
ProviderId,
Twox64Concat,
ApplicationIdentifier<T>,
ApplicationRegistryEntry<T::MaxProviderNameSize, T::MaxProviderLogo250X100Size>,
OptionQuery,
>;
```
Comment on lines +80 to +106
Copy link
Collaborator

Choose a reason for hiding this comment

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

I appreciate the reuse of the ApplicationRegistryEntry structure, but I think they will end up diverging (either over time, or before this document is accepted...). ProviderRegistryEntry may end up containing more information regarding the Provider as a legal entity (similar to a DNS record), while ApplicationRegistryEntry would not necessarily evolve in such a way, being more or less a marketing distinction drawn by the Provider.

ex:
Provider Meta could/should reference information about the real-world ownership + "trustworthiness" of said entity.
Applications Meta.Facebook, Meta.Instagram, and Meta.Threads, being simply different product offerings of the owning entity, need have nothing other than name+icon (possible other descriptive fields, but entirely at the discretion of the Provider to describe).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think it is reasonable to at least alias or even duplicate the ApplicationRegistryEntry to a separate ProviderRegistryEntry. For clarity if nothing else.

I would sat that your namespacing is what ProviderToApplicationRegistryEntry does: <ProviderId>.<ApplicationId>

That said, I'm not sure the trustworthiness can remain at the Provider level. For your example, it would be important that Meta.Threads has the validated DNS: threads.net and that it not apply to other Meta applications.

I am trying (and perhaps this is part of the issue here) to avoid needing to have every Provider also complete the Application data. Given that I expect <50% need both. Perhaps a better way to handle this is flipping the naming around. Rename ApplicationRegistryEntry to ProviderRegistryEntry. Then an ApplicationId can "represent" themselves with a different ProviderRegistryEntry and it is a bit more clear that Application level is an override of the default for the Provider level.

Copy link
Collaborator

Choose a reason for hiding this comment

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

If we anticipate that an Application may require a good deal of the same meta-info as a Provider for purposes of trustworthiness, then I think it's reasonable to clone/alias the info types for now.

5. `MaxProviderNameSize` be increased to `256`.
6. `MaxProviderLogo250X100Size` be created and the limit set to `131_072` (128 KiB).

### **Mainnet Approval Flow** <a id='governance'></a>

_Any_ change to the Provider or Application Context must be approved by governance.
For now, that governance approval is any single Frequency Council member.

```mermaid
sequenceDiagram
participant P as Provider
participant D as Provider Dashboard
participant F as Frequency
participant G as Frequency Council

note over P,G: Provider Registration
P->>D: Login
D-->>+F: Create MSA
F-->>-D: MSA created
P->>D: Request to be Provider form
P->>D: Add Applications as needed
D-->>+F: Generate Frequency Council Proposal
G->>F: Review and Approve Proposal
F->>F: Execute Provider registration
F-->>-D: MSA is a Provider

note over P,G: Provider Update Registration
P->>D: Login
P->>D: See Provider and Application Information
P->>D: Request to update Provider form
P->>D: Update/add Applications as needed
D-->>+F: Generate Frequency Council Proposal
G->>F: Review and Approve Update Proposal
F->>F: Execute Provider changes as an upsert
F-->>-D: Update display
P->>D: See Updated Provider and Application Information
```

#### Open Questions
- Is this a set or edit pattern for the applications?
- Should adding/updating applications be a separate call?
- Should adding/updating a translation be a separate call?

#### Implementation Suggestion

To limit the amount of unapproved bytes intended to be interpreted as images on chain, an option would be to merely submit the hashes of images for approval.
This hash would then be allowlisted for that provider.
Once approved, that provider could submit the image to chain.
In the governance process, a link to the image would need to be submitted.

### **Example of Wallet Usage via SIWF** <a id='siwf'></a>

SIWF [Signed Request Payload](https://projectlibertylabs.github.io/siwf/v2/docs/DataStructures/All.html) can expand the optional `applicationContext` value with a new optional `id` field that is the text of the `ApplicationIdentifier` on chain.
This would allow a smooth transition between `applicationContext.url` and `applicationContext.id` with both being optional.

The Wallet would then:
1. Verify the SIWF Signed Request.
2. Lookup the Provider via the `publicKey` in the SIWF Signed Request.
3. If any, fetch the Application Identifier from Frequency.
4. Display the information from the `ApplicationRegistryEntry` (or the Provider Registry Entry `ProviderToRegistryEntry` if there is no application context identifier) to the user to help them know who they are authorizing.
5. Allow the user to continue the login process.

### **Provider Dashboard Steps** <a id='dashboard'></a>

Provider Dashboard needs to be able to:

- Create a provider without any application context other than the default provider context
- Update the default provider context, logos, and translations
- Add new Application Contexts with a identifier (unique to that provider), logos, and translations
- Remove an existing Application Context
- Update an Application Contexts with new logos, and translations


## Non-goals

- Implementation of verified credentials for applications (Aka FooBar is approved by <Consumer Org>)
- Providing for independent body to perform verification

## Benefits and Risk

### Benefit: User protection and Application diversity

Users will have a greater confidence when they are logging into an application that the application is represented honestly, even with the continuous risk of trusting any new application with user data.

### Risk: Initial structure of only one Frequency Council member approving changes in an application

Tricking a single member is much simpler than a more detailed vetting process; however, at this stage, the number of providers is small.

This process should be re-evaluated as the number of Providers grows.

### Risk: Logo Images on Chain

This provides a direct way to place image content on chain, intended to be interpreted as image content.
While this must still pass through the governance step to be used by others via the content the image would still be in the chain history as there is always a risk of problematic images being proposed.
This risk is mitigated by:
- A registered provider must be taking the action
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not clear from the sequence diagram, at least for the initial provider creation flow; it looks like all application data (including image bytes) would be recorded on-chain as part of the provider proposal.

Wouldn't the mitigation be submitting the image hashes rather than the images, as discussed in the "Implementation Suggestion" section?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Applied some notes to highlight this.

- Larger images require larger token fees to cover the cost
- IF applied, the suggested hash requirement for the image upload could remove this issue entirely

The mitigation is enough for the benefit of clear branding for users to outweigh this risk.

## Alternatives and Rationale

1. Trusted Domains
2. Off-chain authentication and verification

### Verify and Just Trust a Domain

While using the domain name system for verification is fine, the issue remains that a malicious Provider could still portray themselves as another application via a Phishing attack.
The desired trust is that the Provider is not maliciously presenting themselves, not that the domain is correct according to the user which would prevent phishing.

Example phishing attack: Foobar.co could represent themselves as Foobar.com and display the logo of Foobar.com from `https://foobar.co/images/logo.png`.

### Off-chain Authentication and Verification

The wallet interface could also (via some mechanism) reach out for the verification or have an allowlist of verified providers.

However, this either requires a centralized service or a patchwork of verifications.
Self-verification is not possible due to the phishing attack.
There is a coordination service of Frequency, but using a schema or other non-verified setup would still require reaching out and extending trust to some other 3rd-party or patchwork verification system.

In the end this solution results in these two problems:
- 3rd-party patchwork systems increase friction and complexity.
- External centralization is undesirable.

There is a future where 3rd-party verification can be used in conjunction with on-chain approval.