Как стать автором
Обновить

Комментарии 31

А есть какие-нибудь готовые библиотеки для популярных языков, чтобы не заниматься самому подсчётом подписей, ответами на webfinger итд? Хочу получать Активити в виде высокоуровневых событий на любимом языке программирования и дальше уже что-то с ними делать.

Есть — как минимум для php, для js и для go. Для C#, вроде, ничего нет, но ты можешь исправить эту ситуацию :)

Если мне не изменяет память, для PHP их две: одна завязана на конкретную БД без каких-либо абстракций и интерфейсов, а другая странноватая в целом.

Есть еще реализация от автора Pixelfed, но он не выделял ее в библиотеку.

Реализаций полно, в т.ч. и на питоне, и даже на C вроде есть, но это всё на практике оказалось не самое трудоёмкое. Приходилось ещё разбираться почему с мастодоном одно работает, а с френдикой или пиксельфедом нет и т.п.

Как относится ActivityPub к протоколу WebSub? Это одно и тоже или разные вещи?

Разные. Общее только то, что и то, и другое - подписка на рассылку обновлений.

Хм. Оба вроде используют JSON-LD формат. Что нужно выбрать для максимального охвата происходящих в интернетах событий тогда? Я планирую прикрутить это к Awakari

А что понимается под "происходящими в интернете событиями"? ActivityPub — это на 99% про социальные штуки всякие, тот же мастодон. Существуют мосты в другие протоколы, но именно чтобы нативная поддержка — это именно соцсети. Ну и вордпресс, с недавнего времени, если владелец сайта включил.

WebSub для меня существует сугубо теоретически, использования его на практике я (пока?) не видел.

Мне нужна какая нибудь замена RSS с поддержкой push, например, на вебхук. Чтобы можно было получать уведомления о происходящем в популярных соцсетях на определённые темы

Ну это явно не ActivityPub, наверняка существуют сервисы, которые так умеют. Но вряд ли бесплатно. Каким-нибудь маркетолухам и прочим сммщикам такое бывает нужно, а это же всё Серьёзный Бизнес™.

Почему же не actvitypub? Мало используется в популярных сервисах?

В популярных централизованных сервисах вообще не используется.

Круто! Вот бы и на Хабре появилась поддержка ActivityPub!

Я как-то хотел свою реализацию написать, но стал спотыкаться на подписях заголовков... Мастодон посылал меня с такими подписями. После чего я решил отложить это дело на лучшие времена и остался на френдике, которая сейчас какого-то фига (лично у меня, а возможно и вовсе вопросы хостеру нужно задавать, а не воркеру) активити не отправляет.

Ну а статья полезная, оставлю в закладках 👍

Можете потестить свои подписи с моим сервером Smithereen, он отвечает подробными сообщениями об ошибках в таких случаях.

О, а я с вами уже в федиверс пересекался) спасибо.

Раньше было @[email protected] , сейчас @[email protected]

Непонятно, а как собственно писать свои посты или туты, как принято их называть в мастодоне, и сохранять у себя в профиле, чтоб другие могли прийти и почитать, о чём я пишу?

Писать — это как раз Create{Note}, который описан в статье. Сохранять в профиле — это outbox. Можете в мастодоне посмотреть, это коллекция с пагинацией со всеми вашими исходящими активити. Сам мастодон, правда, её с других серверов не прогружает.

Кстати, а есть кто прогружает? А то я у себя вроде и реализовал, но так и не тестил, судя по логам сервера ни outbox, ни реплаи к комментам спросом не пользуются другими инстансами, кроме каких-то ботов туда вроде никто не обращается.

Outbox, кажется, никто, а реплаи я прогружаю в Smithereen при репосте или при открытии поста по ссылке (и меня бесит, что у некоторых этой коллекции нет)

...на тот же адрес, по которому вы видите профиль в браузере:

Профиль чей и где? Непонятно. У меня вообще нет никакого профиля. Я только экспериментирую. Я так понял надо вместо mastodon.social указать свой домен?

Не понятно что за ACTOR_ID когда надо формировать заголовок Signature. Решил ставить URL до своего профиля.

В общем, с третьего захода удалось сгенерировать корректную подпись и начать правильно отдавать информацию о своём акторе. Но выскакивает ошибка Вашего сервера.

Unhandled exception: smithereen.exceptions.InternalServerErrorException: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry 'SaemonZixel-y777.ru' for key 'users.username'

Тестирую вот отсюда: http://y777.ru/test-send-activity

