diff --git a/fep/9098/fep-9098.md b/fep/9098/fep-9098.md new file mode 100644 index 0000000..07fa846 --- /dev/null +++ b/fep/9098/fep-9098.md @@ -0,0 +1,129 @@ +--- +slug: "9098" +authors: silverpill <@silverpill@mitra.social> +type: implementation +status: DRAFT +dateReceived: 2025-07-06 +discussionsTo: https://codeberg.org/silverpill/feps/issues +--- +# FEP-9098: Custom emojis + +## Summary + +This document describes how custom emojis are implemented in [ActivityPub] network. + +## History + +Custom emojis were introduced by Pleroma ([commits](https://gitgud.io/lambadalambda/pleroma/-/compare/c17c8ce36d35db03a007a264cc2e507afa9b803e...7c82b8219734102ff24d9dc24226c08351e608cc)) and Mastodon ([PR](https://github.com/mastodon/mastodon/pull/4988)) in 2017. + +## Requirements + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC-2119]. + +## Emoji object + +Custom emojis are represented as `Emoji` objects (the full type IRI is `http://joinmastodon.org/ns#Emoji`). The `Emoji` object has the following properties: + +- `id` (RECOMMENDED): the unique identifier of the custom emoji. Some implementations omit this property (i.e. the object is anonymous). +- `type` (REQUIRED): the `Emoji` string. +- `name` (REQUIRED): the [shortcode][Shortcode] of the custom emoji (the name of the emoji, enclosed in colons). +- `updated` (OPTIONAL): the date when custom emoji was updated, formatted as [RFC-3339] timestamp. +- `icon` (REQUIRED): `Image` object describing emoji image. + - `type` (REQUIRED): the `Image` string. + - `url` (REQUIRED): the URL of the emoji image. + +Example: + +```json +{ + "id": "https://social.example/emoji/blobcat", + "type": "Emoji", + "name": ":blobcat:", + "updated": "1970-01-01T00:00:00Z", + "icon": { + "type": "Image", + "url": "https://social.example/media/blobcat.png" + } +} +``` + +### Uniqueness + +The primary unique identifier of a custom emoji is a combination of its name and the domain name. The domain name can be extracted from the `id` of `Emoji` object or from the `id` of the object within which it is embedded. + +If `id` is not guaranteed to be globally unique, it MUST be omitted. + +### Accessibility + +The short description of a custom emoji can be specified with the `alternateName` property (the full IRI is `http://schema.org/alternateName`). + +### Compatibility + +In order to be compatible with as many servers as possible, implementations SHOULD comply with the following additional requirements: + +- Name contains at least two characters ([Mastodon](https://github.com/mastodon/mastodon/blob/v4.3.7/app/models/custom_emoji.rb#L28)). +- Name matches the regular expression `^[a-zA-Z0-9_]+$` ([Mastodon](https://github.com/mastodon/mastodon/blob/v4.3.7/app/models/custom_emoji.rb#L30)). +- Image media type is `image/png`, `image/gif` or `image/webp` ([Mastodon](https://github.com/mastodon/mastodon/blob/v4.3.7/app/models/custom_emoji.rb#L37)). +- Image size is not greater than 256 KB ([Mastodon](https://github.com/mastodon/mastodon/blob/v4.3.7/app/models/custom_emoji.rb#L27)). +- Image is a square (some clients may display non-squre emojis with a wrong aspect ratio). + +## Using custom emojis + +### Microsyntax + +Custom emojis can be inserted into textual representations of an object using [shortcodes][Shortcode] (shortcode is a name of an emoji enclosed in colons: `:emojiname:`). These textual representations are often specified with `name`, `summary` and `content` properties. + +The corresponding `Emoji` objects are added to the `tag` array of the object. + +Example: + +```json +{ + "type": "Note", + "content": "

:blobcat:

", + "tag": [ + { + "id": "https://social.example/emoji/blobcat", + "type": "Emoji", + "name": ":blobcat:", + "icon": { + "type": "Image", + "url": "https://social.example/media/blobcat.png" + } + } + ] +} +``` + +### Rendering + +Applications typically replace custom emoji shortcodes with `` HTML tags and render the output as HTML. + +To prevent [Cross-Site Scripting (XSS)][XSS] attacks, implementers MUST ensure that: + +- Emoji names, descriptions, URLs and other strings that are used in replacements do not contain reserved HTML characters. +- When HTML content (e.g. `summary`, `content`) is processed, shortcodes are replaced only inside [Text][DOM-Text] nodes. +- Reserved HTML characters in text are escaped before replacing shortcodes. + +## Implementations + +This document is based on implementations of custom emojis in Pleroma, Mastodon, Misskey and Fedibird. + +## References + +- Christine Lemmer-Webber, Jessica Tallon, Erin Shepherd, Amy Guy, Evan Prodromou, [ActivityPub], 2018 +- S. Bradner, [Key words for use in RFCs to Indicate Requirement Levels][RFC-2119], 1997 +- G. Klyne, C. Newman, [Date and Time on the Internet: Timestamps][RFC-3339], 2002 + +[ActivityPub]: https://www.w3.org/TR/activitypub/ +[RFC-2119]: https://tools.ietf.org/html/rfc2119.html +[RFC-3339]: https://www.rfc-editor.org/rfc/rfc3339 +[Shortcode]: https://emojipedia.org/shortcodes +[XSS]: https://owasp.org/www-community/attacks/xss/ +[DOM-Text]: https://developer.mozilla.org/en-US/docs/Web/API/Text + +## Copyright + +CC0 1.0 Universal (CC0 1.0) Public Domain Dedication + +To the extent possible under law, the authors of this Fediverse Enhancement Proposal have waived all copyright and related or neighboring rights to this work.