README.md 8.02 KB
Newer Older
1 2
# ActivityPub for Drupal

3 4
Implements the ActivityPub protocol for your site. Readers will be able to
follow content on Mastodon and other federated platforms that support
swentel's avatar
swentel committed
5
ActivityPub. Responses are possible too (Reply, Like, Announce) with more to
6 7
come.

swentel's avatar
swentel committed
8
The module has been tested with the following federated platforms:
9

swentel's avatar
swentel committed
10
- Mastodon: follow/accept, post notes (with image), reply
swentel's avatar
swentel committed
11
- Pleroma: follow/accept, post notes, reply
swentel's avatar
swentel committed
12
- Pixelfed: follow/accept, reply
13

14 15
Open an issue if you have successfully interacted with another platform!

16 17 18 19 20 21 22 23
## Features

- Enable ActivityPub per user
- Block remote domains from posting
- Map Activity types to content types
- discovery via Webfinger module
- outbox and followers endpoints
- HttpSignature for authorization
swentel's avatar
swentel committed
24
- Accept follow requests, Undo (follow)
25 26 27
- Configure Activity types and properties
- Send posts via drush or cron

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
## Installation and configuration.

Use composer require drupal/activitypub to get all dependencies:

- Drupal webfinger module
- Drupal nodeinfo module
- landrok/activitypub library

1. Enable Activitypub module
2. Configure permissions:
    - 'view user profiles' for anonymous users
    - 'allow users to enable activitypub' for authenticated user (or a role)
3. At this point, when a user has enabled activitypub at user
/x/activitypub/settings, they should be discoverable. Try searching for
@handle@domain on Mastodon. If you follow this user, an entry will arrive
in the inbox and an Accept outbox entry will be created automatically
4. Configure global settings at admin/config/services/activitypub to
select how to process those outbox activities. Then either run cron,
configure a crontab for the drush command or manually call it. The
outbox activities will be send then.
5. On admin/config/services/activitypub/activitypub-type you get an overview
of all ActivityPub Type configuration entities. Two are enabled (and locked)
when enabling this module, which are the 'Accept' and 'Delete' types.
6. Create your own configuration
    - Select 'Type plugin', only dynamic types are available
    - Select the content type which you want to map
    - Select the activity (See '1' and '2' underneath)
    - Select the object (use Note if you do not want to populate a title)
    - Map properties to the content type fields
7. When saved, go to the content type you selected. You can now select the
entity which will process this node in the 'ActivityPub outbox' fieldset.

**important**

1. The 'Send to' fieldset must currently have a value and point to a remote
user. Sending a post to multiple followers is in development and will arrive
soon.
2. Make sure a 'Reply' URL points to the canonical URL. For example,
do not use the URL in your browser for a Mastodon status
    - Will work: https://mastodon.social/@swentel/104960564425633436
    - Will not work: https://mastodon.social/web/statuses/104960564425633436

Footnotes:

1. Use Create when you want to send regular posts (e.g note, article or reply)
2. 'Announce' usually stands for the 'Boost'/'Retweet' response

## Plugins

ActivityPub types (activities, objects, etc) are managed by plugins. This module
ships with two types of plugins:

- Dynamic types: map content types and properties
- Static types: manages the 'Accept', 'Follow' and 'Undo' activity type.

**Important**: as this module is still alpha, the interface and methods will most
likely change, so be careful when implementing your own plugin. If a change
happens, the release notes of a new release will document those changes.

87 88 89
## Public and Private keys

Public and private keys are saved in private://activitypub/keys.
swentel's avatar
swentel committed
90
The default path can be overridden in settings.php via settings:
91 92

```
swentel's avatar
swentel committed
93
$settings['activitypub_keys_path'] = '/your/path/';
94 95
```

96
## Default avatar
97

98
The default avatar path can be overridden in settings.php via settings:
99

100 101 102 103 104 105 106 107 108 109 110 111
```
$settings['activitypub_default_avatar_path'] = '/default/image.png';
```

## Inbox and outbox

Every user has an inbox and outbox where activities from remote users are stored.

'Accept', 'Undo' and handled by the 'Static types' plugin. All other activity
types will be stored, but do not have any impact.

An overview can be found at user/x/activitypub.
112

113 114 115
## Sending posts to followers

