activitypub-1.0.x-dev/src/Controller/InboxController.php

src/Controller/InboxController.php
<?php

namespace Drupal\activitypub\Controller;

use Drupal\activitypub\Entity\ActivityPubActivityInterface;
use Drupal\activitypub\Entity\ActivitypubActorInterface;
use Drupal\user\UserInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;

class InboxController extends BaseController {

  /**
   * Inbox routing callback.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   * @param \Drupal\user\UserInterface $user
   * @param \Drupal\activitypub\Entity\ActivitypubActorInterface $activitypub_actor
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   */
  public function inbox(Request $request, UserInterface $user, ActivitypubActorInterface $activitypub_actor) {
    $status = 400;
    $payload = @json_decode((string)$request->getContent(), TRUE);
    $actor = !empty($payload['actor']) ? $payload['actor'] : '';
    $id = !empty($payload['id']) ? $payload['id'] : '';

    if ($request->getMethod() == 'POST' && !empty($payload) && !empty($actor) && !empty($id)) {
      try {
        if (!$this->domainIsBlocked($activitypub_actor->getBlockedDomains(), $actor)) {

          $log_error_signature = $this->config('activitypub.settings')->get('log_error_signature');
          $log_success_signature = $this->config('activitypub.settings')->get('log_success_signature');
          $log_followee_check = $this->config('activitypub.settings')->get('log_followee_check');

          // The signature check is used to set the status of the activity.
          // There is a big chance some might fail depending how the request is
          // signed and which rfc version is used. In case the verification
          // fails, we allow posts to be followed in case the actor is a
          // followee of the current user.
          try {
            $published = $this->activityPubSignature->verifySignature($request, $actor, $this->activityPubUtility->getServer());
            if ($published) {
              if ($log_success_signature) {
                $this->getLogger('activitypub')->notice('Signature verified for id @id', ['@id' => $id]);
              }
            }
            elseif (isset($payload['type']) && in_array($payload['type'], $this->activityPubUtility->getTimelineTypes())) {
              $published = $this->isFollowee($actor, $activitypub_actor->getOwnerId());
              if ($log_followee_check) {
                if ($published) {
                  $this->getLogger('activitypub')->notice('Post published: @actor follows @followee', ['@actor' => $activitypub_actor->getName(), '@followee' => $payload['actor']]);
                }
                else {
                  $this->getLogger('activitypub')->notice('Post left unpublished: @actor does not follow @followee', ['@actor' => $activitypub_actor->getName(), '@followee' => $payload['actor']]);
                }
              }
            }
          }
          catch (\Exception $e) {
            $published = FALSE;
            if ($log_error_signature) {
              $this->getLogger('activitypub')->error('Inbox signature/followee exception: @message', ['@message' => $e->getMessage()]);
            }
          }

          // Get the object.
          $object = $this->getObject($payload);

          /** @var \Drupal\activitypub\Entity\Storage\ActivityPubActivityStorage $storage */
          $storage = $this->entityTypeManager()->getStorage('activitypub_activity');
          $values = [
            'uid' => $user->id(),
            'collection' => ActivityPubActivityInterface::INBOX,
            'external_id' => $id,
            'type' => $payload['type'],
            'actor' => $actor,
            'object' => $object,
            'payload' => (string) $request->getContent(),
            'status' => $published,
          ];

          if (is_array($payload['object']) && !empty($payload['object']['inReplyTo'])) {
            $values['reply'] = $payload['object']['inReplyTo'];
          }

          /** @var \Drupal\activitypub\Entity\ActivityPubActivityInterface $activity */
          $activity = $storage->create($values);
          $doSave = TRUE;
          $activity->preInboxSave($doSave);
          if ($doSave) {
            $activity->save();
          }
          elseif ($this->config('activitypub.settings')->get('log_unsaved_inbox_activity')) {
            $this->getLogger('activitypub')->notice('Not saved - Payload: @payload', ['@payload' => print_r($payload, 1)]);
          }

          $status = 202;
        }
        else {
          $status = 403;
        }
      }
      catch (\Exception $e) {
        if ($this->config('activitypub.settings')->get('log_general_inbox_error')) {
          $this->getLogger('activitypub')->error('Inbox general error: @message - @content', ['@message' => $e->getMessage(), '@content' => (string) $request->getContent()]);
        }
      }
    }

    return new JsonResponse(NULL, $status);
  }

  /**
   * Returns if the actor is followed by the user.
   *
   * @param $followee
   * @param $uid
   *
   * @return bool
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  protected function isFollowee($followee, $uid) {

    $conditions = [
      'type' => 'Follow',
      'status' => 1,
      'object' => $followee,
      'uid' => $uid,
      'collection' => ActivityPubActivityInterface::OUTBOX,
    ];

    /** @var \Drupal\activitypub\Entity\Storage\ActivityPubActivityStorage $storage */
    $storage = $this->entityTypeManager()->getStorage('activitypub_activity');
    $count = $storage->getActivityCount($conditions);

    return $count === 1;
  }

  /**
   * Returns whether the actor is blocked or not.
   *
   * @param $domains
   * @param $actor
   *
   * @return false
   */
  protected function domainIsBlocked($domains, $actor) {
    $blocked = FALSE;

    if (!empty($domains)) {
      $blocked = $this->pathMatcher->matchPath($actor, $domains);
    }

    return $blocked;
  }

  /**
   * Gets the object.
   *
   * @param $payload
   *
   * @return mixed|string
   */
  protected function getObject($payload) {
    $object = '';

    if (isset($payload['object'])) {
      if (is_array($payload['object']) && isset($payload['object']['object'])) {
        if ($payload['type'] == 'Accept' && isset($payload['object']['actor'])) {
          $object = $payload['object']['actor'];
        }
        else {
          $object = $payload['object']['object'];
        }
      }
      elseif (is_array($payload['object']) && isset($payload['object']['id'])) {
        $object = $payload['object']['id'];
      }
      elseif ($payload['type'] == 'Move' && !empty($payload['target'])) {
        $object = $payload['target'];
      }
      elseif (is_string($payload['object'])) {
        $object = $payload['object'];
      }
    }

    return $object;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc