Skip to content

Commit cd5fa75

Browse files
owenpearsonclaude
andauthored
fix: generate message and annotation ids with the URL-safe base64 alphabet
An id travels in a URL path, where the standard alphabet's `+` and `/` are not safe to carry. RSL1k1 asks only for "base64-encoding a sequence of at least 9 bytes" and names no alphabet, so both encodings conform. `test_idempotent_library_generated` decodes a generated id, and needs the matching decoder to do so. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent b9198e1 commit cd5fa75

3 files changed

Lines changed: 3 additions & 3 deletions

File tree

‎ably/rest/annotations.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ async def __send_annotation(self, annotation: Annotation, params: dict | None =
130130
# RSAN1c4: Generate random ID if not provided (for idempotent publishing)
131131
# Spec: base64-encode at least 9 random bytes, append ':0'
132132
if not annotation.id and self.__client_options.idempotent_rest_publishing:
133-
random_id = base64.b64encode(os.urandom(9)).decode('ascii') + ':0'
133+
random_id = base64.urlsafe_b64encode(os.urandom(9)).decode('ascii') + ':0'
134134
annotation = annotation._copy_with(id=random_id)
135135

136136
# RSAN1c3: encrypt the data payload on an encrypted channel

‎ably/rest/channel.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def __publish_request_body(self, messages):
6060
if self.ably.options.idempotent_rest_publishing:
6161
# RSL1k1
6262
if all(message.id is None for message in messages):
63-
base_id = base64.b64encode(os.urandom(12)).decode()
63+
base_id = base64.urlsafe_b64encode(os.urandom(12)).decode()
6464
for serial, message in enumerate(messages):
6565
message.id = f'{base_id}:{serial}'
6666

‎test/ably/rest/restchannelpublish_test.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ def test_idempotent_library_generated(self):
503503
message = Message('name', 'data')
504504
request_body = channel._Channel__publish_request_body(messages=[message])
505505
base_id, serial = request_body['id'].split(':')
506-
assert len(base64.b64decode(base_id)) >= 9
506+
assert len(base64.urlsafe_b64decode(base_id)) >= 9
507507
assert serial == '0'
508508

509509
# RSL1k2

0 commit comments

Comments
 (0)