mirror of https://github.com/caronc/apprise
Bluesky DID Lookup bugfix
parent
19a201ff44
commit
0fce832483
|
@ -84,6 +84,7 @@ class NotifyBlueSky(NotifyBase):
|
|||
xrpc_suffix_session = "/xrpc/com.atproto.server.createSession"
|
||||
xrpc_suffix_record = "/xrpc/com.atproto.repo.createRecord"
|
||||
xrpc_suffix_blob = "/xrpc/com.atproto.repo.uploadBlob"
|
||||
plc_directory = 'https://plc.directory/{did}'
|
||||
|
||||
# BlueSky is kind enough to return how many more requests we're allowed to
|
||||
# continue to make within it's header response as:
|
||||
|
@ -138,6 +139,7 @@ class NotifyBlueSky(NotifyBase):
|
|||
self.__access_token = self.store.get('access_token')
|
||||
self.__refresh_token = None
|
||||
self.__access_token_expiry = datetime.now(timezone.utc)
|
||||
self.__endpoint = self.store.get('endpoint')
|
||||
|
||||
if not self.user:
|
||||
msg = 'A BlueSky UserID/Handle must be specified.'
|
||||
|
@ -146,6 +148,8 @@ class NotifyBlueSky(NotifyBase):
|
|||
|
||||
# Set our default host
|
||||
self.host = self.bluesky_default_host
|
||||
self.__endpoint = f'https://{self.host}' \
|
||||
if not self.host else self.__endpoint
|
||||
|
||||
# Identify our Handle (if define)
|
||||
results = HANDLE_HOST_PARSE_RE.match(self.user)
|
||||
|
@ -169,7 +173,7 @@ class NotifyBlueSky(NotifyBase):
|
|||
blobs = []
|
||||
|
||||
if attach and self.attachment_support:
|
||||
url = f'https://{self.host}{self.xrpc_suffix_blob}'
|
||||
url = f'{self.__endpoint}{self.xrpc_suffix_blob}'
|
||||
# We need to upload our payload first so that we can source it
|
||||
# in remaining messages
|
||||
for no, attachment in enumerate(attach, start=1):
|
||||
|
@ -217,14 +221,15 @@ class NotifyBlueSky(NotifyBase):
|
|||
blobs.append((response.get('blob'), filename))
|
||||
|
||||
# Prepare our URL
|
||||
url = f'https://{self.host}{self.xrpc_suffix_record}'
|
||||
did, endpoint = self.get_identifier()
|
||||
url = f'{endpoint}{self.xrpc_suffix_record}'
|
||||
|
||||
# prepare our batch of payloads to create
|
||||
payloads = []
|
||||
|
||||
payload = {
|
||||
"collection": "app.bsky.feed.post",
|
||||
"repo": self.get_identifier(),
|
||||
"repo": did,
|
||||
"record": {
|
||||
"text": body,
|
||||
# 'YYYY-mm-ddTHH:MM:SSZ'
|
||||
|
@ -286,12 +291,17 @@ class NotifyBlueSky(NotifyBase):
|
|||
user = self.user
|
||||
|
||||
user = f'{user}.{self.host}' if '.' not in user else f'{user}'
|
||||
key = f'did.{user}'
|
||||
did = self.store.get(key)
|
||||
if did:
|
||||
return did
|
||||
did_key = f'did.{user}'
|
||||
endpoint_key = f'endpoint.{user}'
|
||||
|
||||
url = f'https://{self.host}{self.xrpc_suffix_did}'
|
||||
did = self.store.get(did_key)
|
||||
endpoint = self.store.get(endpoint_key)
|
||||
if did and endpoint:
|
||||
# Early return
|
||||
return did, endpoint
|
||||
|
||||
# Step 1: Acquire DID from bsky.app
|
||||
url = f'https://public.api.bsky.app{self.xrpc_suffix_did}'
|
||||
params = {'handle': user}
|
||||
|
||||
# Send Login Information
|
||||
|
@ -305,12 +315,70 @@ class NotifyBlueSky(NotifyBase):
|
|||
|
||||
if not postokay or not response or 'did' not in response:
|
||||
# We failed
|
||||
return False
|
||||
return (False, False)
|
||||
|
||||
# Acquire our Decentralized Identitifer
|
||||
# Store our DID
|
||||
did = response.get('did')
|
||||
self.store.set(key, did)
|
||||
return did
|
||||
|
||||
# Step 2: Use DID to find the PDS
|
||||
if did.startswith("did:plc:"):
|
||||
pds_url = self.plc_directory.format(did=did)
|
||||
|
||||
# PDS Query
|
||||
postokay, service_response = self._fetch(
|
||||
pds_url,
|
||||
method='GET',
|
||||
# We set this boolean so internal recursion doesn't take place.
|
||||
login=login,
|
||||
)
|
||||
if not postokay or not service_response or \
|
||||
'service' not in service_response:
|
||||
# We failed
|
||||
return (False, False)
|
||||
|
||||
endpoint = next(
|
||||
(s["serviceEndpoint"]
|
||||
for s in service_response.get("service", [])
|
||||
if s["type"] == "AtprotoPersonalDataServer"),
|
||||
None,
|
||||
)
|
||||
|
||||
elif did.startswith("did:web:"):
|
||||
# Convert to domain
|
||||
domain = did[8:]
|
||||
web_did_url = f"https://{domain}/.well-known/did.json"
|
||||
postokay, service_response = self._fetch(
|
||||
web_did_url,
|
||||
method='GET',
|
||||
# We set this boolean so internal recursion doesn't take place.
|
||||
login=login,
|
||||
)
|
||||
if not postokay or not service_response or \
|
||||
'service' not in service_response:
|
||||
# We failed
|
||||
self.logger.warning(
|
||||
'Could not fetch DID document for did:web identity '
|
||||
'{}; ensure {} is available.'.format(did, web_did_url)
|
||||
)
|
||||
return (False, False)
|
||||
|
||||
endpoint = next(
|
||||
(s["serviceEndpoint"]
|
||||
for s in service_response.get("service", [])
|
||||
if s["type"] == "AtprotoPersonalDataServer"),
|
||||
None,
|
||||
)
|
||||
|
||||
else:
|
||||
raise RuntimeError("Unknown BlueSky DID scheme")
|
||||
|
||||
# Step 3: Send to correct endpoint
|
||||
if not endpoint:
|
||||
raise RuntimeError("Failed to resolve BlueSky PDS endpoint")
|
||||
|
||||
self.store.set(did_key, did)
|
||||
self.store.set(endpoint_key, endpoint)
|
||||
return (did, endpoint)
|
||||
|
||||
def login(self):
|
||||
"""
|
||||
|
@ -318,11 +386,11 @@ class NotifyBlueSky(NotifyBase):
|
|||
"""
|
||||
|
||||
# Acquire our Decentralized Identitifer
|
||||
did = self.get_identifier(self.user, login=True)
|
||||
did, self.__endpoint = self.get_identifier(self.user, login=True)
|
||||
if not did:
|
||||
return False
|
||||
|
||||
url = f'https://{self.host}{self.xrpc_suffix_session}'
|
||||
url = f'{self.__endpoint}{self.xrpc_suffix_session}'
|
||||
|
||||
payload = {
|
||||
"identifier": did,
|
||||
|
@ -392,6 +460,7 @@ class NotifyBlueSky(NotifyBase):
|
|||
'access_token', self.__access_token, self.__access_token_expiry)
|
||||
self.store.set(
|
||||
'refresh_token', self.__refresh_token, self.__access_token_expiry)
|
||||
self.store.set('endpoint', self.__endpoint)
|
||||
|
||||
self.logger.info('Authenticated to BlueSky as {}.{}'.format(
|
||||
self.user, self.host))
|
||||
|
|
|
@ -90,7 +90,12 @@ apprise_url_tests = (
|
|||
'requests_response_text': {
|
||||
'accessJwt': 'abcd',
|
||||
'refreshJwt': 'abcd',
|
||||
'did': 'did:1234',
|
||||
'did': 'did:plc:1234',
|
||||
# Support plc response
|
||||
'service': [{
|
||||
'type': 'AtprotoPersonalDataServer',
|
||||
'serviceEndpoint': 'https://example.pds.io'
|
||||
}]
|
||||
},
|
||||
}),
|
||||
('bluesky://user@app-pw3', {
|
||||
|
@ -100,9 +105,14 @@ apprise_url_tests = (
|
|||
'requests_response_text': {
|
||||
'accessJwt': 'abcd',
|
||||
'refreshJwt': 'abcd',
|
||||
'did': 'did:1234',
|
||||
'did': 'did:plc:1234',
|
||||
# For handling attachments
|
||||
'blob': 'content',
|
||||
# Support plc response
|
||||
'service': [{
|
||||
'type': 'AtprotoPersonalDataServer',
|
||||
'serviceEndpoint': 'https://example.pds.io'
|
||||
}]
|
||||
},
|
||||
}),
|
||||
('bluesky://user.example.ca@app-pw3', {
|
||||
|
@ -112,9 +122,14 @@ apprise_url_tests = (
|
|||
'requests_response_text': {
|
||||
'accessJwt': 'abcd',
|
||||
'refreshJwt': 'abcd',
|
||||
'did': 'did:1234',
|
||||
'did': 'did:plc:1234',
|
||||
# For handling attachments
|
||||
'blob': 'content',
|
||||
# Support plc response
|
||||
'service': [{
|
||||
'type': 'AtprotoPersonalDataServer',
|
||||
'serviceEndpoint': 'https://example.pds.io'
|
||||
}]
|
||||
},
|
||||
}),
|
||||
# A duplicate of the entry above, this will cause cache to be referenced
|
||||
|
@ -125,9 +140,14 @@ apprise_url_tests = (
|
|||
'requests_response_text': {
|
||||
'accessJwt': 'abcd',
|
||||
'refreshJwt': 'abcd',
|
||||
'did': 'did:1234',
|
||||
'did': 'did:plc:1234',
|
||||
# For handling attachments
|
||||
'blob': 'content',
|
||||
# Support plc response
|
||||
'service': [{
|
||||
'type': 'AtprotoPersonalDataServer',
|
||||
'serviceEndpoint': 'https://example.pds.io'
|
||||
}]
|
||||
},
|
||||
}),
|
||||
('bluesky://user@app-pw', {
|
||||
|
@ -138,7 +158,12 @@ apprise_url_tests = (
|
|||
'requests_response_text': {
|
||||
'accessJwt': 'abcd',
|
||||
'refreshJwt': 'abcd',
|
||||
'did': 'did:1234',
|
||||
'did': 'did:plc:1234',
|
||||
# Support plc response
|
||||
'service': [{
|
||||
'type': 'AtprotoPersonalDataServer',
|
||||
'serviceEndpoint': 'https://example.pds.io'
|
||||
}]
|
||||
},
|
||||
}),
|
||||
('bluesky://user@app-pw', {
|
||||
|
@ -149,7 +174,12 @@ apprise_url_tests = (
|
|||
'requests_response_text': {
|
||||
'accessJwt': 'abcd',
|
||||
'refreshJwt': 'abcd',
|
||||
'did': 'did:1234',
|
||||
'did': 'did:plc:1234',
|
||||
# Support plc response
|
||||
'service': [{
|
||||
'type': 'AtprotoPersonalDataServer',
|
||||
'serviceEndpoint': 'https://example.pds.io'
|
||||
}]
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
@ -163,7 +193,12 @@ def good_response(data=None):
|
|||
response.content = json.dumps({
|
||||
'accessJwt': 'abcd',
|
||||
'refreshJwt': 'abcd',
|
||||
'did': 'did:1234',
|
||||
'did': 'did:plc:1234',
|
||||
# Support plc response
|
||||
'service': [{
|
||||
'type': 'AtprotoPersonalDataServer',
|
||||
'serviceEndpoint': 'https://example.pds.io'
|
||||
}]
|
||||
} if data is None else data)
|
||||
|
||||
response.status_code = requests.codes.ok
|
||||
|
@ -363,7 +398,12 @@ def test_plugin_bluesky_general(mocker):
|
|||
response_obj = {
|
||||
'accessJwt': 'abcd',
|
||||
'refreshJwt': 'abcd',
|
||||
'did': 'did:1234'
|
||||
'did': 'did:plc:1234',
|
||||
# Support plc response
|
||||
'service': [{
|
||||
'type': 'AtprotoPersonalDataServer',
|
||||
'serviceEndpoint': 'https://example.pds.io'
|
||||
}]
|
||||
}
|
||||
request.content = json.dumps(response_obj)
|
||||
|
||||
|
@ -413,16 +453,19 @@ def test_plugin_bluesky_attachments_basic(
|
|||
attach=attach) is True
|
||||
|
||||
# Verify API calls.
|
||||
assert mock_get.call_count == 1
|
||||
assert mock_get.call_count == 2
|
||||
assert mock_get.call_args_list[0][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.identity.resolveHandle'
|
||||
'https://public.api.bsky.app/xrpc/com.atproto.identity.resolveHandle'
|
||||
assert mock_get.call_args_list[1][0][0] == \
|
||||
'https://plc.directory/did:plc:1234'
|
||||
|
||||
assert mock_post.call_count == 3
|
||||
assert mock_post.call_args_list[0][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.server.createSession'
|
||||
'https://example.pds.io/xrpc/com.atproto.server.createSession'
|
||||
assert mock_post.call_args_list[1][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.repo.uploadBlob'
|
||||
'https://example.pds.io/xrpc/com.atproto.repo.uploadBlob'
|
||||
assert mock_post.call_args_list[2][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.repo.createRecord'
|
||||
'https://example.pds.io/xrpc/com.atproto.repo.createRecord'
|
||||
|
||||
|
||||
@patch('requests.post')
|
||||
|
@ -445,14 +488,17 @@ def test_plugin_bluesky_attachments_bad_message_response(
|
|||
attach=attach) is False
|
||||
|
||||
# Verify API calls.
|
||||
assert mock_get.call_count == 1
|
||||
assert mock_get.call_count == 2
|
||||
assert mock_get.call_args_list[0][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.identity.resolveHandle'
|
||||
'https://public.api.bsky.app/xrpc/com.atproto.identity.resolveHandle'
|
||||
assert mock_get.call_args_list[1][0][0] == \
|
||||
'https://plc.directory/did:plc:1234'
|
||||
|
||||
assert mock_post.call_count == 2
|
||||
assert mock_post.call_args_list[0][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.server.createSession'
|
||||
'https://example.pds.io/xrpc/com.atproto.server.createSession'
|
||||
assert mock_post.call_args_list[1][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.repo.uploadBlob'
|
||||
'https://example.pds.io/xrpc/com.atproto.repo.uploadBlob'
|
||||
|
||||
|
||||
@patch('requests.post')
|
||||
|
@ -475,14 +521,17 @@ def test_plugin_bluesky_attachments_upload_fails(
|
|||
attach=attach) is False
|
||||
|
||||
# Verify API calls.
|
||||
assert mock_get.call_count == 1
|
||||
assert mock_get.call_count == 2
|
||||
assert mock_get.call_args_list[0][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.identity.resolveHandle'
|
||||
'https://public.api.bsky.app/xrpc/com.atproto.identity.resolveHandle'
|
||||
assert mock_get.call_args_list[1][0][0] == \
|
||||
'https://plc.directory/did:plc:1234'
|
||||
|
||||
assert mock_post.call_count == 2
|
||||
assert mock_post.call_args_list[0][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.server.createSession'
|
||||
'https://example.pds.io/xrpc/com.atproto.server.createSession'
|
||||
assert mock_post.call_args_list[1][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.repo.uploadBlob'
|
||||
'https://example.pds.io/xrpc/com.atproto.repo.uploadBlob'
|
||||
|
||||
|
||||
@patch('requests.post')
|
||||
|
@ -506,14 +555,16 @@ def test_plugin_bluesky_attachments_invalid_attachment(
|
|||
attach=attach) is False
|
||||
|
||||
# Verify API calls.
|
||||
assert mock_get.call_count == 1
|
||||
assert mock_get.call_count == 2
|
||||
assert mock_get.call_args_list[0][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.identity.resolveHandle'
|
||||
'https://public.api.bsky.app/xrpc/com.atproto.identity.resolveHandle'
|
||||
assert mock_get.call_args_list[1][0][0] == \
|
||||
'https://plc.directory/did:plc:1234'
|
||||
|
||||
# No post request as attachment is not good.
|
||||
assert mock_post.call_count == 1
|
||||
assert mock_post.call_args_list[0][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.server.createSession'
|
||||
'https://example.pds.io/xrpc/com.atproto.server.createSession'
|
||||
|
||||
|
||||
@patch('requests.post')
|
||||
|
@ -546,28 +597,30 @@ def test_plugin_bluesky_attachments_multiple_batch(
|
|||
attach=attach) is True
|
||||
|
||||
# Verify API calls.
|
||||
assert mock_get.call_count == 1
|
||||
assert mock_get.call_count == 2
|
||||
assert mock_get.call_args_list[0][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.identity.resolveHandle'
|
||||
'https://public.api.bsky.app/xrpc/com.atproto.identity.resolveHandle'
|
||||
assert mock_get.call_args_list[1][0][0] == \
|
||||
'https://plc.directory/did:plc:1234'
|
||||
assert mock_post.call_count == 9
|
||||
assert mock_post.call_args_list[0][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.server.createSession'
|
||||
'https://example.pds.io/xrpc/com.atproto.server.createSession'
|
||||
assert mock_post.call_args_list[1][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.repo.uploadBlob'
|
||||
'https://example.pds.io/xrpc/com.atproto.repo.uploadBlob'
|
||||
assert mock_post.call_args_list[2][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.repo.uploadBlob'
|
||||
'https://example.pds.io/xrpc/com.atproto.repo.uploadBlob'
|
||||
assert mock_post.call_args_list[3][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.repo.uploadBlob'
|
||||
'https://example.pds.io/xrpc/com.atproto.repo.uploadBlob'
|
||||
assert mock_post.call_args_list[4][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.repo.uploadBlob'
|
||||
'https://example.pds.io/xrpc/com.atproto.repo.uploadBlob'
|
||||
assert mock_post.call_args_list[5][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.repo.createRecord'
|
||||
'https://example.pds.io/xrpc/com.atproto.repo.createRecord'
|
||||
assert mock_post.call_args_list[6][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.repo.createRecord'
|
||||
'https://example.pds.io/xrpc/com.atproto.repo.createRecord'
|
||||
assert mock_post.call_args_list[7][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.repo.createRecord'
|
||||
'https://example.pds.io/xrpc/com.atproto.repo.createRecord'
|
||||
assert mock_post.call_args_list[8][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.repo.createRecord'
|
||||
'https://example.pds.io/xrpc/com.atproto.repo.createRecord'
|
||||
|
||||
# If we call the functions again, the only difference is
|
||||
# we no longer need to resolve the handle or create a session
|
||||
|
@ -589,21 +642,21 @@ def test_plugin_bluesky_attachments_multiple_batch(
|
|||
assert mock_get.call_count == 0
|
||||
assert mock_post.call_count == 8
|
||||
assert mock_post.call_args_list[0][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.repo.uploadBlob'
|
||||
'https://example.pds.io/xrpc/com.atproto.repo.uploadBlob'
|
||||
assert mock_post.call_args_list[1][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.repo.uploadBlob'
|
||||
'https://example.pds.io/xrpc/com.atproto.repo.uploadBlob'
|
||||
assert mock_post.call_args_list[2][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.repo.uploadBlob'
|
||||
'https://example.pds.io/xrpc/com.atproto.repo.uploadBlob'
|
||||
assert mock_post.call_args_list[3][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.repo.uploadBlob'
|
||||
'https://example.pds.io/xrpc/com.atproto.repo.uploadBlob'
|
||||
assert mock_post.call_args_list[4][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.repo.createRecord'
|
||||
'https://example.pds.io/xrpc/com.atproto.repo.createRecord'
|
||||
assert mock_post.call_args_list[5][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.repo.createRecord'
|
||||
'https://example.pds.io/xrpc/com.atproto.repo.createRecord'
|
||||
assert mock_post.call_args_list[6][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.repo.createRecord'
|
||||
'https://example.pds.io/xrpc/com.atproto.repo.createRecord'
|
||||
assert mock_post.call_args_list[7][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.repo.createRecord'
|
||||
'https://example.pds.io/xrpc/com.atproto.repo.createRecord'
|
||||
|
||||
|
||||
@patch('requests.post')
|
||||
|
@ -622,9 +675,98 @@ def test_plugin_bluesky_auth_failure(
|
|||
body='body', title='title', notify_type=NotifyType.INFO) is False
|
||||
|
||||
# Verify API calls.
|
||||
assert mock_get.call_count == 1
|
||||
assert mock_get.call_count == 2
|
||||
assert mock_get.call_args_list[0][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.identity.resolveHandle'
|
||||
'https://public.api.bsky.app/xrpc/com.atproto.identity.resolveHandle'
|
||||
assert mock_get.call_args_list[1][0][0] == \
|
||||
'https://plc.directory/did:plc:1234'
|
||||
assert mock_post.call_count == 1
|
||||
assert mock_post.call_args_list[0][0][0] == \
|
||||
'https://bsky.social/xrpc/com.atproto.server.createSession'
|
||||
'https://example.pds.io/xrpc/com.atproto.server.createSession'
|
||||
|
||||
|
||||
@patch('requests.post')
|
||||
@patch('requests.get')
|
||||
def test_plugin_bluesky_did_web_and_plc_resolution(
|
||||
mock_get, mock_post, bluesky_url, good_message_response):
|
||||
"""
|
||||
NotifyBlueSky() - Full coverage of did:web and did:plc path
|
||||
"""
|
||||
|
||||
# Step 1: Identity resolution response (public.api.bsky.app)
|
||||
identity_response = good_response({
|
||||
'did': 'did:plc:abcdefg1234567'
|
||||
})
|
||||
|
||||
# Step 2: PLC Directory lookup
|
||||
plc_response = good_response({
|
||||
'service': [{
|
||||
'type': 'AtprotoPersonalDataServer',
|
||||
'serviceEndpoint': 'https://example.pds.io'
|
||||
}]
|
||||
})
|
||||
|
||||
# Step 3: Auth session
|
||||
session_response = good_response()
|
||||
|
||||
# Step 4: Create post
|
||||
post_response = good_response()
|
||||
|
||||
mock_get.side_effect = [identity_response, plc_response]
|
||||
mock_post.side_effect = [session_response, post_response]
|
||||
|
||||
obj = Apprise.instantiate(bluesky_url)
|
||||
assert obj.notify(
|
||||
body='Resolved PLC Flow') is True
|
||||
|
||||
# Reset for did:web test
|
||||
identity_response = good_response({
|
||||
'did': 'did:web:example.com'
|
||||
})
|
||||
|
||||
web_did_response = good_response({
|
||||
'service': [{
|
||||
'type': 'AtprotoPersonalDataServer',
|
||||
'serviceEndpoint': 'https://example.com'
|
||||
}]
|
||||
})
|
||||
|
||||
mock_get.side_effect = [identity_response, web_did_response]
|
||||
mock_post.side_effect = [session_response, post_response]
|
||||
|
||||
obj = Apprise.instantiate(bluesky_url)
|
||||
assert obj.notify(
|
||||
body='Resolved WEB Flow') is True
|
||||
|
||||
# Invalid DID scheme
|
||||
bad_did_response = good_response({
|
||||
'did': 'did:unsupported:scheme'
|
||||
})
|
||||
|
||||
mock_get.side_effect = [bad_did_response]
|
||||
obj = Apprise.instantiate(bluesky_url)
|
||||
|
||||
with pytest.raises(RuntimeError):
|
||||
obj.notify(body='fail due to bad scheme')
|
||||
|
||||
|
||||
@patch('requests.get')
|
||||
def test_plugin_bluesky_pds_resolution_failures(mock_get):
|
||||
"""
|
||||
NotifyBlueSky() - Missing service field or invalid service endpoint
|
||||
"""
|
||||
identity_response = good_response({'did': 'did:plc:missing-service'})
|
||||
plc_no_service = good_response({'foo': 'bar'})
|
||||
|
||||
mock_get.side_effect = [identity_response, plc_no_service]
|
||||
obj = NotifyBlueSky(user='handle', password='pass')
|
||||
did, endpoint = obj.get_identifier()
|
||||
assert (did, endpoint) == (False, False)
|
||||
|
||||
identity_response = good_response({'did': 'did:web:example.com'})
|
||||
web_did_no_service = good_response({'foo': 'bar'})
|
||||
|
||||
mock_get.side_effect = [identity_response, web_did_no_service]
|
||||
obj = NotifyBlueSky(user='handle', password='pass')
|
||||
did, endpoint = obj.get_identifier()
|
||||
assert (did, endpoint) == (False, False)
|
||||
|
|
Loading…
Reference in New Issue