Revert "use Protocol.create_for for all protocols, not just HAS_COPIES ones"

This reverts commit 9f9ecce187.

Not 100% sure but I suspect this caused #1929. Reverting while I debug more.
pull/1933/head
Ryan Barrett 2025-05-13 13:42:09 -07:00
rodzic 3b37484b72
commit 37096e2ed2
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 6BE31FDF4776E9D4
6 zmienionych plików z 43 dodań i 76 usunięć

Wyświetl plik

@ -3,12 +3,10 @@ from base64 import b64encode
from hashlib import sha256
import itertools
import logging
import random
import re
from urllib.parse import quote_plus, urljoin, urlparse
from unittest.mock import MagicMock
from Crypto.PublicKey import RSA
from flask import abort, g, redirect, request
from google.cloud import ndb
from google.cloud.ndb.query import FilterNode, OR, Query
@ -36,7 +34,6 @@ from common import (
error,
host_url,
LOCAL_DOMAINS,
long_to_base64,
PRIMARY_DOMAIN,
PROTOCOL_DOMAINS,
redirect_wrap,
@ -46,7 +43,7 @@ from common import (
)
from ids import BOT_ACTOR_AP_IDS
import memcache
from models import fetch_objects, Follower, KEY_BITS, Object, PROTOCOLS, User
from models import fetch_objects, Follower, Object, PROTOCOLS, User
from protocol import activity_id_memcache_key, DELETE_TASK_DELAY, Protocol
import webfinger
@ -88,7 +85,7 @@ def instance_actor():
global _INSTANCE_ACTOR
if _INSTANCE_ACTOR is None:
import web
_INSTANCE_ACTOR = web.Web.get_or_create(PRIMARY_DOMAIN, propagate=True)
_INSTANCE_ACTOR = web.Web.get_or_create(PRIMARY_DOMAIN)
return _INSTANCE_ACTOR
@ -230,28 +227,6 @@ class ActivityPub(User, Protocol):
kwargs['prefer_id'] = False
return super().user_page_path(rest=rest, **kwargs)
@classmethod
def create_for(cls, user):
"""Creates an AP keypair for a non-APProto user.
Can use urandom() and do nontrivial math, so this can take time
depending on the amount of randomness available and compute needed.
Args:
user (models.User)
"""
assert not isinstance(user, ActivityPub)
if not user.public_exponent or not user.private_exponent or not user.mod:
assert (not user.public_exponent and not user.private_exponent
and not user.mod), id
key = RSA.generate(KEY_BITS, randfunc=random.randbytes
if appengine_info.DEBUG else None)
user.mod = long_to_base64(key.n)
user.public_exponent = long_to_base64(key.e)
user.private_exponent = long_to_base64(key.d)
user.put()
@classmethod
def target_for(cls, obj, shared=False):
"""Returns ``obj``'s or its author's/actor's inbox, if available."""
@ -1076,8 +1051,7 @@ def _load_user(handle_or_id, create=False):
assert id
try:
user = (proto.get_or_create(id, propagate=True) if create
else proto.get_by_id(id))
user = proto.get_or_create(id) if create else proto.get_by_id(id)
except ValueError as e:
logging.warning(e)
user = None

Wyświetl plik

@ -5,6 +5,7 @@ from functools import lru_cache
import itertools
import json
import logging
import random
import re
from threading import Lock
from urllib.parse import quote, urlparse
@ -29,6 +30,7 @@ import common
from common import (
base64_to_long,
DOMAIN_RE,
long_to_base64,
OLD_ACCOUNT_AGE,
PROTOCOL_DOMAINS,
report_error,
@ -375,13 +377,30 @@ class User(StringIdModel, metaclass=ProtocolUserMeta):
proto = PROTOCOLS[label]
if proto == cls:
continue
elif user.is_enabled(proto):
try:
proto.create_for(user)
except (ValueError, AssertionError):
logger.info(f'failed creating {proto.LABEL} copy',
exc_info=True)
util.remove(user.enabled_protocols, proto.LABEL)
elif proto.HAS_COPIES:
if not user.get_copy(proto) and user.is_enabled(proto):
try:
proto.create_for(user)
except (ValueError, AssertionError):
logger.info(f'failed creating {proto.LABEL} copy',
exc_info=True)
util.remove(user.enabled_protocols, proto.LABEL)
else:
logger.debug(f'{proto.LABEL} not enabled or user copy already exists, skipping propagate')
# generate keys for all protocols _except_ our own
#
# these can use urandom() and do nontrivial math, so they can take time
# depending on the amount of randomness available and compute needed.
if cls.LABEL != 'activitypub':
if (not user.public_exponent or not user.private_exponent or not user.mod):
assert (not user.public_exponent and not user.private_exponent
and not user.mod), id
key = RSA.generate(KEY_BITS,
randfunc=random.randbytes if DEBUG else None)
user.mod = long_to_base64(key.n)
user.public_exponent = long_to_base64(key.e)
user.private_exponent = long_to_base64(key.d)
try:
user.put()
@ -586,9 +605,10 @@ class User(StringIdModel, metaclass=ProtocolUserMeta):
added = False
# do this even if there's an existing copy since we might need to
# reactivate it, which create_for should do
to_proto.create_for(self)
if to_proto.LABEL in ids.COPIES_PROTOCOLS:
# do this even if there's an existing copy since we might need to
# reactivate it, which create_for should do
to_proto.create_for(self)
@ndb.transactional()
def enable():

Wyświetl plik

@ -497,22 +497,20 @@ class Protocol:
@classmethod
def create_for(cls, user):
"""Creates or re-activate a user in this protocol.
"""Creates or re-activate a copy user in this protocol.
If this protocol has copies, adds the new copy user to :attr:`copies`.
If the copy user already exists and active, does nothing.
Should add the copy user to :attr:`copies`.
By default, does nothing.
If the copy user already exists and active, should do nothing.
Args:
user (models.User): original source user. Shouldn't already have a
copy user for this protocol in :attr:`copies`.
Raises:
ValueError: if we can't create the given user in this protocol
ValueError: if we can't create a copy of the given user in this protocol
"""
if cls.HAS_COPIES:
raise NotImplementedError()
raise NotImplementedError()
@classmethod
def send(to_cls, obj, url, from_user=None, orig_obj_id=None):

Wyświetl plik

@ -72,8 +72,7 @@ class UserTest(TestCase):
self.assertIsNone(Web.get_by_id('y.za'))
def test_get_or_create(self):
user = Fake.get_or_create('fake:user', enabled_protocols=['activitypub'],
propagate=True)
user = Fake.get_or_create('fake:user')
assert not user.existing
assert user.mod
@ -188,17 +187,11 @@ class UserTest(TestCase):
self.assertIsNone(Fake.get_or_create('fake:user', manual_opt_out=True))
def test_public_pem(self):
bot = self.make_user(id='ap.brid.gy', cls=Web)
self.user.enable_protocol(ActivityPub)
pem = self.user.public_pem()
self.assertTrue(pem.decode().startswith('-----BEGIN PUBLIC KEY-----\n'), pem)
self.assertTrue(pem.decode().endswith('-----END PUBLIC KEY-----'), pem)
def test_private_pem(self):
bot = self.make_user(id='ap.brid.gy', cls=Web)
self.user.enable_protocol(ActivityPub)
pem = self.user.private_pem()
self.assertTrue(pem.decode().startswith('-----BEGIN RSA PRIVATE KEY-----\n'), pem)
self.assertTrue(pem.decode().endswith('-----END RSA PRIVATE KEY-----'), pem)
@ -452,19 +445,6 @@ class UserTest(TestCase):
self.assertIsNone(OtherFake().get_copy(Fake))
def test_enable_protocol_calls_create_for(self):
bot = self.make_user(id='ap.brid.gy', cls=Web)
user = Fake(id='fake:user')
user.put()
self.assertIsNone(user.public_exponent)
self.assertIsNone(user.private_exponent)
user.enable_protocol(ActivityPub)
self.assertIsNotNone(user.public_exponent)
self.assertIsNotNone(user.private_exponent)
def test_count_followers(self):
self.assertEqual((0, 0), self.user.count_followers())

Wyświetl plik

@ -295,8 +295,7 @@ Web.DEFAULT_ENABLED_PROTOCOLS += ('fake', 'other')
# expensive to generate.
requests.post(f'http://{ndb_client.host}/reset')
with ndb_client.context():
global_user = activitypub._INSTANCE_ACTOR = Fake.get_or_create(
'fake:user', propagate=True, enabled_protocols=['activitypub'])
global_user = activitypub._INSTANCE_ACTOR = Fake.get_or_create('fake:user')
class TestCase(unittest.TestCase, testutil.Asserts):

10
web.py
Wyświetl plik

@ -192,7 +192,7 @@ class Web(User, Protocol):
return None
if verify or (verify is None and not user.existing):
user = user.verify(**kwargs)
user = user.verify()
if not allow_opt_out and user.status:
return None
@ -289,13 +289,9 @@ class Web(User, Protocol):
return super().status
def verify(self, **kwargs):
def verify(self):
"""Fetches site a couple ways to check for redirects and h-card.
Args:
**kwargs: passed through to :meth:`Web.get_or_create` if this user is a www
domain and we need to call it to create a new root domain user.
Returns:
web.Web: user that was verified. May be different than self! eg if
self's domain started with www and we switch to the root domain.
@ -314,7 +310,7 @@ class Web(User, Protocol):
logger.info(f'{root_site} serves ok ; using {root} instead')
root_user = Web.get_or_create(
root, enabled_protocols=self.enabled_protocols,
allow_opt_out=True, **kwargs)
allow_opt_out=True)
self.use_instead = root_user.key
self.put()
return root_user.verify()