From 05da9d75cfacf397abfaf58b06c6c3def3ae7261 Mon Sep 17 00:00:00 2001 From: Marat Alekperov Date: Mon, 12 Jan 2026 01:01:38 +0000 Subject: [PATCH] Updated device id and secret specs according to the cocoa implementation. --- textile/features.textile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/textile/features.textile b/textile/features.textile index 131f7be8..4ec099e2 100644 --- a/textile/features.textile +++ b/textile/features.textile @@ -1345,7 +1345,7 @@ h3(#activation-state-machine). Activation State Machine ***** @(RSH3a2a2)@ If a custom @registerCallback@ was provided to @Push#activate@, pass it the local @DeviceDetails@. ***** @(RSH3a2a3)@ Otherwise, makes an asynchronous HTTP PUT request to @/push/deviceRegistrations/:deviceId@ using the local @DeviceDetails@ with the push details as body. When the registration validation request is complete, a @RegistrationSynced@ or @SyncRegistrationFailed@ event should be fired. ***** @(RSH3a2a4)@ Transitions to @WaitingForRegistrationSync@. -**** @(RSH3a2b)@ If the local device does not have @id@ or @deviceSecret@, both are generated locally. The @id@ must be a unique identifier (e.g. UUID, GUID). The @deviceSecret@ must be created using secure random data with sufficient entropy to generate a digest of at least 32 bytes (eg using sha256) and encoding that digest with base64. The local @DeviceDetails@ is updated with the resulting @deviceId@ and @deviceSecret@. If either the @id@ or the @deviceSecret@ is lost then a new pair must be created. +**** @(RSH3a2b)@ This clause has been replaced by "@RSH8a1@":#RSH8a1. It was valid up to and including specification version @3.0@. **** @(RSH3a2c)@ If the local device has the necessary push details (registration token, etc.), sends a @GotPushDeviceDetails@ event. **** @(RSH3a2d)@ If the local device does not have the necessary push details, it initiates a request to the underlying platform (or otherwise generates them) **** @(RSH3a2e)@ Transitions to @WaitingForPushDeviceDetails@. @@ -1412,7 +1412,8 @@ h3(#activation-state-machine). Activation State Machine *** @(RSH3g1)@ On event @CalledDeactivate@: **** @(RSH3g1a)@ Transitions to @WaitingForDeregistration@. *** @(RSH3g2)@ On event @Deregistered@: -**** @(RSH3g2a)@ Clears all local @DeviceDetails@. +**** @(RSH3g2a)@ This clause has been replaced by "@RSH3g2d@":#RSH3g2d. It was valid up to and including specification version @3.0@. +**** @(RSH3g2d)@ Generates a new pair of device @id@ and @deviceSecret@ as described in "RSH8a1":#RSH8a1. Clears all other local @DeviceDetails@. **** @(RSH3g2b)@ Makes @Push#deactivate@ return or call its callback with no error. **** @(RSH3g2c)@ Transitions to @NotActivated@. *** @(RSH3g3)@ On event @DeregistrationFailed@: @@ -1453,7 +1454,9 @@ h3(#local-device). LocalDevice *** @(RSH8k1)@ @deviceIdentityToken@ string? – populated as described in "RSH8c":#RSH8c *** @(RSH8k2)@ @deviceSecret@ string – populated as described in "RSH8b":#RSH8b. (Note: This property being non-nullable is not actually consistent with "@RSH3a2b@":#RSH3a2b; that spec point implies that @id@ and @deviceSecret@ both start off unset and are only set upon a @CalledActivate@ event. However, since @deviceSecret@ needs to have the same nullability as @id@ — since per @RSH3a2b@ either both or neither should be set — to reflect the behaviour described in the spec we would have to make @LocalDevice#id@ nullable, but this is incompatible with the superclass @DeviceDetails@. In reality, our implementations of @LocalDevice@ actually generate @id@ and @deviceSecret@ when the device is fetched, i.e. not following @RSH3a2b@. What we _should_ do is either make @LocalDevice@ stop inheriting from @DeviceDetails@, or change the specified behaviour for when to generate @id@ and @deviceSecret@ to match our implementations, or both. See spec issues "#180":https://github.com/ably/specification/issues/180 and "#25":https://github.com/ably/specification/issues/25. For now, this note exists to reduce confusion.) ** @(RSH8a)@ The @LocalDevice@ is initialised when first required, either as a result of a call to @RestClient#device@ or @RealtimeClient#device@, or as a result of an operation involving the Activation State Machine. The @LocalDevice@ @id@, @clientId@, @deviceSecret@ and @deviceIdentityToken@ attributes are populated, together with any @recipient@-related attributes, to the extent that they exist, from the persisted state. -** @(RSH8b)@ The @LocalDevice@ @id@ and @deviceSecret@ attributes are generated, and persisted as part of the @LocalDevice@ state, when required by step "@(RSH3a2b)@":#RSH3a2b in the Activation State Machine. At that time, the @clientId@ attribute is also initialised, if the client is identified according to "@(RSA7)@":#RSA7. +*** @(RSH8a1)@ If the local device storage does not have id or deviceSecret, both are generated locally. The id must be a unique identifier (e.g. UUID, GUID). The deviceSecret must be created using secure random data with sufficient entropy to generate a digest of at least 32 bytes (eg using sha256) and encoding that digest with base64. The local DeviceDetails is updated with the resulting deviceId and deviceSecret. If either the id or the deviceSecret is lost then a new pair must be created. +** @(RSH8b)@ This clause has been replaced by "@RSH8l@":#RSH8l. It was valid up to and including specification version @3.0@. +** @(RSH8l)@ If the client is identified according to (RSA7), the clientId attribute is initialized during the activation of the state machine. ** @(RSH8c)@ Following successful registration of a @LocalDevice@, following the procedure in "@(RSH3c2a)@":#RSH3c2a, the now known @deviceIdentityToken@ is set and persisted. ** @(RSH8d)@ If the @LocalDevice@ is created by an unidentified client (see "@(RSA7)@":#RSA7 ) and therefore has no @clientId@ set, but the client subsequently becomes identified (as a result of "@(RSA7b2)@":#RSA7b2 or "@(RSA7b3)@":#RSA7b3 ), then the @LocalDevice@ @clientId@ is set and persisted. ** @(RSH8e)@ If the @LocalDevice@ @clientId@ becomes set as a result of "@(RSH8d)@":#RSH8d, and the @LocalDevice@ is already registered (ie the @deviceIdentityToken@ is set), and the ActivationStateMachine is in any state other than @NotActivated@, then a @GotPushDeviceDetails@ event is sent to "the state machine":#RSH3 once the effects of "@(RSH8d)@":#RSH8d are visible, ie. once @LocalDevice@ @clientId@ is set.