Activities in the outbox are stored in a queue and send either by
116
cron or drush. Configure this at /admin/config/services/activitypub
117

swentel's avatar
swentel committed
118 119 120
The drush command is activitypub:send-activities which has 3 parameters
- send: send activity request (defaults to 1)
- delete: remove queue item (defaults to 1)
121
- debug: show command line debug messages (defaults to 0)
swentel's avatar
swentel committed
122

123
## Drush commands
swentel's avatar
swentel committed
124

125 126 127 128
- activitypub:send-activities: send activities ready to be processed
- activitypub:add-to-queue: adds an outbox activity to the queue
- activitypub:delete-activity: send a delete request
- activitypub:webfinger-info: test command to get info about a remote user
129 130 131 132 133

## FAQ

### Can I follow users

swentel's avatar
typo  
swentel committed
134
Technically this would possible with a new plugin, but there's no (decent)
135
interface to view the incoming posts. In combination with the IndieWeb module,
swentel's avatar
swentel committed
136
you can set up a great stack where you can follow content from any source, and
137 138 139 140 141 142 143 144 145
interact with it as well.

### Can I use this together with the IndieWeb module

As mentioned in the previous question, you can use the Microsub module to
follow users and then use your favorite client to read content and interact via
Micropub.

If you are using a Micropub client (or in-built in a Reader), using one or
swentel's avatar
swentel committed
146 147
more syndication targets can help you to create an outbox request. Create a
syndication target which is not a URL. These won't be added then to the
swentel's avatar
swentel committed
148
webmention queue. Once done, you need to implement two hooks with custom code:
149 150

```
swentel's avatar
swentel committed
151 152 153 154 155 156 157 158 159 160 161 162 163
/**
 * Implements hook_indieweb_micropub_node_pre_create_alter().
 */
function hook_indieweb_micropub_node_pre_create_alter(&$values, &$payload) {
  // Reset mp-syndicate-to in case you configure to automatically send
  // a webmention to the link found in in-reply-to.
  if (!empty($payload['mp-syndicate-to'])) {
    if (in_array('activitypub_reply', $payload['mp-syndicate-to'])) {
      $payload['mp-syndicate-to'] = ['activitypub_reply'];
    }
  }
}

swentel's avatar
swentel committed
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
/**
 * Implements hook_indieweb_micropub_node_saved().
 */
function hook_indieweb_micropub_node_saved(NodeInterface $node, $values, $payload, $payload_original) {
  if (!empty($payload_original['mp-syndicate-to'])) {
    foreach ($payload_original['mp-syndicate-to'] as $target) {
      switch ($target) {
        // Value of syndication target.
        case 'activitypub_reply':
          if ($node->bundle() == 'reply') {

            $values = [
              'status' => TRUE,
              'collection' => 'outbox',
              // id of reply config entity
              'config_id' => 'reply',
              'uid' => $node->getOwnerId(),
              // Replace {actor_name} with the activitypub name.
              'actor' => 'https://yourdomain.com/user/1/activitypub/{actor_name}',
              'entity_type_id' => 'node',
              'entity_id' => $node->id(),
              'processed' => FALSE,
            ];

            // This is a reply, so we have the in-reply-to microformat value.
            // Other values of this can be 'followers' or the canonical link
            // of a user.
            $values['object'] = $payload_original['in-reply-to'][0];

            /** @var \Drupal\activitypub\Entity\ActivityPubActivityInterface $activity */
            $activity = \Drupal::entityTypeManager()->getStorage('activitypub_activity')->create($values);
            $activity->save();
            \Drupal::service('activitypub.outbox.client')->createQueueItem($activity);
            Cache::invalidateTags(['user:' . $node->getOwnerId()]);
          }
          break;
      }
    }
  }
}
204 205 206 207 208 209 210
```

### Can I send DM's

You can not at this moment, but you should probably just use e-mail :)
Although not tested yet, DM's probably will arrive in the inbox when a remote
user would send one.
swentel's avatar
swentel committed
211 212 213 214 215 216 217 218

## Sponsors

I would like to extend many thanks to the following sponsors for funding development.

- [NLnet Foundation](https://nlnet.nl) and [NGI0
Discovery](https://nlnet.nl/discovery/), part of the [Next Generation
Internet](https://ngi.eu) initiative.