forked from mirrors/catstodon
Merge branch 'glitch-soc' into develop
This commit is contained in:
commit
c7e37c256e
21 changed files with 104 additions and 200 deletions
61
.github/workflows/build-security.yml
vendored
Normal file
61
.github/workflows/build-security.yml
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
name: Build security nightly container image
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
compute-suffix:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- id: version_vars
|
||||
env:
|
||||
TZ: Etc/UTC
|
||||
run: |
|
||||
echo mastodon_version_prerelease=nightly.$(date --date='next day' +'%Y-%m-%d')-security>> $GITHUB_OUTPUT
|
||||
outputs:
|
||||
prerelease: ${{ steps.version_vars.outputs.mastodon_version_prerelease }}
|
||||
|
||||
build-image:
|
||||
needs: compute-suffix
|
||||
uses: ./.github/workflows/build-container-image.yml
|
||||
with:
|
||||
file_to_build: Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
use_native_arm64_builder: false
|
||||
cache: false
|
||||
push_to_images: |
|
||||
ghcr.io/${{ github.repository_owner }}/mastodon
|
||||
version_prerelease: ${{ needs.compute-suffix.outputs.prerelease }}
|
||||
labels: |
|
||||
org.opencontainers.image.description=Nightly build image used for testing purposes
|
||||
flavor: |
|
||||
latest=true
|
||||
tags: |
|
||||
type=raw,value=edge
|
||||
type=raw,value=nightly
|
||||
type=schedule,pattern=${{ needs.compute-suffix.outputs.prerelease }}
|
||||
secrets: inherit
|
||||
|
||||
build-image-streaming:
|
||||
needs: compute-suffix
|
||||
uses: ./.github/workflows/build-container-image.yml
|
||||
with:
|
||||
file_to_build: streaming/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
use_native_arm64_builder: false
|
||||
cache: false
|
||||
push_to_images: |
|
||||
ghcr.io/${{ github.repository_owner }}/mastodon-streaming
|
||||
version_prerelease: ${{ needs.compute-suffix.outputs.prerelease }}
|
||||
labels: |
|
||||
org.opencontainers.image.description=Nightly build image used for testing purposes
|
||||
flavor: |
|
||||
latest=true
|
||||
tags: |
|
||||
type=raw,value=edge
|
||||
type=raw,value=nightly
|
||||
type=schedule,pattern=${{ needs.compute-suffix.outputs.prerelease }}
|
||||
secrets: inherit
|
|
@ -266,7 +266,7 @@ module SignatureVerification
|
|||
stoplight_wrap_request { ResolveAccountService.new.call(key_id.delete_prefix('acct:'), suppress_errors: false) }
|
||||
elsif !ActivityPub::TagManager.instance.local_uri?(key_id)
|
||||
account = ActivityPub::TagManager.instance.uri_to_actor(key_id)
|
||||
account ||= stoplight_wrap_request { ActivityPub::FetchRemoteKeyService.new.call(key_id, id: false, suppress_errors: false) }
|
||||
account ||= stoplight_wrap_request { ActivityPub::FetchRemoteKeyService.new.call(key_id, suppress_errors: false) }
|
||||
account
|
||||
end
|
||||
rescue Mastodon::PrivateNetworkAddressError => e
|
||||
|
|
|
@ -155,8 +155,8 @@ module JsonLdHelper
|
|||
end
|
||||
end
|
||||
|
||||
def fetch_resource(uri, id, on_behalf_of = nil, request_options: {})
|
||||
unless id
|
||||
def fetch_resource(uri, id_is_known, on_behalf_of = nil, request_options: {})
|
||||
unless id_is_known
|
||||
json = fetch_resource_without_id_validation(uri, on_behalf_of)
|
||||
|
||||
return if !json.is_a?(Hash) || unsupported_uri_scheme?(json['id'])
|
||||
|
|
|
@ -167,6 +167,10 @@ export const Conversation = ({ conversation, scrollKey, onMoveUp, onMoveDown })
|
|||
}
|
||||
}, [dispatch, lastStatus, expanded]);
|
||||
|
||||
if (!lastStatus) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const menu = [
|
||||
{ text: intl.formatMessage(messages.open), action: handleClick },
|
||||
null,
|
||||
|
|
|
@ -1,158 +0,0 @@
|
|||
{
|
||||
"about.fork_disclaimer": "Glitch-soc est un logiciel gratuit et open source, fork de Mastodon.",
|
||||
"account.disclaimer_full": "Les informations ci-dessous peuvent être incomplètes.",
|
||||
"account.follows": "Abonnements",
|
||||
"account.joined": "Ici depuis {date}",
|
||||
"account.suspended_disclaimer_full": "Cet utilisateur a été suspendu par un modérateur.",
|
||||
"account.view_full_profile": "Voir le profil complet",
|
||||
"advanced_options.icon_title": "Options avancées",
|
||||
"advanced_options.local-only.long": "Ne pas envoyer aux autres instances",
|
||||
"advanced_options.local-only.short": "Uniquement en local",
|
||||
"advanced_options.local-only.tooltip": "Ce post est uniquement local",
|
||||
"advanced_options.threaded_mode.long": "Ouvre automatiquement une réponse lors de la publication",
|
||||
"advanced_options.threaded_mode.short": "Mode thread",
|
||||
"advanced_options.threaded_mode.tooltip": "Mode thread activé",
|
||||
"boost_modal.missing_description": "Ce post contient des médias sans description",
|
||||
"column.favourited_by": "Ajouté en favori par",
|
||||
"column.heading": "Divers",
|
||||
"column.reblogged_by": "Partagé par",
|
||||
"column.subheading": "Autres options",
|
||||
"column_header.profile": "Profil",
|
||||
"column_subheading.lists": "Listes",
|
||||
"column_subheading.navigation": "Navigation",
|
||||
"community.column_settings.allow_local_only": "Afficher seulement les posts locaux",
|
||||
"compose.attach": "Joindre…",
|
||||
"compose.attach.doodle": "Dessiner quelque chose",
|
||||
"compose.attach.upload": "Téléverser un fichier",
|
||||
"compose.content-type.html": "HTML",
|
||||
"compose.content-type.markdown": "Markdown",
|
||||
"compose.content-type.plain": "Text brut",
|
||||
"compose_form.poll.multiple_choices": "Choix multiples",
|
||||
"compose_form.poll.single_choice": "Choix unique",
|
||||
"compose_form.spoiler": "Cacher le texte derrière un avertissement",
|
||||
"confirmation_modal.do_not_ask_again": "Ne plus demander confirmation",
|
||||
"confirmations.deprecated_settings.confirm": "Utiliser les préférences de Mastodon",
|
||||
"confirmations.deprecated_settings.message": "Certaines {app_settings} de glitch-soc que vous utilisez ont été remplacées par les {preferences} de Mastodon et seront remplacées :",
|
||||
"confirmations.missing_media_description.confirm": "Envoyer quand même",
|
||||
"confirmations.missing_media_description.edit": "Modifier le média",
|
||||
"confirmations.missing_media_description.message": "Au moins un média joint manque d'une description. Pensez à décrire tous les médias attachés pour les malvoyant·e·s avant de publier votre post.",
|
||||
"confirmations.unfilter.author": "Auteur",
|
||||
"confirmations.unfilter.confirm": "Afficher",
|
||||
"confirmations.unfilter.edit_filter": "Modifier le filtre",
|
||||
"confirmations.unfilter.filters": "Correspondance avec {count, plural, one {un filtre} other {plusieurs filtres}}",
|
||||
"content-type.change": "Type de contenu",
|
||||
"direct.group_by_conversations": "Grouper par conversation",
|
||||
"endorsed_accounts_editor.endorsed_accounts": "Comptes mis en avant",
|
||||
"favourite_modal.combo": "Vous pouvez appuyer sur {combo} pour passer ceci la prochaine fois",
|
||||
"firehose.column_settings.allow_local_only": "Afficher les messages locaux dans \"Tous\"",
|
||||
"home.column_settings.advanced": "Avancé",
|
||||
"home.column_settings.filter_regex": "Filtrer par expression régulière",
|
||||
"home.column_settings.show_direct": "Afficher les MPs",
|
||||
"home.settings": "Paramètres de la colonne",
|
||||
"keyboard_shortcuts.bookmark": "ajouter aux marque-pages",
|
||||
"keyboard_shortcuts.secondary_toot": "Envoyer le post en utilisant les paramètres secondaires de confidentialité",
|
||||
"keyboard_shortcuts.toggle_collapse": "Plier/déplier les posts",
|
||||
"media_gallery.sensitive": "Sensible",
|
||||
"moved_to_warning": "Ce compte a déménagé vers {moved_to_link} et ne peut donc plus accepter de nouveaux abonné·e·s.",
|
||||
"navigation_bar.app_settings": "Paramètres de l'application",
|
||||
"navigation_bar.featured_users": "Utilisateurs mis en avant",
|
||||
"navigation_bar.keyboard_shortcuts": "Raccourcis clavier",
|
||||
"navigation_bar.misc": "Autres",
|
||||
"notification.markForDeletion": "Ajouter aux éléments à supprimer",
|
||||
"notification_purge.btn_all": "Sélectionner\ntout",
|
||||
"notification_purge.btn_apply": "Effacer\nla sélection",
|
||||
"notification_purge.btn_invert": "Inverser\nla sélection",
|
||||
"notification_purge.btn_none": "Annuler\nla sélection",
|
||||
"notification_purge.start": "Activer le mode de nettoyage des notifications",
|
||||
"notifications.marked_clear": "Effacer les notifications sélectionnées",
|
||||
"notifications.marked_clear_confirmation": "Voulez-vous vraiment effacer de manière permanente toutes les notifications sélectionnées ?",
|
||||
"settings.always_show_spoilers_field": "Toujours activer le champ de rédaction de l'avertissement de contenu",
|
||||
"settings.auto_collapse": "Repliage automatique",
|
||||
"settings.auto_collapse_all": "Tout",
|
||||
"settings.auto_collapse_height": "Hauteur (en pixels) pour qu'un pouet soit considéré comme long",
|
||||
"settings.auto_collapse_lengthy": "Posts longs",
|
||||
"settings.auto_collapse_media": "Posts avec média",
|
||||
"settings.auto_collapse_notifications": "Notifications",
|
||||
"settings.auto_collapse_reblogs": "Boosts",
|
||||
"settings.auto_collapse_replies": "Réponses",
|
||||
"settings.close": "Fermer",
|
||||
"settings.collapsed_statuses": "Posts repliés",
|
||||
"settings.compose_box_opts": "Zone de rédaction",
|
||||
"settings.confirm_before_clearing_draft": "Afficher une fenêtre de confirmation avant d'écraser le message en cours de rédaction",
|
||||
"settings.confirm_boost_missing_media_description": "Afficher une fenêtre de confirmation avant de partager des posts manquant de description des médias",
|
||||
"settings.confirm_missing_media_description": "Afficher une fenêtre de confirmation avant de publier des posts manquant de description de média",
|
||||
"settings.content_warnings": "Content warnings",
|
||||
"settings.content_warnings.regexp": "Expression rationnelle",
|
||||
"settings.content_warnings_filter": "Avertissement de contenu à ne pas automatiquement déplier :",
|
||||
"settings.content_warnings_media_outside": "Afficher les médias en dehors des avertissements de contenu",
|
||||
"settings.content_warnings_media_outside_hint": "Reproduit le comportement par défaut de Mastodon, les médias attachés ne sont plus affectés par le bouton d'affichage d'un post avec avertissement",
|
||||
"settings.content_warnings_shared_state": "Affiche/cache le contenu de toutes les copies à la fois",
|
||||
"settings.content_warnings_shared_state_hint": "Reproduit le comportement par défaut de Mastodon, le bouton d'avertissement de contenu affecte toutes les copies d'un post à la fois. Cela empêchera le repliement automatique de n'importe quelle copie d'un post avec un avertissement déplié",
|
||||
"settings.content_warnings_unfold_opts": "Options de dépliement automatique",
|
||||
"settings.deprecated_setting": "Cette option est maintenant définie par les {settings_page_link} de Mastodon",
|
||||
"settings.enable_collapsed": "Activer le repliement des posts",
|
||||
"settings.enable_collapsed_hint": "Les posts repliés ont une partie de leur contenu caché pour libérer de l'espace sur l'écran. C'est une option différente de l'avertissement de contenu",
|
||||
"settings.enable_content_warnings_auto_unfold": "Déplier automatiquement les avertissements de contenu",
|
||||
"settings.general": "Général",
|
||||
"settings.hicolor_privacy_icons": "Indicateurs de confidentialité en couleurs",
|
||||
"settings.hicolor_privacy_icons.hint": "Affiche les indicateurs de confidentialité dans des couleurs facilement distinguables",
|
||||
"settings.image_backgrounds": "Images en arrière-plan",
|
||||
"settings.image_backgrounds_media": "Prévisualiser les médias d'un post replié",
|
||||
"settings.image_backgrounds_media_hint": "Si le post a un média attaché, utiliser le premier comme arrière-plan du post",
|
||||
"settings.image_backgrounds_users": "Donner aux posts repliés une image en arrière-plan",
|
||||
"settings.inline_preview_cards": "Cartes d'aperçu pour les liens externes",
|
||||
"settings.layout_opts": "Mise en page",
|
||||
"settings.media": "Média",
|
||||
"settings.media_fullwidth": "Utiliser toute la largeur pour les aperçus",
|
||||
"settings.media_letterbox": "Afficher les médias en Letterbox",
|
||||
"settings.media_letterbox_hint": "Réduit le média et utilise une letterbox pour afficher l'image entière plutôt que de l'étirer et de la rogner",
|
||||
"settings.media_reveal_behind_cw": "Toujours afficher les médias sensibles avec avertissement",
|
||||
"settings.notifications.favicon_badge": "Badge de notifications non lues dans la favicon",
|
||||
"settings.notifications.favicon_badge.hint": "Ajoute un badge dans la favicon pour alerter d'une notification non lue",
|
||||
"settings.notifications.tab_badge": "Badge de notifications non lues",
|
||||
"settings.notifications.tab_badge.hint": "Affiche un badge de notifications non lues dans les icônes des colonnes quand la colonne n'est pas ouverte",
|
||||
"settings.notifications_opts": "Options des notifications",
|
||||
"settings.pop_in_left": "Gauche",
|
||||
"settings.pop_in_player": "Activer le lecteur pop-in",
|
||||
"settings.pop_in_position": "Position du lecteur pop-in :",
|
||||
"settings.pop_in_right": "Droite",
|
||||
"settings.preferences": "Preferences",
|
||||
"settings.prepend_cw_re": "Préfixer les avertissements avec \"re: \" lors d'une réponse",
|
||||
"settings.preselect_on_reply": "Présélectionner les noms d’utilisateur·rices lors de la réponse",
|
||||
"settings.preselect_on_reply_hint": "Présélectionner les noms d'utilisateurs après le premier lors d'une réponse à une conversation à plusieurs participants",
|
||||
"settings.rewrite_mentions": "Réécrire les mentions dans les posts affichés",
|
||||
"settings.rewrite_mentions_acct": "Réécrire avec le nom d'utilisateur·rice et le domaine (lorsque le compte est distant)",
|
||||
"settings.rewrite_mentions_no": "Ne pas réécrire les mentions",
|
||||
"settings.rewrite_mentions_username": "Réécrire avec le nom d’utilisateur·rice",
|
||||
"settings.shared_settings_link": "préférences de l'utilisateur",
|
||||
"settings.show_action_bar": "Afficher les boutons d'action dans les posts repliés",
|
||||
"settings.show_content_type_choice": "Afficher le choix du type de contenu lors de la création des posts",
|
||||
"settings.show_reply_counter": "Afficher une estimation du nombre de réponses",
|
||||
"settings.side_arm": "Bouton secondaire de publication :",
|
||||
"settings.side_arm.none": "Aucun",
|
||||
"settings.side_arm_reply_mode": "Quand vous répondez à un post, le bouton secondaire de publication devrait :",
|
||||
"settings.side_arm_reply_mode.copy": "Copier la confidentialité du post auquel vous répondez",
|
||||
"settings.side_arm_reply_mode.keep": "Garder la confidentialité établie",
|
||||
"settings.side_arm_reply_mode.restrict": "Restreindre la confidentialité de la réponse à celle du post auquel vous répondez",
|
||||
"settings.status_icons": "Icônes des posts",
|
||||
"settings.status_icons_language": "Indicateur de langue",
|
||||
"settings.status_icons_local_only": "Indicateur de post local",
|
||||
"settings.status_icons_media": "Indicateur de médias et sondage",
|
||||
"settings.status_icons_reply": "Indicateur de réponses",
|
||||
"settings.status_icons_visibility": "Indicateur de la confidentialité du post",
|
||||
"settings.swipe_to_change_columns": "Glissement latéral pour changer de colonne (mobile uniquement)",
|
||||
"settings.tag_misleading_links": "Étiqueter les liens trompeurs",
|
||||
"settings.tag_misleading_links.hint": "Ajouter une indication visuelle avec l'hôte cible du lien à chaque lien ne le mentionnant pas explicitement",
|
||||
"settings.wide_view": "Vue élargie (mode ordinateur uniquement)",
|
||||
"settings.wide_view_hint": "Étire les colonnes pour mieux remplir l'espace disponible.",
|
||||
"status.collapse": "Replier",
|
||||
"status.has_audio": "Contient des fichiers audio attachés",
|
||||
"status.has_pictures": "Contient des images attachées",
|
||||
"status.has_preview_card": "Contient une carte de prévisualisation attachée",
|
||||
"status.has_video": "Contient des vidéos attachées",
|
||||
"status.in_reply_to": "Ce post est une réponse",
|
||||
"status.is_poll": "Ce post est un sondage",
|
||||
"status.local_only": "Visible uniquement depuis votre instance",
|
||||
"status.sensitive_toggle": "Cliquer pour voir",
|
||||
"status.uncollapse": "Déplier"
|
||||
}
|
|
@ -156,7 +156,7 @@ class ActivityPub::Activity
|
|||
if object_uri.start_with?('http')
|
||||
return if ActivityPub::TagManager.instance.local_uri?(object_uri)
|
||||
|
||||
ActivityPub::FetchRemoteStatusService.new.call(object_uri, id: true, on_behalf_of: @account.followers.local.first, request_id: @options[:request_id])
|
||||
ActivityPub::FetchRemoteStatusService.new.call(object_uri, on_behalf_of: @account.followers.local.first, request_id: @options[:request_id])
|
||||
elsif @object['url'].present?
|
||||
::FetchRemoteStatusService.new.call(@object['url'], request_id: @options[:request_id])
|
||||
end
|
||||
|
|
|
@ -19,7 +19,7 @@ class ActivityPub::LinkedDataSignature
|
|||
return unless type == 'RsaSignature2017'
|
||||
|
||||
creator = ActivityPub::TagManager.instance.uri_to_actor(creator_uri)
|
||||
creator = ActivityPub::FetchRemoteKeyService.new.call(creator_uri, id: false) if creator&.public_key.blank?
|
||||
creator = ActivityPub::FetchRemoteKeyService.new.call(creator_uri) if creator&.public_key.blank?
|
||||
|
||||
return if creator.nil?
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
class ActivityPub::FetchRemoteAccountService < ActivityPub::FetchRemoteActorService
|
||||
# Does a WebFinger roundtrip on each call, unless `only_key` is true
|
||||
def call(uri, id: true, prefetched_body: nil, break_on_redirect: false, only_key: false, suppress_errors: true, request_id: nil)
|
||||
def call(uri, prefetched_body: nil, break_on_redirect: false, only_key: false, suppress_errors: true, request_id: nil)
|
||||
actor = super
|
||||
return actor if actor.nil? || actor.is_a?(Account)
|
||||
|
||||
|
|
|
@ -10,15 +10,15 @@ class ActivityPub::FetchRemoteActorService < BaseService
|
|||
SUPPORTED_TYPES = %w(Application Group Organization Person Service).freeze
|
||||
|
||||
# Does a WebFinger roundtrip on each call, unless `only_key` is true
|
||||
def call(uri, id: true, prefetched_body: nil, break_on_redirect: false, only_key: false, suppress_errors: true, request_id: nil)
|
||||
def call(uri, prefetched_body: nil, break_on_redirect: false, only_key: false, suppress_errors: true, request_id: nil)
|
||||
return if domain_not_allowed?(uri)
|
||||
return ActivityPub::TagManager.instance.uri_to_actor(uri) if ActivityPub::TagManager.instance.local_uri?(uri)
|
||||
|
||||
@json = begin
|
||||
if prefetched_body.nil?
|
||||
fetch_resource(uri, id)
|
||||
fetch_resource(uri, true)
|
||||
else
|
||||
body_to_json(prefetched_body, compare_id: id ? uri : nil)
|
||||
body_to_json(prefetched_body, compare_id: uri)
|
||||
end
|
||||
rescue Oj::ParseError
|
||||
raise Error, "Error parsing JSON-LD document #{uri}"
|
||||
|
|
|
@ -6,23 +6,10 @@ class ActivityPub::FetchRemoteKeyService < BaseService
|
|||
class Error < StandardError; end
|
||||
|
||||
# Returns actor that owns the key
|
||||
def call(uri, id: true, prefetched_body: nil, suppress_errors: true)
|
||||
def call(uri, suppress_errors: true)
|
||||
raise Error, 'No key URI given' if uri.blank?
|
||||
|
||||
if prefetched_body.nil?
|
||||
if id
|
||||
@json = fetch_resource_without_id_validation(uri)
|
||||
if actor_type?
|
||||
@json = fetch_resource(@json['id'], true)
|
||||
elsif uri != @json['id']
|
||||
raise Error, "Fetched URI #{uri} has wrong id #{@json['id']}"
|
||||
end
|
||||
else
|
||||
@json = fetch_resource(uri, id)
|
||||
end
|
||||
else
|
||||
@json = body_to_json(prefetched_body, compare_id: id ? uri : nil)
|
||||
end
|
||||
@json = fetch_resource(uri, false)
|
||||
|
||||
raise Error, "Unable to fetch key JSON at #{uri}" if @json.nil?
|
||||
raise Error, "Unsupported JSON-LD context for document #{uri}" unless supported_context?(@json)
|
||||
|
|
|
@ -8,14 +8,14 @@ class ActivityPub::FetchRemoteStatusService < BaseService
|
|||
DISCOVERIES_PER_REQUEST = 1000
|
||||
|
||||
# Should be called when uri has already been checked for locality
|
||||
def call(uri, id: true, prefetched_body: nil, on_behalf_of: nil, expected_actor_uri: nil, request_id: nil)
|
||||
def call(uri, prefetched_body: nil, on_behalf_of: nil, expected_actor_uri: nil, request_id: nil)
|
||||
return if domain_not_allowed?(uri)
|
||||
|
||||
@request_id = request_id || "#{Time.now.utc.to_i}-status-#{uri}"
|
||||
@json = if prefetched_body.nil?
|
||||
fetch_resource(uri, id, on_behalf_of)
|
||||
fetch_resource(uri, true, on_behalf_of)
|
||||
else
|
||||
body_to_json(prefetched_body, compare_id: id ? uri : nil)
|
||||
body_to_json(prefetched_body, compare_id: uri)
|
||||
end
|
||||
|
||||
return unless supported_context?
|
||||
|
@ -65,7 +65,7 @@ class ActivityPub::FetchRemoteStatusService < BaseService
|
|||
|
||||
def account_from_uri(uri)
|
||||
actor = ActivityPub::TagManager.instance.uri_to_resource(uri, Account)
|
||||
actor = ActivityPub::FetchRemoteAccountService.new.call(uri, id: true, request_id: @request_id) if actor.nil? || actor.possibly_stale?
|
||||
actor = ActivityPub::FetchRemoteAccountService.new.call(uri, request_id: @request_id) if actor.nil? || actor.possibly_stale?
|
||||
actor
|
||||
end
|
||||
|
||||
|
|
|
@ -277,7 +277,7 @@ class ActivityPub::ProcessAccountService < BaseService
|
|||
|
||||
def moved_account
|
||||
account = ActivityPub::TagManager.instance.uri_to_resource(@json['movedTo'], Account)
|
||||
account ||= ActivityPub::FetchRemoteAccountService.new.call(@json['movedTo'], id: true, break_on_redirect: true, request_id: @options[:request_id])
|
||||
account ||= ActivityPub::FetchRemoteAccountService.new.call(@json['movedTo'], break_on_redirect: true, request_id: @options[:request_id])
|
||||
account
|
||||
end
|
||||
|
||||
|
|
|
@ -48,7 +48,15 @@ class FetchResourceService < BaseService
|
|||
body = response.body_with_limit
|
||||
json = body_to_json(body)
|
||||
|
||||
[json['id'], { prefetched_body: body, id: true }] if supported_context?(json) && (equals_or_includes_any?(json['type'], ActivityPub::FetchRemoteActorService::SUPPORTED_TYPES) || expected_type?(json))
|
||||
return unless supported_context?(json) && (equals_or_includes_any?(json['type'], ActivityPub::FetchRemoteActorService::SUPPORTED_TYPES) || expected_type?(json))
|
||||
|
||||
if json['id'] != @url
|
||||
return if terminal
|
||||
|
||||
return process(json['id'], terminal: true)
|
||||
end
|
||||
|
||||
[@url, { prefetched_body: body }]
|
||||
elsif !terminal
|
||||
link_header = response['Link'] && parse_link_header(response)
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ module Mastodon
|
|||
end
|
||||
|
||||
def default_prerelease
|
||||
'alpha.0'
|
||||
'alpha.1'
|
||||
end
|
||||
|
||||
def prerelease
|
||||
|
@ -25,7 +25,7 @@ module Mastodon
|
|||
end
|
||||
|
||||
def catstodon_revision
|
||||
'1.0.14'
|
||||
'1.0.15'
|
||||
end
|
||||
|
||||
def build_metadata
|
||||
|
|
|
@ -56,7 +56,7 @@ RSpec.describe ActivityPub::LinkedDataSignature do
|
|||
|
||||
allow(ActivityPub::FetchRemoteKeyService).to receive(:new).and_return(service_stub)
|
||||
|
||||
allow(service_stub).to receive(:call).with('http://example.com/alice', id: false) do
|
||||
allow(service_stub).to receive(:call).with('http://example.com/alice') do
|
||||
sender.update!(public_key: old_key)
|
||||
sender
|
||||
end
|
||||
|
@ -64,7 +64,7 @@ RSpec.describe ActivityPub::LinkedDataSignature do
|
|||
|
||||
it 'fetches key and returns creator' do
|
||||
expect(subject.verify_actor!).to eq sender
|
||||
expect(service_stub).to have_received(:call).with('http://example.com/alice', id: false).once
|
||||
expect(service_stub).to have_received(:call).with('http://example.com/alice').once
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ RSpec.describe ActivityPub::FetchRemoteAccountService, type: :service do
|
|||
end
|
||||
|
||||
describe '#call' do
|
||||
let(:account) { subject.call('https://example.com/alice', id: true) }
|
||||
let(:account) { subject.call('https://example.com/alice') }
|
||||
|
||||
shared_examples 'sets profile data' do
|
||||
it 'returns an account' do
|
||||
|
|
|
@ -18,7 +18,7 @@ RSpec.describe ActivityPub::FetchRemoteActorService, type: :service do
|
|||
end
|
||||
|
||||
describe '#call' do
|
||||
let(:account) { subject.call('https://example.com/alice', id: true) }
|
||||
let(:account) { subject.call('https://example.com/alice') }
|
||||
|
||||
shared_examples 'sets profile data' do
|
||||
it 'returns an account' do
|
||||
|
|
|
@ -55,7 +55,7 @@ RSpec.describe ActivityPub::FetchRemoteKeyService, type: :service do
|
|||
end
|
||||
|
||||
describe '#call' do
|
||||
let(:account) { subject.call(public_key_id, id: false) }
|
||||
let(:account) { subject.call(public_key_id) }
|
||||
|
||||
context 'when the key is a sub-object from the actor' do
|
||||
before do
|
||||
|
|
|
@ -57,7 +57,7 @@ RSpec.describe FetchResourceService, type: :service do
|
|||
|
||||
let(:json) do
|
||||
{
|
||||
id: 1,
|
||||
id: 'http://example.com/foo',
|
||||
'@context': ActivityPub::TagManager::CONTEXT,
|
||||
type: 'Note',
|
||||
}.to_json
|
||||
|
@ -83,27 +83,27 @@ RSpec.describe FetchResourceService, type: :service do
|
|||
let(:content_type) { 'application/activity+json; charset=utf-8' }
|
||||
let(:body) { json }
|
||||
|
||||
it { is_expected.to eq [1, { prefetched_body: body, id: true }] }
|
||||
it { is_expected.to eq ['http://example.com/foo', { prefetched_body: body }] }
|
||||
end
|
||||
|
||||
context 'when content type is ld+json with profile' do
|
||||
let(:content_type) { 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' }
|
||||
let(:body) { json }
|
||||
|
||||
it { is_expected.to eq [1, { prefetched_body: body, id: true }] }
|
||||
it { is_expected.to eq ['http://example.com/foo', { prefetched_body: body }] }
|
||||
end
|
||||
|
||||
context 'when link header is present' do
|
||||
let(:headers) { { 'Link' => '<http://example.com/foo>; rel="alternate"; type="application/activity+json"' } }
|
||||
|
||||
it { is_expected.to eq [1, { prefetched_body: json, id: true }] }
|
||||
it { is_expected.to eq ['http://example.com/foo', { prefetched_body: json }] }
|
||||
end
|
||||
|
||||
context 'when content type is text/html' do
|
||||
let(:content_type) { 'text/html' }
|
||||
let(:body) { '<html><head><link rel="alternate" href="http://example.com/foo" type="application/activity+json"/></head></html>' }
|
||||
|
||||
it { is_expected.to eq [1, { prefetched_body: json, id: true }] }
|
||||
it { is_expected.to eq ['http://example.com/foo', { prefetched_body: json }] }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -139,6 +139,7 @@ describe ResolveURLService, type: :service do
|
|||
stub_request(:get, url).to_return(status: 302, headers: { 'Location' => status_url })
|
||||
body = ActiveModelSerializers::SerializableResource.new(status, serializer: ActivityPub::NoteSerializer, adapter: ActivityPub::Adapter).to_json
|
||||
stub_request(:get, status_url).to_return(body: body, headers: { 'Content-Type' => 'application/activity+json' })
|
||||
stub_request(:get, uri).to_return(body: body, headers: { 'Content-Type' => 'application/activity+json' })
|
||||
end
|
||||
|
||||
it 'returns status by url' do
|
||||
|
|
|
@ -14,6 +14,7 @@ Capybara.register_driver :headless_chrome do |app|
|
|||
options = Selenium::WebDriver::Chrome::Options.new
|
||||
options.add_argument '--headless=new'
|
||||
options.add_argument '--window-size=1680,1050'
|
||||
options.browser_version = '120'
|
||||
|
||||
Capybara::Selenium::Driver.new(
|
||||
app,
|
||||
|
|
Loading…
Reference in a new issue