Files
rfc-index/status/71/push-notification-server.html
2025-12-22 13:04:47 +00:00

932 lines
61 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE HTML>
<html lang="en" class="ayu" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>71/Push Notification Server - Vac RFC</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="../../favicon.svg">
<link rel="shortcut icon" href="../../favicon.png">
<link rel="stylesheet" href="../../css/variables.css">
<link rel="stylesheet" href="../../css/general.css">
<link rel="stylesheet" href="../../css/chrome.css">
<link rel="stylesheet" href="../../css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../../highlight.css">
<link rel="stylesheet" href="../../tomorrow-night.css">
<link rel="stylesheet" href="../../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<link rel="stylesheet" href="../../custom.css">
</head>
<body class="sidebar-visible no-js">
<div id="body-container">
<!-- Provide site root to javascript -->
<script>
var path_to_root = "../../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "ayu";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('ayu')
html.classList.add(theme);
var body = document.querySelector('body');
body.classList.remove('no-js')
body.classList.add('js');
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var body = document.querySelector('body');
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
body.classList.remove('sidebar-visible');
body.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded affix "><a href="../../index.html">Introduction</a></li><li class="chapter-item expanded "><a href="../../vac/index.html"><strong aria-hidden="true">1.</strong> Vac</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../vac/1/coss.html"><strong aria-hidden="true">1.1.</strong> 1/COSS</a></li><li class="chapter-item expanded "><a href="../../vac/2/mvds.html"><strong aria-hidden="true">1.2.</strong> 2/MVDS</a></li><li class="chapter-item expanded "><a href="../../vac/3/remote-log.html"><strong aria-hidden="true">1.3.</strong> 3/Remote Log</a></li><li class="chapter-item expanded "><a href="../../vac/4/mvds-meta.html"><strong aria-hidden="true">1.4.</strong> 4/MVDS Meta</a></li><li class="chapter-item expanded "><a href="../../vac/25/libp2p-dns-discovery.html"><strong aria-hidden="true">1.5.</strong> 25/Libp2p DNS Discovery</a></li><li class="chapter-item expanded "><a href="../../vac/32/rln-v1.html"><strong aria-hidden="true">1.6.</strong> 32/RLN-V1</a></li><li class="chapter-item expanded "><a href="../../vac/raw/index.html"><strong aria-hidden="true">1.7.</strong> Raw</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../vac/raw/consensus-hashgraphlike.html"><strong aria-hidden="true">1.7.1.</strong> Consensus Hashgraphlike</a></li><li class="chapter-item expanded "><a href="../../vac/raw/decentralized-messaging-ethereum.html"><strong aria-hidden="true">1.7.2.</strong> Decentralized Messaging Ethereum</a></li><li class="chapter-item expanded "><a href="../../vac/raw/eth-mls-offchain.html"><strong aria-hidden="true">1.7.3.</strong> ETH MLS Offchain</a></li><li class="chapter-item expanded "><a href="../../vac/raw/eth-mls-onchain.html"><strong aria-hidden="true">1.7.4.</strong> ETH MLS Onchain</a></li><li class="chapter-item expanded "><a href="../../vac/raw/deleted/eth-secpm.html"><strong aria-hidden="true">1.7.5.</strong> ETH SecPM</a></li><li class="chapter-item expanded "><a href="../../vac/raw/gossipsub-tor-push.html"><strong aria-hidden="true">1.7.6.</strong> Gossipsub Tor Push</a></li><li class="chapter-item expanded "><a href="../../vac/raw/logos-capability-discovery.html"><strong aria-hidden="true">1.7.7.</strong> Logos Capability Discovery</a></li><li class="chapter-item expanded "><a href="../../vac/raw/mix.html"><strong aria-hidden="true">1.7.8.</strong> Mix</a></li><li class="chapter-item expanded "><a href="../../vac/raw/noise-x3dh-double-ratchet.html"><strong aria-hidden="true">1.7.9.</strong> Noise X3DH Double Ratchet</a></li><li class="chapter-item expanded "><a href="../../vac/raw/rln-interep-spec.html"><strong aria-hidden="true">1.7.10.</strong> RLN Interep Spec</a></li><li class="chapter-item expanded "><a href="../../vac/raw/rln-stealth-commitments.html"><strong aria-hidden="true">1.7.11.</strong> RLN Stealth Commitments</a></li><li class="chapter-item expanded "><a href="../../vac/raw/rln-v2.html"><strong aria-hidden="true">1.7.12.</strong> RLN-V2</a></li><li class="chapter-item expanded "><a href="../../vac/raw/sds.html"><strong aria-hidden="true">1.7.13.</strong> SDS</a></li></ol></li><li class="chapter-item expanded "><a href="../../vac/template.html"><strong aria-hidden="true">1.8.</strong> Template</a></li></ol></li><li class="chapter-item expanded "><a href="../../waku/index.html"><strong aria-hidden="true">2.</strong> Waku</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../waku/standards/core/index.html"><strong aria-hidden="true">2.1.</strong> Standards - Core</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../waku/standards/core/10/waku2.html"><strong aria-hidden="true">2.1.1.</strong> 10/Waku2</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/11/relay.html"><strong aria-hidden="true">2.1.2.</strong> 11/Relay</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/12/filter.html"><strong aria-hidden="true">2.1.3.</strong> 12/Filter</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/13/store.html"><strong aria-hidden="true">2.1.4.</strong> 13/Store</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/14/message.html"><strong aria-hidden="true">2.1.5.</strong> 14/Message</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/15/bridge.html"><strong aria-hidden="true">2.1.6.</strong> 15/Bridge</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/17/rln-relay.html"><strong aria-hidden="true">2.1.7.</strong> 17/RLN Relay</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/19/lightpush.html"><strong aria-hidden="true">2.1.8.</strong> 19/Lightpush</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/31/enr.html"><strong aria-hidden="true">2.1.9.</strong> 31/ENR</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/33/discv5.html"><strong aria-hidden="true">2.1.10.</strong> 33/Discv5</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/34/peer-exchange.html"><strong aria-hidden="true">2.1.11.</strong> 34/Peer Exchange</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/36/bindings-api.html"><strong aria-hidden="true">2.1.12.</strong> 36/Bindings API</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/64/network.html"><strong aria-hidden="true">2.1.13.</strong> 64/Network</a></li><li class="chapter-item expanded "><a href="../../waku/standards/core/66/metadata.html"><strong aria-hidden="true">2.1.14.</strong> 66/Metadata</a></li></ol></li><li class="chapter-item expanded "><a href="../../waku/standards/application/index.html"><strong aria-hidden="true">2.2.</strong> Standards - Application</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../waku/standards/application/20/toy-eth-pm.html"><strong aria-hidden="true">2.2.1.</strong> 20/Toy ETH PM</a></li><li class="chapter-item expanded "><a href="../../waku/standards/application/26/payload.html"><strong aria-hidden="true">2.2.2.</strong> 26/Payload</a></li><li class="chapter-item expanded "><a href="../../waku/standards/application/53/x3dh.html"><strong aria-hidden="true">2.2.3.</strong> 53/X3DH</a></li><li class="chapter-item expanded "><a href="../../waku/standards/application/54/x3dh-sessions.html"><strong aria-hidden="true">2.2.4.</strong> 54/X3DH Sessions</a></li></ol></li><li class="chapter-item expanded "><a href="../../waku/standards/legacy/index.html"><strong aria-hidden="true">2.3.</strong> Standards - Legacy</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../waku/standards/legacy/6/waku1.html"><strong aria-hidden="true">2.3.1.</strong> 6/Waku1</a></li><li class="chapter-item expanded "><a href="../../waku/standards/legacy/7/data.html"><strong aria-hidden="true">2.3.2.</strong> 7/Data</a></li><li class="chapter-item expanded "><a href="../../waku/standards/legacy/8/mail.html"><strong aria-hidden="true">2.3.3.</strong> 8/Mail</a></li><li class="chapter-item expanded "><a href="../../waku/standards/legacy/9/rpc.html"><strong aria-hidden="true">2.3.4.</strong> 9/RPC</a></li></ol></li><li class="chapter-item expanded "><a href="../../waku/informational/index.html"><strong aria-hidden="true">2.4.</strong> Informational</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../waku/informational/22/toy-chat.html"><strong aria-hidden="true">2.4.1.</strong> 22/Toy Chat</a></li><li class="chapter-item expanded "><a href="../../waku/informational/23/topics.html"><strong aria-hidden="true">2.4.2.</strong> 23/Topics</a></li><li class="chapter-item expanded "><a href="../../waku/informational/27/peers.html"><strong aria-hidden="true">2.4.3.</strong> 27/Peers</a></li><li class="chapter-item expanded "><a href="../../waku/informational/29/config.html"><strong aria-hidden="true">2.4.4.</strong> 29/Config</a></li><li class="chapter-item expanded "><a href="../../waku/informational/30/adaptive-nodes.html"><strong aria-hidden="true">2.4.5.</strong> 30/Adaptive Nodes</a></li></ol></li><li class="chapter-item expanded "><a href="../../waku/deprecated/index.html"><strong aria-hidden="true">2.5.</strong> Deprecated</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../waku/deprecated/5/waku0.html"><strong aria-hidden="true">2.5.1.</strong> 5/Waku0</a></li><li class="chapter-item expanded "><a href="../../waku/deprecated/16/rpc.html"><strong aria-hidden="true">2.5.2.</strong> 16/RPC</a></li><li class="chapter-item expanded "><a href="../../waku/deprecated/18/swap.html"><strong aria-hidden="true">2.5.3.</strong> 18/Swap</a></li><li class="chapter-item expanded "><a href="../../waku/deprecated/fault-tolerant-store.html"><strong aria-hidden="true">2.5.4.</strong> Fault Tolerant Store</a></li></ol></li></ol></li><li class="chapter-item expanded "><a href="../../nomos/index.html"><strong aria-hidden="true">3.</strong> Nomos</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../nomos/raw/index.html"><strong aria-hidden="true">3.1.</strong> Raw</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../nomos/raw/nomosda-encoding.html"><strong aria-hidden="true">3.1.1.</strong> NomosDA Encoding</a></li><li class="chapter-item expanded "><a href="../../nomos/raw/nomosda-network.html"><strong aria-hidden="true">3.1.2.</strong> NomosDA Network</a></li><li class="chapter-item expanded "><a href="../../nomos/raw/p2p-hardware-requirements.html"><strong aria-hidden="true">3.1.3.</strong> P2P Hardware Requirements</a></li><li class="chapter-item expanded "><a href="../../nomos/raw/p2p-nat-solution.html"><strong aria-hidden="true">3.1.4.</strong> P2P NAT Solution</a></li><li class="chapter-item expanded "><a href="../../nomos/raw/p2p-network-bootstrapping.html"><strong aria-hidden="true">3.1.5.</strong> P2P Network Bootstrapping</a></li><li class="chapter-item expanded "><a href="../../nomos/raw/p2p-network.html"><strong aria-hidden="true">3.1.6.</strong> P2P Network</a></li><li class="chapter-item expanded "><a href="../../nomos/raw/sdp.html"><strong aria-hidden="true">3.1.7.</strong> SDP</a></li></ol></li><li class="chapter-item expanded "><a href="../../nomos/deprecated/index.html"><strong aria-hidden="true">3.2.</strong> Deprecated</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../nomos/deprecated/claro.html"><strong aria-hidden="true">3.2.1.</strong> Claro</a></li></ol></li></ol></li><li class="chapter-item expanded "><a href="../../codex/index.html"><strong aria-hidden="true">4.</strong> Codex</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../codex/raw/index.html"><strong aria-hidden="true">4.1.</strong> Raw</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../codex/raw/codex-block-exchange.html"><strong aria-hidden="true">4.1.1.</strong> Block Exchange</a></li><li class="chapter-item expanded "><a href="../../codex/raw/codex-marketplace.html"><strong aria-hidden="true">4.1.2.</strong> Marketplace</a></li></ol></li></ol></li><li class="chapter-item expanded "><a href="../../status/index.html"><strong aria-hidden="true">5.</strong> Status</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../status/24/curation.html"><strong aria-hidden="true">5.1.</strong> 24/Curation</a></li><li class="chapter-item expanded "><a href="../../status/28/featuring.html"><strong aria-hidden="true">5.2.</strong> 28/Featuring</a></li><li class="chapter-item expanded "><a href="../../status/55/1to1-chat.html"><strong aria-hidden="true">5.3.</strong> 55/1-to-1 Chat</a></li><li class="chapter-item expanded "><a href="../../status/56/communities.html"><strong aria-hidden="true">5.4.</strong> 56/Communities</a></li><li class="chapter-item expanded "><a href="../../status/61/community-history-service.html"><strong aria-hidden="true">5.5.</strong> 61/Community History Service</a></li><li class="chapter-item expanded "><a href="../../status/62/payloads.html"><strong aria-hidden="true">5.6.</strong> 62/Payloads</a></li><li class="chapter-item expanded "><a href="../../status/63/keycard-usage.html"><strong aria-hidden="true">5.7.</strong> 63/Keycard Usage</a></li><li class="chapter-item expanded "><a href="../../status/65/account-address.html"><strong aria-hidden="true">5.8.</strong> 65/Account Address</a></li><li class="chapter-item expanded "><a href="../../status/71/push-notification-server.html" class="active"><strong aria-hidden="true">5.9.</strong> 71/Push Notification Server</a></li><li class="chapter-item expanded "><a href="../../status/raw/index.html"><strong aria-hidden="true">5.10.</strong> Raw</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../status/raw/simple-scaling.html"><strong aria-hidden="true">5.10.1.</strong> Simple Scaling</a></li><li class="chapter-item expanded "><a href="../../status/raw/status-app-protocols.html"><strong aria-hidden="true">5.10.2.</strong> Status App Protocols</a></li><li class="chapter-item expanded "><a href="../../status/raw/status-mvds.html"><strong aria-hidden="true">5.10.3.</strong> Status MVDS</a></li><li class="chapter-item expanded "><a href="../../status/raw/url-data.html"><strong aria-hidden="true">5.10.4.</strong> URL Data</a></li><li class="chapter-item expanded "><a href="../../status/raw/url-scheme.html"><strong aria-hidden="true">5.10.5.</strong> URL Scheme</a></li></ol></li><li class="chapter-item expanded "><a href="../../status/deprecated/index.html"><strong aria-hidden="true">5.11.</strong> Deprecated</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../status/deprecated/3rd-party.html"><strong aria-hidden="true">5.11.1.</strong> 3rd Party</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/account.html"><strong aria-hidden="true">5.11.2.</strong> Account</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/client.html"><strong aria-hidden="true">5.11.3.</strong> Client</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/dapp-browser-API-usage.html"><strong aria-hidden="true">5.11.4.</strong> Dapp Browser API Usage</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/eips.html"><strong aria-hidden="true">5.11.5.</strong> EIPs</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/ethereum-usage.html"><strong aria-hidden="true">5.11.6.</strong> Ethereum Usage</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/group-chat.html"><strong aria-hidden="true">5.11.7.</strong> Group Chat</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/IPFS-gateway-for-sticker-Pack.html"><strong aria-hidden="true">5.11.8.</strong> IPFS Gateway for Sticker Pack</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/keycard-usage-for-wallet-and-chat-keys.html"><strong aria-hidden="true">5.11.9.</strong> Keycard Usage for Wallet and Chat Keys</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/notifications.html"><strong aria-hidden="true">5.11.10.</strong> Notifications</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/payloads.html"><strong aria-hidden="true">5.11.11.</strong> Payloads</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/push-notification-server.html"><strong aria-hidden="true">5.11.12.</strong> Push Notification Server</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/secure-transport.html"><strong aria-hidden="true">5.11.13.</strong> Secure Transport</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/waku-mailserver.html"><strong aria-hidden="true">5.11.14.</strong> Waku Mailserver</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/waku-usage.html"><strong aria-hidden="true">5.11.15.</strong> Waku Usage</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/whisper-mailserver.html"><strong aria-hidden="true">5.11.16.</strong> Whisper Mailserver</a></li><li class="chapter-item expanded "><a href="../../status/deprecated/whisper-usage.html"><strong aria-hidden="true">5.11.17.</strong> Whisper Usage</a></li></ol></li></ol></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<!-- Track and set sidebar scroll position -->
<script>
var sidebarScrollbox = document.querySelector('#sidebar .sidebar-scrollbox');
sidebarScrollbox.addEventListener('click', function(e) {
if (e.target.tagName === 'A') {
sessionStorage.setItem('sidebar-scroll', sidebarScrollbox.scrollTop);
}
}, { passive: true });
var sidebarScrollTop = sessionStorage.getItem('sidebar-scroll');
sessionStorage.removeItem('sidebar-scroll');
if (sidebarScrollTop) {
// preserve sidebar scroll position when navigating via links within sidebar
sidebarScrollbox.scrollTop = sidebarScrollTop;
} else {
// scroll sidebar to current active section when navigating via "next/previous chapter" buttons
var activeSection = document.querySelector('#sidebar .active');
if (activeSection) {
activeSection.scrollIntoView({ block: 'center' });
}
}
</script>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Vac RFC</h1>
<div class="right-buttons">
<a href="../../print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/vacp2p/rfc-index" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="71status-push-notification-server"><a class="header" href="#71status-push-notification-server">71/STATUS-PUSH-NOTIFICATION-SERVER</a></h1>
<div class="rfc-meta">
<table>
<tr><th>Name</th><td>Push Notification Server</td></tr>
<tr><th>Slug</th><td>71</td></tr>
<tr><th>Status</th><td>draft</td></tr>
<tr><th>Category</th><td>Standards Track</td></tr>
<tr><th>Editor</th><td>Jimmy Debe &lt;jimmy@status.im&gt;</td></tr>
<tr><th>Contributors</th><td>Andrea Maria Piana &lt;andreap@status.im&gt;</td></tr>
</table>
</div>
<!-- timeline:start -->
<h2 id="timeline"><a class="header" href="#timeline">Timeline</a></h2>
<ul>
<li><strong>2025-12-22</strong><a href="https://github.com/vacp2p/rfc-index/blob/b1a578393edf8487ccc97a5f25b25af9bf41efb3/docs/status/71/push-notification-server.md"><code>b1a5783</code></a> — Chore/mdbook updates (#237)</li>
<li><strong>2025-12-18</strong><a href="https://github.com/vacp2p/rfc-index/blob/d03e699084774ebecef9c6d4662498907c5e2080/docs/status/71/push-notification-server.md"><code>d03e699</code></a> — ci: add mdBook configuration (#233)</li>
<li><strong>2024-09-13</strong><a href="https://github.com/vacp2p/rfc-index/blob/3ab314d87d4525ff1296bf3d9ec634d570777b91/status/71/push-notification-server.md"><code>3ab314d</code></a> — Fix Files for Linting (#94)</li>
<li><strong>2024-02-07</strong><a href="https://github.com/vacp2p/rfc-index/blob/3e21cc0aabe72b00bf2e6ce51ed889e929e4a047/status/71/push-notification-server.md"><code>3e21cc0</code></a> — Update push-notification-server.md</li>
<li><strong>2024-02-05</strong><a href="https://github.com/vacp2p/rfc-index/blob/5bce32702ae3dcb1c05f491804a745724533db7e/status/71/push-notification-server.md"><code>5bce327</code></a> — Update push-notification-server.md</li>
<li><strong>2024-02-02</strong><a href="https://github.com/vacp2p/rfc-index/blob/8df3f006cf6a9dd64c3cfa8c99256330cc696df7/status/71/push-notification-server.md"><code>8df3f00</code></a> — Update and rename PUSH-NOTIFICATIONS.md to push-notification-server.md</li>
<li><strong>2024-01-27</strong><a href="https://github.com/vacp2p/rfc-index/blob/eb7c5bf71edd47cf0b5d0f0919013cdea17c4f43/status/71/PUSH-NOTIFICATIONS.md"><code>eb7c5bf</code></a> — Create PUSH-NOTIFICATIONS.md</li>
</ul>
<!-- timeline:end -->
<h2 id="abstract"><a class="header" href="#abstract">Abstract</a></h2>
<p>A push notification server implementation for IOS devices and Android devices.
This specification provides a set of methods that allow clients
to use push notification services in mobile environments.</p>
<h2 id="background"><a class="header" href="#background">Background</a></h2>
<p>Push notification for iOS and
Android devices can only be implemented by relying on
<a href="https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1">APN</a>,
Apple Push Notification, service for iOS or
<a href="https://firebase.google.com/">Firebase</a> for Android.</p>
<p>For some Android devices, foreground services are restricted,
requiring a user to grant authorization to applications
to use foreground notifications.
Apple iOS devices restrict notifications to
a few internal functions that every application can not use.
Applications on iOS can request execution time when they are in the background.
This has a limited set of use cases for example,
it will not schedule any time if the application was closed with force quit.
Requesting execution time is not responsive enough to
implement a push notification system.
Status provides a set of methods to acheive push notification services.</p>
<p>Since this can not be safely implemented in a privacy-preserving manner,
clients need to be given an option to opt-in to receive and send push notifications.
They are disabled by default.</p>
<h2 id="specification"><a class="header" href="#specification">Specification</a></h2>
<p>The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”,
“SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and
“OPTIONAL” in this document are to be interpreted as described in <a href="https://www.ietf.org/rfc/rfc2119.txt">2119</a>.</p>
<h3 id="definitions"><a class="header" href="#definitions">Definitions</a></h3>
<div class="table-wrapper"><table><thead><tr><th>Terminology</th><th>Description</th></tr></thead><tbody>
<tr><td>client</td><td>A node that implements the Status specifications.</td></tr>
<tr><td>user</td><td>The owner of a device that runs a client.</td></tr>
<tr><td>server</td><td>A service that performs push notifications.</td></tr>
<tr><td>Waku-Store</td><td>A Waku node that decides to provide functionality to store messages permanently and deliver the messages to requesting clients. As described in <a href="../../waku/standards/core/13/store.html">13/WAKU-STORE</a> specification.</td></tr>
</tbody></table>
</div>
<h3 id="server-components"><a class="header" href="#server-components">Server Components</a></h3>
<div class="table-wrapper"><table><thead><tr><th>Components</th><th>Description</th></tr></thead><tbody>
<tr><td>gorush Instance</td><td>Only used by push notification servers and MUST be publicly available.</td></tr>
<tr><td>Push Notification Server</td><td>Used by clients to register for receiving and sending notifications.</td></tr>
<tr><td>Registering Client</td><td>A client that wants to receive push notifications.</td></tr>
<tr><td>Sending Client</td><td>A client that wants to send push notifications.</td></tr>
</tbody></table>
</div>
<h3 id="requirements"><a class="header" href="#requirements">Requirements</a></h3>
<p>The party releasing the app MUST possess a certificate
for the Apple Push Notification service and
it MUST run a <a href="https://github.com/appleboy/gorush">gorush</a>
publicly accessible server for sending the actual notification.
The party releasing the app MUST run its own <a href="https://github.com/appleboy/gorush">gorush</a>.</p>
<h3 id="push-notification-server-flow"><a class="header" href="#push-notification-server-flow">Push Notification Server Flow</a></h3>
<h4 id="registration-process"><a class="header" href="#registration-process">Registration Process</a></h4>
<p><img src="./images/registration.png" alt="registration" /></p>
<h4 id="sending-and-receiving-notification-process"><a class="header" href="#sending-and-receiving-notification-process">Sending and Receiving Notification Process</a></h4>
<p><img src="./images/notification.png" alt="notification" /></p>
<h3 id="registering-client"><a class="header" href="#registering-client">Registering Client</a></h3>
<p>Registering a client with a push notification service.</p>
<ul>
<li>
<p>A client MAY register with one or
more push notification services in order to increase availability.</p>
</li>
<li>
<p>A client SHOULD make sure that all the notification services they registered with
have the same information about their tokens.</p>
</li>
<li>
<p>A <code>PNR message</code> (Push Notification Registration) MUST be sent to the
<a href="../../waku/standards/application/54/x3dh-sessions.html">partitioned topic</a>
for the public key of the node, encrypted with this key.</p>
</li>
<li>
<p>The message MUST be wrapped in a
<a href="../62/payloads.html"><code>ApplicationMetadataMessage</code></a> with type set to <code>PUSH_NOTIFICATION_REGISTRATION</code>.</p>
</li>
<li>
<p>The marshaled protobuf payload MUST also be encrypted with AES-GCM
using the DiffieHellman key generated from the client and server identity.
This is done in order to ensure that the extracted key from the signature
will be considered invalid if it cant decrypt the payload.</p>
</li>
</ul>
<p>The content of the message MUST contain the following <a href="https://developers.google.com/protocol-buffers/">protobuf record</a>:</p>
<pre><code class="language-protobuf">message PushNotificationRegistration {
enum TokenType {
UNKNOWN_TOKEN_TYPE = 0;
APN_TOKEN = 1;
FIREBASE_TOKEN = 2;
}
TokenType token_type = 1;
string device_token = 2;
string installation_id = 3;
string access_token = 4;
bool enabled = 5;
uint64 version = 6;
repeated bytes allowed_key_list = 7;
repeated bytes blocked_chat_list = 8;
bool unregister = 9;
bytes grant = 10;
bool allow_from_contacts_only = 11;
string apn_topic = 12;
bool block_mentions = 13;
repeated bytes allowed_mentions_chat_list = 14;
}
</code></pre>
<p>A push notification server will handle the message according to the following rules:</p>
<ul>
<li>
<p>it MUST extract the public key of the sender from the signature and
verify that the payload can be decrypted successfully.</p>
</li>
<li>
<p>it MUST verify that <code>token_type</code> is supported.</p>
</li>
<li>
<p>it MUST verify that <code>device_token</code> is non empty.</p>
</li>
<li>
<p>it MUST verify that <code>installation_id</code> is non empty.</p>
</li>
<li>
<p>it MUST verify that <code>version</code> is non-zero and
greater than the currently stored version for the public key and
<code>installation_id</code> of the sender, if any.</p>
</li>
<li>
<p>it MUST verify that <code>grant</code> is non empty and according to the Grant Server specs.</p>
</li>
<li>
<p>it MUST verify that <code>access_token</code> is a valid uuid.</p>
</li>
<li>
<p>it MUST verify that <code>apn_topic</code> is set if token_type is APN_TOKEN.</p>
</li>
<li>
<p>The message MUST be wrapped in a
<a href="../62/payloads.html"><code>ApplicationMetadataMessage</code></a> with type set to <code>PUSH_NOTIFICATION_REGISTRATION_RESPONSE</code>.</p>
</li>
</ul>
<p>The payload of the response is:</p>
<pre><code class="language-protobuf">message PushNotificationRegistrationResponse {
bool success = 1;
ErrorType error = 2;
bytes request_id = 3;
enum ErrorType {
UNKNOWN_ERROR_TYPE = 0;
MALFORMED_MESSAGE = 1;
VERSION_MISMATCH = 2;
UNSUPPORTED_TOKEN_TYPE = 3;
INTERNAL_ERROR = 4;
}
}
</code></pre>
<p>A client SHOULD listen for a response sent on the
<a href="../../waku/standards/application/54/x3dh-sessions.html">partitioned topic</a>
that the key used to register.
If success is true the client has registered successfully.</p>
<p>If <code>success</code> is <code>false</code>:</p>
<blockquote>
<p>If <code>MALFORMED_MESSAGE</code> is returned,
the request SHOULD NOT be retried without ensuring that it is correctly formed.
If <code>INTERNAL_ERROR</code> is returned, the request MAY be retried,
but the client MUST backoff exponentially.</p>
</blockquote>
<h4 id="handle-errors"><a class="header" href="#handle-errors">Handle Errors</a></h4>
<ul>
<li>
<p>If the message cant be decrypted, the message MUST be discarded.</p>
</li>
<li>
<p>If <code>token_type</code> is not supported, a response MUST be sent with <code>error</code> set to <code>UNSUPPORTED_TOKEN_TYPE</code>.</p>
</li>
<li>
<p>If <code>token</code>, <code>installation_id</code>, <code>device_tokens</code>, <code>version</code> are empty,
a response MUST be sent with <code>error</code> set to <code>MALFORMED_MESSAGE</code>.</p>
</li>
<li>
<p>If the <code>version</code> is equal or less than the currently stored <code>version</code>,
a response MUST be sent with <code>error</code> set to <code>VERSION_MISMATCH</code>.</p>
</li>
<li>
<p>If any other error occurs the <code>error</code> SHOULD be set to <code>INTERNAL_ERROR</code>.</p>
</li>
<li>
<p>If the response is successful <code>success</code> MUST be set to <code>true</code> otherwise
a response MUST be sent with <code>success</code> set to <code>false</code>.</p>
</li>
<li>
<p><code>request_id</code> SHOULD be set to the
<a href="https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf"><code>SHAKE-256</code></a>
of the encrypted payload.</p>
</li>
<li>
<p>The response MUST be sent on the
<a href="../../waku/standards/application/54/x3dh-sessions.html">partitioned topic</a>
of the sender and MUST not be encrypted using
the secure transport to facilitate the usage of ephemeral keys.</p>
</li>
<li>
<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>
</li>
</ul>
<h2 id="push-notification-server"><a class="header" href="#push-notification-server">Push Notification Server</a></h2>
<p>A node that handles receiving and sending push notifications for clients.</p>
<h3 id="query-topic"><a class="header" href="#query-topic">Query Topic</a></h3>
<p>On successful registration the server MUST be listening to the topic derived from:</p>
<blockquote>
<p><code>0x</code> + HexEncode(Shake256(CompressedClientPublicKey))</p>
</blockquote>
<p>Using the topic derivation algorithm described here and listen for client queries.</p>
<h4 id="server-grant"><a class="header" href="#server-grant">Server Grant</a></h4>
<p>A client MUST authorize a push notification server to send them push notifications.
This is done by building a grant which is specific to a given client-server pair.
When receiving a grant,
the server MUST validate that the signature matches the registering client.</p>
<p>The grant is built as:</p>
<pre><code class="language-js">`Signature(Keccak256(CompressedPublicKeyOfClient.CompressedPublicKeyOfServer.AccessToken), PrivateKeyOfClient)`
</code></pre>
<h4 id="unregistering-with-a-server"><a class="header" href="#unregistering-with-a-server">Unregistering with a Server</a></h4>
<ul>
<li>To unregister a client MUST send a <code>PushNotificationRegistration</code>
request as described above with <code>unregister</code> set to <code>true</code>,
or removing their device information.</li>
<li>The server MUST remove all data about this user if <code>unregistering</code> is <code>true</code>,
apart from the <code>hash</code> of the public key and
the <code>version</code> of the last options,
in order to make sure that old messages are not processed.</li>
<li>A client MAY unregister from a server on explicit logout
if multiple chat keys are used on a single device.</li>
</ul>
<h4 id="re-registering-with-a-server"><a class="header" href="#re-registering-with-a-server">Re-registering with a Server</a></h4>
<ul>
<li>A client SHOULD re-register with the node if the APN or FIREBASE token changes.</li>
<li>When re-registering a client SHOULD ensure
that it has the most up-to-date <code>PushNotificationRegistration</code> and
increment <code>version</code> if necessary.</li>
<li>Once re-registered, a client SHOULD advertise the changes.
Changing options is handled the same as re-registering.</li>
</ul>
<h4 id="advertising-a-server"><a class="header" href="#advertising-a-server">Advertising a Server</a></h4>
<p>Each user registered with one or more push notification servers
SHOULD advertise periodically the push notification services
they have registered with for each device they own.</p>
<pre><code class="language-protobuf">message PushNotificationQueryInfo {
string access_token = 1;
string installation_id = 2;
bytes public_key = 3;
repeated bytes allowed_user_list = 4;
bytes grant = 5;
uint64 version = 6;
bytes server_public_key = 7;
}
message ContactCodeAdvertisement {
repeated PushNotificationQueryInfo push_notification_info = 1;
}
</code></pre>
<h4 id="handle-advertisement-message"><a class="header" href="#handle-advertisement-message">Handle Advertisement Message</a></h4>
<ul>
<li>The message MUST be wrapped in a
<a href="../62/payloads.html"><code>ApplicationMetadataMessage</code></a> with type set to <code>PUSH_NOTIFICATION_QUERY_INFO</code>.</li>
<li>If no filtering is done based on public keys,
the access token SHOULD be included in the advertisement.
Otherwise it SHOULD be left empty.</li>
<li>This SHOULD be advertised on the
<a href="../../waku/standards/application/53/x3dh.html">contact code topic</a> and
SHOULD be coupled with normal contact-code advertisement.</li>
<li>When a user register or re-register with a push notification service,
their contact-code SHOULD be re-advertised.</li>
<li>Multiple servers MAY be advertised for the same installation_id
 for redundancy reasons.</li>
</ul>
<h4 id="discovering-a-server"><a class="header" href="#discovering-a-server">Discovering a Server</a></h4>
<p>To discover a push notification service for a given user, their
<a href="../../waku/standards/application/53/x3dh.html">contact code topic</a>
SHOULD be listened to.
A Waku-Store node can be queried for the specific topic
to retrieve the most up-to-date contact code.</p>
<h4 id="querying-a-server"><a class="header" href="#querying-a-server">Querying a Server</a></h4>
<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>
<pre><code class="language-protobuf">message PushNotificationQuery {
repeated bytes public_keys = 1;
}
</code></pre>
<h4 id="handle-query-message"><a class="header" href="#handle-query-message">Handle Query Message</a></h4>
<ul>
<li>The message MUST be wrapped in a
<a href="../62/payloads.html"><code>ApplicationMetadataMessage</code></a> with type set to <code>PUSH_NOTIFICATION_QUERY</code>.</li>
<li>it MUST be sent to the server on the topic derived from the hashed public key
of the key we are querying,
<a href="#query-topic">as described above</a>.</li>
<li>An ephemeral key SHOULD be used and SHOULD NOT be encrypted using the <a href="../../waku/standards/application/53/x3dh.html">secure transport</a>.</li>
</ul>
<p>If the server has information about the client a response MUST be sent:</p>
<pre><code class="language-protobuf">message PushNotificationQueryInfo {
string access_token = 1;
string installation_id = 2;
bytes public_key = 3;
repeated bytes allowed_user_list = 4;
bytes grant = 5;
uint64 version = 6;
bytes server_public_key = 7;
}
message PushNotificationQueryResponse {
repeated PushNotificationQueryInfo info = 1;
bytes message_id = 2;
bool success = 3;
}
</code></pre>
<h4 id="handle-query-response"><a class="header" href="#handle-query-response">Handle Query Response</a></h4>
<ul>
<li>
<p>A <code>PushNotificationQueryResponse</code> message MUST be wrapped in a
<a href="../62/payloads.html"><code>ApplicationMetadataMessage</code></a> with type set to <code>PUSH_NOTIFICATION_QUERY_RESPONSE</code>.
Otherwise a response MUST NOT be sent.</p>
</li>
<li>
<p>If <code>allowed_key_list</code> is not set <code>access_token</code> MUST be set
and <code>allowed_key_list</code> MUST NOT be set.</p>
</li>
<li>
<p>If <code>allowed_key_list</code> is set <code>allowed_key_list</code> MUST be set and
<code>access_token</code> MUST NOT be set.</p>
</li>
<li>
<p>If <code>access_token</code> is returned,
the <code>access_token</code> SHOULD be used to send push notifications.</p>
</li>
<li>
<p>If <code>allowed_key_list</code> are returned,
the client SHOULD decrypt each token by generating an <code>AES-GCM</code> symmetric key
from the DiffieHellman between the target client and itself.
If AES decryption succeeds,
it will return a valid <code>uuid</code> which is what is used for access_token.
The token SHOULD be used to send push notifications.</p>
</li>
<li>
<p>The response MUST be sent on the
<a href="../../waku/standards/application/54/x3dh-sessions.html">partitioned topic</a>
of the sender and
MUST NOT be encrypted using the
<a href="../../waku/standards/application/53/x3dh.html">secure transport</a>
to facilitate the usage of ephemeral keys.</p>
</li>
<li>
<p>On receiving a response,
a client MUST verify <code>grant</code> to ensure that the server
has been authorized to send push notification to a given client.</p>
</li>
</ul>
<h3 id="sending-client"><a class="header" href="#sending-client">Sending Client</a></h3>
<p>Sending a push notification</p>
<ul>
<li>
<p>When sending a push notification,
only the <code>installation_id</code> for the devices targeted by the message SHOULD be used.</p>
</li>
<li>
<p>If a message is for all the user devices,
all the <code>installation_id</code> known to the client MAY be used.</p>
</li>
<li>
<p>The number of devices MAY be capped in order to reduce resource consumption.</p>
</li>
<li>
<p>At least 3 devices SHOULD be targeted, ordered by last activity.</p>
</li>
<li>
<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>
</li>
</ul>
<pre><code class="language-protobuf">message PushNotification {
string access_token = 1;
string chat_id = 2;
bytes public_key = 3;
string installation_id = 4;
bytes message = 5;
PushNotificationType type = 6;
enum PushNotificationType {
UNKNOWN_PUSH_NOTIFICATION_TYPE = 0;
MESSAGE = 1;
MENTION = 2;
}
bytes author = 7;
}
message PushNotificationRequest {
repeated PushNotification requests = 1;
bytes message_id = 2;
}
</code></pre>
<h4 id="handle-notification-request"><a class="header" href="#handle-notification-request">Handle Notification Request</a></h4>
<ul>
<li>
<p>A <code>PushNotificationRequest</code> message MUST be wrapped in a
<a href="../62/payloads.html"><code>ApplicationMetadataMessage</code></a> with type set to <code>PUSH_NOTIFICATION_REQUEST</code>.</p>
</li>
<li>
<p>Where <code>message</code> is the encrypted payload of the message and
<code>chat_id</code> is the <code>SHAKE-256</code> of the <code>chat_id</code>.
<code>message_id</code> is the id of the message,
<code>author</code> is the <code>SHAKE-256</code> of the public key of the sender.</p>
</li>
<li>
<p>If multiple server are available for a given push notification,
only one notification MUST be sent.</p>
</li>
<li>
<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>
</li>
<li>
<p>This message SHOULD be sent using an ephemeral key.</p>
</li>
</ul>
<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
<a href="https://github.com/appleboy/gorush">gorush</a> instance with the following data:</p>
<pre><code class="language-yaml">{
"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>
<p>Where platform is 1 for iOS and 2 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>
<pre><code class="language-protobuf">message PushNotificationReport {
bool success = 1;
ErrorType error = 2;
enum ErrorType {
UNKNOWN_ERROR_TYPE = 0;
WRONG_TOKEN = 1;
INTERNAL_ERROR = 2;
NOT_REGISTERED = 3;
}
bytes public_key = 3;
string installation_id = 4;
}
</code></pre>
<pre><code class="language-protobuf">message PushNotificationResponse {
bytes message_id = 1;
repeated PushNotificationReport reports = 2;
}
</code></pre>
<p>Where <code>message_id</code> is the <code>message_id</code> sent by the client.</p>
<h4 id="handle-notification-response"><a class="header" href="#handle-notification-response">Handle Notification Response</a></h4>
<ul>
<li>
<p>A <code>PushNotificationResponse</code> message MUST be wrapped in a
<a href="../62/payloads.html"><code>ApplicationMetadataMessage</code></a> with type set to <code>PUSH_NOTIFICATION_RESPONSE</code>.</p>
</li>
<li>
<p>The response MUST be sent on the
<a href="../../waku/standards/application/54/x3dh-sessions.html">partitioned topic</a>
of the sender and
MUST not be encrypted using the
<a href="../../waku/standards/application/53/x3dh.html">secure transport</a>
to facilitate the usage of ephemeral keys.</p>
</li>
<li>
<p>If the request is accepted <code>success</code> MUST be set to <code>true</code>.
Otherwise <code>success</code> MUST be set to <code>false</code>.</p>
</li>
<li>
<p>If <code>error</code> is <code>BAD_TOKEN</code> the client MAY query again the server for the token and
retry the request.</p>
</li>
<li>
<p>If <code>error</code> is <code>INTERNAL_ERROR</code> the client MAY retry the request.</p>
</li>
</ul>
<h3 id="protobuf-description"><a class="header" href="#protobuf-description">Protobuf Description</a></h3>
<h4 id="pushnotificationregistration"><a class="header" href="#pushnotificationregistration">PushNotificationRegistration</a></h4>
<p><code>token_type</code>: the type of token. Currently supported is <code>APN_TOKEN</code> for Apple Push.</p>
<p><code>device_token</code>: the actual push notification token sent by <code>Firebase</code> or
<code>APN</code> and <code>FIREBASE_TOKEN</code> for firebase.</p>
<p><code>installation_id</code>: the <code>installation_id</code> of the device.</p>
<p><code>access_token</code>: the access token that will be given to clients to send push notifications.</p>
<p><code>enabled</code>: whether the device wants to be sent push notifications.</p>
<p><code>version</code>: a monotonically increasing number identifying the current <code>PushNotificationRegistration</code>.
Any time anything is changed in the record it MUST be increased by the client,
otherwise the request will not be accepted.</p>
<p><code>allowed_key_list</code>: a list of <code>access_token</code> encrypted with the AES key
generated by DiffieHellman between the publisher and the allowed contact.</p>
<p><code>blocked_chat_list</code>: a list of <code>SHA2-256</code> hashes of chat ids.
Any chat id in this list will not trigger a notification.</p>
<p><code>unregister</code>: whether the account should be unregistered.</p>
<p><code>grant</code>: the grant for this specific server.</p>
<p><code>allow_from_contacts_only</code>: whether the client only wants
push notifications from contacts.</p>
<p><code>apn_topic</code>: the APN topic for the push notification.</p>
<p><code>block_mentions</code>: whether the client does not want to be notified on mentions.</p>
<p><code>allowed_mentions_chat_list</code>: a list of SHA2-256 hashes of chat ids
where we want to receive mentions.</p>
<p>DATA DISCLOSED</p>
<ul>
<li>
<p>Type of device owned by a given user.</p>
</li>
<li>
<p>The <code>FIREBASE</code> or <code>APN</code> push notification token,</p>
</li>
<li>
<p>Hash of the <code>chat_id</code> a user is not interested in for notifications,</p>
</li>
<li>
<p>The number of times a push notification record has been modified by the user,</p>
</li>
<li>
<p>The number of contacts a client has, in case <code>allowed_key_list</code> is set.</p>
</li>
</ul>
<h4 id="pushnotificationregistrationresponse"><a class="header" href="#pushnotificationregistrationresponse">PushNotificationRegistrationResponse</a></h4>
<p><code>success</code>: whether the registration was successful</p>
<p><code>error</code>: the error type, if any</p>
<p><code>request_id</code>: the <code>SHAKE-256</code> hash of the <code>signature</code> of the request</p>
<p><code>preferences</code>: the server stored preferences in case of an error</p>
<h4 id="contactcodeadvertisement"><a class="header" href="#contactcodeadvertisement">ContactCodeAdvertisement</a></h4>
<p><code>push_notification_info</code>: the information for each device advertised</p>
<p>DATA DISCLOSED</p>
<ul>
<li>The chat key of the sender</li>
</ul>
<h4 id="pushnotificationquery"><a class="header" href="#pushnotificationquery">PushNotificationQuery</a></h4>
<p><code>public_keys</code>: the <code>SHAKE-256</code> of the public keys the client is interested in</p>
<p>DATA DISCLOSED</p>
<ul>
<li>The hash of the public keys the client is interested in</li>
</ul>
<h4 id="pushnotificationqueryinfo"><a class="header" href="#pushnotificationqueryinfo">PushNotificationQueryInfo</a></h4>
<p><code>access_token</code>: the access token used to send a push notification</p>
<p><code>installation_id</code>: the <code>installation_id</code> of the device associated with the <code>access_token</code>.</p>
<p><code>public_key</code>: the <code>SHAKE-256</code> of the public key associated with this <code>access_token</code>
and <code>installation_id</code>.</p>
<p><code>allowed_key_list</code>: a list of encrypted access tokens to be returned
to the client in case theres any filtering on public keys in place.</p>
<p><code>grant</code>: the grant used to register with this server.</p>
<p><code>version</code>: the version of the registration on the server.</p>
<p><code>server_public_key</code>: the compressed public key of the server.</p>
<h4 id="pushnotificationqueryresponse"><a class="header" href="#pushnotificationqueryresponse">PushNotificationQueryResponse</a></h4>
<p><code>info</code>: a list of <code>PushNotificationQueryInfo</code>.</p>
<p><code>message_id</code>: the message id of the <code>PushNotificationQueryInfo</code>
the server is replying to.</p>
<p><code>success</code>: whether the query was successful.</p>
<h4 id="pushnotification"><a class="header" href="#pushnotification">PushNotification</a></h4>
<p><code>access_token</code>: the access token used to send a push notification.
<code>chat_id</code>: the <code>SHAKE-256</code> of the <code>chat_id</code>.
<code>public_key</code>: the <code>SHAKE-256</code> of the compressed public key of the receiving client.
<code>installation_id</code>: the <code>installation_id</code> of the receiving client.
<code>message</code>: the encrypted message that is being notified on.
<code>type</code>: the type of the push notification, either <code>MESSAGE</code> or <code>MENTION</code>
<code>author</code>: the <code>SHAKE-256</code> of the public key of the sender</p>
<p>Data disclosed</p>
<ul>
<li>
<p>The <code>SHAKE-256</code> hash of the <code>chat_id</code> the notification is to be sent for</p>
</li>
<li>
<p>The cypher text of the message</p>
</li>
<li>
<p>The <code>SHAKE-256</code> hash of the public key of the sender</p>
</li>
<li>
<p>The type of notification</p>
</li>
</ul>
<h4 id="pushnotificationrequest"><a class="header" href="#pushnotificationrequest">PushNotificationRequest</a></h4>
<p><code>requests</code>: a list of PushNotification
<code>message_id</code>: the <a href="../62/payloads.html">Status message id</a></p>
<p>Data disclosed</p>
<ul>
<li>The status <code>message_id</code> for which the notification is for</li>
</ul>
<h4 id="pushnotificationresponse"><a class="header" href="#pushnotificationresponse">PushNotificationResponse</a></h4>
<p><code>message_id</code>: the <code>message_id</code> being notified on.
<code>reports</code>: a list of <code>PushNotificationReport</code></p>
<h4 id="pushnotificationreport"><a class="header" href="#pushnotificationreport">PushNotificationReport</a></h4>
<p><code>success</code>: whether the push notification was successful.
<code>error</code>: the type of the error in case of failure.
<code>public_key</code>: the public key of the user being notified.
<code>installation_id</code>: the <code>installation_id</code> of the user being notified.</p>
<h3 id="anonymous-mode"><a class="header" href="#anonymous-mode">Anonymous Mode</a></h3>
<p>In order to preserve privacy, the client MAY provide anonymous mode of operations
to propagate information about the user.
A client in anonymous mode can register with the server
using a key that is different from their chat key.
This will hide their real chat key. This public key is effectively a secret and
SHOULD only be disclosed to clients approved to notify a user.</p>
<ul>
<li>
<p>A client MAY advertise the access token on the
<a href="../../waku/standards/application/53/x3dh.html">contact-code topic</a>
of the key generated.</p>
</li>
<li>
<p>A client MAY share their public key contact updates in the
<a href="https://developers.google.com/protocol-buffers/">protobuf record</a>.</p>
</li>
<li>
<p>A client receiving a push notification public key
SHOULD listen to the contact code topic of the push notification public key for updates.</p>
</li>
</ul>
<p>The method described above effectively does not share the identity of the sender
nor the receiver to the server, but
MAY result in missing push notifications
as the propagation of the secret is left to the client.
This can be mitigated by <a href="../62/payloads.html">device syncing</a>,
but not completely addressed.</p>
<h2 id="securityprivacy-considerations"><a class="header" href="#securityprivacy-considerations">Security/Privacy Considerations</a></h2>
<p>If anonymous mode is not used,
when registering with a push notification service a client will disclose:</p>
<ul>
<li>
<p>The devices that will receive notifications.</p>
</li>
<li>
<p>The chat key.</p>
</li>
</ul>
<p>A client MAY disclose:</p>
<ul>
<li>The hash of the <code>chat_id</code> they want to filter out.</li>
</ul>
<p>When running in anonymous mode, the clients chat key is not disclosed.</p>
<p>When querying a push notification server a client will disclose:</p>
<ul>
<li>That it is interested in sending push notification to another client,
but querying clients chat key is not disclosed.</li>
</ul>
<p>When sending a push notification a client will disclose:</p>
<ul>
<li>The <code>shake-256</code> of the <code>chat_id</code>.</li>
</ul>
<h2 id="copyright"><a class="header" href="#copyright">Copyright</a></h2>
<p>Copyright and related rights waived via <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0</a>.</p>
<h2 id="references"><a class="header" href="#references">References</a></h2>
<ol>
<li><a href="https://github.com/status-im/specs/blob/master/docs/raw/push-notification-server.md">PUSH-NOTIFICATION-SERVER, Initial Specification</a></li>
<li><a href="https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1">Push Notification, Apple Developer</a></li>
<li><a href="https://firebase.google.com">Firebase</a></li>
<li><a href="../../waku/standards/core/13/store.html">13/WAKU2-STORE</a></li>
<li><a href="https://github.com/appleboy/gorush">gorush</a></li>
<li><a href="../../waku/standards/application/54/x3dh-sessions.html">54/WAKU2-X3DH-SESSIONS</a></li>
<li><a href="../62/payloads.html">62/PAYLOAD</a></li>
<li><a href="https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf">SHAKE-256</a></li>
<li><a href="https://developers.google.com/protocol-buffers">Protocol Buffers</a></li>
<li><a href="../../waku/standards/application/53/x3dh.html">53/WAKU2-X3DH</a></li>
</ol>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../../status/65/account-address.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../../status/raw/index.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../../status/65/account-address.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../../status/raw/index.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../../elasticlunr.min.js"></script>
<script src="../../mark.min.js"></script>
<script src="../../searcher.js"></script>
<script src="../../clipboard.min.js"></script>
<script src="../../highlight.js"></script>
<script src="../../book.js"></script>
<!-- Custom JS scripts -->
<script src="../../scripts/rfc-index.js"></script>
</div>
</body>
</html>