Commit graph

78 commits

Author SHA1 Message Date
fr33domlover
ef57f29a54 Adapt Activity/Create/Note to new ActivityPub typeclass and add safety checks 2019-03-10 06:42:03 +00:00
fr33domlover
61d1aa6720 Define HMAC based access token and switch CapSignKey from Ed25519 to HMAC 2019-03-09 21:21:36 +00:00
fr33domlover
6e721797e9 Catch sig generation error when sending signed HTTP POST 2019-03-05 08:26:41 +00:00
fr33domlover
17524b6ee1 Remove hardcoded-to-2 limit on length of an actor's list of public keys 2019-02-24 01:21:42 +00:00
fr33domlover
0912b8e291 Use the DB for checking key usage by actors
* When we refetch a personal key, we never need to separately fetch the actor
* When we refetch a shared key, check usage in DB and insert usage to DB
2019-02-23 17:17:52 +00:00
fr33domlover
b53a7b4f48 Refactor actor key fetching code a bit 2019-02-22 08:30:43 +00:00
fr33domlover
1affe269bb Refactor HTTP sig verification DB update code 2019-02-22 07:20:19 +00:00
fr33domlover
d3e14b3edf Add LocalURI type for recording shared URI host 2019-02-21 23:59:53 +00:00
fr33domlover
aefb2aaee7 Add InstanceURI datatype 2019-02-20 07:40:25 +00:00
fr33domlover
312ccf6979 When verifying HTTP sig with known shared key, verify actor lists the key
Previously, when verifying an HTTP signature and we fetched the key and
discovered it's shared, we'd fetch the actor and make sure it lists the key URI
in the `publicKey` field. But if we already knew the key, had it cached in our
DB, we wouldn't check the actor at all, despite not knowing whether it lists
the key.

