diff options
-rw-r--r-- | lib/Command/CacheRefresh.php | 3 | ||||
-rw-r--r-- | lib/Cron/Cache.php | 5 | ||||
-rw-r--r-- | lib/Db/ActorsRequest.php | 28 | ||||
-rw-r--r-- | lib/Db/CacheActorsRequest.php | 40 | ||||
-rw-r--r-- | lib/Interfaces/Actor/PersonInterface.php | 11 | ||||
-rw-r--r-- | lib/Model/ActivityPub/Actor/Person.php | 10 | ||||
-rw-r--r-- | lib/Service/AccountService.php | 25 | ||||
-rw-r--r-- | lib/Service/ActorService.php | 20 | ||||
-rw-r--r-- | lib/Service/CacheActorService.php | 1 | ||||
-rw-r--r-- | lib/Service/SignatureService.php | 24 |
10 files changed, 151 insertions, 16 deletions
diff --git a/lib/Command/CacheRefresh.php b/lib/Command/CacheRefresh.php index 413e958f..c90355a3 100644 --- a/lib/Command/CacheRefresh.php +++ b/lib/Command/CacheRefresh.php @@ -102,6 +102,9 @@ class CacheRefresh extends Base { */ protected function execute(InputInterface $input, OutputInterface $output) { + $result = $this->actorService->blindKeyRotation(); + $output->writeLn($result . ' key pairs refreshed'); + $result = $this->actorService->manageCacheLocalActors(); $output->writeLn($result . ' local accounts regenerated'); diff --git a/lib/Cron/Cache.php b/lib/Cron/Cache.php index fdaae753..ed7d2ee4 100644 --- a/lib/Cron/Cache.php +++ b/lib/Cron/Cache.php @@ -95,6 +95,11 @@ class Cache extends TimedJob { private function manageCache() { try { + $this->accountService->blindKeyRotation(); + } catch (Exception $e) { + } + + try { $this->accountService->manageCacheLocalActors(); } catch (Exception $e) { } diff --git a/lib/Db/ActorsRequest.php b/lib/Db/ActorsRequest.php index be241ab4..cedb6bab 100644 --- a/lib/Db/ActorsRequest.php +++ b/lib/Db/ActorsRequest.php @@ -30,11 +30,13 @@ declare(strict_types=1); namespace OCA\Social\Db; +use DateTime; use OCA\Social\Exceptions\ActorDoesNotExistException; use OCA\Social\Exceptions\SocialAppConfigException; use OCA\Social\Model\ActivityPub\Actor\Person; use OCA\Social\Service\ConfigService; use OCA\Social\Service\MiscService; +use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; class ActorsRequest extends ActorsRequestBuilder { @@ -77,7 +79,11 @@ class ActorsRequest extends ActorsRequestBuilder { 'preferred_username', $qb->createNamedParameter($actor->getPreferredUsername()) ) ->setValue('public_key', $qb->createNamedParameter($actor->getPublicKey())) - ->setValue('private_key', $qb->createNamedParameter($actor->getPrivateKey())); + ->setValue('private_key', $qb->createNamedParameter($actor->getPrivateKey())) + ->setValue( + 'creation', + $qb->createNamedParameter(new DateTime('now'), IQueryBuilder::PARAM_DATE) + ); $qb->execute(); @@ -85,6 +91,9 @@ class ActorsRequest extends ActorsRequestBuilder { } + /** + * @param Person $actor + */ public function update(Person $actor) { $qb = $this->getActorsUpdateSql(); $qb->set('avatar_version', $qb->createNamedParameter($actor->getAvatarVersion())); @@ -95,6 +104,23 @@ class ActorsRequest extends ActorsRequestBuilder { /** + * @param Person $actor + */ + public function refreshKeys(Person $actor) { + $qb = $this->getActorsUpdateSql(); + $qb->set('public_key', $qb->createNamedParameter($actor->getPublicKey())) + ->set('private_key', $qb->createNamedParameter($actor->getPrivateKey())) + ->set( + 'creation', + $qb->createNamedParameter(new DateTime('now'), IQueryBuilder::PARAM_DATE) + ); + $this->limitToIdString($qb, $actor->getId()); + + $qb->execute(); + } + + + /** * return Actor from database based on the username * * @param string $username diff --git a/lib/Db/CacheActorsRequest.php b/lib/Db/CacheActorsRequest.php index 7fb7ec5c..bca8b39d 100644 --- a/lib/Db/CacheActorsRequest.php +++ b/lib/Db/CacheActorsRequest.php @@ -103,6 +103,46 @@ class CacheActorsRequest extends CacheActorsRequestBuilder { /** + * insert cache about an Actor in database. + * + * @param Person $actor + */ + public function update(Person $actor) { + $qb = $this->getCacheActorsUpdateSql(); + $qb->set('account', $qb->createNamedParameter($actor->getAccount())) + ->set('following', $qb->createNamedParameter($actor->getFollowing())) + ->set('followers', $qb->createNamedParameter($actor->getFollowers())) + ->set('inbox', $qb->createNamedParameter($actor->getInbox())) + ->set('shared_inbox', $qb->createNamedParameter($actor->getSharedInbox())) + ->set('outbox', $qb->createNamedParameter($actor->getOutbox())) + ->set('featured', $qb->createNamedParameter($actor->getFeatured())) + ->set('url', $qb->createNamedParameter($actor->getUrl())) + ->set('preferred_username', $qb->createNamedParameter($actor->getPreferredUsername())) + ->set('name', $qb->createNamedParameter($actor->getName())) + ->set('summary', $qb->createNamedParameter($actor->getSummary())) + ->set('public_key', $qb->createNamedParameter($actor->getPublicKey())) + ->set('source', $qb->createNamedParameter($actor->getSource())) + ->set('details', $qb->createNamedParameter(json_encode($actor->getDetails()))) + ->set( + 'creation', + $qb->createNamedParameter(new DateTime('now'), IQueryBuilder::PARAM_DATE) + ); + + if ($actor->gotIcon()) { + $iconId = $actor->getIcon() + ->getId(); + } else { + $iconId = $actor->getIconId(); + } + $qb->set('icon_id', $qb->createNamedParameter($iconId)); + + $this->limitToIdString($qb, $actor->getId()); + + $qb->execute(); + } + + + /** * get Cached version of an Actor, based on the UriId * * @param string $id diff --git a/lib/Interfaces/Actor/PersonInterface.php b/lib/Interfaces/Actor/PersonInterface.php index 9dfe83cd..acea191f 100644 --- a/lib/Interfaces/Actor/PersonInterface.php +++ b/lib/Interfaces/Actor/PersonInterface.php @@ -110,7 +110,9 @@ class PersonInterface implements IActivityPubInterface { */ public function getItemById(string $id): ACore { try { - return $this->cacheActorsRequest->getFromId($id); + $actor = $this->cacheActorsRequest->getFromId($id); + + return $actor; } catch (CacheActorDoesNotExistException $e) { throw new ItemNotFoundException(); } @@ -122,7 +124,12 @@ class PersonInterface implements IActivityPubInterface { */ public function save(ACore $person) { /** @var Person $person */ - $this->actorService->save($person); + try { + $this->getItemById($person->getId()); + $this->actorService->update($person); + } catch (ItemNotFoundException $e) { + $this->actorService->save($person); + } } diff --git a/lib/Model/ActivityPub/Actor/Person.php b/lib/Model/ActivityPub/Actor/Person.php index 5d215fda..6383ca03 100644 --- a/lib/Model/ActivityPub/Actor/Person.php +++ b/lib/Model/ActivityPub/Actor/Person.php @@ -31,6 +31,7 @@ declare(strict_types=1); namespace OCA\Social\Model\ActivityPub\Actor; +use DateTime; use JsonSerializable; use OCA\Social\Exceptions\UrlCloudException; use OCA\Social\Model\ActivityPub\ACore; @@ -474,7 +475,12 @@ class Person extends ACore implements JsonSerializable { */ public function importFromDatabase(array $data) { parent::importFromDatabase($data); - $this->setPreferredUsername($this->validate(self::AS_USERNAME, 'preferred_username', $data, '')) + + $dTime = new DateTime($this->get('creation', $data, 'yesterday')); + + $this->setPreferredUsername( + $this->validate(self::AS_USERNAME, 'preferred_username', $data, '') + ) ->setName($this->validate(self::AS_USERNAME, 'name', $data, '')) ->setAccount($this->validate(self::AS_ACCOUNT, 'account', $data, '')) ->setPublicKey($this->get('public_key', $data, '')) @@ -486,7 +492,7 @@ class Person extends ACore implements JsonSerializable { ->setSharedInbox($this->validate(self::AS_URL, 'shared_inbox', $data, '')) ->setFeatured($this->validate(self::AS_URL, 'featured', $data, '')) ->setDetails($this->getArray('details', $data, [])) - ->setCreation($this->getInt('creation', $data, 0)); + ->setCreation($dTime->getTimestamp()); } diff --git a/lib/Service/AccountService.php b/lib/Service/AccountService.php index 62b183e2..ff868350 100644 --- a/lib/Service/AccountService.php +++ b/lib/Service/AccountService.php @@ -53,6 +53,9 @@ use OCP\IUserManager; class AccountService { + const KEY_PAIR_LIFESPAN = 7; + + use TArrayTools; @@ -310,4 +313,26 @@ class AccountService { } + /** + * @throws Exception + * @return int + */ + public function blindKeyRotation(): int { + $update = $this->actorsRequest->getAll(); + $count = 0; + foreach ($update as $actor) { + try { + if ($actor->getCreation() < (time() - (self::KEY_PAIR_LIFESPAN * 3600 * 24))) { + $this->signatureService->generateKeys($actor); + $this->actorsRequest->refreshKeys($actor); + $count++; + } + } catch (Exception $e) { + } + } + + return $count; + } + + } diff --git a/lib/Service/ActorService.php b/lib/Service/ActorService.php index 6b2438f7..8dea61bd 100644 --- a/lib/Service/ActorService.php +++ b/lib/Service/ActorService.php @@ -124,6 +124,24 @@ class ActorService { * @param Person $actor */ public function save(Person $actor) { + $this->cacheDocumentIfNeeded($actor); + $this->cacheActorsRequest->save($actor); + } + + + /** + * @param Person $actor + */ + public function update(Person $actor) { + $this->cacheDocumentIfNeeded($actor); + $this->cacheActorsRequest->update($actor); + } + + + /** + * @param Person $actor + */ + private function cacheDocumentIfNeeded(Person $actor) { if ($actor->gotIcon()) { try { $icon = $this->cacheDocumentsRequest->getBySource( @@ -135,8 +153,6 @@ class ActorService { $this->cacheDocumentsRequest->save($actor->getIcon()); } } - - $this->cacheActorsRequest->save($actor); } } diff --git a/lib/Service/CacheActorService.php b/lib/Service/CacheActorService.php index 07babd87..d4e4473f 100644 --- a/lib/Service/CacheActorService.php +++ b/lib/Service/CacheActorService.php @@ -130,7 +130,6 @@ class CacheActorService { try { if ($refresh) { - $this->cacheActorsRequest->deleteFromId($id); throw new CacheActorDoesNotExistException(); } diff --git a/lib/Service/SignatureService.php b/lib/Service/SignatureService.php index 2b693b1b..4e328ec1 100644 --- a/lib/Service/SignatureService.php +++ b/lib/Service/SignatureService.php @@ -214,13 +214,19 @@ class SignatureService { $signature = new LinkedDataSignature(); $signature->import(json_decode($object->getSource(), true)); $signature->setPublicKey($this->retrieveKey($actorId)); - if ($signature->verify()) { - $object->setOrigin( - $this->getKeyOrigin($actorId), SignatureService::ORIGIN_SIGNATURE - ); + if (!$signature->verify()) { + $signature->setPublicKey($this->retrieveKey($actorId, true)); + } - return true; + if (!$signature->verify()) { + return false; } + + $object->setOrigin( + $this->getKeyOrigin($actorId), SignatureService::ORIGIN_SIGNATURE + ); + + return true; } catch (LinkedDataSignatureMissingException $e) { } @@ -345,7 +351,9 @@ class SignatureService { /** - * @param $keyId + * @param string $keyId + * + * @param bool $refresh * * @return string * @throws InvalidOriginException @@ -359,8 +367,8 @@ class SignatureService { * @throws SocialAppConfigException * @throws ItemUnknownException */ - private function retrieveKey($keyId): string { - $actor = $this->cacheActorService->getFromId($keyId); + private function retrieveKey(string $keyId, bool $refresh = false): string { + $actor = $this->cacheActorService->getFromId($keyId, $refresh); return $actor->getPublicKey(); } |