mirror of
https://github.com/vacp2p/rfc-index.git
synced 2026-01-09 07:38:09 -05:00
800 lines
66 KiB
HTML
800 lines
66 KiB
HTML
<!DOCTYPE HTML>
|
||
<html lang="en" class="ayu" dir="ltr">
|
||
<head>
|
||
<!-- Book generated using mdBook -->
|
||
<meta charset="UTF-8">
|
||
<title>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"><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" class="active"><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="push-notification-server"><a class="header" href="#push-notification-server">PUSH-NOTIFICATION-SERVER</a></h1>
|
||
<div class="rfc-meta">
|
||
<table>
|
||
<tr><th>Name</th><td>Push notification server</td></tr>
|
||
<tr><th>Status</th><td>deprecated</td></tr>
|
||
<tr><th>Editor</th><td>Filip Dimitrijevic <filip@status.im></td></tr>
|
||
<tr><th>Contributors</th><td>Andrea Maria Piana <andreap@status.im></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/deprecated/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/deprecated/push-notification-server.md"><code>d03e699</code></a> — ci: add mdBook configuration (#233)</li>
|
||
<li><strong>2025-04-29</strong> — <a href="https://github.com/vacp2p/rfc-index/blob/614348a4982aa9e519ccff8b8fbcd4c554683288/status/deprecated/push-notification-server.md"><code>614348a</code></a> — Status deprecated update2 (#134)</li>
|
||
</ul>
|
||
<!-- timeline:end -->
|
||
<h2 id="reason"><a class="header" href="#reason">Reason</a></h2>
|
||
<p>Push notifications for iOS devices and some 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 service</a> for iOS or <a href="https://firebase.google.com/">Firebase</a>.</p>
|
||
<p>This is useful for Android devices that do not support foreground services
|
||
or that often kill the foreground service.</p>
|
||
<p>iOS only allows certain kind of applications to keep a connection open when in the
|
||
background, VoIP for example, which current status client does not qualify for.</p>
|
||
<p>Applications on iOS can also request execution time when they are in the <a href="https://developer.apple.com/documentation/uikit/app_and_environment/scenes/preparing_your_ui_to_run_in_the_background/updating_your_app_with_background_app_refresh">background</a>
|
||
but it has a limited set of use cases, for example it won't schedule any time
|
||
if the application was force quit,
|
||
and generally is not responsive enough to implement a push notification system.</p>
|
||
<p>Therefore Status provides a set of Push notification services
|
||
that can be used to achieve this functionality.</p>
|
||
<p>Because this can't be safely implemented in a privacy preserving manner,
|
||
clients MUST be given an option to opt-in to receiving and sending push notifications.
|
||
They are disabled by default.</p>
|
||
<h2 id="requirements"><a class="header" href="#requirements">Requirements</a></h2>
|
||
<p>The party releasing the app MUST possess a certificate for the Apple Push Notification service
|
||
and its has to run a <a href="https://github.com/appleboy/gorush">gorush</a> publicly accessible server for sending the actual notification.
|
||
The party releasing the app, Status in this case, needs to run its own <a href="https://github.com/appleboy/gorush">gorush</a></p>
|
||
<h2 id="components"><a class="header" href="#components">Components</a></h2>
|
||
<h3 id="gorush-instance"><a class="header" href="#gorush-instance">Gorush instance</a></h3>
|
||
<p>A <a href="https://github.com/appleboy/gorush">gorush</a> instance MUST be publicly available,
|
||
this will be used only by push notification servers.</p>
|
||
<h3 id="push-notification-server-1"><a class="header" href="#push-notification-server-1">Push notification server</a></h3>
|
||
<p>A push notification server used by clients to register for receiving and sending push notifications.</p>
|
||
<h3 id="registering-client"><a class="header" href="#registering-client">Registering client</a></h3>
|
||
<p>A Status client that wants to receive push notifications</p>
|
||
<h3 id="sending-client"><a class="header" href="#sending-client">Sending client</a></h3>
|
||
<p>A Status client that wants to send push notifications</p>
|
||
<h2 id="registering-with-the-push-notification-service"><a class="header" href="#registering-with-the-push-notification-service">Registering with the push notification service</a></h2>
|
||
<p>A client MAY register with one or more Push Notification services of their choice.</p>
|
||
<p>A <code>PNR message</code> (Push Notification Registration) MUST be sent to the <a href="status/deprecated/waku-usage/#partitioned-topic">partitioned topic</a>
|
||
for the public key of the node, encrypted with this key.</p>
|
||
<p>The message MUST be wrapped in a <a href="status/deprecated/payload/#payload-wrapper"><code>ApplicationMetadataMessage</code></a> with type set to <code>PUSH_NOTIFICATION_REGISTRATION</code>.</p>
|
||
<p>The marshaled protobuf payload MUST also be encrypted with AES-GCM
|
||
using the Diffie–Hellman key generated from the client and server identity.</p>
|
||
<p>This is done in order to ensure that the extracted key from the signature will be
|
||
considered invalid if it can't decrypt the payload.</p>
|
||
<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>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>token_type</code> is supported</li>
|
||
<li>it MUST verify that <code>device_token</code> is non empty</li>
|
||
<li>it MUST verify that <code>installation_id</code> is non empty</li>
|
||
<li>it MUST verify that <code>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>grant</code> is non empty and according to the <a href="#server-grant">specs</a></li>
|
||
<li>it MUST verify that <code>access_token</code> is a valid <a href="https://tools.ietf.org/html/rfc4122"><code>uuid</code></a></li>
|
||
<li>it MUST verify that <code>apn_topic</code> is set if <code>token_type</code> is <code>APN_TOKEN</code></li>
|
||
</ul>
|
||
<p>If the message can't be decrypted, the message MUST be discarded.</p>
|
||
<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>
|
||
<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>
|
||
<p>If the <code>version</code> is equal or less than the currently stored version, a response MUST
|
||
be sent with <code>error</code> set to <code>VERSION_MISMATCH</code>.</p>
|
||
<p>If any other error occurs the <code>error</code> should be set to <code>INTERNAL_ERROR</code>.</p>
|
||
<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>
|
||
<p><code>request_id</code> should be set to the <code>SHAKE-256</code> of the encrypted payload.</p>
|
||
<p>The response MUST be sent on the <a href="status/deprecated/waku-usage.html#partitioned-topic">partitioned topic</a> of the sender
|
||
and MUST not be encrypted using the <a href="status/deprecated/secure-transport">secure transport</a> to facilitate the usage of ephemeral keys.</p>
|
||
<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>The message MUST be wrapped in a <a href="status/deprecated/payloads.html#payload-wrapper"><code>ApplicationMetadataMessage</code></a> with type set to <code>PUSH_NOTIFICATION_REGISTRATION_RESPONSE</code>.</p>
|
||
<p>A client SHOULD listen for a response sent on the <a href="status/deprecated/waku-usage/#partitioned-topic">partitioned topic</a>
|
||
that the key used to register.</p>
|
||
<p>If <code>success</code> is <code>true</code> the client has registered successfully.</p>
|
||
<p>If <code>success</code> is <code>false</code>:</p>
|
||
<ul>
|
||
<li>If <code>MALFORMED_MESSAGE</code> is returned, the request SHOULD NOT be retried without ensuring that it is correctly formed.</li>
|
||
<li>If <code>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 class="header" href="#query-topic">Query topic</a></h3>
|
||
<p>On successful registration the server MUST be listening to the topic derived from:</p>
|
||
<pre><code class="language-protobuf"> 0XHexEncode(Shake256(CompressedClientPublicKey))
|
||
</code></pre>
|
||
<p>Using the topic derivation algorithm described <a href="status/deprecated/waku-usage/#public-chats">here</a>
|
||
and listen for client queries.</p>
|
||
<h3 id="server-grant"><a class="header" href="#server-grant">Server grant</a></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>
|
||
<pre><code class="language-protobuf"> Signature(Keccak256(CompressedPublicKeyOfClient . CompressedPublicKeyOfServer . AccessToken), PrivateKeyOfClient)
|
||
</code></pre>
|
||
<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 class="header" href="#re-registering-with-the-push-notification-server">Re-registering with the push notification server</a></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>PushNotificationRegistration</code> and increment <code>version</code> if necessary.</p>
|
||
<p>Once re-registered, a client SHOULD advertise the changes.</p>
|
||
<h2 id="changing-options"><a class="header" href="#changing-options">Changing options</a></h2>
|
||
<p>This is handled in exactly the same way as re-registering above.</p>
|
||
<h2 id="unregistering-from-push-notifications"><a class="header" href="#unregistering-from-push-notifications">Unregistering from push notifications</a></h2>
|
||
<p>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.</p>
|
||
<p>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.</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 class="header" href="#advertising-a-push-notification-server">Advertising a push notification server</a></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>
|
||
<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>
|
||
<p>The message MUST be wrapped in a <a href="status/deprecated/payloads/#payload-wrapper"><code>ApplicationMetadataMessage</code></a> with type set to <code>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="/status/deprecated/waku-usage.html#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>installation_id</code> for redundancy reasons.</p>
|
||
<h2 id="discovering-a-push-notification-server"><a class="header" href="#discovering-a-push-notification-server">Discovering a push notification server</a></h2>
|
||
<p>To discover a push notification service for a given user, their <a href="status/deprecated/waku-usage/#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 class="header" href="#querying-the-push-notification-server">Querying the push notification server</a></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>
|
||
<pre><code class="language-protobuf">message PushNotificationQuery {
|
||
repeated bytes public_keys = 1;
|
||
}
|
||
</code></pre>
|
||
<p>The message MUST be wrapped in a <a href="status/deprecated/payloads/#payload-wrapper"><code>ApplicationMetadataMessage</code></a> with type set to <code>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="status/deprecated/secure-transport.html">secure transport</a>.</p>
|
||
<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>
|
||
<p>A <code>PushNotificationQueryResponse</code> message MUST be wrapped in a <a href="status/deprecated/payloads.html#payload-wrapper"><code>ApplicationMetadataMessage</code></a> with type set to <code>PUSH_NOTIFICATION_QUERY_RESPONSE</code>.</p>
|
||
<p>Otherwise a response MUST NOT be sent.</p>
|
||
<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>
|
||
<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>
|
||
<p>If <code>access_token</code> is returned, the <code>access_token</code> SHOULD be used to send push notifications.</p>
|
||
<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 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>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 <a href="status/deprecated/waku-usage/#partitioned-topic">partitioned topic</a> of the sender
|
||
and MUST not be encrypted using the <a href="status/deprecated/secure-transport.html">secure transport</a> to facilitate
|
||
the usage of ephemeral keys.</p>
|
||
<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>
|
||
<h2 id="sending-a-push-notification"><a class="header" href="#sending-a-push-notification">Sending a push notification</a></h2>
|
||
<p>When sending a push notification, only the <code>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>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>
|
||
<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>
|
||
<p>A <code>PushNotificationRequest</code> message MUST be wrapped in a <a href="/status/deprecated/payloads.html#payload-wrapper"><code>ApplicationMetadataMessage</code></a> with type set to <code>PUSH_NOTIFICATION_REQUEST</code>.</p>
|
||
<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>
|
||
<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>
|
||
<pre><code class="language-protobuf">{
|
||
"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 <code>1</code> for IOS and <code>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>
|
||
<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;
|
||
}
|
||
|
||
message PushNotificationResponse {
|
||
bytes message_id = 1;
|
||
repeated PushNotificationReport reports = 2;
|
||
}
|
||
</code></pre>
|
||
<p>A <code>PushNotificationResponse</code> message MUST be wrapped in a <a href="/status/deprecated/payloads.html#payload-wrapper"><code>ApplicationMetadataMessage</code></a> with type set to <code>PUSH_NOTIFICATION_RESPONSE</code>.</p>
|
||
<p>Where <code>message_id</code> is the <code>message_id</code> sent by the client.</p>
|
||
<p>The response MUST be sent on the <a href="/status/deprecated/waku-usage.html#partitioned-topic">partitioned topic</a> of the sender
|
||
and MUST not be encrypted using the <a href="/status/deprecated/secure-transport.html">secure transport</a> to facilitate
|
||
the usage of ephemeral keys.</p>
|
||
<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>
|
||
<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>
|
||
<p>If <code>error</code> is <code>INTERNAL_ERROR</code> the client MAY retry the request.</p>
|
||
<h2 id="flow"><a class="header" href="#flow">Flow</a></h2>
|
||
<h3 id="registration-process"><a class="header" href="#registration-process">Registration process</a></h3>
|
||
<ul>
|
||
<li>A client will generate a notification token through <code>APN</code> or <code>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 class="header" href="#sending-a-notification">Sending a notification</a></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 class="header" href="#receiving-a-push-notification">Receiving a push notification</a></h3>
|
||
<ul>
|
||
<li>On receiving the notification, a client can open the right account by checking the
|
||
<code>installation_id</code> included. The <code>chat_id</code> MAY be used to open the chat if present.</li>
|
||
<li><code>message</code> can be decrypted and presented to the user. Otherwise messages can be pulled from the mailserver if the <code>message_id</code> is no already present.</li>
|
||
</ul>
|
||
<h2 id="protobuf-description"><a class="header" href="#protobuf-description">Protobuf description</a></h2>
|
||
<h3 id="pushnotificationregistration"><a class="header" href="#pushnotificationregistration">PushNotificationRegistration</a></h3>
|
||
<p><code>token_type</code>: the type of token. Currently supported is <code>APN_TOKEN</code> for Apple Push
|
||
<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.
|
||
<code>installation_id</code>: the <a href="/status/deprecated/account.html"><code>installation_id</code></a> of the device
|
||
<code>access_token</code>: the access token that will be given to clients to send push notifications
|
||
<code>enabled</code>: whether the device wants to be sent push notifications
|
||
<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.
|
||
<code>allowed_key_list</code>: a list of <code>access_token</code> encrypted with the AES key generated
|
||
by Diffie–Hellman between the publisher and the allowed
|
||
contact.
|
||
<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.
|
||
<code>unregister</code>: whether the account should be unregistered
|
||
<code>grant</code>: the grant for this specific server
|
||
<code>allow_from_contacts_only</code>: whether the client only wants push notifications from contacts
|
||
<code>apn_topic</code>: the APN topic for the push notification
|
||
<code>block_mentions</code>: whether the client does not want to be notified on mentions
|
||
<code>allowed_mentions_chat_list</code>: a list of <code>SHA2-256</code> hashes of chat ids where we want to receive mentions</p>
|
||
<h4 id="data-disclosed"><a class="header" href="#data-disclosed">Data disclosed</a></h4>
|
||
<ul>
|
||
<li>Type of device owned by a given user</li>
|
||
<li>The <code>FIREBASE</code> or <code>APN</code> push notification token</li>
|
||
<li>Hash of the chat_id a user is not interested in for notifications</li>
|
||
<li>The times a push notification record has been modified by the user</li>
|
||
<li>The number of contacts a client has, in case <code>allowed_key_list</code> is set</li>
|
||
</ul>
|
||
<h3 id="pushnotificationregistrationresponse"><a class="header" href="#pushnotificationregistrationresponse">PushNotificationRegistrationResponse</a></h3>
|
||
<p><code>success</code>: whether the registration was successful
|
||
<code>error</code>: the error type, if any
|
||
<code>request_id</code>: the <code>SHAKE-256</code> hash of the <code>signature</code> of the request
|
||
<code>preferences</code>: the server stored preferences in case of an error</p>
|
||
<h3 id="contactcodeadvertisement"><a class="header" href="#contactcodeadvertisement">ContactCodeAdvertisement</a></h3>
|
||
<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>
|
||
<h3 id="pushnotificationquery"><a class="header" href="#pushnotificationquery">PushNotificationQuery</a></h3>
|
||
<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>
|
||
<h3 id="pushnotificationqueryinfo"><a class="header" href="#pushnotificationqueryinfo">PushNotificationQueryInfo</a></h3>
|
||
<p><code>access_token</code>: the access token used to send a push notification
|
||
<code>installation_id</code>: the <code>installation_id</code> of the device associated with the <code>access_token</code>
|
||
<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>
|
||
<code>allowed_key_list</code>: a list of encrypted access tokens to be returned
|
||
to the client in case there's any filtering on public keys in place.
|
||
<code>grant</code>: the grant used to register with this server.
|
||
<code>version</code>: the version of the registration on the server.
|
||
<code>server_public_key</code>: the compressed public key of the server.</p>
|
||
<h3 id="pushnotificationqueryresponse"><a class="header" href="#pushnotificationqueryresponse">PushNotificationQueryResponse</a></h3>
|
||
<p><code>info</code>: a list of <code>PushNotificationQueryInfo</code>.
|
||
<code>message_id</code>: the message id of the <code>PushNotificationQueryInfo</code> the server is replying to.
|
||
<code>success</code>: whether the query was successful.</p>
|
||
<h3 id="pushnotification"><a class="header" href="#pushnotification">PushNotification</a></h3>
|
||
<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 installation id 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>The <code>SHAKE-256</code> of the <code>chat_id</code> the notification is to be sent for</li>
|
||
<li>The cypher text of the message</li>
|
||
<li>The <code>SHAKE-256</code> of the public key of the sender</li>
|
||
<li>The type of notification</li>
|
||
</ul>
|
||
<h3 id="pushnotificationrequest"><a class="header" href="#pushnotificationrequest">PushNotificationRequest</a></h3>
|
||
<p><code>requests</code>: a list of <code>PushNotification</code>
|
||
<code>message_id</code>: the <a href="/status/deprecated/payloads.html">status message id</a></p>
|
||
<p>Data disclosed</p>
|
||
<ul>
|
||
<li>The status message id for which the notification is for</li>
|
||
</ul>
|
||
<h3 id="pushnotificationresponse"><a class="header" href="#pushnotificationresponse">PushNotificationResponse</a></h3>
|
||
<p><code>message_id</code>: the <code>message_id</code> being notified on.
|
||
<code>reports</code>: a list of <code>PushNotificationReport</code></p>
|
||
<h3 id="pushnotificationreport"><a class="header" href="#pushnotificationreport">PushNotificationReport</a></h3>
|
||
<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 installation id of the user being notified.</p>
|
||
<h2 id="anonymous-mode-of-operations"><a class="header" href="#anonymous-mode-of-operations">Anonymous mode of operations</a></h2>
|
||
<p>An anonymous mode of operations MAY be provided by the client, where the
|
||
responsibility of propagating information about the user is left to the client,
|
||
in order to preserve privacy.</p>
|
||
<p>A client in anonymous mode can register with the server using a key different
|
||
from their chat key.
|
||
This will hide their real chat key.</p>
|
||
<p>This public key is effectively a secret and SHOULD only be disclosed to clients that you the user wants to be notified by.</p>
|
||
<p>A client MAY advertise the access token on the contact-code topic of the key generated.
|
||
A client MAY share their public key through <a href="/status/deprecated/payloads.html#contact-update">contact updates</a></p>
|
||
<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>
|
||
<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.</p>
|
||
<p>This can be mitigated by <a href="/status/deprecated/payloads.html">device syncing</a>, but not completely
|
||
addressed.</p>
|
||
<h2 id="security-considerations"><a class="header" href="#security-considerations">Security considerations</a></h2>
|
||
<p>If no anonymous mode is used, when registering with a push notification service a client discloses:</p>
|
||
<ul>
|
||
<li>The chat key</li>
|
||
<li>The devices that will receive notifications</li>
|
||
</ul>
|
||
<p>A client MAY disclose:</p>
|
||
<ul>
|
||
<li>The hash of the chat_ids they want to filter out</li>
|
||
</ul>
|
||
<p>When running in anonymous mode, the client's 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 the querying client's chat key is not disclosed</li>
|
||
</ul>
|
||
<p>When sending a push notification a client discloses:</p>
|
||
<ul>
|
||
<li>The <code>SHAKE-256</code> of the chat id</li>
|
||
</ul>
|
||
<p>[//]: This section can be removed, for now leaving it here in order to help with the
|
||
review process. Point can be integrated, suggestion welcome.</p>
|
||
<h2 id="faq"><a class="header" href="#faq">FAQ</a></h2>
|
||
<h3 id="why-having-acl-done-at-the-server-side-and-not-the-client"><a class="header" href="#why-having-acl-done-at-the-server-side-and-not-the-client">Why having ACL done at the server side and not the client?</a></h3>
|
||
<p>We looked into silent notification for
|
||
<a href="https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app">IOS</a> (android has no equivalent)
|
||
but can't be used as it's expected to receive maximum 2/3 per hour, so not our use case. There
|
||
are also issue when the user force quit the app.</p>
|
||
<h3 id="why-using-an-access-token"><a class="header" href="#why-using-an-access-token">Why using an access token?</a></h3>
|
||
<p>The access token is used to decouple the requesting information from the user from
|
||
actually sending the push notification.</p>
|
||
<p>Some ACL is necessary otherwise it would be too easy to spam users (it's still fairly
|
||
trivial, but with this method you could allow only contacts to send you push notifications).</p>
|
||
<p>Therefore your identity must be revealed to the server either when sending or querying.</p>
|
||
<p>By using an access token we increase deniability, as the server would know
|
||
who requested the token but not necessarily who sent a push notification.
|
||
Correlation between the two can be trivial in some cases.</p>
|
||
<p>This also allows a mode of use as we had before, where the server does not propagate
|
||
info at all, and it's left to the user to propagate the token, through contact requests
|
||
for example.</p>
|
||
<h3 id="why-advertise-with-the-bundle"><a class="header" href="#why-advertise-with-the-bundle">Why advertise with the bundle?</a></h3>
|
||
<p>Advertising with the bundle allows us to piggy-back on an already implemented behavior
|
||
and save some bandwidth in cases where is not filtering by public keys</p>
|
||
<h3 id="whats-the--bandwidth-impact-for-this"><a class="header" href="#whats-the--bandwidth-impact-for-this">What's the bandwidth impact for this?</a></h3>
|
||
<p>Generally speaking, for each 1-to-1 message and group chat message you will sending
|
||
1 and <code>number of participants</code> push notifications. This can be optimized if
|
||
multiple users are using the same push notification server. Queries have also
|
||
a bandwidth impact but they are made only when actually needed</p>
|
||
<h3 id="whats-the-information-disclosed"><a class="header" href="#whats-the-information-disclosed">What's the information disclosed?</a></h3>
|
||
<p>The data disclosed with each message sent by the client is above, but for a summary:</p>
|
||
<p>When you register with a push notification service you may disclose:</p>
|
||
<ol>
|
||
<li>Your chat key</li>
|
||
<li>Which devices you have</li>
|
||
<li>The hash of the chat_ids you want to filter out</li>
|
||
<li>The hash of the public keys you are interested/not interested in</li>
|
||
</ol>
|
||
<p>When you query a notification service you may disclose:</p>
|
||
<ol>
|
||
<li>Your chat key</li>
|
||
<li>The fact that you are interested in sending push notification to a given user</li>
|
||
</ol>
|
||
<p>Effectively this is fairly revealing if the user has a whitelist implemented.
|
||
Therefore sending notification should be optional.</p>
|
||
<h3 id="what-prevents-a-user-from-generating-a-random-key-and-getting-an-access-token-and-spamming"><a class="header" href="#what-prevents-a-user-from-generating-a-random-key-and-getting-an-access-token-and-spamming">What prevents a user from generating a random key and getting an access token and spamming?</a></h3>
|
||
<p>Nothing really, that's the same as the status app as a whole. the only mechanism that prevents
|
||
this is using a white-list as described above,
|
||
but that implies disclosing your true identity to the push notification server.</p>
|
||
<h3 id="why-not-0-knowledge-proofsquantum-computing"><a class="header" href="#why-not-0-knowledge-proofsquantum-computing">Why not 0-knowledge proofs/quantum computing</a></h3>
|
||
<p>We start simple, we can iterate</p>
|
||
<h3 id="how-to-handle-backwardforward-compatibility"><a class="header" href="#how-to-handle-backwardforward-compatibility">How to handle backward/forward compatibility</a></h3>
|
||
<p>Most of the request have a target, so protocol negotiation can happen. We cannot negotiated
|
||
the advertisement as that's effectively a broadcast, but those info should not change and we can
|
||
always accrete the message.</p>
|
||
<h3 id="why-ack_key"><a class="header" href="#why-ack_key">Why ack_key?</a></h3>
|
||
<p>That's necessary to avoid duplicated push notifications and allow for the retry
|
||
in case the notification is not successful.</p>
|
||
<p>Deduplication of the push notification is done on the client side, to reduce a bit
|
||
of centralization and also in order not to have to modify gorush.</p>
|
||
<h3 id="can-i-run-my-own-node"><a class="header" href="#can-i-run-my-own-node">Can I run my own node?</a></h3>
|
||
<p>Sure, the methods allow that</p>
|
||
<h3 id="can-i-register-with-multiple-nodes-for-redundancy"><a class="header" href="#can-i-register-with-multiple-nodes-for-redundancy">Can I register with multiple nodes for redundancy</a></h3>
|
||
<p>Yep</p>
|
||
<h3 id="what-does-my-node-disclose"><a class="header" href="#what-does-my-node-disclose">What does my node disclose?</a></h3>
|
||
<p>Your node will disclose the IP address is running from, as it makes an HTTP post to
|
||
gorush. A waku adapter could be used, but please not now.</p>
|
||
<h3 id="does-this-have-high-reliability-requirements"><a class="header" href="#does-this-have-high-reliability-requirements">Does this have high-reliability requirements?</a></h3>
|
||
<p>The gorush server yes, no way around it.</p>
|
||
<p>The rest, kind of, at least one node having your token needs to be up for you to receive notifications.
|
||
But you can register with multiple servers (desktop, status, etc) if that's a concern.</p>
|
||
<h3 id="can-someone-else-ie-not-status-run-this"><a class="header" href="#can-someone-else-ie-not-status-run-this">Can someone else (i.e not status) run this?</a></h3>
|
||
<p>Push notification servers can be run by anyone. Gorush can be run by anyone I take,
|
||
but we are in charge of the certificate, so they would not be able to notify status-clients.</p>
|
||
<h2 id="changelog"><a class="header" href="#changelog">Changelog</a></h2>
|
||
<h3 id="version-01"><a class="header" href="#version-01">Version 0.1</a></h3>
|
||
<p><a href="https://github.com/status-im/specs/commit/">Released</a></p>
|
||
<ul>
|
||
<li>Initial version</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>
|
||
<ul>
|
||
<li><a href="https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1">APN Service</a></li>
|
||
<li><a href="https://developer.apple.com/documentation/uikit/app_and_environment/scenes/preparing_your_ui_to_run_in_the_background/updating_your_app_with_background_app_refresh">Background Execution on iOS</a></li>
|
||
<li><a href="https://firebase.google.com/">Firebase</a></li>
|
||
<li><a href="https://github.com/appleboy/gorush">Gorush</a></li>
|
||
<li><a href="https://tools.ietf.org/html/rfc4122">UUID Specification</a></li>
|
||
<li><a href="/status/deprecated/secure-transport.html">Secure Transport</a></li>
|
||
<li><a href="https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app">Silent Notifications on iOS</a></li>
|
||
<li><a href="/status/deprecated/waku-usage.html">Waku Usage</a></li>
|
||
<li><a href="https://github.com/ensdomains/ens">ENS Contract</a></li>
|
||
<li><a href="/status/deprecated/payloads.html">Payloads</a></li>
|
||
</ul>
|
||
|
||
</main>
|
||
|
||
<nav class="nav-wrapper" aria-label="Page navigation">
|
||
<!-- Mobile navigation buttons -->
|
||
<a rel="prev" href="../../status/deprecated/payloads.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/deprecated/secure-transport.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/deprecated/payloads.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/deprecated/secure-transport.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>
|