With this patch, we now always GET the actor when the key is shared,
determining the actor URI from the `ActivityPub-Actor` request header, and we
verify that the actor lists the key URI. We do that regardless of whether or
not we have the key in the DB, although these two cases and handled in
different parts of the code right now (for a new key, it's in Web.ActivityPub
fetchKey; for a known key, it's in Vervis.Foundation httpVerifySig).
2019-02-18 09:20:13 +00:00
fr33domlover
fa5c509a25 When we fetch a stand-alone personal key, make sure AP-Actor matches key owner
If the key we fetched is a shared key, the only way to determine the actor to
which the signature applies is to read the HTTP header ActivityPub-Actor. But
if it's a personal key, we can detect the actor by checking the key's owner
field. Still, if that actor header is provided, we now compare it to the key
owner and make sure they're identical.

When fetching a key that is embedded in the actor document, we were already
comparing the actor ID with the actor header, so that part didn't require
changes.
2019-02-17 00:14:05 +00:00
fr33domlover
9e0314fa09 Store remote actors' inbox URIs in DB, avoiding some actor fetch
When a local user wants to publish an activity, we were always GETing the
recipient actor, so that we could determine their inbox and POST the activity
to it. But now, instead, whenever we GET an actor (whether it's for the key sig
verification or for determining inbox URI), we keep their inbox URI in the
database, and we don't need to GET it again next time.
2019-02-14 23:27:40 +00:00
fr33domlover
754709833a When a client posts to their outbox, allow only Create Note, not near-any JSON 2019-02-12 11:53:24 +00:00
fr33domlover
c2bf470fb6 Generate and keep permanent salt for generating hashids for URIs 2019-02-08 21:54:22 +00:00
fr33domlover
8ac559d064 New datatype FedURI for @id URIs
Using a dedicated type allows to record in the type the guarantees that we
provide, such as scheme being HTTPS and authority being present. Allows to
replace ugly `fromJust` and such with direct field access.
2019-02-07 23:08:28 +00:00
fr33domlover
e325175a9c Publish 2 rotating instance-scope keys instead of the one-implicitly-shared-key
Before, there was a single key used as a personal key for all actors. Now,
things work like this:

- There are 2 keys, each time one is rotated, this way the old key remains
  valid and we can freely rotate without a risk of race conditions on other
  servers and end up with our posts being rejected
- The keys are explicitly instance-scope keys, all actors refer to them
- We add the ActivityPub-Actor header to all activity POSTs we send, to declare
  for which specific actor our signature applies. Activities and otherwise
  different payloads may have varying ways to specify attribution; using this
  header will be a standard uniform way to specify the actor, regardless of
  payload format. Of course, servers should make sure the actual activity is
  attributed to the same actor we specified in the header. (This is important
  with instance-scope keys; for personal keys it's not critical)
2019-02-07 10:34:33 +00:00
fr33domlover
8166d5b5eb Support for instance-scope keys when verifying HTTP signature 2019-02-06 02:48:23 +00:00
fr33domlover
400245cf34 Accept HTTP signatures made with shared instance-scope actor keys 2019-02-05 13:02:15 +00:00
fr33domlover
c2c4e24497 Support actor key expiration
Allow keys to specify expiration time using w3c security vocabulary. If a key
has expired, we treat it like sig validation failure and re-fetch the key from
the other server. And we never accept a sig, even a valid sig, if the key has
expired.

Since servers keep actors and keys in the DB, expiration can be a nice way to
ask that keys aren't used more than we want them to. The security vocab spec
also recommends to set expiration time on keys, so it's nice to support this
feature.
2019-02-05 04:05:44 +00:00
fr33domlover
37b3416a41 Support remote actors specifying 2 keys, and DB storage of these keys
It's now possible for activities we be attributed to actors that have more than
one key. We allow up to 2 keys. We also store in the DB. Scaling to support any
number of keys is trivial, but I'm limiting to 2 to avoid potential trouble and
because 2 is the actual number we need.

By having 2 keys, and replacing only one of them in each rotation, we avoid
race conditions. With 1 key, the following can happen:

1. We send an activity to another server
2. We rotate our key
3. The server reaches the activity in its processing queue, tries to verify our
   request signature, but fails because it can't fetch the key. It's the old
   key and we discarded it already, replaced it with the new one

When we use 2 keys, the previous key remains available and other servers have
time to finish processing our requests signed with that key. We can safely
rotate, without worrying about whether the user sent anything right before the
rotation time.

Caveat: With this feature, we allow OTHER servers to rotate freely. It's safe
because it's optional, but it's just Vervis right now. Once Vervis itself
starts using 2 keys, it will be able to rotate freely without race condition
risk, but probably Mastodon etc. won't accept its signatures because of the use
of 2 keys and because they're server-scope keys.

Maybe I can get these features adopted by the fediverse?
2019-02-04 19:38:50 +00:00
fr33domlover
02da508ed0 Allow actor publicKey to be a URI, and require the URI to match the Sig keyId 2019-02-04 10:07:25 +00:00
fr33domlover
c336d56036 Allow actor public key to be in a separate document 2019-02-03 23:39:56 +00:00
fr33domlover
21c8df1251 Actor public key specifies whether it's shared
Shared key means the key is used for multiple actors. I'm not sure explicitly
specifying this will be necessary, but I prefer to have it in place to help
with debugging in case something unexpected comes from other servers, or my
format overlaps with stuff used in other software and encodes a different
meaning.

Each public key can specify whether it's shared or personal, and this patch
checks for that when verifying a request signature. It rejects shared keys,
accepting valid sigs only from personal keys.

Very soon I'll add shared key support.
2019-02-03 11:12:18 +00:00
fr33domlover
991296faa1 Move some JSON/AP codec utils to new Data.Aeson.Local module 2019-02-03 11:01:36 +00:00
fr33domlover
e6f987817e Fix: HTTP signature wasn't being sent in AP POSTs 2019-02-03 10:59:35 +00:00
fr33domlover
04e26a911d In httpGetAP, if we got an unexpected Content-Type, specify it in error message 2019-01-21 22:24:09 +00:00
fr33domlover
1f47ca39eb Federation test outbox page with form for entering JSON 2019-01-21 15:54:57 +00:00
fr33domlover
49807ed27f Start big route change, doesn't build yet
I decided to add some safety to routes:

- Use dedicated newtypes
- Use CI for the CI-unique DB fields

Since such a change requires so many changes in many source files, this
is also a chance to do other such breaking changes. I'm recording the
change gradually. It won't build until I finish, so for now don't waste
time trying to build the app.
2016-05-23 12:24:14 +00:00