mirror of https://github.com/status-im/specs.git
119 lines
73 KiB
HTML
119 lines
73 KiB
HTML
|
<!DOCTYPE html> <html lang="en-US"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <title>16/PUSH-NOTIFICATION-SERVER - Status Specification</title> <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"> <link rel="stylesheet" href="/assets/css/just-the-docs-default.css"> <script type="text/javascript" src="/assets/js/vendor/lunr.min.js"></script> <script type="text/javascript" src="/assets/js/just-the-docs.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Begin Jekyll SEO tag v2.7.1 --> <title>16/PUSH-NOTIFICATION-SERVER | Status Specification</title> <meta name="generator" content="Jekyll v4.2.1" /> <meta property="og:title" content="16/PUSH-NOTIFICATION-SERVER" /> <meta property="og:locale" content="en_US" /> <link rel="canonical" href="https://specs.status.im/raw/16" /> <meta property="og:url" content="https://specs.status.im/raw/16" /> <meta property="og:site_name" content="Status Specification" /> <meta name="twitter:card" content="summary" /> <meta property="twitter:title" content="16/PUSH-NOTIFICATION-SERVER" /> <script type="application/ld+json"> {"@type":"WebPage","url":"https://specs.status.im/raw/16","headline":"16/PUSH-NOTIFICATION-SERVER","@context":"https://schema.org"}</script> <!-- End Jekyll SEO tag --> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="svg-link" viewBox="0 0 24 24"> <title>Link</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"> <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path> </svg> </symbol> <symbol id="svg-search" viewBox="0 0 24 24"> <title>Search</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"> <circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line> </svg> </symbol> <symbol id="svg-menu" viewBox="0 0 24 24"> <title>Menu</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-menu"> <line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line> </svg> </symbol> <symbol id="svg-arrow-right" viewBox="0 0 24 24"> <title>Expand</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right"> <polyline points="9 18 15 12 9 6"></polyline> </svg> </symbol> <symbol id="svg-doc" viewBox="0 0 24 24"> <title>Document</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file"> <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline> </svg> </symbol> </svg> <div class="side-bar"> <div class="site-header"> <a href="https://specs.status.im/" class="site-title lh-tight"> Status Specification </a> <a href="#" id="menu-button" class="site-button"> <svg viewBox="0 0 24 24" class="icon"><use xlink:href="#svg-menu"></use></svg> </a> </div> <nav role="navigation" aria-label="Main" id="site-nav" class="site-nav"> <ul class="nav-list"><li class="nav-list-item"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="https://specs.status.im/stable/" class="nav-list-link">Stable specs</a><ul class="nav-list "><li class="nav-list-item "><a href="h
|
|||
|
<span class="kd">enum</span> <span class="n">TokenType</span> <span class="p">{</span>
|
|||
|
<span class="na">UNKNOWN_TOKEN_TYPE</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
|
|||
|
<span class="na">APN_TOKEN</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
|
|||
|
<span class="na">FIREBASE_TOKEN</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
|
|||
|
<span class="p">}</span>
|
|||
|
<span class="n">TokenType</span> <span class="na">token_type</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
|
|||
|
<span class="kt">string</span> <span class="na">device_token</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
|
|||
|
<span class="kt">string</span> <span class="na">installation_id</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
|
|||
|
<span class="kt">string</span> <span class="na">access_token</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
|
|||
|
<span class="kt">bool</span> <span class="na">enabled</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
|
|||
|
<span class="kt">uint64</span> <span class="na">version</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
|
|||
|
<span class="k">repeated</span> <span class="kt">bytes</span> <span class="na">allowed_key_list</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
|
|||
|
<span class="k">repeated</span> <span class="kt">bytes</span> <span class="na">blocked_chat_list</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
|
|||
|
<span class="kt">bool</span> <span class="na">unregister</span> <span class="o">=</span> <span class="mi">9</span><span class="p">;</span>
|
|||
|
<span class="kt">bytes</span> <span class="na">grant</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
|
|||
|
<span class="kt">bool</span> <span class="na">allow_from_contacts_only</span> <span class="o">=</span> <span class="mi">11</span><span class="p">;</span>
|
|||
|
<span class="kt">string</span> <span class="na">apn_topic</span> <span class="o">=</span> <span class="mi">12</span><span class="p">;</span>
|
|||
|
<span class="kt">bool</span> <span class="na">block_mentions</span> <span class="o">=</span> <span class="mi">13</span><span class="p">;</span>
|
|||
|
<span class="k">repeated</span> <span class="kt">bytes</span> <span class="na">allowed_mentions_chat_list</span> <span class="o">=</span> <span class="mi">14</span><span class="p">;</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</code></pre></div></div> <p>A push notification server will handle the message according to the following rules:</p> <ul> <li>it MUST extract the public key of the sender from the signature and verify that the payload can be decrypted successfully.</li> <li>it MUST verify that <code class="language-plaintext highlighter-rouge">token_type</code> is supported</li> <li>it MUST verify that <code class="language-plaintext highlighter-rouge">device_token</code> is non empty</li> <li>it MUST verify that <code class="language-plaintext highlighter-rouge">installation_id</code> is non empty</li> <li>it MUST verify that <code class="language-plaintext highlighter-rouge">version</code> is non-zero and greater than the currently stored version for the public key and installation id of the sender, if any</li> <li>it MUST verify that <code class="language-plaintext highlighter-rouge">grant</code> is non empty and according to the <a href="#server-grant">specs</a></li> <li>it MUST verify that <code class="language-plaintext highlighter-rouge">access_token</code> is a valid <a href="https://tools.ietf.org/html/rfc4122"><code class="language-plaintext highlighter-rouge">uuid</code></a></li> <li>it MUST verify that <code class="language-plaintext highlighter-rouge">apn_topic</code> is set if <code class="language-plaintext highlighter-rouge">token_type</code> is <code class="language-plaintext highlighter-rouge">APN_TOKEN</code></li> </ul> <p>If the message can’t be decrypted, the message MUST be discarded.</p> <p>If <code class="language-plaintext highlighter-rouge">token_type</code> is not supported, a response MUST be sent with <code class="language-plaintext highlighter-rouge">error</code> set to <code class="language-plaintext highlighter-rouge">UNSUPPORTED_TOKEN_TYPE</code>.</p> <p>If <code class="language-plaintext highlighter-rouge">token</code>,<code class="language-plaintext highlighter-rouge">installation_id</code>,<code class="language-plaintext highlighter-rouge">device_tokens</code>,<code class="language-plaintext highlighter-rouge">version</code> are empty, a response MUST be sent with <code class="language-plaintext highlighter-rouge">error</code> set to <code class="language-plaintext highlighter-rouge">MALFORMED_MESSAGE</code>.</p> <p>If the <code class="language-plaintext highlighter-rouge">version</code> is equal or less than the currently stored version, a response MUST be sent with <code class="language-plaintext highlighter-rouge">error</code> set to <code class="language-plaintext highlighter-rouge">VERSION_MISMATCH</code>.</p> <p>If any other error occurs the <code class="language-plaintext highlighter-rouge">error</code> should be set to <code class="language-plaintext highlighter-rouge">INTERNAL_ERROR</code>.</p> <p>If the response is successful <code class="language-plaintext highlighter-rouge">success</code> MUST be set to <code class="language-plaintext highlighter-rouge">true</code> otherwise a response MUST be sent with <code class="language-plaintext highlighter-rouge">success</code> set to <code class="language-plaintext highlighter-rouge">false</code>.</p> <p><code class="language-plaintext highlighter-rouge">request_id</code> should be set to the <code class="language-plaintext highlighter-rouge">SHAKE-256</code> of the encrypted payload.</p> <p>The response MUST be sent on the [partitioned topic][./10-waku-usage.md#partitioned-topic] of the sender and MUST not be encrypted using the <a href="../docs/stable/5-secure-transport.md">secure transport</a> to facilitate the usage of ephemeral keys.</p> <p>The payload of the response is:</p> <div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">PushNotificationRegistrationResponse</span> <span class="p">{</span>
|
|||
|
<span class="kt">bool</span> <span class="na">success</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
|
|||
|
<span class="n">ErrorType</span> <span class="na">error</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
|
|||
|
<span class="kt">bytes</span> <span class="na">request_id</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
|
|||
|
|
|||
|
<span class="kd">enum</span> <span class="n">ErrorType</span> <span class="p">{</span>
|
|||
|
<span class="na">UNKNOWN_ERROR_TYPE</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
|
|||
|
<span class="na">MALFORMED_MESSAGE</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
|
|||
|
<span class="na">VERSION_MISMATCH</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
|
|||
|
<span class="na">UNSUPPORTED_TOKEN_TYPE</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
|
|||
|
<span class="na">INTERNAL_ERROR</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
|
|||
|
<span class="p">}</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</code></pre></div></div> <p>The message MUST be wrapped in a <a href="../stable/6-payloads.6#payload-wrapper"><code class="language-plaintext highlighter-rouge">ApplicationMetadataMessage</code></a> with type set to <code class="language-plaintext highlighter-rouge">PUSH_NOTIFICATION_REGISTRATION_RESPONSE</code>.</p> <p>A client SHOULD listen for a response sent on the [partitioned topic][./10-waku-usage.md#partitioned-topic] that the key used to register.</p> <p>If <code class="language-plaintext highlighter-rouge">success</code> is <code class="language-plaintext highlighter-rouge">true</code> the client has registered successfully.</p> <p>If <code class="language-plaintext highlighter-rouge">success</code> is <code class="language-plaintext highlighter-rouge">false</code>:</p> <ul> <li>If <code class="language-plaintext highlighter-rouge">MALFORMED_MESSAGE</code> is returned, the request SHOULD NOT be retried without ensuring that it is correctly formed.</li> <li>If <code class="language-plaintext highlighter-rouge">INTERNAL_ERROR</code> is returned, the request MAY be retried, but the client MUST backoff exponentially</li> </ul> <p>A client MAY register with multiple Push Notification Servers in order to increase availability.</p> <p>A client SHOULD make sure that all the notification services they registered with have the same information about their tokens.</p> <p>If no response is returned the request SHOULD be considered failed and MAY be retried with the same server or a different one, but clients MUST exponentially backoff after each trial.</p> <p>If the request is successful the token SHOULD be <a href="#advertising-a-push-notification-server">advertised</a> as described below</p> <h3 id="query-topic"> <a href="#query-topic" class="anchor-heading" aria-labelledby="query-topic"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Query topic </h3> <p>On successful registration the server MUST be listening to the topic derived from:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 0XHexEncode(Shake256(CompressedClientPublicKey))
|
|||
|
</code></pre></div></div> <p>Using the topic derivation algorithm described <a href="../stable/10-waku-usage.md#public-chats">here</a> and listen for client queries.</p> <h3 id="server-grant"> <a href="#server-grant" class="anchor-heading" aria-labelledby="server-grant"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Server grant </h3> <p>A push notification server needs to demonstrate to a client that it was authorized by the client to send them push notifications. This is done by building a grant which is specific to a given client-server pair. The grant is built as follow:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Signature(Keccak256(CompressedPublicKeyOfClient . CompressedPublicKeyOfServer . AccessToken), PrivateKeyOfClient)
|
|||
|
</code></pre></div></div> <p>When receiving a grant the server MUST be validate that the signature matches the registering client.</p> <h2 id="re-registering-with-the-push-notification-server"> <a href="#re-registering-with-the-push-notification-server" class="anchor-heading" aria-labelledby="re-registering-with-the-push-notification-server"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Re-registering with the push notification server </h2> <p>A client SHOULD re-register with the node if the APN or FIREBASE token changes.</p> <p>When re-registering a client SHOULD ensure that it has the most up-to-date <code class="language-plaintext highlighter-rouge">PushNotificationRegistration</code> and increment <code class="language-plaintext highlighter-rouge">version</code> if necessary.</p> <p>Once re-registered, a client SHOULD advertise the changes.</p> <h2 id="changing-options"> <a href="#changing-options" class="anchor-heading" aria-labelledby="changing-options"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Changing options </h2> <p>This is handled in exactly the same way as re-registering above.</p> <h2 id="unregistering-from-push-notifications"> <a href="#unregistering-from-push-notifications" class="anchor-heading" aria-labelledby="unregistering-from-push-notifications"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Unregistering from push notifications </h2> <p>To unregister a client MUST send a <code class="language-plaintext highlighter-rouge">PushNotificationRegistration</code> request as described above with <code class="language-plaintext highlighter-rouge">unregister</code> set to <code class="language-plaintext highlighter-rouge">true</code>, or removing their device information.</p> <p>The server MUST remove all data about this user if <code class="language-plaintext highlighter-rouge">unregistering</code> is <code class="language-plaintext highlighter-rouge">true</code>, apart from the <code class="language-plaintext highlighter-rouge">hash</code> of the public key and the <code class="language-plaintext highlighter-rouge">version</code> of the last options, in order to make sure that old messages are not processed.</p> <p>A client MAY unregister from a server on explicit logout if multiple chat keys are used on a single device.</p> <h2 id="advertising-a-push-notification-server"> <a href="#advertising-a-push-notification-server" class="anchor-heading" aria-labelledby="advertising-a-push-notification-server"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Advertising a push notification server </h2> <p>Each user registered with one or more push notification servers SHOULD advertise periodically the push notification services that they have registered with for each device they own.</p> <div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">PushNotificationQueryInfo</span> <span class="p">{</span>
|
|||
|
<span class="kt">string</span> <span class="na">access_token</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
|
|||
|
<span class="kt">string</span> <span class="na">installation_id</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
|
|||
|
<span class="kt">bytes</span> <span class="na">public_key</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
|
|||
|
<span class="k">repeated</span> <span class="kt">bytes</span> <span class="na">allowed_user_list</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
|
|||
|
<span class="kt">bytes</span> <span class="na">grant</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
|
|||
|
<span class="kt">uint64</span> <span class="na">version</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
|
|||
|
<span class="kt">bytes</span> <span class="na">server_public_key</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
|
|||
|
<span class="p">}</span>
|
|||
|
|
|||
|
<span class="kd">message</span> <span class="nc">ContactCodeAdvertisement</span> <span class="p">{</span>
|
|||
|
<span class="k">repeated</span> <span class="n">PushNotificationQueryInfo</span> <span class="na">push_notification_info</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</code></pre></div></div> <p>The message MUST be wrapped in a <a href="../stable/6-payloads.6#payload-wrapper"><code class="language-plaintext highlighter-rouge">ApplicationMetadataMessage</code></a> with type set to <code class="language-plaintext highlighter-rouge">PUSH_NOTIFICATION_QUERY_INFO</code>.</p> <p>If no filtering is done based on public keys, the access token SHOULD be included in the advertisement. Otherwise it SHOULD be left empty.</p> <p>This SHOULD be advertised on the <a href="./10-waku-usage.md#contact-code-topic">contact code topic</a> and SHOULD be coupled with normal contact-code advertisement.</p> <p>Every time a user register or re-register with a push notification service, their contact-code SHOULD be re-advertised.</p> <p>Multiple servers MAY be advertised for the same <code class="language-plaintext highlighter-rouge">installation_id</code> for redundancy reasons.</p> <h2 id="discovering-a-push-notification-server"> <a href="#discovering-a-push-notification-server" class="anchor-heading" aria-labelledby="discovering-a-push-notification-server"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Discovering a push notification server </h2> <p>To discover a push notification service for a given user, their <a href="./10-waku-usage.md#contact-code-topic">contact code topic</a> SHOULD be listened to. A mailserver can be queried for the specific topic to retrieve the most up-to-date contact code.</p> <h2 id="querying-the-push-notification-server"> <a href="#querying-the-push-notification-server" class="anchor-heading" aria-labelledby="querying-the-push-notification-server"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Querying the push notification server </h2> <p>If a token is not present in the latest advertisement for a user, the server SHOULD be queried directly.</p> <p>To query a server a message:</p> <div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">PushNotificationQuery</span> <span class="p">{</span>
|
|||
|
<span class="k">repeated</span> <span class="kt">bytes</span> <span class="na">public_keys</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</code></pre></div></div> <p>The message MUST be wrapped in a <a href="../stable/6-payloads.6#payload-wrapper"><code class="language-plaintext highlighter-rouge">ApplicationMetadataMessage</code></a> with type set to <code class="language-plaintext highlighter-rouge">PUSH_NOTIFICATION_QUERY</code>.</p> <p>MUST be sent to the server on the topic derived from the hashed public key of the key we are querying, as <a href="#query-topic">described above</a>.</p> <p>An ephemeral key SHOULD be used and SHOULD NOT be encrypted using the <a href="../docs/stable/5-secure-transport.md">secure transport</a>.</p> <p>If the server has information about the client a response MUST be sent:</p> <div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">PushNotificationQueryInfo</span> <span class="p">{</span>
|
|||
|
<span class="kt">string</span> <span class="na">access_token</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
|
|||
|
<span class="kt">string</span> <span class="na">installation_id</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
|
|||
|
<span class="kt">bytes</span> <span class="na">public_key</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
|
|||
|
<span class="k">repeated</span> <span class="kt">bytes</span> <span class="na">allowed_user_list</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
|
|||
|
<span class="kt">bytes</span> <span class="na">grant</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
|
|||
|
<span class="kt">uint64</span> <span class="na">version</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
|
|||
|
<span class="kt">bytes</span> <span class="na">server_public_key</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
|
|||
|
<span class="p">}</span>
|
|||
|
|
|||
|
<span class="kd">message</span> <span class="nc">PushNotificationQueryResponse</span> <span class="p">{</span>
|
|||
|
<span class="k">repeated</span> <span class="n">PushNotificationQueryInfo</span> <span class="na">info</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
|
|||
|
<span class="kt">bytes</span> <span class="na">message_id</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
|
|||
|
<span class="kt">bool</span> <span class="na">success</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</code></pre></div></div> <p>A <code class="language-plaintext highlighter-rouge">PushNotificationQueryResponse</code> message MUST be wrapped in a <a href="../stable/6-payloads.6#payload-wrapper"><code class="language-plaintext highlighter-rouge">ApplicationMetadataMessage</code></a> with type set to <code class="language-plaintext highlighter-rouge">PUSH_NOTIFICATION_QUERY_RESPONSE</code>.</p> <p>Otherwise a response MUST NOT be sent.</p> <p>If <code class="language-plaintext highlighter-rouge">allowed_key_list</code> is not set <code class="language-plaintext highlighter-rouge">access_token</code> MUST be set and <code class="language-plaintext highlighter-rouge">allowed_key_list</code> MUST NOT be set.</p> <p>If <code class="language-plaintext highlighter-rouge">allowed_key_list</code> is set <code class="language-plaintext highlighter-rouge">allowed_key_list</code> MUST be set and <code class="language-plaintext highlighter-rouge">access_token</code> MUST NOT be set.</p> <p>If <code class="language-plaintext highlighter-rouge">access_token</code> is returned, the <code class="language-plaintext highlighter-rouge">access_token</code> SHOULD be used to send push notifications.</p> <p>If <code class="language-plaintext highlighter-rouge">allowed_key_list</code> are returned, the client SHOULD decrypt each token by generating an <code class="language-plaintext highlighter-rouge">AES-GCM</code> symmetric key from the Diffie–Hellman between the target client and itself If AES decryption succeeds it will return a valid <a href="https://tools.ietf.org/html/rfc4122"><code class="language-plaintext highlighter-rouge">uuid</code></a> which is what is used for access_token. The token SHOULD be used to send push notifications.</p> <p>The response MUST be sent on the [partitioned topic][./10-waku-usage.md#partitioned-topic] of the sender and MUST not be encrypted using the <a href="../docs/stable/5-secure-transport.md">secure transport</a> to facilitate the usage of ephemeral keys.</p> <p>On receiving a response a client MUST verify <code class="language-plaintext highlighter-rouge">grant</code> to ensure that the server has been authorized to send push notification to a given client.</p> <h2 id="sending-a-push-notification"> <a href="#sending-a-push-notification" class="anchor-heading" aria-labelledby="sending-a-push-notification"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Sending a push notification </h2> <p>When sending a push notification, only the <code class="language-plaintext highlighter-rouge">installation_id</code> for the devices targeted by the message SHOULD be used.</p> <p>If a message is for all the user devices, all the <code class="language-plaintext highlighter-rouge">installation_id</code> known to the client MAY be used.</p> <p>The number of devices MAY be capped in order to reduce resource consumption.</p> <p>At least 3 devices SHOULD be targeted, ordered by last activity.</p> <p>For any device that a token is available, or that a token is successfully queried, a push notification message SHOULD be sent to the corresponding push notification server.</p> <div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">PushNotification</span> <span class="p">{</span>
|
|||
|
<span class="kt">string</span> <span class="na">access_token</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
|
|||
|
<span class="kt">string</span> <span class="na">chat_id</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
|
|||
|
<span class="kt">bytes</span> <span class="na">public_key</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
|
|||
|
<span class="kt">string</span> <span class="na">installation_id</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
|
|||
|
<span class="kt">bytes</span> <span class="kd">message</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
|
|||
|
<span class="n">PushNotificationType</span> <span class="na">type</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
|
|||
|
<span class="kd">enum</span> <span class="n">PushNotificationType</span> <span class="p">{</span>
|
|||
|
<span class="na">UNKNOWN_PUSH_NOTIFICATION_TYPE</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
|
|||
|
<span class="na">MESSAGE</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
|
|||
|
<span class="na">MENTION</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
|
|||
|
<span class="p">}</span>
|
|||
|
<span class="kt">bytes</span> <span class="na">author</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
|
|||
|
<span class="p">}</span>
|
|||
|
|
|||
|
<span class="kd">message</span> <span class="nc">PushNotificationRequest</span> <span class="p">{</span>
|
|||
|
<span class="k">repeated</span> <span class="n">PushNotification</span> <span class="na">requests</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
|
|||
|
<span class="kt">bytes</span> <span class="na">message_id</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</code></pre></div></div> <p>A <code class="language-plaintext highlighter-rouge">PushNotificationRequest</code> message MUST be wrapped in a <a href="../stable/6-payloads.6#payload-wrapper"><code class="language-plaintext highlighter-rouge">ApplicationMetadataMessage</code></a> with type set to <code class="language-plaintext highlighter-rouge">PUSH_NOTIFICATION_REQUEST</code>.</p> <p>Where <code class="language-plaintext highlighter-rouge">message</code> is the encrypted payload of the message and <code class="language-plaintext highlighter-rouge">chat_id</code> is the <code class="language-plaintext highlighter-rouge">SHAKE-256</code> of the <code class="language-plaintext highlighter-rouge">chat_id</code>. <code class="language-plaintext highlighter-rouge">message_id</code> is the id of the message <code class="language-plaintext highlighter-rouge">author</code> is the <code class="language-plaintext highlighter-rouge">SHAKE-256</code> of the public key of the sender.</p> <p>If multiple server are available for a given push notification, only one notification MUST be sent.</p> <p>If no response is received a client SHOULD wait at least 3 seconds, after which the request MAY be retried against a different server</p> <p>This message SHOULD be sent using an ephemeral key.</p> <p>On receiving the message, the push notification server MUST validate the access token. If the access token is valid, a notification MUST be sent to the gorush instance with the following data:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{
|
|||
|
"notifications": [
|
|||
|
{
|
|||
|
"tokens": ["token_a", "token_b"],
|
|||
|
"platform": 1,
|
|||
|
"message": "You have a new message",
|
|||
|
"data": {
|
|||
|
"chat_id": chat_id,
|
|||
|
"message": message,
|
|||
|
"installation_ids": [installation_id_1, installation_id_2]
|
|||
|
}
|
|||
|
}
|
|||
|
]
|
|||
|
}
|
|||
|
</code></pre></div></div> <p>Where platform is <code class="language-plaintext highlighter-rouge">1</code> for IOS and <code class="language-plaintext highlighter-rouge">2</code> for Firebase, according to the <a href="https://github.com/appleboy/gorush">gorush documentation</a></p> <p>A server MUST return a response message:</p> <div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">PushNotificationReport</span> <span class="p">{</span>
|
|||
|
<span class="kt">bool</span> <span class="na">success</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
|
|||
|
<span class="n">ErrorType</span> <span class="na">error</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
|
|||
|
<span class="kd">enum</span> <span class="n">ErrorType</span> <span class="p">{</span>
|
|||
|
<span class="na">UNKNOWN_ERROR_TYPE</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
|
|||
|
<span class="na">WRONG_TOKEN</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
|
|||
|
<span class="na">INTERNAL_ERROR</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
|
|||
|
<span class="na">NOT_REGISTERED</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
|
|||
|
<span class="p">}</span>
|
|||
|
<span class="kt">bytes</span> <span class="na">public_key</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
|
|||
|
<span class="kt">string</span> <span class="na">installation_id</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
|
|||
|
<span class="p">}</span>
|
|||
|
|
|||
|
<span class="kd">message</span> <span class="nc">PushNotificationResponse</span> <span class="p">{</span>
|
|||
|
<span class="kt">bytes</span> <span class="na">message_id</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
|
|||
|
<span class="k">repeated</span> <span class="n">PushNotificationReport</span> <span class="na">reports</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</code></pre></div></div> <p>A <code class="language-plaintext highlighter-rouge">PushNotificationResponse</code> message MUST be wrapped in a <a href="../stable/6-payloads.6#payload-wrapper"><code class="language-plaintext highlighter-rouge">ApplicationMetadataMessage</code></a> with type set to <code class="language-plaintext highlighter-rouge">PUSH_NOTIFICATION_RESPONSE</code>.</p> <p>Where <code class="language-plaintext highlighter-rouge">message_id</code> is the <code class="language-plaintext highlighter-rouge">message_id</code> sent by the client.</p> <p>The response MUST be sent on the [partitioned topic][./10-waku-usage.md#partitioned-topic] of the sender and MUST not be encrypted using the <a href="../docs/stable/5-secure-transport.md">secure transport</a> to facilitate the usage of ephemeral keys.</p> <p>If the request is accepted <code class="language-plaintext highlighter-rouge">success</code> MUST be set to <code class="language-plaintext highlighter-rouge">true</code>. Otherwise <code class="language-plaintext highlighter-rouge">success</code> MUST be set to <code class="language-plaintext highlighter-rouge">false</code>.</p> <p>If <code class="language-plaintext highlighter-rouge">error</code> is <code class="language-plaintext highlighter-rouge">BAD_TOKEN</code> the client MAY query again the server for the token and retry the request.</p> <p>If <code class="language-plaintext highlighter-rouge">error</code> is <code class="language-plaintext highlighter-rouge">INTERNAL_ERROR</code> the client MAY retry the request.</p> <h2 id="flow"> <a href="#flow" class="anchor-heading" aria-labelledby="flow"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Flow </h2> <h3 id="registration-process"> <a href="#registration-process" class="anchor-heading" aria-labelledby="registration-process"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Registration process </h3> <ul> <li>A client will generate a notification token through <code class="language-plaintext highlighter-rouge">APN</code> or <code class="language-plaintext highlighter-rouge">Firebase</code>.</li> <li>The client will <a href="#registering-with-the-push-notification-service">register</a> with one or more push notification server of their choosing.</li> <li>The server should process the response and respond according to the success of the operation</li> <li>If the request is not successful it might be retried, and adjusted according to the response. A different server can be also used.</li> <li>Once the request is successful the client should <a href="#advertising-a-push-notification-server">advertise</a> the new coordinates</li> </ul> <h3 id="sending-a-notification"> <a href="#sending-a-notification" class="anchor-heading" aria-labelledby="sending-a-notification"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Sending a notification </h3> <ul> <li>A client should prepare a message and extract the targeted installation-ids</li> <li>It should retrieve the most up to date information for a given user, either by querying a push notification server, a mailserver if not listening already to the given topic, or checking the database locally</li> <li>It should then <a href="#sending-a-push-notification">send</a> a push notification according to the rules described</li> <li>The server should then send a request to the gorush server including all the required information</li> </ul> <h3 id="receiving-a-push-notification"> <a href="#receiving-a-push-notification" class="anchor-heading" aria-labelledby="receiving-a-push-notification"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Receiving a push notification </h3> <ul> <li>On receiving the notification, a client can open the right account by checking the <code class="language-plaintext highlighter-rouge">installation_id</code> included. The <code class="language-plaintext highlighter-rouge">chat_id</code> MAY be used to open the chat if present.</li> <li><
|