mirror of
https://github.com/vacp2p/rfc.vac.dev.git
synced 2026-08-31 12:11:11 +00:00
172 lines
155 KiB
HTML
172 lines
155 KiB
HTML
<!doctype html>
|
||
<html lang="en" dir="ltr" class="docs-wrapper docs-doc-page docs-version-current plugin-docs plugin-id-status docs-doc-id-deprecated/push-notification-server">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="generator" content="Docusaurus v2.4.1">
|
||
<title data-rh="true">PUSH-NOTIFICATION-SERVER | Vac Research</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:url" content="https://vac.dev/status/deprecated/push-notification-server"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="image" content="https://vac.dev/_og/218ac8e3e600c51b89b88a125ad948ebe37687f5.png"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-status-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-status-current"><meta data-rh="true" property="og:title" content="PUSH-NOTIFICATION-SERVER | Vac Research"><meta data-rh="true" name="description" content="Status provides a set of Push notification services that can be used to achieve this functionality."><meta data-rh="true" property="og:description" content="Status provides a set of Push notification services that can be used to achieve this functionality."><link data-rh="true" rel="icon" href="/theme/image/favicon.ico"><link data-rh="true" rel="canonical" href="https://vac.dev/status/deprecated/push-notification-server"><link data-rh="true" rel="alternate" href="https://vac.dev/status/deprecated/push-notification-server" hreflang="en"><link data-rh="true" rel="alternate" href="https://vac.dev/status/deprecated/push-notification-server" hreflang="x-default"><link rel="alternate icon" type="image/png" href="/theme/image/favicon.png">
|
||
<link rel="icon" type="image/svg+xml" href="/theme/image/favicon.svg">
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css" integrity="sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM" crossorigin="anonymous"><link rel="stylesheet" href="/assets/css/styles.7f69a75a.css">
|
||
<link rel="preload" href="/assets/js/runtime~main.db01e95f.js" as="script">
|
||
<link rel="preload" href="/assets/js/main.7bd63d25.js" as="script">
|
||
<meta property="og:image" content="https://vac.dev/_og/218ac8e3e600c51b89b88a125ad948ebe37687f5.png"><meta name="twitter:image" content="https://vac.dev/_og/218ac8e3e600c51b89b88a125ad948ebe37687f5.png"></head>
|
||
<body class="navigation-with-keyboard">
|
||
<script>!function(){function t(t){document.documentElement.setAttribute("data-theme",t)}var e=function(){var t=null;try{t=new URLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}return t}()||function(){var t=null;try{t=localStorage.getItem("theme")}catch(t){}return t}();t(null!==e?e:"dark")}()</script><div id="__docusaurus">
|
||
<style data-emotion="css-global 3rtehh">.lsd-button{width:auto;cursor:pointer;padding:6px 24px;}.lsd-button--disabled{cursor:default;opacity:0.34;}.lsd-button--large{padding:10px 40px;}.lsd-button--medium{padding:6px 24px;}.lsd-button--small{padding:6px 12px;}.lsd-button:hover:not(.lsd-button--disabled) .lsd-button__text{-webkit-text-decoration:underline;text-decoration:underline;}.lsd-button--with-icon{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}.lsd-button__icon{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:100%;}.lsd-button--large.lsd-button--with-icon{padding:10px 0px 10px 18px;}.lsd-button--large.lsd-button--with-icon .lsd-button__icon{width:42px;}.lsd-button--medium.lsd-button--with-icon{padding:6px 0px 6px 14px;}.lsd-button--medium.lsd-button--with-icon .lsd-button__icon{width:38px;}.lsd-button--small.lsd-button--with-icon{padding:6px 0px 6px 12px;}.lsd-button--small.lsd-button--with-icon .lsd-button__icon{width:34px;}.lsd-button--outlined{background:none;border:1px solid rgb(var(--lsd-border-primary));}.lsd-button--outlined .lsd-button__text{color:rgb(var(--lsd-text-primary));}.lsd-button--filled{background:rgb(var(--lsd-surface-secondary));border:1px solid rgb(var(--lsd-border-primary));}.lsd-button--filled .lsd-button__text{color:rgb(var(--lsd-text-secondary));}</style><style data-emotion="css-global 10bahxd">.lsd-icon-button{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;cursor:pointer;background:none;padding:0;border:1px solid rgb(var(--lsd-border-primary));}.lsd-icon-button--filled{background-color:rgb(var(--lsd-icon-primary));}.lsd-icon-button--filled svg{--lsd-icon-primary:var(--lsd-icon-secondary);}.lsd-icon-button--disabled{opacity:0.34;cursor:default;}.lsd-icon-button--large{width:40px;height:40px;}.lsd-icon-button--medium{width:32px;height:32px;}.lsd-icon-button--small{width:28px;height:28px;}</style><style data-emotion="css-global icqph9">.lsd-icon-button-group{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;}.lsd-icon-button-group--outlined .lsd-icon-button:not(:last-child){border-right:none;}</style><style data-emotion="css-global 1f43ub2">body *{font-family:var(--lsd-typography-generic-font-family);}.lsd-typography{color:rgb(var(--lsd-text-primary));}.lsd-typography--sans-serif,.lsd-typography--sans-serif *{font-family:sans-serif;}.lsd-typography--serif,.lsd-typography--serif *{font-family:serif;}.lsd-typography--monospace,.lsd-typography--monospace *{font-family:monospace;}.lsd-typography--display1{color:rgb(var(--lsd-text-primary));font-weight:var(--lsd-display1-fontWeight);font-size:var(--lsd-display1-fontSize);line-height:var(--lsd-display1-lineHeight);}.lsd-typography--display2{color:rgb(var(--lsd-text-primary));font-weight:var(--lsd-display2-fontWeight);font-size:var(--lsd-display2-fontSize);line-height:var(--lsd-display2-lineHeight);}.lsd-typography--display3{color:rgb(var(--lsd-text-primary));font-weight:var(--lsd-display3-fontWeight);font-size:var(--lsd-display3-fontSize);line-height:var(--lsd-display3-lineHeight);}.lsd-typography--display4{color:rgb(var(--lsd-text-primary));font-weight:var(--lsd-display4-fontWeight);font-size:var(--lsd-display4-fontSize);line-height:var(--lsd-display4-lineHeight);}h1,.lsd-typography--h1{color:rgb(var(--lsd-text-primary));font-weight:var(--lsd-h1-fontWeight);font-size:var(--lsd-h1-fontSize);line-height:var(--lsd-h1-lineHeight);}h2,.lsd-typography--h2{color:rgb(var(--lsd-text-primary));font-weight:var(--lsd-h2-fontWeight);font-size:var(--lsd-h2-fontSize);line-height:var(--lsd-h2-lineHeight);}h3,.lsd-typography--h3{color:rgb(var(--lsd-text-primary));font-weight:var(--lsd-h3-fontWeight);font-size:var(--lsd-h3-fontSize);line-height:var(--lsd-h3-lineHeight);}h4,.lsd-typography--h4{color:rgb(var(--lsd-text-primary));font-weight:var(--lsd-h4-fontWeight);font-size:var(--lsd-h4-fontSize);line-height:var(--lsd-h4-lineHeight);}h5,.lsd-typography--h5{color:rgb(var(--lsd-text-primary));font-weight:var(--lsd-h5-fontWeight);font-size:var(--lsd-h5-fontSize);line-height:var(--lsd-h5-lineHeight);}h6,.lsd-typography--h6{color:rgb(var(--lsd-text-primary));font-weight:var(--lsd-h6-fontWeight);font-size:var(--lsd-h6-fontSize);line-height:var(--lsd-h6-lineHeight);}.lsd-typography--subtitle1{color:rgb(var(--lsd-text-primary));font-weight:var(--lsd-subtitle1-fontWeight);font-size:var(--lsd-subtitle1-fontSize);line-height:var(--lsd-subtitle1-lineHeight);}.lsd-typography--subtitle2{color:rgb(var(--lsd-text-primary));font-weight:var(--lsd-subtitle2-fontWeight);font-size:var(--lsd-subtitle2-fontSize);line-height:var(--lsd-subtitle2-lineHeight);}.lsd-typography--subtitle3{color:rgb(var(--lsd-text-primary));font-weight:var(--lsd-subtitle3-fontWeight);font-size:var(--lsd-subtitle3-fontSize);line-height:var(--lsd-subtitle3-lineHeight);}.lsd-typography--subtitle4{color:rgb(var(--lsd-text-primary));font-weight:var(--lsd-subtitle4-fontWeight);font-size:var(--lsd-subtitle4-fontSize);line-height:var(--lsd-subtitle4-lineHeight);}body,.lsd-typography--body1{color:rgb(var(--lsd-text-primary));font-weight:var(--lsd-body1-fontWeight);font-size:var(--lsd-body1-fontSize);line-height:var(--lsd-body1-lineHeight);}.lsd-typography--body2{color:rgb(var(--lsd-text-primary));font-weight:var(--lsd-body2-fontWeight);font-size:var(--lsd-body2-fontSize);line-height:var(--lsd-body2-lineHeight);}.lsd-typography--body3{color:rgb(var(--lsd-text-primary));font-weight:var(--lsd-body3-fontWeight);font-size:var(--lsd-body3-fontSize);line-height:var(--lsd-body3-lineHeight);}label,.lsd-typography--label1{color:rgb(var(--lsd-text-primary));font-weight:var(--lsd-label1-fontWeight);font-size:var(--lsd-label1-fontSize);line-height:var(--lsd-label1-lineHeight);}.lsd-typography--label2{color:rgb(var(--lsd-text-primary));font-weight:var(--lsd-label2-fontWeight);font-size:var(--lsd-label2-fontSize);line-height:var(--lsd-label2-lineHeight);}.lsd-typography--primary{color:rgb(var(--lsd-text-primary));}.lsd-typography--secondary{color:rgb(var(--lsd-text-secondary));}input{color:rgb(var(--lsd-text-primary));font-size:var(--lsd-body1-fontSize);font-weight:var(--lsd-body1-fontWeight);}h1,h2,h3,h4,h5,h6,p,span{margin:0;}</style><style data-emotion="css-global 1yxb6i5">.lsd-icon--primary.lsd-icon--filled,.lsd-icon--primary.lsd-icon--filled *{fill:rgb(var(--lsd-icon-primary));}.lsd-icon--primary $.lsd-icon--stroked,.lsd-icon--primary $.lsd-icon--stroked *{fill:rgb(var(--lsd-icon-primary));}.lsd-icon--secondary.lsd-icon--filled,.lsd-icon--secondary.lsd-icon--filled *{fill:rgb(var(--lsd-icon-secondary));}.lsd-icon--secondary $.lsd-icon--stroked,.lsd-icon--secondary $.lsd-icon--stroked *{fill:rgb(var(--lsd-icon-secondary));}</style><style data-emotion="css-global 1hozxbf">.lsd-tab-item{background:rgb(var(--lsd-surface-primary));border:1px solid transparent;cursor:pointer;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;box-sizing:border-box;}.lsd-tab-item:hover{-webkit-text-decoration:underline;text-decoration:underline;}.lsd-tab-item:not(lsd-tab-item--selected){border-bottom:1px solid rgb(var(--lsd-border-primary));}.lsd-tab-item--text{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;}.lsd-tab-item--icon{margin-left:14px;}.lsd-tab-item--selected{border:1px solid rgb(var(--lsd-border-primary));}.lsd-tab-item--selected:hover{-webkit-text-decoration:none;text-decoration:none;}.lsd-tab-item--with-icon{-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;}.lsd-tab-item--disabled{cursor:default;opacity:0.34;}.lsd-tab-item--disabled:hover{-webkit-text-decoration:none;text-decoration:none;}.lsd-tab-item--small{padding:6px 12px;}.lsd-tab-item--small .lsd-tab-item--icon{margin-left:10px;}.lsd-tab-item--medium{padding:6px 14px;}.lsd-tab-item--medium .lsd-tab-item--icon{margin-left:12px;}.lsd-tab-item--large{padding:10px 18px;}.lsd-tab-item--large .lsd-tab-item--icon{margin-left:14px;}</style><style data-emotion="css-global 1a24j7d">.lsd-tabs{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;overflow:auto;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;max-width:100%;border-bottom:1px solid rgb(var(--lsd-border-primary));}.lsd-tabs>*{-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;}.lsd-tabs .lsd-tab-item{border-bottom:none;}.lsd-tabs--full-width{width:100%;-webkit-box-pack:stretch;-ms-flex-pack:stretch;-webkit-justify-content:stretch;justify-content:stretch;}.lsd-tabs--full-width>*{width:100%;-webkit-flex:1 0;-ms-flex:1 0;flex:1 0;}.lsd-tabs{-ms-overflow-style:none;scrollbar-width:none;}.lsd-tabs::-webkit-scrollbar{display:none;}.lsd-tabs__left-scroll-control{left:0;}.lsd-tabs__right-scroll-control{right:0;}.lsd-tabs__right-scroll-control,.lsd-tabs__left-scroll-control{top:0;-webkit-flex:0 1;-ms-flex:0 1;flex:0 1;position:-webkit-sticky;position:sticky;}</style><style data-emotion="css-global 1v7gjjb">.lsd-dropdown-menu{position:absolute;top:0;left:0;opacity:0;visibility:hidden;margin:0;padding:0;box-sizing:border-box;background:rgb(var(--lsd-surface-primary));overflow:auto;border:1px solid rgb(var(--lsd-border-primary));border-top:0;}.lsd-dropdown-menu>div{border:0;}.lsd-dropdown-menu>div:not(:last-child){border-bottom:1px solid rgb(var(--lsd-border-primary));}.lsd-dropdown-menu--open{opacity:1;visibility:visible;}.lsd-dropdown-menu--large{max-height:220px;}.lsd-dropdown-menu--medium{max-height:176px;}.lsd-dropdown-menu--small{max-height:154px;}</style><style data-emotion="css-global hyd3xb">.lsd-dropdown:not(.lsd-dropdown--disabled):not(
|
||
.lsd-dropdown--error
|
||
) .lsd-dropdown__trigger:hover .lsd-dropdown__option-label,.lsd-dropdown:not(.lsd-dropdown--disabled):not(
|
||
.lsd-dropdown--error
|
||
) .lsd-dropdown__trigger:focus .lsd-dropdown__option-label{-webkit-text-decoration:underline;text-decoration:underline;}.lsd-dropdown__label{display:block;}.lsd-dropdown__button-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;}.lsd-dropdown__trigger{width:100%;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;border:none;cursor:pointer;background:none;}.lsd-dropdown__trigger:focus{outline:none;}.lsd-dropdown__option-label{cursor:inherit;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}.lsd-dropdown__icons{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;gap:8px;}.lsd-dropdown__icon{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}.lsd-dropdown__supporting-text{margin:6px 14px;}.lsd-dropdown--error .lsd-dropdown__option-label{-webkit-text-decoration:line-through;text-decoration:line-through;}.lsd-dropdown--disabled{opacity:0.34;cursor:initial;}.lsd-dropdown--large{width:208px;}.lsd-dropdown--large.lsd-dropdown--error{width:230px;}.lsd-dropdown--large .lsd-dropdown__label{margin:0 0 6px 18px;}.lsd-dropdown--large .lsd-dropdown__button-container{height:40px;}.lsd-dropdown--large .lsd-dropdown__trigger{padding:10px 0px 10px 18px;}.lsd-dropdown--large .lsd-dropdown__icons{padding:0px 14px;}.lsd-dropdown--medium{width:188px;}.lsd-dropdown--medium.lsd-dropdown--error{width:210px;}.lsd-dropdown--medium .lsd-dropdown__label{margin:0 0 6px 14px;}.lsd-dropdown--medium .lsd-dropdown__button-container{height:32px;}.lsd-dropdown--medium .lsd-dropdown__trigger{padding:6px 0px 6px 14px;}.lsd-dropdown--medium .lsd-dropdown__icons{padding:0px 12px;}.lsd-dropdown--small{width:164px;}.lsd-dropdown--small.lsd-dropdown--error{width:186px;}.lsd-dropdown--small .lsd-dropdown__label{margin:0 0 6px 12px;}.lsd-dropdown--small .lsd-dropdown__button-container{height:28px;}.lsd-dropdown--small .lsd-dropdown__trigger{padding:6px 0px 6px 12px;}.lsd-dropdown--small .lsd-dropdown__icons{padding:0px 10px;}.lsd-dropdown--outlined .lsd-dropdown__button-container{border:1px solid rgb(var(--lsd-border-primary));}.lsd-dropdown--underlined .lsd-dropdown__button-container{border:1px solid transparent;border-bottom:1px solid rgb(var(--lsd-border-primary));}</style><style data-emotion="css-global w2g5fy">.lsd-dropdown-item{width:100%;box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;border:1px solid rgb(var(--lsd-border-primary));}.lsd-dropdown-item:not(.lsd-dropdown-item--disabled){cursor:pointer;}.lsd-dropdown-item:not(.lsd-dropdown-item--disabled):hover,.lsd-dropdown-item:not(.lsd-dropdown-item--disabled):focus{outline:none;}.lsd-dropdown-item:not(.lsd-dropdown-item--disabled):hover .lsd-dropdown-item__label,.lsd-dropdown-item:not(.lsd-dropdown-item--disabled):focus .lsd-dropdown-item__label{-webkit-text-decoration:underline;text-decoration:underline;}.lsd-dropdown-item__label{display:block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;}.lsd-dropdown-item--disabled{opacity:0.34;}.lsd-dropdown-item__icon{margin-right:18px;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;}.lsd-dropdown-item--small{padding:5px 9px;height:28px;}.lsd-dropdown-item--medium{padding:5px 11px;height:32px;}.lsd-dropdown-item--large{padding:5px 13px;height:40px;}</style><style data-emotion="css-global ww9kgc">.lsd-breadcrumb__list{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;list-style-type:none;margin:0;padding:0;}.lsd-breadcrumb--disabled .lsd-breadcrumb__list{opacity:0.34;cursor:initial;pointer-events:none;}.lsd-breadcrumb__dropdown-menu{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;overflow:auto;border:1px solid rgb(var(--lsd-border-primary));margin-top:10px;position:absolute;width:auto!important;}.lsd-breadcrumb__dropdown-menu>li{cursor:pointer;}.lsd-breadcrumb__dropdown-menu>li:not(:last-child){border-bottom:1px solid rgb(var(--lsd-border-primary));}.lsd-breadcrumb__dropdown-menu>li:hover,.lsd-breadcrumb__dropdown-menu>li:focus{-webkit-text-decoration:underline;text-decoration:underline;text-decoration-color:rgb(var(--lsd-border-primary));}.lsd-breadcrumb__dropdown-menu li>a{width:164px;padding:5px 11px;}</style><style data-emotion="css-global 4gvini">.lsd-breadcrumb-item{list-style-type:none;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}.lsd-breadcrumb__list>li:not(:last-child)::after{display:inline-block;margin-inline:12px;content:'/';}.lsd-breadcrumb-item__link{-webkit-text-decoration:none;text-decoration:none;cursor:pointer;}.lsd-breadcrumb-item--outlined{padding:3px 11px;border:1px solid rgb(var(--lsd-border-primary));}.lsd-breadcrumb:not(.lsd-breadcrumb--disabled) .lsd-breadcrumb-item__link:hover,.lsd-breadcrumb:not(.lsd-breadcrumb--disabled) .lsd-breadcrumb-item__link:focus{-webkit-text-decoration:underline;text-decoration:underline;text-decoration-color:rgb(var(--lsd-border-primary));}</style><style data-emotion="css-global 1cwg3oc">.lsd-card{box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;}.lsd-card>.lsd-card-header{margin-bottom:-1px;}</style><style data-emotion="css-global v7d76i">.lsd-card-header{box-sizing:border-box;padding:10px 18px;text-align:center;border:1px solid rgb(var(--lsd-border-primary));}.lsd-card-header__title{overflow:hidden;word-break:break-all;}.lsd-card-header--large{padding:10px 18px;}.lsd-card-header--medium{padding:6px 14px;}.lsd-card-header--small{padding:6px 12px;}</style><style data-emotion="css-global 1txgafh">.lsd-card-body{box-sizing:border-box;padding:14px 22px;border:1px solid rgb(var(--lsd-border-primary));}</style><style data-emotion="css-global kzy52c">.lsd-tag{width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;box-sizing:border-box;border:1px solid rgb(var(--lsd-icon-primary));}.lsd-tag:hover,.lsd-tag:focus{-webkit-text-decoration:underline;text-decoration:underline;cursor:pointer;}.lsd-badge--large{padding:3px 11px;gap:12px;height:28px;}.lsd-badge--small{padding:3px 7px;gap:8px;height:24px;}.lsd-tag--filled{background-color:rgb(var(--lsd-icon-primary));}.lsd-tag--filled .lsd-tag__label{color:rgb(var(--lsd-text-secondary));}.lsd-tag--filled svg{--lsd-icon-primary:var(--lsd-icon-secondary);}.lsd-tag--outlined{color:rgb(var(--lsd-text-primary));}.lsd-tag--disabled{opacity:0.3;cursor:initial;pointer-events:none;}</style><style data-emotion="css-global 4wy0ub">.lsd-text-field{box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;}.lsd-text-field__input-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;}.lsd-text-field--disabled{opacity:0.34;}.lsd-text-field__input{border:none;outline:none;font-size:14px;color:rgb(var(--lsd-text-primary));background:none;width:100%;}.lsd-text-field__input:hover{outline:none;}.lsd-text-field__input::-webkit-input-placeholder{color:rgb(var(--lsd-text-primary));opacity:0.3;}.lsd-text-field__input::-moz-placeholder{color:rgb(var(--lsd-text-primary));opacity:0.3;}.lsd-text-field__input:-ms-input-placeholder{color:rgb(var(--lsd-text-primary));opacity:0.3;}.lsd-text-field__input::placeholder{color:rgb(var(--lsd-text-primary));opacity:0.3;}.lsd-text-field--error .lsd-text-field__input{-webkit-text-decoration:line-through;text-decoration:line-through;}.lsd-text-field__supporting-text{width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;}.lsd-text-field--large{width:208px;}.lsd-text-field--large>*{padding:10px 14px 10px 18px;}.lsd-text-field--medium{width:188px;}.lsd-text-field--medium>*{padding:6px 12px 6px 14px;}.lsd-text-field--small{width:164px;}.lsd-text-field--small>*{padding:6px 10px 6px 12px;}.lsd-text-field__label{padding-top:0;padding-bottom:6px;}.lsd-text-field__supporting-text{padding-bottom:0;padding-top:6px;}.lsd-text-field--outlined .lsd-text-field__input-container{border:1px solid rgb(var(--lsd-border-primary));}.lsd-text-field--underlined .lsd-text-field__input-container{border:1px solid transparent;border-bottom:1px solid rgb(var(--lsd-border-primary));}.lsd-text-field__clear-button{padding:0;width:auto;height:auto;margin:0;border:0;}</style><style data-emotion="css-global uhig7c">.lsd-checkbox{position:relative;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}.lsd-checkbox__input{opacity:0;position:absolute;left:0;top:0;padding:0;margin:0;width:100%;height:100%;}.lsd-checkbox:not(.lsd-checkbox--disabled):hover,.lsd-checkbox:not(.lsd-checkbox--disabled).lsd-checkbox--focused{-webkit-text-decoration:underline;text-decoration:underline;}.lsd-checkbox:not(.lsd-checkbox--disabled) .lsd-checkbox__input{cursor:pointer;}.lsd-checkbox--disabled{opacity:0.34;}.lsd-checkbox__label{margin-left:18px;}.lsd-checkbox--large .lsd-checkbox__label{margin-left:18px;}.lsd-checkbox--medium .lsd-checkbox__label{margin-left:14px;}.lsd-checkbox--small .lsd-checkbox__label{margin-left:12px;}</style><style data-emotion="css-global txommo">.lsd-autocomplete{box-sizing:border-box;}.lsd-autocomplete__label{display:block;}.lsd-autocomplete__input-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;}.lsd-autocomplete--disabled{opacity:0.34;}.lsd-autocomplete__input{border:none;outline:none;font-size:14px;color:rgb(var(--lsd-text-primary));background:none;width:100%;}.lsd-autocomplete__input:hover{outline:none;}.lsd-autocomplete__input::-webkit-input-placeholder{color:rgb(var(--lsd-text-primary));opacity:0.3;}.lsd-autocomplete__input::-moz-placeholder{color:rgb(var(--lsd-text-primary));opacity:0.3;}.lsd-autocomplete__input:-ms-input-placeholder{color:rgb(var(--lsd-text-primary));opacity:0.3;}.lsd-autocomplete__input::placeholder{color:rgb(var(--lsd-text-primary));opacity:0.3;}.lsd-autocomplete__icon{cursor:pointer;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}.lsd-autocomplete--error{-webkit-text-decoration:line-through;text-decoration:line-through;}.lsd-autocomplete--large{width:208px;}.lsd-autocomplete--large .lsd-autocomplete__label{margin:0 0 6px 18px;}.lsd-autocomplete--large .lsd-autocomplete__input-container{height:40px;}.lsd-autocomplete--large .lsd-autocomplete__input{padding:9px 17px;}.lsd-autocomplete--large .lsd-autocomplete__icon{padding:12px 13px;}.lsd-autocomplete--medium{width:188px;}.lsd-autocomplete--medium .lsd-autocomplete__label{margin:0 0 6px 14px;}.lsd-autocomplete--medium .lsd-autocomplete__input-container{height:32px;}.lsd-autocomplete--medium .lsd-autocomplete__input{padding:5px 13px;}.lsd-autocomplete--medium .lsd-autocomplete__icon{padding:8px 11px;}.lsd-autocomplete--small{width:164px;}.lsd-autocomplete--small .lsd-autocomplete__label{margin:0 0 6px 12px;}.lsd-autocomplete--small .lsd-autocomplete__input-container{height:28px;}.lsd-autocomplete--small .lsd-autocomplete__input{padding:5px 11px;}.lsd-autocomplete--small .lsd-autocomplete__icon{padding:6px 9px;}.lsd-autocomplete--outlined .lsd-autocomplete__input-container{border:1px solid rgb(var(--lsd-border-primary));}.lsd-autocomplete--underlined .lsd-autocomplete__input-container{border:1px solid transparent;border-bottom:1px solid rgb(var(--lsd-border-primary));}.lsd-autocomplete__dropdown-item-placeholder{opacity:0.5;white-space:pre;}</style><style data-emotion="css-global quxxm6">.lsd-quote{color:rgb(var(--lsd-text-primary));white-space:pre-wrap;}.lsd-quote--indented-inline{border-left:1px solid rgb(var(--lsd-border-primary));padding:4px 8px 4px 28px;}.lsd-quote--parentheses{padding:0px;text-align:center;}.lsd-quote--parentheses::before{content:'***';}.lsd-quote--parentheses::after{content:'***';}</style><style data-emotion="css-global a49t4h">.lsd-collapse{box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;}.lsd-collapse--open .lsd-collapse__content{border-top:1px solid transparent;}.lsd-collapse__content{border:1px solid rgb(var(--lsd-border-primary));}</style><style data-emotion="css-global 12ppw0q">.lsd-collapse-header{box-sizing:border-box;}.lsd-collapse-header:not(.lsd-collapse-header--disabled) .lsd-collapse-header__trigger:hover .lsd-collapse-header__label{-webkit-text-decoration:underline;text-decoration:underline;}.lsd-collapse-header__trigger{width:100%;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;cursor:pointer;background:none;border:1px solid rgb(var(--lsd-border-primary));}.lsd-collapse-header__trigger:focus{outline:none;}.lsd-collapse-header__label{cursor:inherit;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin:auto;}.lsd-collapse-header__icons{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:end;-ms-flex-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end;}.lsd-collapse-header__icon{margin-right:8px;}.lsd-collapse-header--disabled .lsd-collapse-header__trigger{opacity:0.34;cursor:initial;}.lsd-collapse-header--large .lsd-collapse-header__trigger{width:299px;height:40px;padding:9px 17px;}.lsd-collapse-header--medium .lsd-collapse-header__trigger{width:270px;height:32px;padding:5px 13px;}.lsd-collapse-header--small .lsd-collapse-header__trigger{width:235px;height:28px;padding:5px 11px;}</style><style data-emotion="css-global dixc0i">.lsd-checkbox-group{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;gap:6px;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;}.lsd-checkbox-group__label{margin-bottom:6px;}</style><style data-emotion="css-global q2n2hz">.lsd-badge{width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;border:1px solid rgb(var(--lsd-icon-primary));border-radius:20px;}.lsd-badge:hover,.lsd-badge:focus{-webkit-text-decoration:underline;text-decoration:underline;cursor:pointer;}.lsd-badge--large{padding:3px 11px;gap:12px;height:28px;}.lsd-badge--small{padding:3px 7px;gap:8px;height:24px;}.lsd-badge--filled{background-color:rgb(var(--lsd-icon-primary));}.lsd-badge--filled .lsd-badge__label{color:rgb(var(--lsd-text-secondary));}.lsd-badge--filled svg{--lsd-icon-primary:var(--lsd-icon-secondary);}.lsd-badge--outlined{color:rgb(var(--lsd-text-primary));}.lsd-badge--disabled{opacity:0.3;cursor:initial;pointer-events:none;}</style><style data-emotion="css-global rlst54">.lsd-radio-button{position:relative;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}.lsd-radio-button__input{opacity:0;position:absolute;left:0;top:0;padding:0;margin:0;width:100%;height:100%;}.lsd-radio-button:not(.lsd-radio-button--disabled):hover{-webkit-text-decoration:underline;text-decoration:underline;}.lsd-radio-button:not(.lsd-radio-button--disabled) .lsd-radio-button__input{cursor:pointer;}.lsd-radio-button--disabled{opacity:0.34;}.lsd-radio-button__label{margin-left:18px;}.lsd-radio-button--large .lsd-radio-button__label{margin-left:18px;}.lsd-radio-button--medium .lsd-radio-button__label{margin-left:14px;}.lsd-radio-button--small .lsd-radio-button__label{margin-left:12px;}</style><style data-emotion="css-global mo7h6o">.lsd-radio-button-group{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;gap:6px;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;}.lsd-radio-button-group__label{margin-bottom:6px;}</style><style data-emotion="css-global amncrr">.lsd-table{box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;}.lsd-table>.lsd-table-header{margin-bottom:-1px;}</style><style data-emotion="css-global 1fkbozr">.lsd-table-header{box-sizing:border-box;border:1px solid rgb(var(--lsd-border-primary));}</style><style data-emotion="css-global 1fb1r54">.lsd-table-body table{border-collapse:collapse;text-align:center;table-layout:fixed;width:100%;height:auto;}.lsd-table-body table tr:first-of-type td label:has(input[type='radio']){display:none;}.lsd-table-body__toolbar{box-sizing:border-box;padding:10px;border:1px solid rgb(var(--lsd-border-primary));border-bottom:none;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;}</style><style data-emotion="css-global 607rj8">.lsd-table-item{border:1px solid rgb(var(--lsd-border-primary));}.lsd-table-item:has(> label){width:40px;}.lsd-table-item:has(> label) input{position:relative;width:14px;height:14px;margin:auto;}.lsd-table-item:has(> label) span{margin-left:14px!important;}.lsd-table-item--large{padding:10px;}.lsd-table-item--medium{padding:6px 8px;}.lsd-table-item--small{padding:6px;}</style><style data-emotion="css-global 1vlh57l">.lsd-table-row{-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}</style><style data-emotion="css-global 1fw5y3v">.lsd-number-input{width:auto;box-sizing:border-box;}.lsd-number-input__main-container:hover{-webkit-text-decoration:underline;text-decoration:underline;}.lsd-number-input--error .lsd-number-input__main-container{-webkit-text-decoration:line-through;text-decoration:line-through;}.lsd-number-input__label{display:block;}.lsd-number-input__plus-minus-icons{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;}.lsd-number-input__input-container{box-sizing:border-box;border:1px solid rgb(var(--lsd-border-primary));border-left:0px;border-right:0px;}.lsd-number-input__error-icon{cursor:pointer;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:10px 8px;}.lsd-number-input__input-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;}.lsd-number-input--disabled{opacity:0.34;}.lsd-number-input__main-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}.lsd-number-input__input{border:none;outline:none;font-size:14px;color:rgb(var(--lsd-text-primary));background:none;text-align:center;padding:0 4px;}.lsd-number-input__input::-webkit-inner-spin-button{display:none;-webkit-appearance:none;}.lsd-number-input__input:hover{outline:none;}.lsd-number-input__supporting-text{position:absolute;}.lsd-number-input--large .lsd-number-input__label{margin:0 0 6px 18px;}.lsd-number-input--large .lsd-number-input__input-container{height:40px;}.lsd-number-input--large .lsd-number-input__input{width:62px;}.lsd-number-input--large .lsd-number-input__plus-minus-icons{height:40px;width:40px;}.lsd-number-input--large .lsd-number-input__supporting-text{margin:6px 18px 0 18px;}.lsd-number-input--medium .lsd-number-input__label{margin:0 0 6px 14px;}.lsd-number-input--medium .lsd-number-input__input-container{height:32px;}.lsd-number-input--medium .lsd-number-input__input{width:58px;}.lsd-number-input--medium .lsd-number-input__plus-minus-icons{height:32px;width:32px;}.lsd-number-input--medium .lsd-number-input__supporting-text{margin:6px 14px 0 14px;}.lsd-number-input--small .lsd-number-input__label{margin:0 0 6px 12px;}.lsd-number-input--small .lsd-number-input__input-container{height:28px;}.lsd-number-input--small .lsd-number-input__input{width:50px;}.lsd-number-input--small .lsd-number-input__plus-minus-icons{height:28px;width:28px;}.lsd-number-input--small .lsd-number-input__supporting-text{margin:6px 12px 0 12px;}</style><style data-emotion="css-global 12rmo7o">.lsd-modal{box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;position:fixed;top:0;left:0;right:0;bottom:0;background-color:rgba(0, 0, 0, 0.5);display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;z-index:9999;}.lsd-modal__container{position:relative;background:rgb(var(--lsd-surface-primary));padding:20px;max-width:90%;box-sizing:border-box;border:1px solid rgb(var(--lsd-border-primary));}.lsd-modal__header{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}.lsd-modal__close-icon{position:absolute;top:8px;right:8px;cursor:pointer;}.lsd-modal__title-and-subtitle-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;}.lsd-modal--large .lsd-modal__container{min-width:960px;}.lsd-modal--medium .lsd-modal__container{min-width:768px;}.lsd-modal--small .lsd-modal__container{min-width:614px;}.lsd-modal--extra-small .lsd-modal__container{min-width:490px;}</style><style data-emotion="css-global 1k7gzc">.lsd-modal-footer{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}</style><style data-emotion="css-global 1b9t8so">.lsd-modal-body{margin:18px 0;}</style><style data-emotion="css-global dyud2a">.lsd-date-picker{width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;}.lsd-date-picker__calendar{border-top:none!important;}.lsd-date-picker--large .lsd-date-field--large{width:318px;}.lsd-date-picker--medium .lsd-date-field--medium{width:290px;}.lsd-date-picker--small .lsd-date-field--small{width:262px;}</style><style data-emotion="css-global olq3nk">.lsd-date-field{width:auto;box-sizing:border-box;}.lsd-date-field__label{display:block;}.lsd-date-field__input-container__icon{position:absolute;right:0;cursor:pointer;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background-color:rgb(var(--lsd-surface-primary));}.lsd-date-field__input-container__icon:focus{background:blue;background-color:pink;border:1px solid rgb(var(--lsd-border-primary));}.lsd-date-field__input-container__no-icon{position:absolute;right:0;background-color:rgb(var(--lsd-surface-primary));padding:12px;}.lsd-date-field--outlined{border:1px solid rgb(var(--lsd-border-primary));}.lsd-date-field--underlined{border-bottom:1px solid rgb(var(--lsd-border-primary));}.lsd-date-field__input-container{position:relative;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;}.lsd-date-field--disabled{opacity:0.34;}.lsd-date-field__input-container__input{border:none;outline:none;font-size:14px;color:rgb(var(--lsd-text-primary));background:none;width:100%;opacity:0.4;-webkit-transition:opacity 0.2s ease-in-out;transition:opacity 0.2s ease-in-out;}.lsd-date-field__input-container__input::-webkit-inner-spin-button,.lsd-date-field__input-container__input::-webkit-calendar-picker-indicator{display:none;-webkit-appearance:none;}.lsd-date-field__input-container__input:hover{outline:none;}.lsd-date-field__supporting-text{position:absolute;}.lsd-date-field--large{width:208px;}.lsd-date-field--large .lsd-date-field__label{margin:0 0 6px 18px;}.lsd-date-field--large .lsd-date-field__input-container{height:40px;}.lsd-date-field--large .lsd-date-field__input-container__input{padding:9px 0px 9px 17px;}.lsd-date-field--large .lsd-date-field__input-container__icon{padding:12px 13px;}.lsd-date-field--large .lsd-date-field__supporting-text{margin:6px 18px 0 18px;}.lsd-date-field--medium{width:188px;}.lsd-date-field--medium .lsd-date-field__label{margin:0 0 6px 14px;}.lsd-date-field--medium .lsd-date-field__input-container{height:32px;}.lsd-date-field--medium .lsd-date-field__input-container__input{padding:5px 11px 5px 13px;}.lsd-date-field--medium .lsd-date-field__input-container__icon{padding:8px 11px;}.lsd-date-field--medium .lsd-date-field__supporting-text{margin:6px 14px 0 14px;}.lsd-date-field--small{width:164px;}.lsd-date-field--small .lsd-date-field__label{margin:0 0 6px 12px;}.lsd-date-field--small .lsd-date-field__input-container{height:28px;}.lsd-date-field--small .lsd-date-field__input-container__input{padding:5px 9px 5px 11px;font-size:12px;}.lsd-date-field--small .lsd-date-field__input-container__icon{padding:6px 9px;}.lsd-date-field--small .lsd-date-field__supporting-text{margin:6px 12px 0 12px;}.lsd-date-field__input-container__input:invalid,.lsd-date-field__input-container__input--filled{color:rgb(var(--lsd-border-primary));opacity:1;}.lsd-date-field--error .lsd-date-field__input-container__input::-webkit-datetime-edit-year-field,.lsd-date-field--error .lsd-date-field__input-container__input::-webkit-datetime-edit-month-field,.lsd-date-field--error .lsd-date-field__input-container__input::-webkit-datetime-edit-day-field{-webkit-text-decoration:line-through;text-decoration:line-through;}@supports not selector(::-webkit-datetime-edit-day-field){.lsd-date-field--error .lsd-date-field__input-container__input{-webkit-text-decoration:line-through;text-decoration:line-through;}}</style><style data-emotion="css-global 1gjtao4">.lsd-calendar{border:1px solid rgb(var(--lsd-border-primary));visibility:hidden;position:absolute!important;top:0;left:0;opacity:0;visibility:hidden;margin:0;padding:0;box-sizing:border-box;background:rgb(var(--lsd-surface-primary));-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;}.lsd-calendar-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:8px;}.lsd-calendar--open{opacity:1;visibility:visible;}.lsd-calendar-header{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:32px;margin-bottom:8px;}.lsd-calendar__week_day{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;aspect-ratio:1/1;margin-bottom:4px;}.lsd-calendar__change-year{position:relative;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:2px 0xp 2px 8px;gap:6px;border:1px solid transparent;}.lsd-calendar__change-year--active .lsd-calendar__year-and-icon{border:1px solid rgb(var(--lsd-border-primary));}.lsd-calendar__change-year-icon-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;cursor:pointer;border:none;}.lsd-calendar-month{margin-right:8px;}.lsd-calendar__month-and-year{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}.lsd-calendar-day__container{cursor:pointer;background:transparent;position:relative;box-sizing:border-box;border:1px solid transparent;}.lsd-calendar-day{aspect-ratio:1/1;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}.lsd-calendar-day:hover{cursor:pointer;-webkit-text-decoration:underline;text-decoration:underline;text-decoration-color:rgb(var(--lsd-border-primary));}.lsd-calendar-day label:hover{cursor:pointer;}.lsd-calendar-day--selected{border:1px solid rgb(var(--lsd-border-primary));}.lsd-calendar-day--disabled{opacity:0.3;cursor:default;}.lsd-calendar-day__today_indicator{position:absolute;left:50%;-webkit-transform:translateX(-50%);-moz-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%);bottom:2px;}.lsd-calendar--disabled{pointer-events:none;border:1px solid rgba(var(--lsd-border-primary), 0.3);}.lsd-calendar--disabled label{opacity:0.3;}.lsd-calendar--disabled .lsd-calendar__button{opacity:0.3;}.lsd-calendar--disabled .lsd-calendar-day--selected{opacity:0.3;}.lsd-calendar__button{border:1px solid rgb(var(--lsd-border-primary));cursor:pointer;background:transparent;width:32px;height:32px;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;position:absolute;}.lsd-calendar__next-month-button{top:8px;right:8px;}.lsd-calendar__previous-month-button{top:8px;left:8px;}.lsd-calendar-day--border-left{border-left:1px double rgb(var(--lsd-border-primary));}.lsd-calendar-day--border-right{border-right:1px double rgb(var(--lsd-border-primary));}.lsd-calendar-day--border-left-and-right{border-left:1px double rgb(var(--lsd-border-primary));border-right:1px double rgb(var(--lsd-border-primary));}.lsd-calendar-day--border-top-and-bottom{border-top:1px double rgb(var(--lsd-border-primary));border-bottom:1px double rgb(var(--lsd-border-primary));}.lsd-calendar__month-table{border-collapse:collapse;}.lsd-calendar__year-dropdown{box-sizing:border-box;position:absolute;top:100%;left:0;max-height:200px;overflow-y:auto;width:100%;border:1px solid rgb(var(--lsd-border-primary));border-top:none;z-index:1;}.lsd-calendar__year-dropdown .lsd-calendar-year{border-bottom:1px solid rgb(var(--lsd-border-primary));}.lsd-calendar__year-dropdown--hidden{visibility:hidden;}.lsd-calendar-year{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;cursor:pointer;-webkit-transition:background-color 0.2s;transition:background-color 0.2s;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background:rgb(var(--lsd-surface-primary));}.lsd-calendar-year:hover{-webkit-text-decoration:underline;text-decoration:underline;}.lsd-calendar__year-and-icon{border:1px solid rgb(var(--lsd-border-primary));}.lsd-calendar--large .lsd-calendar-year{padding:6px 0px 6px 14px;}.lsd-calendar--large .lsd-calendar__change-year-icon-container{width:32px;}.lsd-calendar--medium .lsd-calendar-year{padding:6px 0px 6px 12px;}.lsd-calendar--medium .lsd-calendar__change-year-icon-container{width:28px;}.lsd-calendar--small .lsd-calendar-year{padding:6px 0px 6px 12px;}.lsd-calendar--small .lsd-calendar__change-year-icon-container{width:28px;}</style><style data-emotion="css-global dlrd7d">.lsd-toast{box-sizing:border-box;display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background:rgb(var(--lsd-surface-primary));border:1px solid rgb(var(--lsd-border-primary));padding:8px;height:-webkit-fit-content;height:-moz-fit-content;height:fit-content;}.lsd-toast__inline-button-container{-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;}.lsd-toast__column-button-container{margin-top:18px;margin-bottom:6px;}.lsd-toast__inline-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;}.lsd-toast__column-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:justify;-webkit-justify-content:space-between;justify-content:space-between;}.lsd-toast__text-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;color:rgb(var(--lsd-text-secondary));padding-left:12px;}.lsd-toast__title{position:relative;}.lsd-toast__information{margin-top:4px;}.lsd-toast__button-container{min-height:28px;min-width:60px;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;padding:0px 12px;}.lsd-toast__close-button{margin-bottom:auto;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;height:28px;width:28px;margin-left:auto;}.lsd-toast__column-icon-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;margin-bottom:auto;position:relative;top:4px;padding-left:4px;}.lsd-toast__inline-icon-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;padding-left:4px;}.lsd-toast__icon{position:relative;}.lsd-toast--large{width:364px;}.lsd-toast--medium{width:336px;}.lsd-toast--small{width:296px;}.lsd-toast--small .lsd-toast__icon{top:0px;}</style><style data-emotion="css-global 5wlfwk">.lsd-toast-provider__toast-container{position:fixed;-webkit-transition:all 230ms cubic-bezier(0.21, 1.02, 0.73, 1);transition:all 230ms cubic-bezier(0.21, 1.02, 0.73, 1);z-index:9999;}.lsd-toast-provider__toast--top-left,.lsd-toast-provider__toast--top-center,.lsd-toast-provider__toast--top-right{top:0;}.lsd-toast-provider__toast--bottom-left,.lsd-toast-provider__toast--bottom-center,.lsd-toast-provider__toast--bottom-right{bottom:0;}.lsd-toast-provider__toast--top-center,.lsd-toast-provider__toast--bottom-center{left:50%;}.lsd-toast-provider__toast--top-right,.lsd-toast-provider__toast--bottom-right{right:0;}</style><style data-emotion="css-global 9yw6e1">.lsd-button-group{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;}.lsd-button-group >*:not(:last-child).lsd-button--outlined,.lsd-button-group >*:not(:last-child) .lsd-button--outlined{border-right:none;}</style><style data-emotion="css-global 17u9w7w">.lsd-date-range-picker{box-sizing:border-box;}.lsd-date-range-picker .lsd-date-field--outlined{border:none;}.lsd-date-range-picker .lsd-date-field__input-container__icon{padding:8px;}.lsd-date-range-picker__label{display:block;}.lsd-date-range-picker__input-container{box-sizing:border-box;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;border:1px solid transparent;}.lsd-date-picker__calendar{border-top:none!important;}.lsd-date-picker__calendar .lsd-tooltip-base__arrow-tip{-webkit-transition:left 0.2s ease-in-out;transition:left 0.2s ease-in-out;}.lsd-date-range-picker--calendar-open .lsd-date-range-picker__input-container{border-bottom:1px solid rgb(var(--lsd-border-primary));}.lsd-date-range-picker__icon{cursor:pointer;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding:0 10px;}.lsd-date-range-picker--disabled{opacity:0.3;}.lsd-date-range-picker__supporting-text{position:absolute;}.lsd-date-range-picker--large{width:318px;}.lsd-date-range-picker--large .lsd-date-field--large{width:156px;}.lsd-date-range-picker--large .lsd-date-field__input-container__input{padding-right:0;}.lsd-date-range-picker--large .lsd-date-field__input-container__icon{padding:11px 12px;}.lsd-date-range-picker--large .lsd-date-range-picker__label{margin:0 0 6px 18px;}.lsd-date-range-picker--large .lsd-date-range-picker__input-container{height:40px;}.lsd-date-range-picker--large .lsd-date-range-picker__supporting-text{margin:6px 18px 0 18px;}.lsd-date-range-picker--medium{width:290px;}.lsd-date-range-picker--medium .lsd-date-field--medium{width:142px;}.lsd-date-range-picker--medium .lsd-date-field__input-container__input{padding-right:0;}.lsd-date-range-picker--medium .lsd-date-field__input-container__icon{padding:7px 8px;}.lsd-date-range-picker--medium .lsd-date-range-picker__label{margin:0 0 6px 14px;}.lsd-date-range-picker--medium .lsd-date-range-picker__input-container{height:32px;}.lsd-date-range-picker--medium .lsd-date-range-picker__supporting-text{margin:6px 14px 0 14px;}.lsd-date-range-picker--small{width:262px;}.lsd-date-range-picker--small .lsd-date-field--small{width:128px;}.lsd-date-range-picker--small .lsd-date-field__input-container__input{padding-right:0;}.lsd-date-range-picker--small .lsd-date-field__input-container__icon{padding:5px 7px;}.lsd-date-range-picker--small .lsd-date-range-picker__label{margin:0 0 6px 12px;}.lsd-date-range-picker--small .lsd-date-range-picker__input-container{height:28px;}.lsd-date-range-picker--small .lsd-date-range-picker__supporting-text{margin:6px 12px 0 12px;}.lsd-date-range-picker__separator{margin-left:3px;width:1px;height:100%;}.lsd-date-range-picker__separator{border-left:1px solid transparent;}.lsd-date-range-picker--outlined{border:1px solid rgb(var(--lsd-border-primary));}.lsd-date-range-picker--outlined .lsd-date-range-picker__separator{border-left:1px solid rgb(var(--lsd-border-primary));}</style><style data-emotion="css-global 19d282h">.lsd-tooltip-base{border:1px solid rgb(var(--lsd-border-primary));position:relative;}.lsd-tooltip-base__arrow-tip{border:1px solid rgb(var(--lsd-border-primary));position:absolute;background:rgb(var(--lsd-surface-primary));}.lsd-tooltip-base__content{background:rgb(var(--lsd-surface-primary));width:100%;height:100%;position:relative;z-index:1;}</style><style data-emotion="css-global js1ujt">html:not([data-theme]){--lsd-display1-fontSize:5.5rem;--lsd-display1-fontWeight:normal;--lsd-display1-lineHeight:6rem;--lsd-display2-fontSize:4rem;--lsd-display2-fontWeight:normal;--lsd-display2-lineHeight:4.5rem;--lsd-display3-fontSize:3.5rem;--lsd-display3-fontWeight:normal;--lsd-display3-lineHeight:4rem;--lsd-display4-fontSize:3rem;--lsd-display4-fontWeight:normal;--lsd-display4-lineHeight:3.5rem;--lsd-h1-fontSize:2.5rem;--lsd-h1-fontWeight:normal;--lsd-h1-lineHeight:3rem;--lsd-h2-fontSize:2rem;--lsd-h2-fontWeight:normal;--lsd-h2-lineHeight:2.5rem;--lsd-h3-fontSize:1.75rem;--lsd-h3-fontWeight:normal;--lsd-h3-lineHeight:2.25rem;--lsd-h4-fontSize:1.5rem;--lsd-h4-fontWeight:normal;--lsd-h4-lineHeight:2rem;--lsd-h5-fontSize:1.25rem;--lsd-h5-fontWeight:normal;--lsd-h5-lineHeight:1.75rem;--lsd-h6-fontSize:1rem;--lsd-h6-fontWeight:normal;--lsd-h6-lineHeight:1.5rem;--lsd-subtitle1-fontSize:1.125rem;--lsd-subtitle1-fontWeight:normal;--lsd-subtitle1-lineHeight:1.5rem;--lsd-subtitle2-fontSize:1rem;--lsd-subtitle2-fontWeight:normal;--lsd-subtitle2-lineHeight:1.5rem;--lsd-subtitle3-fontSize:0.875rem;--lsd-subtitle3-fontWeight:normal;--lsd-subtitle3-lineHeight:1.25rem;--lsd-subtitle4-fontSize:0.75rem;--lsd-subtitle4-fontWeight:normal;--lsd-subtitle4-lineHeight:1rem;--lsd-body1-fontSize:1rem;--lsd-body1-fontWeight:normal;--lsd-body1-lineHeight:1.5rem;--lsd-body2-fontSize:0.875rem;--lsd-body2-fontWeight:normal;--lsd-body2-lineHeight:1.25rem;--lsd-body3-fontSize:0.75rem;--lsd-body3-fontWeight:normal;--lsd-body3-lineHeight:1rem;--lsd-label1-fontSize:0.875rem;--lsd-label1-fontWeight:normal;--lsd-label1-lineHeight:1.25rem;--lsd-label2-fontSize:0.75rem;--lsd-label2-fontWeight:normal;--lsd-label2-lineHeight:1rem;--lsd-typography-generic-font-family:sans-serif;--lsd-theme-primary:0,0,0;--lsd-theme-secondary:255,255,255;--lsd-surface-primary:255,255,255;--lsd-surface-secondary:0,0,0;--lsd-border-primary:0,0,0;--lsd-border-secondary:255,255,255;--lsd-icon-primary:0,0,0;--lsd-icon-secondary:255,255,255;--lsd-text-primary:0,0,0;--lsd-text-secondary:255,255,255;--lsd-text-tertiary:0,0,0,0.34;--lsd-spacing-4:4px;--lsd-spacing-8:8px;--lsd-spacing-16:16px;--lsd-spacing-24:24px;--lsd-spacing-32:32px;--lsd-spacing-40:40px;--lsd-spacing-64:64px;--lsd-spacing-80:80px;--lsd-spacing-96:96px;--lsd-spacing-120:120px;}html[data-theme='light']{--lsd-display1-fontSize:5.5rem;--lsd-display1-fontWeight:normal;--lsd-display1-lineHeight:6rem;--lsd-display2-fontSize:4rem;--lsd-display2-fontWeight:normal;--lsd-display2-lineHeight:4.5rem;--lsd-display3-fontSize:3.5rem;--lsd-display3-fontWeight:normal;--lsd-display3-lineHeight:4rem;--lsd-display4-fontSize:3rem;--lsd-display4-fontWeight:normal;--lsd-display4-lineHeight:3.5rem;--lsd-h1-fontSize:2.5rem;--lsd-h1-fontWeight:normal;--lsd-h1-lineHeight:3rem;--lsd-h2-fontSize:2rem;--lsd-h2-fontWeight:normal;--lsd-h2-lineHeight:2.5rem;--lsd-h3-fontSize:1.75rem;--lsd-h3-fontWeight:normal;--lsd-h3-lineHeight:2.25rem;--lsd-h4-fontSize:1.5rem;--lsd-h4-fontWeight:normal;--lsd-h4-lineHeight:2rem;--lsd-h5-fontSize:1.25rem;--lsd-h5-fontWeight:normal;--lsd-h5-lineHeight:1.75rem;--lsd-h6-fontSize:1rem;--lsd-h6-fontWeight:normal;--lsd-h6-lineHeight:1.5rem;--lsd-subtitle1-fontSize:1.125rem;--lsd-subtitle1-fontWeight:normal;--lsd-subtitle1-lineHeight:1.5rem;--lsd-subtitle2-fontSize:1rem;--lsd-subtitle2-fontWeight:normal;--lsd-subtitle2-lineHeight:1.5rem;--lsd-subtitle3-fontSize:0.875rem;--lsd-subtitle3-fontWeight:normal;--lsd-subtitle3-lineHeight:1.25rem;--lsd-subtitle4-fontSize:0.75rem;--lsd-subtitle4-fontWeight:normal;--lsd-subtitle4-lineHeight:1rem;--lsd-body1-fontSize:1rem;--lsd-body1-fontWeight:normal;--lsd-body1-lineHeight:1.5rem;--lsd-body2-fontSize:0.875rem;--lsd-body2-fontWeight:normal;--lsd-body2-lineHeight:1.25rem;--lsd-body3-fontSize:0.75rem;--lsd-body3-fontWeight:normal;--lsd-body3-lineHeight:1rem;--lsd-label1-fontSize:0.875rem;--lsd-label1-fontWeight:normal;--lsd-label1-lineHeight:1.25rem;--lsd-label2-fontSize:0.75rem;--lsd-label2-fontWeight:normal;--lsd-label2-lineHeight:1rem;--lsd-typography-generic-font-family:sans-serif;--lsd-theme-primary:0,0,0;--lsd-theme-secondary:255,255,255;--lsd-surface-primary:255,255,255;--lsd-surface-secondary:0,0,0;--lsd-border-primary:0,0,0;--lsd-border-secondary:255,255,255;--lsd-icon-primary:0,0,0;--lsd-icon-secondary:255,255,255;--lsd-text-primary:0,0,0;--lsd-text-secondary:255,255,255;--lsd-text-tertiary:0,0,0,0.34;--lsd-spacing-4:4px;--lsd-spacing-8:8px;--lsd-spacing-16:16px;--lsd-spacing-24:24px;--lsd-spacing-32:32px;--lsd-spacing-40:40px;--lsd-spacing-64:64px;--lsd-spacing-80:80px;--lsd-spacing-96:96px;--lsd-spacing-120:120px;}html[data-theme='dark']{--lsd-display1-fontSize:5.5rem;--lsd-display1-fontWeight:normal;--lsd-display1-lineHeight:6rem;--lsd-display2-fontSize:4rem;--lsd-display2-fontWeight:normal;--lsd-display2-lineHeight:4.5rem;--lsd-display3-fontSize:3.5rem;--lsd-display3-fontWeight:normal;--lsd-display3-lineHeight:4rem;--lsd-display4-fontSize:3rem;--lsd-display4-fontWeight:normal;--lsd-display4-lineHeight:3.5rem;--lsd-h1-fontSize:2.5rem;--lsd-h1-fontWeight:normal;--lsd-h1-lineHeight:3rem;--lsd-h2-fontSize:2rem;--lsd-h2-fontWeight:normal;--lsd-h2-lineHeight:2.5rem;--lsd-h3-fontSize:1.75rem;--lsd-h3-fontWeight:normal;--lsd-h3-lineHeight:2.25rem;--lsd-h4-fontSize:1.5rem;--lsd-h4-fontWeight:normal;--lsd-h4-lineHeight:2rem;--lsd-h5-fontSize:1.25rem;--lsd-h5-fontWeight:normal;--lsd-h5-lineHeight:1.75rem;--lsd-h6-fontSize:1rem;--lsd-h6-fontWeight:normal;--lsd-h6-lineHeight:1.5rem;--lsd-subtitle1-fontSize:1.125rem;--lsd-subtitle1-fontWeight:normal;--lsd-subtitle1-lineHeight:1.5rem;--lsd-subtitle2-fontSize:1rem;--lsd-subtitle2-fontWeight:normal;--lsd-subtitle2-lineHeight:1.5rem;--lsd-subtitle3-fontSize:0.875rem;--lsd-subtitle3-fontWeight:normal;--lsd-subtitle3-lineHeight:1.25rem;--lsd-subtitle4-fontSize:0.75rem;--lsd-subtitle4-fontWeight:normal;--lsd-subtitle4-lineHeight:1rem;--lsd-body1-fontSize:1rem;--lsd-body1-fontWeight:normal;--lsd-body1-lineHeight:1.5rem;--lsd-body2-fontSize:0.875rem;--lsd-body2-fontWeight:normal;--lsd-body2-lineHeight:1.25rem;--lsd-body3-fontSize:0.75rem;--lsd-body3-fontWeight:normal;--lsd-body3-lineHeight:1rem;--lsd-label1-fontSize:0.875rem;--lsd-label1-fontWeight:normal;--lsd-label1-lineHeight:1.25rem;--lsd-label2-fontSize:0.75rem;--lsd-label2-fontWeight:normal;--lsd-label2-lineHeight:1rem;--lsd-typography-generic-font-family:sans-serif;--lsd-theme-primary:255,255,255;--lsd-theme-secondary:0,0,0;--lsd-surface-primary:0,0,0;--lsd-surface-secondary:255,255,255;--lsd-border-primary:255,255,255;--lsd-border-secondary:0,0,0;--lsd-icon-primary:255,255,255;--lsd-icon-secondary:0,0,0;--lsd-text-primary:255,255,255;--lsd-text-secondary:0,0,0;--lsd-text-tertiary:255,255,255,0.34;--lsd-spacing-4:4px;--lsd-spacing-8:8px;--lsd-spacing-16:16px;--lsd-spacing-24:24px;--lsd-spacing-32:32px;--lsd-spacing-40:40px;--lsd-spacing-64:64px;--lsd-spacing-80:80px;--lsd-spacing-96:96px;--lsd-spacing-120:120px;}</style><div class="root_QACb"><div role="region" aria-label="Skip to main content"><a class="skipToContent_fXgn" href="#__docusaurus_skipToContent_fallback">Skip to main content</a></div><nav aria-label="Main" class="navbar navbar--fixed-top navbarHideable_OoEf"><div class="navbar__inner"><div class="navbar__left"><a class="navbar__brand" href="/"><div class="navbar__logo"><img src="/theme/image/logo.svg" alt="Vac Research" class="themedImage_kfRS themedImage--light_BL8e" height="26"><img src="/theme/image/logo.svg" alt="Vac Research" class="themedImage_kfRS themedImage--dark_OvIx" height="26"></div><b class="navbar__title text--truncate"></b></a></div><div class="navbar__left-items"></div><div class="navbar__right-items"><div class="iconButtonGroup_ktNv lsd-icon-button-group lsd-icon-button-group--medium lsd-icon-button-group--outlined"><button aria-label="Toggle navigation bar" aria-expanded="false" class="navbar__toggle clean-btn" type="button"><svg width="30" height="30" viewBox="0 0 30 30" aria-hidden="true"><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button></div></div></div><div role="presentation" class="navbar-sidebar__backdrop"></div></nav><div id="__docusaurus_skipToContent_fallback" class="main-wrapper mainWrapper_z2l0 docsWrapper_BCFX"><button aria-label="Scroll back to top" class="clean-btn theme-back-to-top-button backToTopButton_sjWU" type="button"></button><div class="docPage__5DB"><aside class="theme-doc-sidebar-container docSidebarContainer_b6E3"><div class="sidebarViewport_Xe31"><div class="sidebar_UEyd sidebarWithHideableNavbar__00c"><a tabindex="-1" class="sidebarLogo_Ydl9" href="/"><img src="/theme/image/logo.svg" alt="Vac Research" class="themedImage_kfRS themedImage--light_BL8e" height="26"><img src="/theme/image/logo.svg" alt="Vac Research" class="themedImage_kfRS themedImage--dark_OvIx" height="26"><b></b></a><nav aria-label="Docs sidebar" class="menu thin-scrollbar menu_NjKY"><ul class="theme-doc-sidebar-menu menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/status/">Status RFCs</a></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--active" aria-expanded="true" href="/status/deprecated/3rd-party"><svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" class="chevron_How5 lsd-icon lsd-icon--small lsd-icon--filled"><path d="M3.5 8.33875L4.3225 9.16125L7 6.48959L9.6775 9.16125L10.5 8.33875L7 4.83875L3.5 8.33875Z" fill="black"></path></svg><span class="lsd-typography lsd-typography--body2 lsd-typography--primary">deprecated</span></a></div><ul style="display:block;overflow:visible;height:auto" class="menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/status/deprecated/3rd-party">3RD-PARTY</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/status/deprecated/IPFS-gateway-for-sticker-Pack">IPFS-gateway-for-Sticker-Pack</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/status/deprecated/account">ACCOUNT</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/status/deprecated/client">CLIENT</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/status/deprecated/dapp-browser-API-usage">Dapp browser API usage</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/status/deprecated/eips">EIPS</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/status/deprecated/ethereum-usage">ETHEREUM-USAGE</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/status/deprecated/group-chat">GROUP-CHAT</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/status/deprecated/keycard-usage-for-wallet-and-chat-keys">Keycard Usage for Wallet and Chat Keys</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/status/deprecated/notifications">NOTIFICATIONS</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/status/deprecated/payloads">PAYLOADS</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link menu__link--active" aria-current="page" tabindex="0" href="/status/deprecated/push-notification-server">PUSH-NOTIFICATION-SERVER</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/status/deprecated/secure-transport">SECURE-TRANSPORT</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/status/deprecated/waku-mailserver">WAKU-MAILSERVER</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/status/deprecated/waku-usage">WAKU-USAGE</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/status/deprecated/whisper-mailserver">WHISPER-MAILSERVER</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/status/deprecated/whisper-usage">WHISPER-USAGE</a></li></ul></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist" aria-expanded="false" href="/status/raw/simple-scaling"><svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" class="chevron_How5 lsd-icon lsd-icon--small lsd-icon--filled"><path d="M3.5 8.33875L4.3225 9.16125L7 6.48959L9.6775 9.16125L10.5 8.33875L7 4.83875L3.5 8.33875Z" fill="black"></path></svg><span class="lsd-typography lsd-typography--body2 lsd-typography--primary">raw</span></a></div></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/status/24/curation">24/STATUS-CURATION</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/status/28/featuring">28/STATUS-FEATURING</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/status/55/1to1-chat">55/STATUS-1TO1-CHAT</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/status/56/communities">56/STATUS-COMMUNITIES</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/status/61/community-history-service">61/STATUS-Community-History-Service</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/status/62/payloads">62/STATUS-PAYLOADS</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/status/63/keycard-usage">63/STATUS-Keycard-Usage</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/status/65/account-address">65/STATUS-ACCOUNT-ADDRESS</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/status/71/push-notification-server">71/STATUS-PUSH-NOTIFICATION-SERVER</a></li></ul></nav></div></div></aside><main class="docMainContainer_gTbr"><div class="container padding-top--md padding-bottom--lg"><div class="row docItemGrid_SzoZ"><div class="docItemCol_F52z"><div class="docItemContainer_hrrU"><article><nav class="theme-doc-breadcrumbs breadcrumbsContainer_RLvU" aria-label="Breadcrumbs"><ul class="breadcrumbs" itemscope="" itemtype="https://schema.org/BreadcrumbList"><a class="breadcrumbs__item" href="/status"><span class="lsd-typography lsd-typography--body3">Home</span></a><li class="breadcrumbs__item"><span class="lsd-typography lsd-typography--body3 breadcrumbs__link">deprecated</span><meta itemprop="position" content="1"></li><li itemscope="" itemprop="itemListElement" itemtype="https://schema.org/ListItem" class="breadcrumbs__item breadcrumbs__item--active"><span class="lsd-typography lsd-typography--body3 breadcrumbs__link" itemprop="name">PUSH-NOTIFICATION-SERVER</span><meta itemprop="position" content="2"></li></ul></nav><div class="theme-doc-markdown markdown"><header><h1>PUSH-NOTIFICATION-SERVER</h1><div class="tocMobile_imaF"><div class="tocCollapsible_ROek theme-doc-toc-mobile tocMobile_ITEo"><button type="button" class="clean-btn tocCollapsibleButton_dxRj"><div></div><span class="lsd-typography lsd-typography--body2">On this page</span><svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" class="lsd-icon lsd-icon--small lsd-icon--filled"><path d="M10.5 5.66125L9.6775 4.83875L7 7.51041L4.3225 4.83874L3.5 5.66125L7 9.16125L10.5 5.66125Z" fill="black"></path></svg></button></div></div></header><ul><li>Status: deprecated</li><li>Editor: Filip Dimitrijevic <<a href="mailto:filip@status.im" target="_blank" rel="noopener noreferrer">filip@status.im</a>></li><li>Contributors:<ul><li>Andrea Maria Piana <<a href="mailto:andreap@status.im" target="_blank" rel="noopener noreferrer">andreap@status.im</a>></li></ul></li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="reason">Reason<a href="#reason" class="hash-link" aria-label="Direct link to Reason" title="Direct link to 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" target="_blank" rel="noopener noreferrer">APN service</a> for iOS or <a href="https://firebase.google.com/" target="_blank" rel="noopener noreferrer">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" target="_blank" rel="noopener noreferrer">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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="requirements">Requirements<a href="#requirements" class="hash-link" aria-label="Direct link to Requirements" title="Direct link to 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" target="_blank" rel="noopener noreferrer">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" target="_blank" rel="noopener noreferrer">gorush</a></p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="components">Components<a href="#components" class="hash-link" aria-label="Direct link to Components" title="Direct link to Components"></a></h2><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="gorush-instance">Gorush instance<a href="#gorush-instance" class="hash-link" aria-label="Direct link to Gorush instance" title="Direct link to Gorush instance"></a></h3><p>A <a href="https://github.com/appleboy/gorush" target="_blank" rel="noopener noreferrer">gorush</a> instance MUST be publicly available,
|
||
this will be used only by push notification servers.</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="push-notification-server">Push notification server<a href="#push-notification-server" class="hash-link" aria-label="Direct link to Push notification server" title="Direct link to Push notification server"></a></h3><p>A push notification server used by clients to register for receiving and sending push notifications.</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="registering-client">Registering client<a href="#registering-client" class="hash-link" aria-label="Direct link to Registering client" title="Direct link to Registering client"></a></h3><p>A Status client that wants to receive push notifications</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="sending-client">Sending client<a href="#sending-client" class="hash-link" aria-label="Direct link to Sending client" title="Direct link to Sending client"></a></h3><p>A Status client that wants to send push notifications</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="registering-with-the-push-notification-service">Registering with the push notification service<a href="#registering-with-the-push-notification-service" class="hash-link" aria-label="Direct link to Registering with the push notification service" title="Direct link to 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/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/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/" target="_blank" rel="noopener noreferrer">protobuf record</a>:</p><div class="language-protobuf codeBlockContainer_EB2s codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:rgba(var(--lsd-surface-secondary), 0.08)"><div class="codeBlockContent_ugSV"><pre tabindex="0" class="prism-code language-protobuf codeBlock_TWhw thin-scrollbar"><code class="codeBlockLines_LDrR"><span class="token-line" style="color:#F8F8F2"><span class="token plain">message PushNotificationRegistration {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> enum TokenType {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> UNKNOWN_TOKEN_TYPE = 0;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> APN_TOKEN = 1;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> FIREBASE_TOKEN = 2;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> TokenType token_type = 1;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> string device_token = 2;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> string installation_id = 3;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> string access_token = 4;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> bool enabled = 5;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> uint64 version = 6;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> repeated bytes allowed_key_list = 7;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> repeated bytes blocked_chat_list = 8;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> bool unregister = 9;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> bytes grant = 10;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> bool allow_from_contacts_only = 11;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> string apn_topic = 12;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> bool block_mentions = 13;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> repeated bytes allowed_mentions_chat_list = 14;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_Qu4e"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_an20" aria-hidden="true"><div class="icon_S7Kx m_thRi copyButtonIcon_ZL7v"><svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" role="img"><path d="M2.917 12.833c-.321 0-.596-.114-.825-.343a1.121 1.121 0 0 1-.342-.823V3.5h1.167v8.167h6.416v1.166H2.917ZM5.25 10.5c-.32 0-.596-.114-.824-.343a1.121 1.121 0 0 1-.343-.824v-7c0-.32.115-.595.343-.824.229-.229.504-.343.824-.342h5.25c.32 0 .596.114.824.343.229.228.343.503.343.823v7c0 .321-.115.596-.343.825a1.121 1.121 0 0 1-.824.342H5.25Zm0-1.167h5.25v-7H5.25v7Z" fill="#fff"></path></svg></div></span></button></div></div></div><p>A push notification server will handle the message according to the following rules:</p><ul><li>it MUST extract the public key of the sender from the signature and verify that
|
||
the payload can be decrypted successfully.</li><li>it MUST verify that <code>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" target="_blank" rel="noopener noreferrer"><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/status/deprecated/waku-usage##partitioned-topic">partitioned topic</a> of the sender
|
||
and MUST not be encrypted using the <a href="/status/deprecated/status/deprecated/secure-transport">secure transport</a> to facilitate the usage of ephemeral keys.</p><p>The payload of the response is:</p><div class="language-protobuf codeBlockContainer_EB2s codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:rgba(var(--lsd-surface-secondary), 0.08)"><div class="codeBlockContent_ugSV"><pre tabindex="0" class="prism-code language-protobuf codeBlock_TWhw thin-scrollbar"><code class="codeBlockLines_LDrR"><span class="token-line" style="color:#F8F8F2"><span class="token plain">message PushNotificationRegistrationResponse {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> bool success = 1;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> ErrorType error = 2;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> bytes request_id = 3;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> enum ErrorType {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> UNKNOWN_ERROR_TYPE = 0;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> MALFORMED_MESSAGE = 1;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> VERSION_MISMATCH = 2;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> UNSUPPORTED_TOKEN_TYPE = 3;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> INTERNAL_ERROR = 4;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_Qu4e"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_an20" aria-hidden="true"><div class="icon_S7Kx m_thRi copyButtonIcon_ZL7v"><svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" role="img"><path d="M2.917 12.833c-.321 0-.596-.114-.825-.343a1.121 1.121 0 0 1-.342-.823V3.5h1.167v8.167h6.416v1.166H2.917ZM5.25 10.5c-.32 0-.596-.114-.824-.343a1.121 1.121 0 0 1-.343-.824v-7c0-.32.115-.595.343-.824.229-.229.504-.343.824-.342h5.25c.32 0 .596.114.824.343.229.228.343.503.343.823v7c0 .321-.115.596-.343.825a1.121 1.121 0 0 1-.824.342H5.25Zm0-1.167h5.25v-7H5.25v7Z" fill="#fff"></path></svg></div></span></button></div></div></div><p>The message MUST be wrapped in a <a href="/status/deprecated/status/deprecated/payloads##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/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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="query-topic">Query topic<a href="#query-topic" class="hash-link" aria-label="Direct link to Query topic" title="Direct link to Query topic"></a></h3><p>On successful registration the server MUST be listening to the topic derived from:</p><div class="language-protobuf codeBlockContainer_EB2s codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:rgba(var(--lsd-surface-secondary), 0.08)"><div class="codeBlockContent_ugSV"><pre tabindex="0" class="prism-code language-protobuf codeBlock_TWhw thin-scrollbar"><code class="codeBlockLines_LDrR"><span class="token-line" style="color:#F8F8F2"><span class="token plain"> 0XHexEncode(Shake256(CompressedClientPublicKey))</span><br></span></code></pre><div class="buttonGroup_Qu4e"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_an20" aria-hidden="true"><div class="icon_S7Kx m_thRi copyButtonIcon_ZL7v"><svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" role="img"><path d="M2.917 12.833c-.321 0-.596-.114-.825-.343a1.121 1.121 0 0 1-.342-.823V3.5h1.167v8.167h6.416v1.166H2.917ZM5.25 10.5c-.32 0-.596-.114-.824-.343a1.121 1.121 0 0 1-.343-.824v-7c0-.32.115-.595.343-.824.229-.229.504-.343.824-.342h5.25c.32 0 .596.114.824.343.229.228.343.503.343.823v7c0 .321-.115.596-.343.825a1.121 1.121 0 0 1-.824.342H5.25Zm0-1.167h5.25v-7H5.25v7Z" fill="#fff"></path></svg></div></span></button></div></div></div><p>Using the topic derivation algorithm described <a href="/status/deprecated/status/deprecated/waku-usage/#public-chats">here</a>
|
||
and listen for client queries.</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="server-grant">Server grant<a href="#server-grant" class="hash-link" aria-label="Direct link to Server grant" title="Direct link to 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><div class="language-protobuf codeBlockContainer_EB2s codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:rgba(var(--lsd-surface-secondary), 0.08)"><div class="codeBlockContent_ugSV"><pre tabindex="0" class="prism-code language-protobuf codeBlock_TWhw thin-scrollbar"><code class="codeBlockLines_LDrR"><span class="token-line" style="color:#F8F8F2"><span class="token plain"> Signature(Keccak256(CompressedPublicKeyOfClient . CompressedPublicKeyOfServer . AccessToken), PrivateKeyOfClient)</span><br></span></code></pre><div class="buttonGroup_Qu4e"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_an20" aria-hidden="true"><div class="icon_S7Kx m_thRi copyButtonIcon_ZL7v"><svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" role="img"><path d="M2.917 12.833c-.321 0-.596-.114-.825-.343a1.121 1.121 0 0 1-.342-.823V3.5h1.167v8.167h6.416v1.166H2.917ZM5.25 10.5c-.32 0-.596-.114-.824-.343a1.121 1.121 0 0 1-.343-.824v-7c0-.32.115-.595.343-.824.229-.229.504-.343.824-.342h5.25c.32 0 .596.114.824.343.229.228.343.503.343.823v7c0 .321-.115.596-.343.825a1.121 1.121 0 0 1-.824.342H5.25Zm0-1.167h5.25v-7H5.25v7Z" fill="#fff"></path></svg></div></span></button></div></div></div><p>When receiving a grant the server MUST be validate that the signature matches the registering client.</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="re-registering-with-the-push-notification-server">Re-registering with the push notification server<a href="#re-registering-with-the-push-notification-server" class="hash-link" aria-label="Direct link to Re-registering with the push notification server" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="changing-options">Changing options<a href="#changing-options" class="hash-link" aria-label="Direct link to Changing options" title="Direct link to Changing options"></a></h2><p>This is handled in exactly the same way as re-registering above.</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="unregistering-from-push-notifications">Unregistering from push notifications<a href="#unregistering-from-push-notifications" class="hash-link" aria-label="Direct link to Unregistering from push notifications" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="advertising-a-push-notification-server">Advertising a push notification server<a href="#advertising-a-push-notification-server" class="hash-link" aria-label="Direct link to Advertising a push notification server" title="Direct link to 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><div class="language-protobuf codeBlockContainer_EB2s codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:rgba(var(--lsd-surface-secondary), 0.08)"><div class="codeBlockContent_ugSV"><pre tabindex="0" class="prism-code language-protobuf codeBlock_TWhw thin-scrollbar"><code class="codeBlockLines_LDrR"><span class="token-line" style="color:#F8F8F2"><span class="token plain">message PushNotificationQueryInfo {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> string access_token = 1;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> string installation_id = 2;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> bytes public_key = 3;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> repeated bytes allowed_user_list = 4;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> bytes grant = 5;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> uint64 version = 6;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> bytes server_public_key = 7;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">message ContactCodeAdvertisement {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> repeated PushNotificationQueryInfo push_notification_info = 1;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_Qu4e"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_an20" aria-hidden="true"><div class="icon_S7Kx m_thRi copyButtonIcon_ZL7v"><svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" role="img"><path d="M2.917 12.833c-.321 0-.596-.114-.825-.343a1.121 1.121 0 0 1-.342-.823V3.5h1.167v8.167h6.416v1.166H2.917ZM5.25 10.5c-.32 0-.596-.114-.824-.343a1.121 1.121 0 0 1-.343-.824v-7c0-.32.115-.595.343-.824.229-.229.504-.343.824-.342h5.25c.32 0 .596.114.824.343.229.228.343.503.343.823v7c0 .321-.115.596-.343.825a1.121 1.121 0 0 1-.824.342H5.25Zm0-1.167h5.25v-7H5.25v7Z" fill="#fff"></path></svg></div></span></button></div></div></div><p>The message MUST be wrapped in a <a href="/status/deprecated/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##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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="discovering-a-push-notification-server">Discovering a push notification server<a href="#discovering-a-push-notification-server" class="hash-link" aria-label="Direct link to Discovering a push notification server" title="Direct link to Discovering a push notification server"></a></h2><p>To discover a push notification service for a given user, their <a href="/status/deprecated/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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="querying-the-push-notification-server">Querying the push notification server<a href="#querying-the-push-notification-server" class="hash-link" aria-label="Direct link to Querying the push notification server" title="Direct link to 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><div class="language-protobuf codeBlockContainer_EB2s codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:rgba(var(--lsd-surface-secondary), 0.08)"><div class="codeBlockContent_ugSV"><pre tabindex="0" class="prism-code language-protobuf codeBlock_TWhw thin-scrollbar"><code class="codeBlockLines_LDrR"><span class="token-line" style="color:#F8F8F2"><span class="token plain">message PushNotificationQuery {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> repeated bytes public_keys = 1;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_Qu4e"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_an20" aria-hidden="true"><div class="icon_S7Kx m_thRi copyButtonIcon_ZL7v"><svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" role="img"><path d="M2.917 12.833c-.321 0-.596-.114-.825-.343a1.121 1.121 0 0 1-.342-.823V3.5h1.167v8.167h6.416v1.166H2.917ZM5.25 10.5c-.32 0-.596-.114-.824-.343a1.121 1.121 0 0 1-.343-.824v-7c0-.32.115-.595.343-.824.229-.229.504-.343.824-.342h5.25c.32 0 .596.114.824.343.229.228.343.503.343.823v7c0 .321-.115.596-.343.825a1.121 1.121 0 0 1-.824.342H5.25Zm0-1.167h5.25v-7H5.25v7Z" fill="#fff"></path></svg></div></span></button></div></div></div><p>The message MUST be wrapped in a <a href="/status/deprecated/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/status/deprecated/secure-transport">secure transport</a>.</p><p>If the server has information about the client a response MUST be sent:</p><div class="language-protobuf codeBlockContainer_EB2s codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:rgba(var(--lsd-surface-secondary), 0.08)"><div class="codeBlockContent_ugSV"><pre tabindex="0" class="prism-code language-protobuf codeBlock_TWhw thin-scrollbar"><code class="codeBlockLines_LDrR"><span class="token-line" style="color:#F8F8F2"><span class="token plain">message PushNotificationQueryInfo {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> string access_token = 1;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> string installation_id = 2;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> bytes public_key = 3;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> repeated bytes allowed_user_list = 4;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> bytes grant = 5;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> uint64 version = 6;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> bytes server_public_key = 7;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">message PushNotificationQueryResponse {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> repeated PushNotificationQueryInfo info = 1;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> bytes message_id = 2;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> bool success = 3;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_Qu4e"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_an20" aria-hidden="true"><div class="icon_S7Kx m_thRi copyButtonIcon_ZL7v"><svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" role="img"><path d="M2.917 12.833c-.321 0-.596-.114-.825-.343a1.121 1.121 0 0 1-.342-.823V3.5h1.167v8.167h6.416v1.166H2.917ZM5.25 10.5c-.32 0-.596-.114-.824-.343a1.121 1.121 0 0 1-.343-.824v-7c0-.32.115-.595.343-.824.229-.229.504-.343.824-.342h5.25c.32 0 .596.114.824.343.229.228.343.503.343.823v7c0 .321-.115.596-.343.825a1.121 1.121 0 0 1-.824.342H5.25Zm0-1.167h5.25v-7H5.25v7Z" fill="#fff"></path></svg></div></span></button></div></div></div><p>A <code>PushNotificationQueryResponse</code> message MUST be wrapped in a <a href="/status/deprecated/status/deprecated/payloads##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" target="_blank" rel="noopener noreferrer"><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/status/deprecated/waku-usage/#partitioned-topic">partitioned topic</a> of the sender
|
||
and MUST not be encrypted using the <a href="/status/deprecated/status/deprecated/secure-transport">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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="sending-a-push-notification">Sending a push notification<a href="#sending-a-push-notification" class="hash-link" aria-label="Direct link to Sending a push notification" title="Direct link to 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><div class="language-protobuf codeBlockContainer_EB2s codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:rgba(var(--lsd-surface-secondary), 0.08)"><div class="codeBlockContent_ugSV"><pre tabindex="0" class="prism-code language-protobuf codeBlock_TWhw thin-scrollbar"><code class="codeBlockLines_LDrR"><span class="token-line" style="color:#F8F8F2"><span class="token plain">message PushNotification {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> string access_token = 1;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> string chat_id = 2;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> bytes public_key = 3;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> string installation_id = 4;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> bytes message = 5;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> PushNotificationType type = 6;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> enum PushNotificationType {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> UNKNOWN_PUSH_NOTIFICATION_TYPE = 0;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> MESSAGE = 1;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> MENTION = 2;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> bytes author = 7;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">message PushNotificationRequest {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> repeated PushNotification requests = 1;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> bytes message_id = 2;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_Qu4e"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_an20" aria-hidden="true"><div class="icon_S7Kx m_thRi copyButtonIcon_ZL7v"><svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" role="img"><path d="M2.917 12.833c-.321 0-.596-.114-.825-.343a1.121 1.121 0 0 1-.342-.823V3.5h1.167v8.167h6.416v1.166H2.917ZM5.25 10.5c-.32 0-.596-.114-.824-.343a1.121 1.121 0 0 1-.343-.824v-7c0-.32.115-.595.343-.824.229-.229.504-.343.824-.342h5.25c.32 0 .596.114.824.343.229.228.343.503.343.823v7c0 .321-.115.596-.343.825a1.121 1.121 0 0 1-.824.342H5.25Zm0-1.167h5.25v-7H5.25v7Z" fill="#fff"></path></svg></div></span></button></div></div></div><p>A <code>PushNotificationRequest</code> message MUST be wrapped in a <a href="/status/deprecated/payloads##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><div class="language-protobuf codeBlockContainer_EB2s codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:rgba(var(--lsd-surface-secondary), 0.08)"><div class="codeBlockContent_ugSV"><pre tabindex="0" class="prism-code language-protobuf codeBlock_TWhw thin-scrollbar"><code class="codeBlockLines_LDrR"><span class="token-line" style="color:#F8F8F2"><span class="token plain">{</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> "notifications": [</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> "tokens": ["token_a", "token_b"],</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> "platform": 1,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> "message": "You have a new message",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> "data": {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> "chat_id": chat_id,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> "message": message,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> "installation_ids": [installation_id_1, installation_id_2]</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> ]</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_Qu4e"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_an20" aria-hidden="true"><div class="icon_S7Kx m_thRi copyButtonIcon_ZL7v"><svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" role="img"><path d="M2.917 12.833c-.321 0-.596-.114-.825-.343a1.121 1.121 0 0 1-.342-.823V3.5h1.167v8.167h6.416v1.166H2.917ZM5.25 10.5c-.32 0-.596-.114-.824-.343a1.121 1.121 0 0 1-.343-.824v-7c0-.32.115-.595.343-.824.229-.229.504-.343.824-.342h5.25c.32 0 .596.114.824.343.229.228.343.503.343.823v7c0 .321-.115.596-.343.825a1.121 1.121 0 0 1-.824.342H5.25Zm0-1.167h5.25v-7H5.25v7Z" fill="#fff"></path></svg></div></span></button></div></div></div><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" target="_blank" rel="noopener noreferrer">gorush documentation</a></p><p>A server MUST return a response message:</p><div class="language-protobuf codeBlockContainer_EB2s codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:rgba(var(--lsd-surface-secondary), 0.08)"><div class="codeBlockContent_ugSV"><pre tabindex="0" class="prism-code language-protobuf codeBlock_TWhw thin-scrollbar"><code class="codeBlockLines_LDrR"><span class="token-line" style="color:#F8F8F2"><span class="token plain">message PushNotificationReport {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> bool success = 1;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> ErrorType error = 2;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> enum ErrorType {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> UNKNOWN_ERROR_TYPE = 0;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> WRONG_TOKEN = 1;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> INTERNAL_ERROR = 2;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> NOT_REGISTERED = 3;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> bytes public_key = 3;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> string installation_id = 4;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">message PushNotificationResponse {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> bytes message_id = 1;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"> repeated PushNotificationReport reports = 2;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup_Qu4e"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_an20" aria-hidden="true"><div class="icon_S7Kx m_thRi copyButtonIcon_ZL7v"><svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" role="img"><path d="M2.917 12.833c-.321 0-.596-.114-.825-.343a1.121 1.121 0 0 1-.342-.823V3.5h1.167v8.167h6.416v1.166H2.917ZM5.25 10.5c-.32 0-.596-.114-.824-.343a1.121 1.121 0 0 1-.343-.824v-7c0-.32.115-.595.343-.824.229-.229.504-.343.824-.342h5.25c.32 0 .596.114.824.343.229.228.343.503.343.823v7c0 .321-.115.596-.343.825a1.121 1.121 0 0 1-.824.342H5.25Zm0-1.167h5.25v-7H5.25v7Z" fill="#fff"></path></svg></div></span></button></div></div></div><p>A <code>PushNotificationResponse</code> message MUST be wrapped in a <a href="/status/deprecated/payloads##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##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>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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="flow">Flow<a href="#flow" class="hash-link" aria-label="Direct link to Flow" title="Direct link to Flow"></a></h2><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="registration-process">Registration process<a href="#registration-process" class="hash-link" aria-label="Direct link to Registration process" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="sending-a-notification">Sending a notification<a href="#sending-a-notification" class="hash-link" aria-label="Direct link to Sending a notification" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="receiving-a-push-notification">Receiving a push notification<a href="#receiving-a-push-notification" class="hash-link" aria-label="Direct link to Receiving a push notification" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="protobuf-description">Protobuf description<a href="#protobuf-description" class="hash-link" aria-label="Direct link to Protobuf description" title="Direct link to Protobuf description"></a></h2><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="pushnotificationregistration">PushNotificationRegistration<a href="#pushnotificationregistration" class="hash-link" aria-label="Direct link to PushNotificationRegistration" title="Direct link to 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"><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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="data-disclosed">Data disclosed<a href="#data-disclosed" class="hash-link" aria-label="Direct link to Data disclosed" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="pushnotificationregistrationresponse">PushNotificationRegistrationResponse<a href="#pushnotificationregistrationresponse" class="hash-link" aria-label="Direct link to PushNotificationRegistrationResponse" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="contactcodeadvertisement">ContactCodeAdvertisement<a href="#contactcodeadvertisement" class="hash-link" aria-label="Direct link to ContactCodeAdvertisement" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="pushnotificationquery">PushNotificationQuery<a href="#pushnotificationquery" class="hash-link" aria-label="Direct link to PushNotificationQuery" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="pushnotificationqueryinfo">PushNotificationQueryInfo<a href="#pushnotificationqueryinfo" class="hash-link" aria-label="Direct link to PushNotificationQueryInfo" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="pushnotificationqueryresponse">PushNotificationQueryResponse<a href="#pushnotificationqueryresponse" class="hash-link" aria-label="Direct link to PushNotificationQueryResponse" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="pushnotification">PushNotification<a href="#pushnotification" class="hash-link" aria-label="Direct link to PushNotification" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="pushnotificationrequest">PushNotificationRequest<a href="#pushnotificationrequest" class="hash-link" aria-label="Direct link to PushNotificationRequest" title="Direct link to PushNotificationRequest"></a></h3><p><code>requests</code>: a list of <code>PushNotification</code>
|
||
<code>message_id</code>: the <a href="/status/deprecated/payloads">status message id</a></p><p>Data disclosed</p><ul><li>The status message id for which the notification is for</li></ul><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="pushnotificationresponse">PushNotificationResponse<a href="#pushnotificationresponse" class="hash-link" aria-label="Direct link to PushNotificationResponse" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="pushnotificationreport">PushNotificationReport<a href="#pushnotificationreport" class="hash-link" aria-label="Direct link to PushNotificationReport" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="anonymous-mode-of-operations">Anonymous mode of operations<a href="#anonymous-mode-of-operations" class="hash-link" aria-label="Direct link to Anonymous mode of operations" title="Direct link to 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##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">device syncing</a>, but not completely
|
||
addressed.</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="security-considerations">Security considerations<a href="#security-considerations" class="hash-link" aria-label="Direct link to Security considerations" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="faq">FAQ<a href="#faq" class="hash-link" aria-label="Direct link to FAQ" title="Direct link to FAQ"></a></h2><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="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 href="#why-having-acl-done-at-the-server-side-and-not-the-client" class="hash-link" aria-label="Direct link to Why having ACL done at the server side and not the client?" title="Direct link to 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" target="_blank" rel="noopener noreferrer">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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="why-using-an-access-token">Why using an access token?<a href="#why-using-an-access-token" class="hash-link" aria-label="Direct link to Why using an access token?" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="why-advertise-with-the-bundle">Why advertise with the bundle?<a href="#why-advertise-with-the-bundle" class="hash-link" aria-label="Direct link to Why advertise with the bundle?" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="whats-the--bandwidth-impact-for-this">What's the bandwidth impact for this?<a href="#whats-the--bandwidth-impact-for-this" class="hash-link" aria-label="Direct link to What's the bandwidth impact for this?" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="whats-the-information-disclosed">What's the information disclosed?<a href="#whats-the-information-disclosed" class="hash-link" aria-label="Direct link to What's the information disclosed?" title="Direct link to 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><p>1) Your chat key
|
||
2) Which devices you have
|
||
3) The hash of the chat_ids you want to filter out
|
||
4) The hash of the public keys you are interested/not interested in</p><p>When you query a notification service you may disclose:</p><p>1) Your chat key
|
||
2) The fact that you are interested in sending push notification to a given user</p><p>Effectively this is fairly revealing if the user has a whitelist implemented.
|
||
Therefore sending notification should be optional.</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="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 href="#what-prevents-a-user-from-generating-a-random-key-and-getting-an-access-token-and-spamming" class="hash-link" aria-label="Direct link to What prevents a user from generating a random key and getting an access token and spamming?" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="why-not-0-knowledge-proofsquantum-computing">Why not 0-knowledge proofs/quantum computing<a href="#why-not-0-knowledge-proofsquantum-computing" class="hash-link" aria-label="Direct link to Why not 0-knowledge proofs/quantum computing" title="Direct link to Why not 0-knowledge proofs/quantum computing"></a></h3><p>We start simple, we can iterate</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="how-to-handle-backwardforward-compatibility">How to handle backward/forward compatibility<a href="#how-to-handle-backwardforward-compatibility" class="hash-link" aria-label="Direct link to How to handle backward/forward compatibility" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="why-ack_key">Why ack_key?<a href="#why-ack_key" class="hash-link" aria-label="Direct link to Why ack_key?" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="can-i-run-my-own-node">Can I run my own node?<a href="#can-i-run-my-own-node" class="hash-link" aria-label="Direct link to Can I run my own node?" title="Direct link to Can I run my own node?"></a></h3><p>Sure, the methods allow that</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="can-i-register-with-multiple-nodes-for-redundancy">Can I register with multiple nodes for redundancy<a href="#can-i-register-with-multiple-nodes-for-redundancy" class="hash-link" aria-label="Direct link to Can I register with multiple nodes for redundancy" title="Direct link to Can I register with multiple nodes for redundancy"></a></h3><p>Yep</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="what-does-my-node-disclose">What does my node disclose?<a href="#what-does-my-node-disclose" class="hash-link" aria-label="Direct link to What does my node disclose?" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="does-this-have-high-reliability-requirements">Does this have high-reliability requirements?<a href="#does-this-have-high-reliability-requirements" class="hash-link" aria-label="Direct link to Does this have high-reliability requirements?" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="can-someone-else-ie-not-status-run-this">Can someone else (i.e not status) run this?<a href="#can-someone-else-ie-not-status-run-this" class="hash-link" aria-label="Direct link to Can someone else (i.e not status) run this?" title="Direct link to 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 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="changelog">Changelog<a href="#changelog" class="hash-link" aria-label="Direct link to Changelog" title="Direct link to Changelog"></a></h2><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="version-01">Version 0.1<a href="#version-01" class="hash-link" aria-label="Direct link to Version 0.1" title="Direct link to Version 0.1"></a></h3><p><a href="https://github.com/status-im/specs/commit/" target="_blank" rel="noopener noreferrer">Released</a></p><ul><li>Initial version</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="copyright">Copyright<a href="#copyright" class="hash-link" aria-label="Direct link to Copyright" title="Direct link to Copyright"></a></h2><p>Copyright and related rights waived via <a href="https://creativecommons.org/publicdomain/zero/1.0/" target="_blank" rel="noopener noreferrer">CC0</a>.</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="references">References<a href="#references" class="hash-link" aria-label="Direct link to References" title="Direct link to 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" target="_blank" rel="noopener noreferrer">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" target="_blank" rel="noopener noreferrer">Background Execution on iOS</a></li><li><a href="https://firebase.google.com/" target="_blank" rel="noopener noreferrer">Firebase</a></li><li><a href="https://github.com/appleboy/gorush" target="_blank" rel="noopener noreferrer">Gorush</a></li><li><a href="https://tools.ietf.org/html/rfc4122" target="_blank" rel="noopener noreferrer">UUID Specification</a></li><li><a href="/status/deprecated/secure-transport">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" target="_blank" rel="noopener noreferrer">Silent Notifications on iOS</a></li><li><a href="/status/deprecated/waku-usage">Waku Usage</a></li><li><a href="https://github.com/ensdomains/ens" target="_blank" rel="noopener noreferrer">ENS Contract</a></li><li><a href="/status/deprecated/payloads">Payloads</a></li></ul></div></article><nav class="pagination-nav docusaurus-mt-lg" aria-label="Docs pages"><a class="pagination-nav__link pagination-nav__link--prev" href="/status/deprecated/payloads"><div class="icon_S7Kx m_thRi"><svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" role="img"><path d="M11.667 6.417h-7.1l3.261-3.261L7 2.333 2.333 7 7 11.667l.823-.823-3.255-3.26h7.099V6.417Z" fill="#fff"></path></svg></div><span class="lsd-typography lsd-typography--body2 pagination-nav__label">PAYLOADS</span></a><a class="pagination-nav__link pagination-nav__link--next" href="/status/deprecated/secure-transport"><span class="lsd-typography lsd-typography--body2 pagination-nav__label">SECURE-TRANSPORT</span><div class="icon_S7Kx m_thRi"><svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" role="img"><path d="m7 2.333-.823.823 3.255 3.26H2.333v1.167h7.1l-3.256 3.261.823.823L11.667 7 7 2.333Z" fill="#fff"></path></svg></div></a></nav></div></div><div class="gap1_XuuQ"></div><div class="toc_pP_5"><div class="tableOfContents_bqdL thin-scrollbar theme-doc-toc-desktop"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#reason" class="table-of-contents__link toc-highlight">Reason</a></li><li><a href="#requirements" class="table-of-contents__link toc-highlight">Requirements</a></li><li><a href="#components" class="table-of-contents__link toc-highlight">Components</a><ul><li><a href="#gorush-instance" class="table-of-contents__link toc-highlight">Gorush instance</a></li><li><a href="#push-notification-server" class="table-of-contents__link toc-highlight">Push notification server</a></li><li><a href="#registering-client" class="table-of-contents__link toc-highlight">Registering client</a></li><li><a href="#sending-client" class="table-of-contents__link toc-highlight">Sending client</a></li></ul></li><li><a href="#registering-with-the-push-notification-service" class="table-of-contents__link toc-highlight">Registering with the push notification service</a><ul><li><a href="#query-topic" class="table-of-contents__link toc-highlight">Query topic</a></li><li><a href="#server-grant" class="table-of-contents__link toc-highlight">Server grant</a></li></ul></li><li><a href="#re-registering-with-the-push-notification-server" class="table-of-contents__link toc-highlight">Re-registering with the push notification server</a></li><li><a href="#changing-options" class="table-of-contents__link toc-highlight">Changing options</a></li><li><a href="#unregistering-from-push-notifications" class="table-of-contents__link toc-highlight">Unregistering from push notifications</a></li><li><a href="#advertising-a-push-notification-server" class="table-of-contents__link toc-highlight">Advertising a push notification server</a></li><li><a href="#discovering-a-push-notification-server" class="table-of-contents__link toc-highlight">Discovering a push notification server</a></li><li><a href="#querying-the-push-notification-server" class="table-of-contents__link toc-highlight">Querying the push notification server</a></li><li><a href="#sending-a-push-notification" class="table-of-contents__link toc-highlight">Sending a push notification</a></li><li><a href="#flow" class="table-of-contents__link toc-highlight">Flow</a><ul><li><a href="#registration-process" class="table-of-contents__link toc-highlight">Registration process</a></li><li><a href="#sending-a-notification" class="table-of-contents__link toc-highlight">Sending a notification</a></li><li><a href="#receiving-a-push-notification" class="table-of-contents__link toc-highlight">Receiving a push notification</a></li></ul></li><li><a href="#protobuf-description" class="table-of-contents__link toc-highlight">Protobuf description</a><ul><li><a href="#pushnotificationregistration" class="table-of-contents__link toc-highlight">PushNotificationRegistration</a></li><li><a href="#pushnotificationregistrationresponse" class="table-of-contents__link toc-highlight">PushNotificationRegistrationResponse</a></li><li><a href="#contactcodeadvertisement" class="table-of-contents__link toc-highlight">ContactCodeAdvertisement</a></li><li><a href="#pushnotificationquery" class="table-of-contents__link toc-highlight">PushNotificationQuery</a></li><li><a href="#pushnotificationqueryinfo" class="table-of-contents__link toc-highlight">PushNotificationQueryInfo</a></li><li><a href="#pushnotificationqueryresponse" class="table-of-contents__link toc-highlight">PushNotificationQueryResponse</a></li><li><a href="#pushnotification" class="table-of-contents__link toc-highlight">PushNotification</a></li><li><a href="#pushnotificationrequest" class="table-of-contents__link toc-highlight">PushNotificationRequest</a></li><li><a href="#pushnotificationresponse" class="table-of-contents__link toc-highlight">PushNotificationResponse</a></li><li><a href="#pushnotificationreport" class="table-of-contents__link toc-highlight">PushNotificationReport</a></li></ul></li><li><a href="#anonymous-mode-of-operations" class="table-of-contents__link toc-highlight">Anonymous mode of operations</a></li><li><a href="#security-considerations" class="table-of-contents__link toc-highlight">Security considerations</a></li><li><a href="#faq" class="table-of-contents__link toc-highlight">FAQ</a><ul><li><a href="#why-having-acl-done-at-the-server-side-and-not-the-client" class="table-of-contents__link toc-highlight">Why having ACL done at the server side and not the client?</a></li><li><a href="#why-using-an-access-token" class="table-of-contents__link toc-highlight">Why using an access token?</a></li><li><a href="#why-advertise-with-the-bundle" class="table-of-contents__link toc-highlight">Why advertise with the bundle?</a></li><li><a href="#whats-the--bandwidth-impact-for-this" class="table-of-contents__link toc-highlight">What's the bandwidth impact for this?</a></li><li><a href="#whats-the-information-disclosed" class="table-of-contents__link toc-highlight">What's the information disclosed?</a></li><li><a href="#what-prevents-a-user-from-generating-a-random-key-and-getting-an-access-token-and-spamming" class="table-of-contents__link toc-highlight">What prevents a user from generating a random key and getting an access token and spamming?</a></li><li><a href="#why-not-0-knowledge-proofsquantum-computing" class="table-of-contents__link toc-highlight">Why not 0-knowledge proofs/quantum computing</a></li><li><a href="#how-to-handle-backwardforward-compatibility" class="table-of-contents__link toc-highlight">How to handle backward/forward compatibility</a></li><li><a href="#why-ack_key" class="table-of-contents__link toc-highlight">Why ack_key?</a></li><li><a href="#can-i-run-my-own-node" class="table-of-contents__link toc-highlight">Can I run my own node?</a></li><li><a href="#can-i-register-with-multiple-nodes-for-redundancy" class="table-of-contents__link toc-highlight">Can I register with multiple nodes for redundancy</a></li><li><a href="#what-does-my-node-disclose" class="table-of-contents__link toc-highlight">What does my node disclose?</a></li><li><a href="#does-this-have-high-reliability-requirements" class="table-of-contents__link toc-highlight">Does this have high-reliability requirements?</a></li><li><a href="#can-someone-else-ie-not-status-run-this" class="table-of-contents__link toc-highlight">Can someone else (i.e not status) run this?</a></li></ul></li><li><a href="#changelog" class="table-of-contents__link toc-highlight">Changelog</a><ul><li><a href="#version-01" class="table-of-contents__link toc-highlight">Version 0.1</a></li></ul></li><li><a href="#copyright" class="table-of-contents__link toc-highlight">Copyright</a></li><li><a href="#references" class="table-of-contents__link toc-highlight">References</a></li></ul></div></div></div></div></main></div></div><footer class="footer"><div class="container container-fluid firstRow_ar1q"><div class="footer__bottom text--center"><div class="margin-bottom--sm"><a class="footerLogoLink_BH7S" href="/"><img src="/theme/image/logo.svg" alt="Vac Research" class="themedImage_kfRS themedImage--light_BL8e footer__logo" width="22"><img src="/theme/image/logo.svg" alt="Vac Research" class="themedImage_kfRS themedImage--dark_OvIx footer__logo" width="22"></a></div><div class="footer__copyright">Vac @2025<br>All Rights Reserved.</div></div><div class="row footer__links"><div class="col footer__col"><div class="footer__title"></div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://x.com/vacp2p" target="_blank" rel="noopener noreferrer" class="footer__link-item">Twitter<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://discord.gg/PQFdubGt6d" target="_blank" rel="noopener noreferrer" class="footer__link-item">Discord<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://github.com/vacp2p" target="_blank" rel="noopener noreferrer" class="footer__link-item">Github<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li></ul></div><div class="col footer__col"><div class="footer__title"></div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://jobs.status.im/" target="_blank" rel="noopener noreferrer" class="footer__link-item">Work with us<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a class="footer__link-item" href="/terms">Terms & conditions</a></li><li class="footer__item"><a class="footer__link-item" href="/privacy-policy">Privacy Policy</a></li><li class="footer__item"><a class="footer__link-item" href="/security">Security</a></li></ul></div></div></div><div class="secondRow__ww3"><span class="footer__bottom text--center">Built by <a href="https://free.technology/" target="_blank" class="footerLink_sh7M">IFT</a></span><div class="row footer__links"><div class="col footer__col"><div class="footer__title">Research</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://vac.dev" target="_blank" rel="noopener noreferrer" class="footer__link-item">VacP2P<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://afaik.institute" target="_blank" rel="noopener noreferrer" class="footer__link-item">AFAIK<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li></ul></div><div class="col footer__col"><div class="footer__title">Infrastructure</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://waku.org/" target="_blank" rel="noopener noreferrer" class="footer__link-item">Waku<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://nimbus.team/" target="_blank" rel="noopener noreferrer" class="footer__link-item">Nimbus<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://codex.storage" target="_blank" rel="noopener noreferrer" class="footer__link-item">Codex<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://nomos.tech" target="_blank" rel="noopener noreferrer" class="footer__link-item">Nomos<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li></ul></div><div class="col footer__col"><div class="footer__title">Creative Studio</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://acid.info" target="_blank" rel="noopener noreferrer" class="footer__link-item">Acid.info<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li></ul></div><div class="col footer__col"><div class="footer__title">Movement</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://logos.co" target="_blank" rel="noopener noreferrer" class="footer__link-item">Logos<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li></ul></div><div class="col footer__col"><div class="footer__title">User-facing products</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://status.im" target="_blank" rel="noopener noreferrer" class="footer__link-item">Status<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://keycard.tech" target="_blank" rel="noopener noreferrer" class="footer__link-item">Keycard<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li></ul></div></div></div><button class="backToTop_wDfN lsd-button lsd-button--small lsd-button--outlined"><span class="lsd-typography lsd-typography--label2 lsd-button__text">Back to top ↑</span></button></footer></div></div>
|
||
<script src="/assets/js/runtime~main.db01e95f.js"></script>
|
||
<script src="/assets/js/main.7bd63d25.js"></script>
|
||
</body>
|
||
</html> |