Код на PHP следующий:

    $body = '{
  "@context": "https://www.w3.org/ns/activitystreams",
  "id": "http://y777.ru/createTestPost1",
  "type": "Create",
  "actor": "http://y777.ru/users/saemonzixel",
  "to": "https://www.w3.org/ns/activitystreams#Public",
  "object": {
    "id": "http://y777.ru/testPost1",
    "type": "Note",
    "published": "2023-11-05T12:00:00Z",
    "attributedTo": "http://y777.ru/users/saemonzixel",
    "to": "https://www.w3.org/ns/activitystreams#Public",
    "inReplyTo": "https://friends.grishka.me/posts/884435",
    "content": "<p>Привет с Хабра!</p>"
  }
}';
	$date = date('D, j M Y H:i:s T');
	$digest = "SHA-256=".base64_encode(hash('sha256', $body, true));
	$toSign = "(request-target): post /users/1/inbox\nhost: friends.grishka.me\ndate: $date\ndigest: $digest";
	$private_key = file_get_contents('activitypub.private.pem');
	$binary_signature = "";
	openssl_sign($toSign, $binary_signature, $private_key, 'sha256WithRSAEncryption');

	$public_key_pem = file_get_contents('activitypub.public.pem');
	$r = openssl_verify($toSign, $binary_signature, $public_key_pem, "sha256WithRSAEncryption");
	echo "--- toSign ---\n$toSign\n--- openssl_verify() ---\n$r\n";
	
	$context = stream_context_create(array(
				'http' => array(
					'method' => 'POST',
					'content' => $body,
					'header'=> "Date: $date\r\n" .
						"Digest: $digest\r\n" .
						"Signature: keyId=\"http://y777.ru/users/saemonzixel#main-key\",headers=\"(request-target) host date digest\",signature=\"".base64_encode($binary_signature)."\",algorithm=\"rsa-sha256\"\r\n" .
						"Content-Type: application/jrd+json; charset=utf-8\r\n",
					'ignore_errors' => '1'
				),
				"ssl"=>array(
					"verify_peer"=>false,
					"verify_peer_name"=>false,
				)
			));
	$http_resp = file_get_contents("https://friends.grishka.me/users/1/inbox", false, $context);
	echo "--- Response ---\n$http_resp\n\n----------------\n";
	echo "Signature: keyId=\"http://y777.ru/users/saemonzixel#main-key\",headers=\"(request-target) host date digest\",signature=\"".base64_encode($binary_signature)."\",algorithm=\"rsa-sha256\"\r\n";
	file_put_contents('activitypub.log', print_r($http_resp, true), FILE_APPEND);
	exit;

Профиль чей и где? Непонятно. У меня вообще нет никакого профиля.

Это я имел в виду, что если вы хотите посмотреть объект актора с другого сервера. Например, с мастодона.

Unhandled exception: smithereen.exceptions.InternalServerErrorException: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry 'SaemonZixel-y777.ru' for key 'users.username'

О, кажется, вы нашли у меня баг :)
В базе он есть, но с https://, а не http://, потому что я так-то нешифрованный http вообще не поддерживаю. Починил.

Но вообще, конечно, надо придумать, что делать для общего случая, когда в базе уже есть актор с таким username@domain, но с другим ID. Как минимум надо возвращать адекватную ошибку.

Теперь Ваш сервер отвечает: Bad request: In the absence of a valid LD-signature, HTTP signature must be made by the activity actor

Хотя я проверяю подпись публичным ключём и подпись корректная.

Может алгоритм не sha256WithRSAEncryption, а какой-то другой должен быть?

Алгоритм правильный, я бы перепроверил keyId в заголовке, там тоже надо https://

Я перепроверил KeyId, там всё правильно, https нет. У меня на сервере нет и не будет поддержки https.

Я перепроверил подпись на джаве и подпись у меня генерируется правильная.

Вот код, которым проверял:

String message = "(request-target): post /users/1/inbox\nhost: friends.grishka.me\ndate: Sun, 19 Nov 2023 00:04:03 MSK\ndigest: SHA-256=VMA4hX2mi+Wa88vu97Q+JWHm8fWAO1s8xW2Jc7y72eQ=";
byte[] sign = Base64.getDecoder().decode("obYfri5qtRScx51y4JQsn7McQtTU22ZKNTjPWlF7Muq8aQuezlGMsDX7Pwuss7OnLyPrTwMhb2fOBEzsHzWIEtBBD1Le4YDlHBweADTMOX0YymCoAXu4DQezo17U8g3eaM3eNHkI8o1Toh0dkjmTTKg0aciRswwvFDVXxUz99au1UhDk3b68uG2YIw9r3dAuZQTk2SYIliMNSy9K5scc1aoTz87cpl+A/RQm2GXYnp5vml8rzb7J69rOaFckSfRbIMf1sSaiAKR4Ivmt4ltVn1VR+2rwyRoxTGKinmOiJHqx3AwAhCS3rf5yUAHT/tBiTxja4o/SVgN0SaFAYq1NaA=="); 

