From b458498d25dd96f191e832e177f3c247c30b7f6f Mon Sep 17 00:00:00 2001 From: trwnh Date: Mon, 6 Feb 2023 19:14:07 -0600 Subject: [PATCH] Miscellaneous fixes (#1110) * Fix typos in method examples * Fix broken link to sanitize_config (#1115) * Add SIDEKIQ_CONCURRENCY * Fix relref to FilterResult (#1114) * Fix status_ids and rule_ids description (#1126) * fix typo (#1129) * clarify confusing example (mastodon/mastodon#22854) * fix formatting on linked headings (#1139) * fix placeholder entity names (#1157) * better wording * fix scheduledstatus#params.visibility * fix missing: tootctl accounts modify --remove-role * add: status/translate * add deprecation/removal warning to microformats page * clarify further how link verification works * clarify mastodon requirements for webfinger * fix: push param policy -> data[policy] --- archetypes/entities.md | 4 ++ archetypes/methods.md | 4 ++ content/en/admin/config.md | 4 ++ content/en/admin/tootctl.md | 5 +- content/en/entities/FilterStatus.md | 2 +- content/en/entities/Report.md | 4 +- content/en/entities/ScheduledStatus.md | 10 ++-- content/en/entities/Status.md | 2 +- content/en/entities/Translation.md | 50 ++++++++++++++++++ content/en/methods/admin/reports.md | 2 +- content/en/methods/filters.md | 4 +- content/en/methods/instance.md | 2 +- content/en/methods/lists.md | 6 +-- content/en/methods/markers.md | 2 +- content/en/methods/notifications.md | 2 +- content/en/methods/oauth.md | 2 +- content/en/methods/push.md | 4 +- content/en/methods/scheduled_statuses.md | 4 +- content/en/methods/statuses.md | 67 +++++++++++++++++++++++- content/en/spec/activitypub.md | 2 +- content/en/spec/microformats.md | 4 ++ content/en/spec/oauth.md | 31 +++++++---- content/en/spec/webfinger.md | 36 ++++++++++++- content/en/user/profile.md | 28 +++++++--- 24 files changed, 237 insertions(+), 44 deletions(-) create mode 100644 content/en/entities/Translation.md diff --git a/archetypes/entities.md b/archetypes/entities.md index f8774130..07bebffa 100644 --- a/archetypes/entities.md +++ b/archetypes/entities.md @@ -4,6 +4,10 @@ description: menu: docs: parent: entities +aliases: [ + "/api/entities/SOMETHING", + "/api/entities/something", +] --- ## Example diff --git a/archetypes/methods.md b/archetypes/methods.md index 83f6795b..261db256 100644 --- a/archetypes/methods.md +++ b/archetypes/methods.md @@ -4,6 +4,10 @@ description: menu: docs: parent: methods +aliases: [ + "/api/methods/SOMETHING", + "/api/methods/something", +] --- ## What the method does {#anchor} diff --git a/content/en/admin/config.md b/content/en/admin/config.md index b5b06a68..2e48260d 100644 --- a/content/en/admin/config.md +++ b/content/en/admin/config.md @@ -250,6 +250,10 @@ This variable cannot be defined in dotenv (`.env`) files as it's used before the {{< page-ref page="admin/scaling" >}} +#### `SIDEKIQ_CONCURRENCY` + +Added in 4.1. Specific to Sidekiq, this variable determines how many different processes Sidekiq forks into. Defaults to `5`. + #### `WEB_CONCURRENCY` Specific to Puma, this variable determines how many different processes Puma forks into. Defaults to `2`. diff --git a/content/en/admin/tootctl.md b/content/en/admin/tootctl.md index 49cd6b3e..73f20db1 100644 --- a/content/en/admin/tootctl.md +++ b/content/en/admin/tootctl.md @@ -127,6 +127,9 @@ Modify a user account's role, email, active status, approval mode, or 2FA requir `--role ROLE` : Define the existing account's custom role by providing the `name` of that [Role]({{< relref "entities/Role" >}}). Default roles include `Owner`, `Admin`, and `Moderator` (case-sensitive). +`--remove-role` +: Removes the current role from the user. + `--email EMAIL` : Update the user's email address to `EMAIL`. @@ -154,7 +157,7 @@ Modify a user account's role, email, active status, approval mode, or 2FA requir **Version history:**\ 2.6.0 - added\ 3.1.2 - added `--reset-password`\ -4.0.0 - `--role` no longer takes hard-coded `user`, `moderator`, or `admin` roles. Specify the name of the custom Role instead (case-sensitive). +4.0.0 - `--role` no longer takes hard-coded `user`, `moderator`, or `admin` roles. Specify the name of the custom Role instead (case-sensitive). Remove the current role with `--remove-role`. --- diff --git a/content/en/entities/FilterStatus.md b/content/en/entities/FilterStatus.md index b6402e40..3224b188 100644 --- a/content/en/entities/FilterStatus.md +++ b/content/en/entities/FilterStatus.md @@ -32,7 +32,7 @@ aliases: [ ### `status_id` {#keyword} -**Description:** The ID of the filtered Status in the database.\ +**Description:** The ID of the Status that will be filtered.\ **Type:** String (cast from an integer, but not guaranteed to be a number)\ **Version history:**\ 4.0.0 - added diff --git a/content/en/entities/Report.md b/content/en/entities/Report.md index 00fec01c..314fe7c8 100644 --- a/content/en/entities/Report.md +++ b/content/en/entities/Report.md @@ -109,14 +109,14 @@ aliases: [ ### `status_ids` {#status_ids} -**Description:** The domain name of the instance.\ +**Description:** IDs of statuses that have been attached to this report for additional context.\ **Type:** {{}} Array of String (cast from integer), or null\ **Version history:**\ 4.0.0 - added ### `rule_ids` {#rule_ids} -**Description:** The domain name of the instance.\ +**Description:** IDs of the rules that have been cited as a violation by this report.\ **Type:** {{}} Array of String (cast from integer), or null\ **Version history:**\ 4.0.0 - added diff --git a/content/en/entities/ScheduledStatus.md b/content/en/entities/ScheduledStatus.md index 16399848..93171ec3 100644 --- a/content/en/entities/ScheduledStatus.md +++ b/content/en/entities/ScheduledStatus.md @@ -73,7 +73,7 @@ Returned from `GET /api/v1/scheduled_statuses`: ### `scheduled_at` {#scheduled_at} -**Description:** ID of the status in the database.\ +**Description:** The timestamp for when the status will be posted.\ **Type:** String (ISO 8601 Datetime)\ **Version history:**\ 2.7.0 - added @@ -150,8 +150,12 @@ Returned from `GET /api/v1/scheduled_statuses`: #### `params[visibility]` {#params-visibility} -**Description:** The language that will be used for the status.\ -**Type:** {{}} String (ISO 639-1 two-letter language code)\ +**Description:** The visibility that the status will have once it is posted.\ +**Type:** String (Enumerable oneOf)\ +`public` = Visible to everyone, shown in public timelines.\ +`unlisted` = Visible to public, but not included in public timelines.\ +`private` = Visible to followers only, and to any mentioned users.\ +`direct` = Visible only to mentioned users.\ **Version history:**\ 2.7.0 - added diff --git a/content/en/entities/Status.md b/content/en/entities/Status.md index 3e941367..c603e209 100644 --- a/content/en/entities/Status.md +++ b/content/en/entities/Status.md @@ -334,7 +334,7 @@ aliases: [ ### `filtered` {{%optional%}} {#filtered} **Description:** If the current token has an authorized user: The filter and keywords that matched this status.\ -**Type:** Array of [FilterResult]({{ relref "entities/FilterResult" }})\ +**Type:** Array of [FilterResult]({{< relref "entities/FilterResult" >}})\ **Version history:**\ 4.0.0 - added diff --git a/content/en/entities/Translation.md b/content/en/entities/Translation.md new file mode 100644 index 00000000..67d0c475 --- /dev/null +++ b/content/en/entities/Translation.md @@ -0,0 +1,50 @@ +--- +title: Translation +description: Represents the result of machine translating some status content +menu: + docs: + parent: entities +aliases: [ + "/api/entities/Translation", + "/api/entities/translation", +] +--- + +## Example + +```json +{ + "content": "

Hola mundo

", + "detected_source_language": "en", + "provider": "DeepL.com" +} +``` + +## Attributes + +### `content` {#content} + +**Description:** The translated text of the status.\ +**Type:** String (HTML)\ +**Version history:**\ +4.0.0 - added + +### `detected_source_language` {#detected_source_language} + +**Description:** The language of the source text, as auto-detected by the machine translation provider.\ +**Type:** String (ISO 639 language code)\ +**Version history:**\ +4.0.0 - added + +### `provider` {#provider} + +**Description:** The service that provided the machine translation. +**Type:** String\ +**Version history:**\ +4.0.0 - added + +## See also + +{{< page-relref ref="methods/statuses#translate" caption="POST /api/v1/statuses/:id/translate" >}} + +{{< caption-link url="https://github.com/mastodon/mastodon/blob/main/app/serializers/rest/translation_serializer.rb" caption="app/serializers/rest/translation_serializer.rb" >}} \ No newline at end of file diff --git a/content/en/methods/admin/reports.md b/content/en/methods/admin/reports.md index 0e8913c3..f174ea80 100644 --- a/content/en/methods/admin/reports.md +++ b/content/en/methods/admin/reports.md @@ -505,7 +505,7 @@ Reopen a currently closed report, if it is closed. ##### Path parameters :id -: {{}} String. The ID of the SOMETHING in the database. +: {{}} String. The ID of the Report in the database. ##### Headers diff --git a/content/en/methods/filters.md b/content/en/methods/filters.md index 329ff278..d6621031 100644 --- a/content/en/methods/filters.md +++ b/content/en/methods/filters.md @@ -106,7 +106,7 @@ Obtain a single filter group owned by the current user. ##### Path parameters :id -: {{}} String. The ID of the SOMETHING in the database. +: {{}} String. The ID of the Filter in the database. ##### Headers @@ -1355,7 +1355,7 @@ DELETE /api/v1/filters/:id HTTP/1.1 ##### Path parameters :id -: {{}} String. The ID of the SOMETHING in the database. +: {{}} String. The ID of the Filter in the database. ##### Headers diff --git a/content/en/methods/instance.md b/content/en/methods/instance.md index 813e5fc8..54591764 100644 --- a/content/en/methods/instance.md +++ b/content/en/methods/instance.md @@ -466,7 +466,7 @@ The admin has chosen to show domain blocks to no one. The response body is empty ## View extended description {#extended_description} ```http -GET /api/v1/example HTTP/1.1 +GET /api/v1/instance/extended_description HTTP/1.1 ``` Obtain an extended description of this server diff --git a/content/en/methods/lists.md b/content/en/methods/lists.md index 986aa0c6..12e6a189 100644 --- a/content/en/methods/lists.md +++ b/content/en/methods/lists.md @@ -459,7 +459,7 @@ Add accounts to the given list. Note that the user must be following these accou ##### Path parameters :id -: {{}} String. The ID of the SOMETHING in the database. +: {{}} String. The ID of the List in the database. ##### Headers @@ -528,7 +528,7 @@ Remove accounts from the given list. ##### Path parameters :id -: {{}} String. The ID of the SOMETHING in the database. +: {{}} String. The ID of the List in the database. ##### Headers @@ -561,7 +561,7 @@ Invalid or missing Authorization header. ##### 404: Not found -SOMETHING is not owned by you or does not exist +List is not owned by you or does not exist ```json { diff --git a/content/en/methods/markers.md b/content/en/methods/markers.md index bc7a57db..b39618cd 100644 --- a/content/en/methods/markers.md +++ b/content/en/methods/markers.md @@ -44,7 +44,7 @@ timeline[] #### Response ##### 200: OK -timeline[] = ["home", "notifications"] +A request with `?timeline[]=home&timeline[]=notifications` ```json { diff --git a/content/en/methods/notifications.md b/content/en/methods/notifications.md index 9284b9eb..30fc55fe 100644 --- a/content/en/methods/notifications.md +++ b/content/en/methods/notifications.md @@ -175,7 +175,7 @@ Invalid or missing Authorization header. ## Get a single notification {#get-one} ```http -GET /api/v1/notification/:id HTTP/1.1 +GET /api/v1/notifications/:id HTTP/1.1 ``` View information about a notification with a given ID. diff --git a/content/en/methods/oauth.md b/content/en/methods/oauth.md index 6b964e38..a2714847 100644 --- a/content/en/methods/oauth.md +++ b/content/en/methods/oauth.md @@ -102,7 +102,7 @@ client_id : {{}} String. The client ID, obtained during app registration. client_secret -: {{}} String. The client secret, obtained durign app registration. +: {{}} String. The client secret, obtained during app registration. redirect_uri : {{}} String. Set a URI to redirect the user to. If this parameter is set to urn:ietf:wg:oauth:2.0:oob then the token will be shown instead. Must match one of the `redirect_uris` declared during app registration. diff --git a/content/en/methods/push.md b/content/en/methods/push.md index 90e54267..b1b0b646 100644 --- a/content/en/methods/push.md +++ b/content/en/methods/push.md @@ -43,7 +43,7 @@ Add a Web Push API subscription to receive notifications. Each access token can **Version history:**\ 2.4.0 - added\ 3.3.0 - added `data[alerts][status]`\ -3.4.0 - added `policy`\ +3.4.0 - added `data[policy]`\ 3.5.0 - added `data[alerts][update]` and `data[alerts][admin.sign_up]`\ 4.0.0 - added `data[alerts][admin.report]` @@ -95,7 +95,7 @@ data[alerts][admin.sign_up] data[alerts][admin.report] : Boolean. Receive new report notifications? Defaults to false. Must have a role with the appropriate permissions. -policy +data[policy] : String. Specify whether to receive push notifications from `all`, `followed`, `follower`, or `none` users. #### Response diff --git a/content/en/methods/scheduled_statuses.md b/content/en/methods/scheduled_statuses.md index 7156c10c..75a29ea5 100644 --- a/content/en/methods/scheduled_statuses.md +++ b/content/en/methods/scheduled_statuses.md @@ -172,7 +172,7 @@ PUT /api/v1/scheduled_statuses/:id HTTP/1.1 ##### Path parameters :id -: {{}} String. The ID of the SOMETHING in the database. +: {{}} String. The ID of the ScheduledStatus in the database. ##### Headers @@ -253,7 +253,7 @@ DELETE /api/v1/scheduled_statuses/:id HTTP/1.1 ##### Path parameters :id -: {{}} String. The ID of the SOMETHING in the database. +: {{}} String. The ID of the ScheduledStatus in the database. ##### Headers diff --git a/content/en/methods/statuses.md b/content/en/methods/statuses.md index 600d4390..87c59baf 100644 --- a/content/en/methods/statuses.md +++ b/content/en/methods/statuses.md @@ -523,6 +523,71 @@ Status is private or does not exist --- +## Translate a status {#translate} + +```http +POST /api/v1/statuses/:id/translate HTTP/1.1 +``` + +Translate the status content into some language. + +**Returns:** [Translation]({{< relref "entities/translation" >}})\ +**OAuth:** App token + `read:statuses`\ +**Version history:**\ +4.0.0 - added + +#### Request + +##### Path parameters + +:id +: {{}} String. The ID of the Status in the database. + +##### Form data parameters + +lang +: String (ISO 639 language code). The status content will be translated into this language. Defaults to the user's current locale. + +##### Headers + +Authorization +: {{}} Provide this header with `Bearer ` to gain authorized access to this API method. + +#### Response +##### 200: OK + +Translating the first "Hello world" post from mastodon.social into Spanish + +```json +{ + "content": "

Hola mundo

", + "detected_source_language": "en", + "provider": "DeepL.com" +} +``` + +##### 404: Not found + +Status is private or does not exist + +```json +{ + "error": "Record not found" +} +``` + +##### 503: Service unavailable + +The translation request failed + +```json +{ + "error": "Service Unavailable" +} +``` + +--- + ## See who boosted a status {#reblogged_by} ```http @@ -1394,7 +1459,7 @@ Edit a given status to change its text, sensitivity, media attachments, or poll. ##### Path parameters :id -: {{}} String. The ID of the SOMETHING in the database. +: {{}} String. The ID of the Status in the database. ##### Headers diff --git a/content/en/spec/activitypub.md b/content/en/spec/activitypub.md index 0765fbe2..af83c1c4 100644 --- a/content/en/spec/activitypub.md +++ b/content/en/spec/activitypub.md @@ -221,7 +221,7 @@ published ## HTML sanitization {#sanitization} -{{< caption-link url="https://github.com/mastodon/mastodon/blob/master/app/lib/sanitize_config.rb" caption="app/lib/sanitize_config.rb" >}} +{{< caption-link url="https://github.com/mastodon/mastodon/blob/main/lib/sanitize_ext/sanitize_config.rb" caption="lib/sanitize_ext/sanitize_config.rb" >}} Mastodon sanitizes incoming HTML in order to not break assumptions for API client developers. Supported elements include `

`, ``, `
`, and ``. Unsupported elements will be converted to `

`.The sanitizer will keep classes if they begin with microformats prefixes or are semantic classes: diff --git a/content/en/spec/microformats.md b/content/en/spec/microformats.md index 862f3503..c2d68910 100644 --- a/content/en/spec/microformats.md +++ b/content/en/spec/microformats.md @@ -7,6 +7,10 @@ menu: parent: spec --- +{{< hint style="info" >}} +As of v4.0.0, HTML permalinks for statuses and profiles have been deprecated and removed from Mastodon. As a result, Microformats are currently not used within nor generated by Mastodon. +{{< /hint >}} + ## What are microformats? {#intro} [Microformats 2.0](https://microformats.io/) is a standard used to embed metadata directly within an HTML document. Rather than needing to use an API for read-only purposes, a web page can be parsed for certain CSS classes in order to extract information that you have already fetched just by viewing the page, rather than having to separately request that same information from an API. The use of microformats classes allows for semantic parsing of data within a given web page, and can be used to generate feeds, cards, or representations of that data. diff --git a/content/en/spec/oauth.md b/content/en/spec/oauth.md index 14261b4e..5a708799 100644 --- a/content/en/spec/oauth.md +++ b/content/en/spec/oauth.md @@ -11,12 +11,6 @@ menu: The Mastodon API has many methods that require authentication from a client or authorization from a user. This is accomplished with OAuth 2.0, an authorization framework described in [RFC 6749](https://tools.ietf.org/html/rfc6749) that allows third-party applications to obtain limited access to an HTTP service on behalf of a resource owner, through the use of a standardized authorization flow that generates a client access token to be used with HTTP requests. -Mastodon supports the following OAuth 2 flows: - -* **Authorization code flow**: For end-users -* **Password grant flow**: For bots and other single-user applications -* **Client credentials flow**: For applications that do not act on behalf of users - To obtain an OAuth token for a Mastodon website, make sure that you allow your users to specify the domain they want to connect to before login. Use that domain to [acquire a client id/secret]({{< relref "methods/apps#create" >}}) and then [proceed with normal OAuth 2]({{< relref "methods/oauth" >}}). ## OAuth 2 endpoints implemented {#implementation} @@ -25,17 +19,32 @@ The following descriptions are taken from the [Doorkeeper documentation](https:/ {{< caption-link url="https://github.com/mastodon/mastodon/blob/master/config/initializers/doorkeeper.rb" caption="Doorkeeper config initializer" >}} -### [GET /oauth/authorize]({{< relref "methods/oauth#authorize" >}}) +### Authorization endpoint (RFC 6749 Section 3.1) {#authorization} + +[GET /oauth/authorize]({{% relref "methods/oauth#authorize" %}}) Displays an authorization form to the user. If approved, it will create and return an authorization code, then redirect to the desired `redirect_uri`, or show the authorization code if `urn:ietf:wg:oauth:2.0:oob` was requested. -### [POST /oauth/token]({{< relref "methods/oauth#token" >}}) {#post-oauth-token} +### Token endpoint (RFC 6749 Section 3.2) {#token} -Obtain an access token. This corresponds to the token endpoint, section 3.2 of the OAuth 2 RFC. +[POST /oauth/token]({{% relref "methods/oauth#token" %}}) -### [POST /oauth/revoke]({{< relref "methods/oauth#revoke" >}}) {#post-oauth-revoke} +Obtain an access token. Mastodon supports the following OAuth 2 flows: -Post here with client credentials to revoke an access token. This corresponds to the token endpoint, using the OAuth 2.0 Token Revocation RFC (RFC 7009). +Authorization code flow +: For end-users + +Password grant flow +: For bots and other single-user applications + +Client credentials flow +: For applications that do not act on behalf of users + +### Token revocation endpoint (RFC 7009 Section 2) {#revoke} + +[POST /oauth/revoke]({{% relref "methods/oauth#revoke" %}}) + +Post here with client credentials to revoke an access token. ## Common gotchas {#gotchas} diff --git a/content/en/spec/webfinger.md b/content/en/spec/webfinger.md index 34075fc7..ecc6d5aa 100644 --- a/content/en/spec/webfinger.md +++ b/content/en/spec/webfinger.md @@ -71,5 +71,39 @@ This way, we have translated `@Gargron@mastodon.social` to `https://mastodon.soc ``` {{< /code >}} -Note in the above example that `social.example` does not use the same URI structure as Mastodon. Thus, we cannot guess the actor `id` given only the username and domain. However, if `social.example` supports WebFinger, then we can get this `id` by requesting `https://social.example/.well-known/webfinger?resource=acct:username@social.example`and parsing the response for a link with the `application/activity+json` type. +Note in the above example that `social.example` does not use the same URI structure as Mastodon. Thus, we cannot guess the actor `id` given only the username and domain. However, if `social.example` supports WebFinger, then we can get this `id` by requesting `https://social.example/.well-known/webfinger?resource=acct:username@social.example`and parsing the response for a link with the `application/ld+json; profile="https://www.w3.org/ns/activitystreams"` or `application/activity+json` type. This link should also have the link relation `rel="self"`. +## Mastodon's requirements for WebFinger + +When given an account in the form `username@domain` or `@username@domain`, Mastodon will do the following: + +- Construct an `acct:` URI using that username and domain +- Make a WebFinger request for that `resource` + +Using that WebFinger response, Mastodon will check the following: + +- The `subject` is present +- The `links` array contains a link with `rel` of `self` and `type` of either `application/ld+json; profile="https://www.w3.org/ns/activitystreams"` or `application/activity+json` + - The `href` for this link resolves to an ActivityPub actor + +Using that ActivityPub actor representation (which may be provided directly, without the initial WebFinger request), Mastodon will do the following: + +- Take `preferredUsername` and the hostname of the actor's server +- Construct an `acct:` URI using that username and domain +- Make a Webfinger request for that `resource` + +If the `subject` matches the `resource`, then the process stops here. Otherwise, if the `subject` contains a different canonical account URI, then Mastodon will perform an additional Webfinger request for that canonical account URI in order to ensure that this new `resource` links to the same ActivityPub actor with the same criteria being checked. + +In other words, the following cases are valid: + +- Asking `example.com` for the resource `acct:alice@example.com` yields a link to an actor on the domain `example.com` with a `preferredUsername` of `alice`, and the `subject` matches the requested resource `acct:alice@example.com` +- Asking `example.com` for the resource `acct:alice@example.com` yields a link to an actor on the domain `ap.example.com` with a `preferredUsername` of `alice` + - ...then, asking `ap.example.com` for the resource `acct:alice@ap.example.com` yields a `subject` of `acct:alice@example.com` and a link to the same actor + +## See also + +{{< caption-link url="https://github.com/mastodon/mastodon/blob/main/app/services/activitypub/fetch_remote_actor_service.rb" caption="app/services/activitypub/fetch_remote_actor_service.rb" >}} + +{{< caption-link url="https://github.com/mastodon/mastodon/blob/main/app/services/resolve_account_service.rb" caption="app/services/resolve_account_service.rb" >}} + +{{< caption-link url="https://github.com/mastodon/mastodon/blob/main/app/lib/webfinger.rb" caption="app/lib/webfinger.rb" >}} \ No newline at end of file diff --git a/content/en/user/profile.md b/content/en/user/profile.md index b94a881d..f5d453c4 100644 --- a/content/en/user/profile.md +++ b/content/en/user/profile.md @@ -65,7 +65,7 @@ It’s completely up to you what you put there. The content can contain mentions ### Link verification {#verification} -Document-based verification and blue ticks are not possible without a central authority. However, Mastodon can cross-reference the links you put on your profile to prove that you are the real owner of those links. In case one of those links is your personal homepage that is known and trusted, it can serve as the next-best-thing to identity verification. +Document-based verification and blue ticks are not possible without a central authority. However, Mastodon can cross-reference the links you put on your profile to prove that you are the real owner of those links. In case one of those links is your personal homepage that is known and trusted, it can serve as the next-best-thing to identity document verification. {{< hint style="info" >}} Because Mastodon can be self-hosted, there is no better way to verify your identity than to host Mastodon on your own domain, which people already trust. @@ -77,14 +77,26 @@ If you put an HTTPS link in your profile metadata, Mastodon checks if that link Follow me on Mastodon! ``` -More precisely, Mastodon will validate the link under the following conditions: -- It is not within an `iframe` (note that some "block-based" CMS software may wrap block elements within iframes) -- Since 4.0: the hostname does not change after IDN normalization -- it starts with HTTPS -- the resolved page contains at least one `a` or `link` tag with a `rel="me"` -- the `href` attribute on one of those elements is equal to the URL for your Mastodon profile +It may also be embedded directly in the head of your web page: -Alternatively, validation will occur if the resolved page's *first* link has an `href` value that redirects to your Mastodon profile's URL (such as through a link shortener). +```html + +``` + +#### Validation criteria for verified links + +Mastodon will validate the "verified link" profile field under the following conditions: + +- The value of the profile field is **a link that MUST start with HTTPS**. Other values will not be processed. Other types of links are not processed. In particular, plain HTTP links are not processed because they are insecure and may be modified by an attacker in transit. +- Since 4.0: **the hostname must not change after IDN normalization**. This is to prevent homeograph attacks where some Unicode character is used that looks confusingly similar to some ASCII character in a mixed string. For example, `U+0061` (English lowercase "a") and `U+0430` (Cyrillic small letter "а") appear nearly identical, but they are completely different characters. This similarity in appearance could be used maliciously to mislead people. + +Mastodon will then resolve the link and fetch the web page located there, looking for a qualified link that matches the criteria: + +- The resolved page must contain at least one `a` or `link` tag with a `rel="me"` attribute. + - The `href` attribute on one of those elements must be equal to the URL for your Mastodon profile. +- If no links with `rel="me"` are found, Mastodon will look for the *first* link, and the `href` value must redirect to your Mastodon profile's URL. (This provides limited support for web pages that use link shorteners and do not use rel-me.) + +**Any such link must not be within an `iframe`**. An `iframe` effectively means the link is no longer on the same web page, but rather it is on some external web page which is being embedded in the current one. (Note that some "block-based" CMS software may wrap block elements within iframes, which prevents verification for this reason.) {{< hint style="info" >}} Make sure to save your profile *after* adding the rel-me link to your web page! The verification process is triggered when you save your profile, and may take some time before completing. If you have added the rel-me link and verification is not working, then try deleting the link, saving, re-adding the link, and saving again.