-
Notifications
You must be signed in to change notification settings - Fork 16
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
XIP-14: Conversation context metadata schema #14
Conversation
XIPs/xip-10-brandinfo-schema.md
Outdated
|
||
- Aspect ratio: 1:1 | ||
- Minimum resolution: 100x100 | ||
- Maximum resolution: 800x800 |
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.
If these are externally hosted, why such a low maximum?
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.
Based on Darick's suggestions. Thoughts on increasing min resolution @darickdang?
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.
@neekolas Since the image would be used in avatar-like settings (or to complement an avatar), I looked at popular services/libraries such as Gravatar (minimum size 1px) and Libravatar (minimum size is 80x80) standards in addition to Apple's Human Interface Guidelines of having a minimum toucharea of 44x44 (and then I doubled that to add @2x support as the minimum) to create the number you see here.
Open to making it bigger though. Not that strong of an opinion from my end here.
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 just wonder if some apps are going to want a clickable/zoomed view of app icons. Or an extra large icon. Maybe that's not a real concern here.
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 wonder if it might help to include a mockup of a UI showing how the displayName
, profileImage
, and primaryColor
might be used? While the profileImage
might be more obvious, people might be curious about where the displayName
and primaryColor
might be used? An image might also really drive home the value!
And is the idea now that we don't need to use only the conversationId
as conversation label text?
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.
Adding a sample UI is such a good idea @jhaaaa!
Yes, with a conversationId like 'lens.dev/dm/...' there isn't a shared understanding of how to render it? Should the UI display 'Lens', 'lens.dev', or the complete conversationId? The displayName makes it explicit
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.
Great call @jhaaaa. Will look at making an example.
XIPs/xip-10-brandinfo-schema.md
Outdated
|
||
## Security Considerations | ||
|
||
The metadata field can be spoofed by malicious apps to display Names and Images that degrade the user experience and are harmful to the brand’s perception. A mechanism for apps to sign messages and related metadata can enable front-ends to verify if the signature is from a credible source in order to prevent such spoofing. An affordance for client verifiability is under consideration. |
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 invitation is encrypted and authenticated using the sender & recipient keys. So the metadata must have been created by one of the parties if the invitation is successfully unsealed (https://github.com/xmtp/proto/blob/main/proto/message_contents/invitation.proto).
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.
While invitations are authenticated by sender & recipient, setting metadata and conversationId is usually abstracted away from users so front-end clients end up making the decision for what these fields carry.
Spoofing example: A (malicious) client Yash uses to message Martin could set conversationId to a 'lens.dev/...' and set brandInfo that doesn't represent Lens.
Today convoID/metadata<>app/protocol/brand mapping is not verifiable, and therefore relies on good behavior.
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 see, I misread this section. This is however a more general concern that currently apps have complete access to a user's XMTP identity/keys, so a users must necessarily trust the app they are using in all regards not just this particular aspect. It may still be worth mentioning here, but I'm less sure about what the solution should be. Some amount of trust between the user and the app may always be necessary.
Update metadata format: map of strings to strings
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 excited about this XRC, @yash-luna - thank you for designing and articulating it so clearly! Added a few comments for your consideration -- please use only what you find helpful!
XIPs/xip-10-brandinfo-schema.md
Outdated
|
||
- Aspect ratio: 1:1 | ||
- Minimum resolution: 100x100 | ||
- Maximum resolution: 800x800 |
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 wonder if it might help to include a mockup of a UI showing how the displayName
, profileImage
, and primaryColor
might be used? While the profileImage
might be more obvious, people might be curious about where the displayName
and primaryColor
might be used? An image might also really drive home the value!
And is the idea now that we don't need to use only the conversationId
as conversation label text?
Co-authored-by: Jennifer Hasegawa <[email protected]>
Co-authored-by: Jennifer Hasegawa <[email protected]>
Co-authored-by: Jennifer Hasegawa <[email protected]>
Co-authored-by: Jennifer Hasegawa <[email protected]>
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 not sure the Motivation is clear to me.
The examples and text hint towards standardizing Client applications metadata{AppName + Photo} . However the schema naming seems to hint towards conversation metadata {GroupChat Title, GroupChat ProfileImage}
XIPs/xip-10-brandinfo-schema.md
Outdated
conversationId: "mydomain.xyz/abc/qrs", | ||
metadata: { | ||
"displayInfo.prettyName": "My company", | ||
"displayInfo.profileImage": "mydomain.xyz/assets/myimage.png", |
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.
How does displayInfo.profilePicture
differ from a Contact ProfilePicture
or a group conversation image
? Is the intention different?
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 XIP started with the idea of brandInfo/clientMetadata in mind but we realized that the application is broader - i.e. to add context beyond conversationId that allows a frontend to contextualize conversations
Sample UIs and non-clientMetadata examples are work in progress. Sharing most recent UI mock that highlights how they can be utilized for clientMetadata, NftMetadata, or other metadata that contextualizes the conversation.
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 example is very helpful.
I might suggest that we scope the properties to something more descriptive than DisplayInfo.DisplayName
. In particular we should create specific terms around what to collectively call the OpenSea/Lens tags.
e.g. ConversationSource.DisplayName
, ConversationOrigin.DisplayName
, AppSource....
My main thought here is that with groupchats coming in the near future, DisplayName
will become a loaded term.
XIPs/xip-10-brandinfo-schema.md
Outdated
conversationId: "galaxy.chat/dm/uniqueIdentifier", | ||
metadata: { | ||
"displayInfo.prettyName": "Galaxy", | ||
"displayInfo.profileImage": "galaxychat.xyz/brandassets/logo.png", |
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.
What is the rationale behind embedding this data into the Conversation Invites?
Why does the invite not contain a pointer to a central registry, which would be easier for updates?
Why is this information not contained in a metamessage within the conversation?
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.
Rationale is that conversation metadata add nuance & detail to conversationId so this data lives where conversationId lives.
If we consider allowing all metadata to be pointers, and therefore mutable in some sense, should that be considered for conversationId too? I'm curious how the protocol thinks of what data should be mutable vs immutable. Will help make the decision for metadata.
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.
Why does the invite not contain a pointer to a central registry, which would be easier for updates?
The registry approach is worth considering. The big pro is mutability. But there are some meaningful cons too:
- Long term availability. Will the registry still exist 3 years from now? What happens when it disappears?
- Consistency. What happens as different registries decide to change the shape of the returned data? Will all client apps have to support all the different registries. How do clients and registries communicate? At least with this, all conversations/apps that support the standard will work in perpetuity. Immutability is also a feature: you can't break existing convos.
- Ease of use. Running a registry is real work for someone, and they are unlikely to be paid for it. Who is going to run that registry?
Why is this information not contained in a metamessage within the conversation?
This is information about the conversation as a whole. You may want this to be available as soon as the conversation invite has been read, without having to wade through a potentially lengthy history of meta messages (for example, when showing a conversation list).
Also, this is available today and meta messages are somewhere on our roadmap. Even if we think meta messages are a better solution, do we actually see them becoming first class citizens across all our SDKs in the next few quarters?
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 these are valid reasons to embedded into the conversation metadata. I can get behind this.
In my mind a central registry could be ENS with values stored as textfields. It would address Longterm availability (at least in the context of apps), and Ease of use (Passing update costs to the brands/applications). I think consistency will be an issue regardless and a well defined spec is needed.
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.
@jazzz I really like the ENS approach here. It also would help that there would be a recognizable party that would be accountable for the metadata in the event that it changed, which would be recognized by the associated controller address.
Another reason this might be worthwhile is the many varying indexers for the ENS data.
A concern of mine with including the arbitrary data into the payload vs. a registry is in how it might be manipulated, if even not maliciously.
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 what's troubling about the current approach is that the relationship between convoID<->metadata is not fixed, clients can put whatever they want in the metadata given the same convoID. A registry approach can make sure that the same convoID renders the same metadata universally, and it's fairly easy to add authentication mechanisms in the future to make sure only the relevant app owners can change the metadata for each convoID.
If we think a registry is hard to maintain, we can have a file in the SDK that has a hardcoded list of convoID->metadata, an API for client apps to query it, and only accept PR's modifying the metadata from the app owners for each convoID.
I understand that convoID is spoofable today, but I still think it's better not to add multiple layers of spoofability/confusion.
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.
@richardhuaaa agree on the registry component for sure.
I do wonder if somehow the metadata itself can be hashed, and the hash compared against the registry, to know what's authentic. And perhaps the conversationId could be used as a checksum against the metadata, like how you might with a barcode.
Motivation: provide a schema to share details that help frontends render conversationId in the UI. Today frontends do it by truncating the conversationId. The proposed schema provides more information, image & color, in addition to a prettyName. Sharing UI examples in above comments to provide clarity. Overall, your comment makes me wonder whether we should aim for a generic conversation metadata schema or have different schemas catering to different use-cases (clientMetadata, NftMetadata, groupchatMetadata, etc)? |
XIPs/xip-10-brandinfo-schema.md
Outdated
```json | ||
{ | ||
conversationId: "mydomain.xyz/abc/qrs", | ||
metadata: { |
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.
We may want to consider adding an explicit version to this schema, so future updates are easier to deploy.
The scheme could be directly tied to conversationVersion, But then schema changes would result in a bump in both.
Perhaps something explicit like:
metadata: {
"conversationSource_V1": {
"prettyName": "My company",
"profileImage": "mydomain.xyz/assets/myimage.png"
}
}
That would allow the SDK to add multiple Objects to the metadata if older clients need to be supported
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.
@jazzz makes sense. Is there a preference to using a JSON object to an array?
Another route might be:
metadata: {
"type": "conversation",
"version": "1.0",
"content": {
"title": "My company",
"description"; "My description that may be used in an app",
"image": "https://mydomain.xyz/assets/myimage.png",
"imageURI": "ipfs://zafybeict2kq6gt4ikgulypt7h7nwj4hmfi2kevrqvnx2osibfulyy5x3hu/myimage.png"
}
}
One possible advantage I see with this is the addition of other metadata types in the future.
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.
@galligan I like the explicit structure of version, type, content.
I might suggest a structure that looks like:
metadata: [
{
"type": "conversation_source",
"version": "1.0"
"content": {
"title": "My company",
"description"; "My description that may be used in an app",
"image": "https://mydomain.xyz/assets/myimage.png",
"imageURI": "ipfs://zafybeict2kq6gt4ikgulypt7h7nwj4hmfi2kevrqvnx2osibfulyy5x3hu/myimage.png"
}
},
{
"type": "group_info",
"version": "1.0"
"content": {
"name": "Frens",
"admin"; "....",
"image": "ipfs://pkrewapct2kq6gt4ikgulypt7h7nwj4hmfi2kevrqvnx2osibfulypkl39a/myimage.png".
}
}
]
- There should be room for multiple metadata objects
- Objects names ought to be hyper specific to the data it is representing.
Conversation.Image
is ambiguous. Codifying clear names for entities will help developers in the future.
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.
Worth noting that neither an array or nested object are possible with today's metadata. It is strictly a Map<string, string>. Closer to HTTP headers than a free form JavaScript object.
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.
Based on the suggestions above, there's benefits to the protocol and DX to enable metadata to take arrays and/or nested objects. It would enable versioning for metadata schemas and make it friendly for other use cases beyond conversationId context.
@neekolas @jazzz: What are the downsides of such a change? Can it be in scope for xmtp-js v8?
This is somewhat tangential, but have we ever considered changing the term |
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 is a great start, @yash-luna. Would love to have some of the thoughts in this review to be considered. Happy to have a conversation about some of them and go deeper.
XIPs/xip-10-brandinfo-schema.md
Outdated
|
||
## Motivation | ||
|
||
The SDK API currently accepts a unique `conversationId` per address pair and allows `metadata` to be set as well. Today, different apps use these parameters in different ways. Therefore an app may not know how to correctly render in its UI `conversationId` and `metadata` for conversations originating from other apps. We propose a schema to standardize the use of conversation `metadata` for the purpose of app brand expression stemming from the `conversationId`. The `metadata` field may include other non-standard (or future standard) properties. |
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 SDK API currently accepts a unique `conversationId` per address pair and allows `metadata` to be set as well. Today, different apps use these parameters in different ways. Therefore an app may not know how to correctly render in its UI `conversationId` and `metadata` for conversations originating from other apps. We propose a schema to standardize the use of conversation `metadata` for the purpose of app brand expression stemming from the `conversationId`. The `metadata` field may include other non-standard (or future standard) properties. | |
The XMTP SDK API currently accepts a unique `conversationId` per address pair and allows `metadata` to be set as well. Today disparate apps may use these parameters in different ways. As a result, an app may not always render the `conversationId` and associated `metadata` as intended, for conversations originating from other apps. This proposal introduces a schema to standardize the use of the conversation `metadata` for the purpose of a defined brand expression as associated with the `conversationId`. It is also worth noting that the `metadata` field may include other non-standard (or future standard) properties. |
XIPs/xip-10-brandinfo-schema.md
Outdated
```json | ||
{ | ||
conversationId: "mydomain.xyz/abc/qrs", | ||
metadata: { |
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.
@jazzz makes sense. Is there a preference to using a JSON object to an array?
Another route might be:
metadata: {
"type": "conversation",
"version": "1.0",
"content": {
"title": "My company",
"description"; "My description that may be used in an app",
"image": "https://mydomain.xyz/assets/myimage.png",
"imageURI": "ipfs://zafybeict2kq6gt4ikgulypt7h7nwj4hmfi2kevrqvnx2osibfulyy5x3hu/myimage.png"
}
}
One possible advantage I see with this is the addition of other metadata types in the future.
XIPs/xip-10-brandinfo-schema.md
Outdated
} | ||
``` | ||
|
||
The `profileImage` must meet the following criteria: |
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.
"Must" is doing a lot of work here, and in this case are we sure this can be enforceable? If the image is hosted externally, what prevents the image from being changed after the fact and no longer adhering to the rules?
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 originally said 'should' and was changed to 'must' based on @saulmc's comment. I don't have a strong opinion and am ok with changing the verbiage.
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.
Must to me implies that somehow it is enforceable. I'm not sure I see how that would be possible. Should feels more appropriate in this situation but happy to discuss further with @saulmc.
XIPs/xip-10-brandinfo-schema.md
Outdated
- Maximum resolution: 800x800 | ||
- Format: .PNG, .WEBP | ||
|
||
The `primaryColor` must be a hex color code. |
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 there any concern that primaryColor
may conflict with other styles within the same namespace? Perhaps there's something that could be more generic?
Also: what if we were to also include an equivalent of a fall back brand color that would be more generically named. Something like a purple.500
? I suggest this because some front-ends may wish to have some more control over what colors are displayed.
Just imagine a #FF0099
being included in a UI somewhere and how garish that might be to see.
A fallback color would allow the front-end to set up their own interpretation of the colors, and perhaps even ignoring some colors altogether. But it would all be in the service of providing a consistent UI.
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.
How is a fallback color different from a second hex code? Didn't understand how 'a fallback color would allow the front-end to set up their own interpretation of the colors'
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.
@yash-luna to use an analogy, a "fallback" color in this case is the description of a color of paint, whereas the hex code would be similar to the paint code instructions on the outside of a can of paint.
In the fallback case the specific color used would be based off of the developer's interpretation. With the hex color there is no interpretation and it is explicit.
The naming scheme for the fallback could be based off of an existing example, such as Material Design or Tailwind CSS's color palette. It usually has a color name and separate value to indicate darkness or saturation.
If given the choice, if I were developing an app I would always pick the fallback color as I'd have a bit more control over how it should be represented. Without that control, I might ignore the color altogether as the results could really clash with my experience.
XIPs/xip-10-brandinfo-schema.md
Outdated
conversationId: "mydomain.xyz/abc/qrs", | ||
metadata: { | ||
"displayInfo.prettyName": "My company", | ||
"displayInfo.profileImage": "mydomain.xyz/assets/myimage.png", |
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 should also include an affordance for an image URI. For web3-native projects they may have an IPFS, IPLD or other resource URI as a default, with a specific image URL as secondary.
This would provide a front-end with the ability to use a URI directly.
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.
Can the URI be set as a value to profileImage?
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 should also include an affordance for an image URI. For web3-native projects they may have an IPFS, IPLD or other resource URI as a default, with a specific image URL as secondary.
This would provide a front-end with the ability to use a URI directly.
If all of these images are externally hosted, isn't that going to add several additional round trip requests for the browser?
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.
Can the URI be set as a value to profileImage?
@yash-luna it could be, but setting URI as a separate value to URL would have its benefits. For clients that don't support the protocol the URI is pointing to, then it can look at the URL instead.
If all of these images are externally hosted, isn't that going to add several additional round trip requests for the browser?
@petermdenton Possibly. But it can be accounted for. And otherwise I'm not sure where these images will be coming from except through external hosting. Encouraging them to be stored in-protocol may be a slippery slope that we don't want to go down.
With including the URI and using IPFS, a client could easily cache images and maintain integrity without trouble. An image would be fetched via its URI, and could be saved locally with its CID intact such that the image could not be altered without also changing its CID.
XIPs/xip-10-brandinfo-schema.md
Outdated
|
||
## Security considerations | ||
|
||
The `metadata` fields can be spoofed by malicious apps to display names and profile images that degrade the user experience and harm brand perception. A mechanism for apps to sign payloads such as conversation metadata and messages can enable frontends to verify the sending client's identity and prevent such spoofing. An affordance for client verifiability is under consideration. |
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 `metadata` fields can be spoofed by malicious apps to display names and profile images that degrade the user experience and harm brand perception. A mechanism for apps to sign payloads such as conversation metadata and messages can enable frontends to verify the sending client's identity and prevent such spoofing. An affordance for client verifiability is under consideration. | |
A brand's chosen metadata fields and content may be co-opted by other apps to display the same names and profile images which could impact the user experience and perception of a message's origin or affiliation. A mechanism for apps to sign payloads such as conversation metadata and messages could enable frontends to verify the sending client's metadata authenticity and prevent such spoofing. An affordance for verifying metadata could be considered in a future proposal. |
I'm suggesting that we lighten the language on "spoofing" and "malicious" as it's simply an open space, and there's nothing currently preventing a project from co-opting some labels. Not ideal, but we should be careful about using such pointed language as it may diminish its value in other circumstances.
@richardhuaaa It may be useful to include those as additional fields in some fashion, perhaps as the metadata. For example, an app may choose to have multiple conversations between the same parties present. Or perhaps it might attempt to use them to separate "threads". This may not be the intended use but for now that's how it could happen. |
Co-authored-by: Matt Galligan <[email protected]>
Co-authored-by: Matt Galligan <[email protected]>
Co-authored-by: Matt Galligan <[email protected]>
Co-authored-by: Matt Galligan <[email protected]>
No activity for over 6 months. Set status to Stagnant and merging. |
No description provided.