// 1 - reading public key :
Scanner scanner = new Scanner(new File("activitypub.public.pem"));
StringBuilder sb = new StringBuilder();
while (scanner.hasNextLine()) {
	String line = scanner.nextLine();
	if (line.startsWith("---") == false)
		sb.append( line );
}

// 2 - loading public key 
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec( Base64.getDecoder().decode(sb.toString()));
PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(publicKeySpec);

// 3 - verifying content with signature and content :
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initVerify(publicKey);
sig.update(message.getBytes());
if (sig.verify(sign) == false)
	System.out.println("Bad signature!");
else 
	System.out.println("OK!");

У меня на сервере нет и не будет поддержки https.

Так тогда ничего и работать не будет. Все ActivityPub-сервера требуют HTTPS, по-моему это даже часть спецификации. Я потому и написал в статье, что в случае, если нет возможности настроить его полноценно у себя, можно воспользоваться ngrok или каким-нибудь другим аналогичным прокси-сервисом.

Тогда я зря потратил свои силы и время. Печалька.

Похоже что с activitypub мне не по пути.

А в чём проблема с HTTPS, если не секрет?

HTTPS тормозной протокол. С ним сайты открываются медленнее. Я не хочу чтоб мои сайты открывались и работали медленно.

А с точки зрения безопасности: мне нечего скрывать. У меня ничего ценного нет. Да и мнения я о себе невысокого. Кому я вообще нужен?))

Можно конечно заморочится с самоподписным сертификатом, но мне пока-что лень.

Вы, кстати, не знаете, есть ли какой-нибудь стандартизованный способ узнать кто администратор инстанца и как с ним связаться?

HTTPS тормозной протокол. С ним сайты открываются медленнее.

На сколько миллисекунд медленнее? Вы экономите на спичках.

На типичном инстансе потери времени на работу с БД значительно превысят задержки от хендшейков и шифрования. А сессионное шифрование давно аппаратно ускоряемо на CPU и затраты на него заметить будет невозможно без замеров.

А с точки зрения безопасности: мне нечего скрывать.

Если бы вам было что скрывать - вы бы это не выкладывали на публично доступный сайт. Вопрос в том хотят ли пользователи, которые туда пришли чтобы их трафик видели.

Можно конечно заморочится с самоподписным сертификатом, но мне пока-что лень.

Зачем? Let's Encrypt, ZeroSSL и т.п. на что существуют? Берёте простой acme.sh и через несколько минут у вас автоматически обновляющийся сертификат.

Вы, кстати, не знаете, есть ли какой-нибудь стандартизованный способ узнать кто администратор инстанца и как с ним связаться?

У инстансов поддерживающих Mastodon-совместимый API (это делает не только Mastodon) есть такой метод:

GET /api/v2/instance

Например:

https://lor.sh/api/v2/instance
https://mastodon.ml/api/v2/instance

Однако конкретно этот метод в основном есть только в Mastodon. Если мне не изменяет, в Misskey и Pleroma его нет.

А с точки зрения безопасности: мне нечего скрывать. У меня ничего ценного нет. Да и мнения я о себе невысокого. Кому я вообще нужен?))

Есть. Ваш сайт которым кто-то пользуется. Можно например (совсем без вашего ведома):

  • Разместить на нем рекламу - см например https://habr.com/ru/articles/506218/ но это НЕ единственный пример (в тяжелых случаях - возможно что с вопросами по этой рекламе - придут к вам)

  • У вас с сайта можно хоть что-то скачать что пользователь может запустить? Ну вот будет теперь скачиватся то что что надо Кому То (атака против конкретного пользователя или группы пользователей а не вашего сайта, который только средство)

  • На вашем сайте больше одной странице и информация о визите туда может быть (пусть даже психом с диагнозом) расценена как что-то плохое? Вы всем провайдерам по пути (а также всем владельцам middlebox'ов) отдали информацию о том, какие страницы посещает ваши пользователи и даете собрать на них профиль

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

Публикации

Истории