1
0
mirror of https://github.com/moparisthebest/xeps synced 2024-11-21 08:45:04 -05:00

Merge branch 'master' into reaction-restriction

This commit is contained in:
Kevin Smith 2023-02-28 17:41:41 +00:00 committed by GitHub
commit 483841b27c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 3464 additions and 122 deletions

35
.github/workflows/xep-validation.yml vendored Normal file
View File

@ -0,0 +1,35 @@
name: XEP validation
on:
pull_request:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
name: Validate any XEP changes
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Detect changes to XEP files
id: changed-xeps
uses: tj-actions/changed-files@v34
with:
files: |
xep-*.xml
inbox/*
- name: Validate changed file(s)
if: steps.changed-xeps.outputs.any_changed == 'true'
run: |
sudo apt-get install -y libxml2-utils
result=0
for xep in "${{ steps.changed-xeps.outputs.all_changed_files }}"; do
if ! tools/validate-xep0001-conformance.sh "$xep"; then
result=1
fi
done
exit $result

View File

@ -50,6 +50,6 @@ possibility of such damages.
This XMPP Extension Protocol has been contributed in full conformance
with the XSF's Intellectual Property Rights Policy (a copy of which may
be found at http://www.xmpp.org/extensions/ipr-policy.shtml or obtained
be found at https://xmpp.org/about/xsf/ipr-policy/ or obtained
by writing to XSF, P.O. Box 1641, Denver, CO 80201 USA).

View File

@ -97,7 +97,7 @@ $(all_xep_xmls): $(OUTDIR)/%.xml: %.xml $(XMLDEPS)
$(OUTDIR)/xep.xsl: xep.xsl $(OUTDIR)
cp $< $@
$(OUTDIR)/xeplist.xml: $(wildcard *.xml) $(wildcard inbox/*.xml)
$(OUTDIR)/xeplist.xml: $(wildcard *.xml) $(wildcard inbox/*.xml) $(OUTDIR)
./tools/extract-metadata.py > $@
$(EXAMPLESDIR)/%.xml: xep-%.xml $(XMLDEPS) examples.xsl | $(EXAMPLESDIR)

View File

@ -135,9 +135,9 @@ If the PR is not touching a XEP, this guide does not apply.
1. Make sure the standards@ discussion (if it exists) is linked in the
PR.
2. Add the [Needs Author] label.
3. Try to make the XEP Author aware of the change. If you do not know
a GitHub handle of the XEP Author, use the contact info available
for each author in either the XEP or in xep.ent.
3. Try to make the XEP Author aware of the change. Do this with an email to
the author (use the contact info available for each author in either the
XEP or in xep.ent) and cc: standards@.
4. Stop.
5. Otherwise, mark the PR as [Ready to Merge], linking the XEP Authors

595
inbox/cs-2023.xml Normal file
View File

@ -0,0 +1,595 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE xep SYSTEM 'xep.dtd' [
<!ENTITY % ents SYSTEM 'xep.ent'>
%ents;
<!ENTITY component "<note>Support can be enabled via an external component or an internal server module/plugin. If claiming compliance using such an addition, the necessary components/modules/plugins MUST be detailed.</note>">
<!ENTITY usecases "<note>Support for the Entity Use Cases and Occupant Use Cases is REQUIRED; support for the remaining use cases is RECOMMENDED.</note>">
<!ENTITY onlyone "<note>Only one of the recommended providers must be implemented for compliance.</note>">
<!ENTITY nocli "<note>Not required for command line or terminal based interfaces.</note>">
<!ENTITY avatar "<note>While 'User Avatars' is more modern, 'vCard-Based Avatars' is more widely deployed. Although it is suggested that to maximise interoperability with existing software a client fully supports both it is sufficient to claim compliance with this suite if the support for 'vCard-Based Avatars' is read-only.</note>">
<!ENTITY pubsubjid "<note>While 'Personal Eventing Protocol' does not require all the features of 'Publish-Subscribe' to be available on the users' JIDs, and nor does this suite, it is desirable for this to be the case and it is expected that this will a requirement of future Compliance Suites.</note>">
<!ENTITY yes "&#10003;">
<!ENTITY no "&#10005;">
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
<xep>
<header>
<title>XMPP Compliance Suites 2023</title>
<abstract>
This document defines XMPP application categories for different use cases
(Core, Web, IM, and Mobile), and specifies the required XEPs that client and
server software needs to implement for compliance with the use cases.
</abstract>
&LEGALNOTICE;
<number>XXXX</number>
<status>ProtoXEP</status>
<type>Standards Track</type>
<sig>Standards</sig>
<approver>Council</approver>
<dependencies>
<spec>RFC 6120</spec>
<spec>RFC 6121</spec>
<spec>RFC 7395</spec>
<spec>RFC 7590</spec>
<spec>RFC 7622</spec>
<spec>XEP-0030</spec>
<spec>XEP-0045</spec>
<spec>XEP-0048</spec>
<spec>XEP-0049</spec>
<spec>XEP-0084</spec>
<spec>XEP-0085</spec>
<spec>XEP-0114</spec>
<spec>XEP-0115</spec>
<spec>XEP-0124</spec>
<spec>XEP-0163</spec>
<spec>XEP-0191</spec>
<spec>XEP-0198</spec>
<spec>XEP-0206</spec>
<spec>XEP-0223</spec>
<spec>XEP-0249</spec>
<spec>XEP-0280</spec>
<spec>XEP-0313</spec>
<spec>XEP-0352</spec>
<spec>XEP-0368</spec>
<spec>XEP-0402</spec>
</dependencies>
<supersedes>
<spec>XEP-0459</spec>
</supersedes>
<supersededby/>
<shortname>CS2023</shortname>
<author>
<firstname>Georg</firstname>
<surname>Lukas</surname>
<email>georg@op-co.de</email>
<jid>georg@yax.im</jid>
</author>
<revision>
<version>0.0.1</version>
<date>2023-01-25</date>
<initials>gl</initials>
<remark>
<p>First draft based on XEP-0459.</p>
</remark>
</revision>
</header>
<section1 topic='Introduction' anchor='intro'>
<p>
There is a growing number of XMPP Extension Protocols (XEPs) that provide
different building blocks for XMPP-based applications. XMPP software
developers are confronted with the challenge of finding the right
combination of XEPs for a given application profile. Users need a way to
compare applications without resorting to comparing for individual XEP
numbers.
</p>
<p>
This document defines XMPP application <strong>Categories</strong> based on
typical use cases (Core, Web, IM, Mobile) and <strong>Levels</strong>
(Core, Advanced) based on functionality in the respective category. For
each combination of those, the required XEPs are referenced. As the
protocol landscape changes over time, this document is updated roughly
once a year.
</p>
<p>
For developers, this document provides guidance on which specifications
they need to consider when implementing an application of a certain kind.
By completing a compliance test or performing a self-assessment, they can
advertise their implementation as compliant with a given Category and
Level.
</p>
<p>
For users, this provides an easy way to compare implementations based on
their respective advertised compliance levels and year.
</p>
<p>
Unless explicitly noted, support for the listed specifications is REQUIRED
for compliance purposes.
A feature is considered supported if all comma separated feature providers
listed in the "Providers" column are implemented (unless otherwise noted).
</p>
<section2 topic='Changes since 2022' anchor='changes-2022'>
<p>The following changes were made to the Compliance Suites since &xep0459;:</p>
<p>None.</p>
</section2>
<section2 topic='Changes since 2021' anchor='changes-2021'>
<p>The following changes were made to the Compliance Suites since &xep0443;:</p>
<ul>
<li>Renamed "Core Client" and "Core Server" to "Client" and "Server"</li>
<li>Web category:
<ul>
<li>Client: required Connection Mechanism Discovery.</li>
</ul>
</li>
<li>IM category:
<ul>
<li>Advanced Group Chat: replaced &xep0411; with &xep0402; conversion</li>
</ul>
</li>
</ul>
</section2>
<section2 topic='Changes since 2020' anchor='changes-2020'>
<p>The following changes were made to the Compliance Suites since &xep0423;:</p>
<ul>
<li>Introduced new category for <link url='#av'>A/V Calling</link>.</li>
<li>IM Category:
<ul>
<li>Specifications of note: added &xep0393;, &xep0433;, &xep0424;, and &xep0425;</li>
</ul>
</li>
</ul>
</section2>
<section2 topic='Changes since 2019' anchor='changes'>
<p>The following changes were made to the Compliance Suites since &xep0412;:</p>
<ul>
<li>IM Category:
<ul>
<li>Client: added &xep0245;</li>
<li>Client and Server: added &xep0363;</li>
<li>Advanced Client: added &xep0234;, &xep0261;</li>
<li>Advanced Client and Server: added &xep0411;</li>
<li>Specifications of note: added &xep0077; and &xep0157;, &xep0392;, &xep0066; and &xep0385;</li>
</ul>
</li>
<li>Mobile Category:
<ul>
<li>Specifications of note: added &xep0286;</li>
</ul>
</li>
<li>Web Category:
<ul>
<li>Advanced Web: added &xep0156;</li>
</ul>
</li>
</ul>
</section2>
</section1>
<section1 topic='Compliance Categories' anchor='categories'>
<section2 topic='Core Compliance Suite' anchor='core'>
<table caption='XMPP Core Compliance Levels'>
<tr>
<th>Feature</th>
<th>Server</th>
<th>Client</th>
<th>Advanced Server</th>
<th>Advanced Client</th>
<th>Providers</th>
</tr>
<tr>
<td><strong>Core features</strong></td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td>&rfc6120; <note>&rfc7622; is not listed due to the unclear interoperability impact of using PRECIS and Stringprep in the same ecosystem.</note></td>
</tr>
<tr>
<td><strong>TLS</strong></td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td>&rfc7590;</td>
</tr>
<tr>
<td><strong>Direct TLS</strong></td>
<td align='center'>&no;</td>
<td align='center'>&no;</td>
<td align='center'>&yes;<note>Server support of XEP-0368 means having the ability to accept direct TLS connections.</note></td>
<td align='center'>&yes;</td>
<td>&xep0368;</td>
</tr>
<tr>
<td><strong>Feature discovery</strong></td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td>&xep0030;</td>
</tr>
<tr>
<td><strong>Feature broadcasts</strong></td>
<td align='center'>&no;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td>&xep0115;</td>
</tr>
<tr>
<td><strong>Server Extensibility</strong></td>
<td align='center'>&yes;</td>
<td align='center'>N/A</td>
<td align='center'>&yes;</td>
<td align='center'>N/A</td>
<td>&xep0114;</td>
</tr>
<tr>
<td><strong>Event publishing</strong></td>
<td align='center'>&no;</td>
<td align='center'>&no;</td>
<td align='center'>&yes;&pubsubjid;</td>
<td align='center'>&yes;</td>
<td>&xep0163;</td>
</tr>
</table>
</section2>
<section2 topic='Web Compliance Suite' anchor='web'>
<p>
To be considered XMPP web compliant, all features from the core
compliance category must be met, as well as all features in this suite.
</p>
<table caption='XMPP Web Compliance Levels'>
<tr>
<th>Feature</th>
<th>Server</th>
<th>Client</th>
<th>Advanced Server</th>
<th>Advanced Client</th>
<th>Providers</th>
</tr>
<tr>
<td><strong>Web Connection Mechanisms</strong></td>
<td align='center'>&yes;&component;</td>
<td align='center'>&yes;&onlyone;</td>
<td align='center'>&yes;&component;</td>
<td align='center'>&yes;&onlyone;</td>
<td>&rfc7395;, &xep0206; (See also: &xep0124;)</td>
</tr>
<tr>
<td><strong>Connection Mechanism Discovery</strong></td>
<td align='center'>&no;</td>
<td align='center'>&yes;</td>
<td align='center'>N/A</td>
<td align='center'>&yes;</td>
<td>&xep0156;</td>
</tr>
</table>
</section2>
<section2 topic='IM Compliance Suite' anchor='im'>
<p>
To be considered XMPP IM compliant, all features from the core
compliance category must be met, as well as all features in this suite.
</p>
<table caption='XMPP IM Compliance Levels'>
<tr>
<th>Feature</th>
<th>Server</th>
<th>Client</th>
<th>Advanced Server</th>
<th>Advanced Client</th>
<th>Providers</th>
</tr>
<tr>
<td><strong>Core features</strong></td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td>&rfc6121;</td>
</tr>
<tr>
<td><strong>The /me Command</strong></td>
<td align='center'>N/A</td>
<td align='center'>&yes;</td>
<td align='center'>N/A</td>
<td align='center'>&yes;</td>
<td>&xep0245;</td>
</tr>
<tr>
<td><strong>User Avatars</strong></td>
<td align='center'>N/A</td>
<td align='center'>&no;</td>
<td align='center'>N/A</td>
<td align='center'>&yes;&nocli;</td>
<td>&xep0084;</td>
</tr>
<tr>
<td><strong>User Avatar Compatibility</strong></td>
<td align='center'>&no;</td>
<td align='center'>&no;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;&nocli;</td>
<td>&xep0398;, &xep0153;</td>
</tr>
<tr>
<td><strong>vcard-temp</strong></td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td>&xep0054;</td>
</tr>
<tr>
<td><strong>Outbound Message Synchronization</strong></td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td>&xep0280;</td>
</tr>
<tr>
<td><strong>User Blocking</strong></td>
<td align='center'>&no;</td>
<td align='center'>&no;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td>&xep0191;</td>
</tr>
<tr>
<td><strong>Group Chat</strong></td>
<td align='center'>&yes;&component;</td>
<td align='center'>&yes;&usecases;</td>
<td align='center'>&yes;&component;</td>
<td align='center'>&yes;&usecases;</td>
<td>&xep0045;<note>Implementations should take note that future versions of these compliance suites may rely on &xep0369; instead.</note>, &xep0249;</td>
</tr>
<tr>
<td><strong>Advanced Group Chat</strong></td>
<td align='center'>&no;</td>
<td align='center'>&no;</td>
<td align='center'>&yes;&component;</td>
<td align='center'>&yes;</td>
<td>&xep0048;, &xep0313;<note>Support for requesting history from a MUC archive as opposed to from the user's account.</note>, &xep0402;<note>Usage of which should only happen when the 'urn:xmpp:bookmarks:1#compat' is exposed by the server, otherwise &xep0049; should be used instead.</note>, &xep0410;</td>
</tr>
<tr>
<td><strong>Persistent Storage of Private Data via PubSub</strong></td>
<td align='center'>&no;</td>
<td align='center'>&no;</td>
<td align='center'>&yes;&component;</td>
<td align='center'>&yes;</td>
<td>&xep0223;</td>
</tr>
<tr>
<td><strong>Private XML Storage</strong></td>
<td align='center'>&no;</td>
<td align='center'>&no;</td>
<td align='center'>&yes;&component;</td>
<td align='center'>&yes;</td>
<td>&xep0049; (only recommended for legacy bookmarks support)</td>
</tr>
<tr>
<td><strong>Stream Management</strong></td>
<td align='center'>&no;</td>
<td align='center'>&no;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td>&xep0198;</td>
</tr>
<tr>
<td><strong>Message Acknowledgements</strong></td>
<td align='center'>N/A</td>
<td align='center'>&no;</td>
<td align='center'>N/A</td>
<td align='center'>&yes;</td>
<td>&xep0184;</td>
</tr>
<tr>
<td><strong>History Storage / Retrieval</strong></td>
<td align='center'>&no;</td>
<td align='center'>&no;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td>&xep0313;</td>
</tr>
<tr>
<td><strong>Chat States</strong></td>
<td align='center'>N/A</td>
<td align='center'>&no;</td>
<td align='center'>N/A</td>
<td align='center'>&yes;</td>
<td>&xep0085;</td>
</tr>
<tr>
<td><strong>Message Correction</strong></td>
<td align='center'>N/A</td>
<td align='center'>&no;</td>
<td align='center'>N/A</td>
<td align='center'>&yes;</td>
<td>&xep0308;</td>
</tr>
<tr>
<td><strong>File Upload</strong></td>
<td align='center'>&yes;&component;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;&component;</td>
<td align='center'>&yes;</td>
<td>&xep0363;</td>
</tr>
<tr>
<td><strong>Direct File Transfer</strong></td>
<td align='center'>N/A</td>
<td align='center'>&no;</td>
<td align='center'>N/A</td>
<td align='center'>&yes;</td>
<td>&xep0234;, &xep0261;</td>
</tr>
</table>
<p>
Further specifications of note, which are not required for compliance:
</p>
<ul>
<li>For public IM networks: &xep0077; (should be supported, but not enabled in default server configurations) and &xep0157;</li>
<li>File uploads should be indicated using &xep0066;, optionally also using &xep0385;</li>
<li>&xep0392; for cross-client consistency of user names</li>
<li>&xep0393; for simple styling of plaintext messages that is loosely compatible with legacy IM networks</li>
<li>&xep0433; to improve the discovery of public rooms hosted on a domain</li>
<li>&xep0424; and &xep0425; for managing misbehavior in public rooms</li>
</ul>
</section2>
<section2 topic='Mobile Compliance Suite' anchor='mobile'>
<p>
To be considered XMPP mobile compliant, all features from the core
compliance category must be met, as well as all features in this suite.
</p>
<table caption='XMPP Mobile Compliance Levels'>
<tr>
<th>Feature</th>
<th>Server</th>
<th>Client</th>
<th>Advanced Server</th>
<th>Advanced Client</th>
<th>Providers</th>
</tr>
<tr>
<td><strong>Stream Management</strong></td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td>&xep0198;</td>
</tr>
<tr>
<td><strong>Client State Indication</strong></td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td>&xep0352;</td>
</tr>
<tr>
<td><strong>Third Party Push Notifications</strong></td>
<td align='center'>&no;</td>
<td align='center'>&no;</td>
<td align='center'>&yes;&component;</td>
<td align='center'>&yes;<note>Only on platforms that disallow long-lasting background connections.</note></td>
<td>&xep0357;</td>
</tr>
</table>
<p>
Further specifications of note, which are not required for compliance:
</p>
<ul>
<li>&xep0286;</li>
</ul>
</section2>
<section2 topic='A/V Calling Compliance Suite' anchor='av'>
<p>
To be considered XMPP A/V calling compliant, all features from the core
compliance category must be met, as well as all features in this suite.
</p>
<table caption='A/V Calling Compliance Levels'>
<tr>
<th>Feature</th>
<th>Server</th>
<th>Client</th>
<th>Advanced Server</th>
<th>Advanced Client</th>
<th>Providers</th>
</tr>
<tr>
<td><strong>Call Setup</strong></td>
<td align='center'>N/A</td>
<td align='center'>&yes;</td>
<td align='center'>N/A</td>
<td align='center'>&yes;</td>
<td>&xep0167;, &xep0353;</td>
</tr>
<tr>
<td><strong>Transport</strong></td>
<td align='center'>N/A</td>
<td align='center'>&yes;</td>
<td align='center'>N/A</td>
<td align='center'>&yes;</td>
<td>&xep0176;</td>
</tr>
<tr>
<td><strong>Encryption</strong></td>
<td align='center'>N/A</td>
<td align='center'>&yes;</td>
<td align='center'>N/A</td>
<td align='center'>&yes;</td>
<td>&xep0320;</td>
</tr>
<tr>
<td><strong>STUN/TURN server discovery</strong></td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td align='center'>&yes;</td>
<td>&xep0215;</td>
</tr>
<tr>
<td><strong>Quality and Performance improvements</strong></td>
<td align='center'>N/A</td>
<td align='center'>&no;</td>
<td align='center'>N/A</td>
<td align='center'>&yes;</td>
<td>&xep0293;, &xep0294;, &xep0338;, &xep0339;</td>
</tr>
</table>
</section2>
</section1>
<section1 topic='Future Development' anchor='future'>
<p>This section outlines the protocol specifications that are relevant for
developers, but are not ready yet to be required for Compliance.
Developers are encouraged to implement those and
to share their experience and feedback.</p>
<ul>
<li>Client connection optimizations: &xep0386; and &xep0409;, maybe also &xep0397;</li>
<li>Improved on-boarding of new users:
<ul>
<li>&xep0401; to create account invitations</li>
<li>&xep0379; for contact invitations</li>
<li>&xep0445; to register accounts based on an invitation</li>
</ul>
</li>
<li>&xep0333;</li>
<li>&xep0369;</li>
<li>End-to-End Encryption (E2EE): &xep0380; for tagging encrypted messages, &xep0420; to protect all payloads; and also one or multiple of the following for actual encryption:
<ul>
<li>&xep0384; and &xep0396;</li>
<li>&xep0374;</li>
</ul>
</li>
<li>&xep0402; to phase out &xep0048; and &xep0049;</li>
<li>&xep0225; to phase out &xep0114;</li>
<li>&xep0390; to phase out &xep0115;</li>
<li>&xep0455;</li>
</ul>
</section1>
<section1 topic='Implementation Notes' anchor='impl'>
<p>
Some of the protocol specifications referenced herein have their own
dependencies; developers need to consult the relevant specifications for
further information.
</p>
</section1>
<section1 topic='Security Considerations' anchor='security'>
<p>
This document introduces no additional security considerations above and
beyond those defined in the documents on which it depends.
</p>
</section1>
<section1 topic='IANA Considerations' anchor='iana'>
<p>This document requires no interaction with &IANA;.</p>
</section1>
<section1 topic='XMPP Registrar Considerations' anchor='registrar'>
<p>This document requires no interaction with the &REGISTRAR;.</p>
</section1>
<section1 topic='Acknowledgements' anchor='ack'>
<p>
The author would like to thank Guus der Kinderen, Dele Olajide, Marc
Laporte, Dave Cridland, Daniel Gultsch, Florian Schmaus, Tobias Markmann,
and Jonas Schäfer for their suggestions.
</p>
</section1>
</xep>

126
inbox/xep-sla.xml Normal file
View File

@ -0,0 +1,126 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE xep SYSTEM 'xep.dtd' [
<!ENTITY % ents SYSTEM 'xep.ent'>
%ents;
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
<xep>
<header>
<title>Stream Limits Advertisement</title>
<abstract>This specification defines a way for an XMPP entity to announce the limits it will enforce for data received on a stream.</abstract>
&LEGALNOTICE;
<number>xxxx</number>
<status>ProtoXEP</status>
<type>Standards Track</type>
<sig>Standards</sig>
<approver>Council</approver>
<dependencies>
<spec>XMPP Core</spec>
</dependencies>
<supersedes/>
<supersededby/>
<shortname>sla</shortname>
<author>
<firstname>Kim</firstname>
<surname>Alvefur</surname>
<email>zash@zash.se</email>
<jid>zash@zash.se</jid>
</author>
&mwild;
<revision>
<version>0.0.1</version>
<date>2022-10-20</date>
<initials>ka, mw</initials>
<remark><p>First draft.</p></remark>
</revision>
</header>
<section1 topic='Introduction' anchor='intro'>
<p>This documents describes a mechanism for communicating limits, such as stanza size limits that is in effect on a particular stream, in order to allow the sending party to avoid reaching those limits.</p>
<section2 topic='Problem statement' anchor='intro-problem'>
<p>Where stanza size limits have been deployed, very often this leads to problems with large stanzas causing connection outages, most often &xep0084; and &xep0053; result stanzas, which can be very large due to embedded images.</p>
<p>If stanza size limit violations are met with stream errors then this may lead to temporary connection outage, which may a few seconds to recover from.</p>
</section2>
</section1>
<section1 topic='Requirements' anchor='reqs'>
<ul>
<li>Enable discovery of the stanza size limit in use on a stream.</li>
<li>Support for bi-directional streams.</li>
</ul>
<p>These requirements will enable XMPP clients and servers to adapt data they generate, such that it will fit within the limits required by the recipient, or reject overly large stanzas early, rather than following a trial-and-error approach.</p>
</section1>
<section1 topic='Use Cases' anchor='usecases'>
<section2 topic='Server advertises limits to connecting entity' anchor='advertise'>
<p>For any XMPP stream, there is an "initiating entity" (a client or server) and a "responding entity" that they are connecting to. The responding entity advertises its limits in the &lt;stream:features/> element that it sends at the start of the stream.</p>
<p>The limits are enclosed in a &lt;limits/> element qualified by the 'urn:xmpp:stream-limits:0' namespace. This element SHOULD contain the following child elements:</p>
<dl>
<di>
<dt>&lt;max-bytes/></dt>
<dd>Contains an integer representing the maximum size of any first-level stream elements (including stanzas), in bytes the announcing entity is willing to accept. Guidance on acceptable limits is provided in &rfc6120; section 13.12.</dd>
</di>
<di>
<dt>&lt;idle-seconds/></dt>
<dd>Contains an integer representing the number of seconds without any traffic from the iniating entity after which the server may consider the stream idle, and either perform liveness checks (using e.g. &xep0198; or &xep0199;) or terminate the stream. Guidance on handling idle connections is provided in &rfc6120; section 4.6.</dd>
</di>
</dl>
<example caption='Advertising limits to connecting entity'><![CDATA[
<stream:features>
<mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
<mechanism>SCRAM-SHA-1</mechanism>
<mechanism>PLAIN</mechanism>
</mechanisms>
<limits xmlns="urn:xmpp:stream-limits:0">
<max-bytes>10000</max-bytes>
<idle-seconds>1800</idle-seconds>
</limits>
</stream:features>
]]></example>
</section2>
<section2 topic='Connecting server announces limits on bidirectional stream' anchor='advertise-bidi'>
<p>Servers using &xep0288; to establish a bidirectional stream with another server do not get an opportunity to send &lt;stream:features/> to the responding entity. For a server to advertise the limits about what it is willing to accept on such a stream, the &lt;limits/> element can be included in the &lt;bidi/> element.</p>
<example caption='Advertising limits to responding entity over bidirectional stream'><![CDATA[
<bidi xmlns='urn:xmpp:bidi'>
<limits xmlns="urn:xmpp:stream-limits:0">
<max-bytes>10000</max-bytes>
<idle-seconds>1800</idle-seconds>
</limits>
</bidi>
]]></example>
</section2>
</section1>
<section1 topic='Business Rules' anchor='rules'>
<p>If, after serialization, a stanza exceeds the limits that have been advertised on a stream, it SHOULD NOT be sent on that stream. Instead, a server SHOULD return an error to the sender. Such an error SHOULD contain the &lt;policy-violation/> error condition, and SHOULD NOT contain a 'by' attribute (as the policy being violated is not the current entity's). A &lt;text/> may also be included, explaining the limit that would be exceeded.</p>
<p>It is acceptable for the limits on a stream to change whenever new stream features are announced - such as before and after authentication of the connecting entity.</p>
</section1>
<section1 topic='Implementation Notes' anchor='impl'>
<p>OPTIONAL.</p>
</section1>
<section1 topic='Accessibility Considerations' anchor='access'>
<p>OPTIONAL.</p>
</section1>
<section1 topic='Internationalization Considerations' anchor='i18n'>
<p>OPTIONAL.</p>
</section1>
<section1 topic='Security Considerations' anchor='security'>
<p>REQUIRED.</p>
<p>Very large stanzas may incur memory and processing costs on the receiving entity. Advertising the actual limits could inform an attacker of how large a stanza to construct in order to maximize e.g. DoS effectiveness. Best combined with network level rate limits on raw bytes.</p>
</section1>
<section1 topic='IANA Considerations' anchor='iana'>
<p>None.</p>
</section1>
<section1 topic='XMPP Registrar Considerations' anchor='registrar'>
<p>This specification defines the following namespace:</p>
<ul>
<li>urn:xmpp:stream-limits:0</li>
</ul>
<p>Also, the following stream feature:</p>
<ul>
<li><code>&lt;limits xmlns='urn:xmpp:stream-limits:0'/></code></li>
</ul>
</section1>
<section1 topic='Design Considerations' anchor='design'>
<p>The ability for a client to announce limits on what it will receive on a client-to-server stream is deliberately not provided by this specification. This vastly simplifies discovery of the maximum limits between any two JIDs, and it avoids situations where the server is unable to deliver incoming stanzas to some or all of an account's connected clients. Clients will already be protected from denial-of-service through excessive stanza sizes due to the server's own limits.</p>
</section1>
<section1 topic='XML Schema' anchor='schema'>
<p>TBD.</p>
</section1>
</xep>

View File

@ -115,7 +115,7 @@ function Doc(body, metadata, variables)
end
add("</remark>");
else
add(("<%s>%s</%s>"):format(field, tostring(sv), field));
add(tostring(sv));
end
add(string.format("</%s>", field));
end

View File

@ -101,6 +101,12 @@ def extract_xep_metadata(document):
else:
last_call = None
tags = []
tags_elem = minidom_find_child(header, "tags")
if tags_elem is not None:
for child in minidom_children(tags_elem):
tags.append(minidom_get_text(child))
return {
"last_revision": {
"version": last_revision_version,
@ -113,6 +119,7 @@ def extract_xep_metadata(document):
"sig": sig,
"abstract": abstract,
"shortname": shortname,
"tags": tags,
"title": title,
"approver": approver,
"last_call": last_call,
@ -137,6 +144,12 @@ def make_metadata_element(number, metadata, accepted, *, protoname=None):
if metadata["shortname"] is not None:
result.append(text_element("shortname", metadata["shortname"]))
if metadata["tags"]:
tags = etree.Element("tags")
for tag in metadata["tags"]:
tags.append(text_element("tag", tag))
result.append(tags)
if metadata["last_revision"]["version"] is not None:
last_revision = metadata["last_revision"]
revision_el = etree.Element("last-revision")

207
tools/triage.sh Executable file
View File

@ -0,0 +1,207 @@
#!/bin/bash
# this should enforce as much of docs/TRIAGING.md as possible, run in top directory of xeps repo
# usage: triage.sh $pr_title [$pr_commit] [$merge_base]
# the last two will be HEAD and `git merge-base $pr_commit master` by default if not sent in
# for testing you can:
# git fetch origin +refs/pull/1254/merge
# git checkout FETCH_HEAD
# and only send in pr_title
# test cases:
# multiple xeps changed: git checkout 58cec1b6fb30ccc3b44c9dff34b94f53e958c1ac; ./tools/triage.sh 'XEP-0072, XEP-0096, XEP-0214: fix xmlns in sipub examples' 58cec1b6fb30ccc3b44c9dff34b94f53e958c1ac e4d3f721c2cf9fc7ed42c3428d098b2b3be3c8ed
# protoxep: git fetch origin +refs/pull/1254/merge; git checkout FETCH_HEAD; ./tools/triage.sh "ProtoXEP: Stream Limits Advertisement"
# one xep changed: git fetch origin +refs/pull/1249/merge; git checkout FETCH_HEAD; ./tools/triage.sh 'XEP-0444: bla'
set -euo pipefail
pr_title="$1"
shift
pr_commit=""
if [ $# -ge 1 ]
then
pr_commit="$1"
shift
else
pr_commit="HEAD"
fi
merge_base=""
if [ $# -ge 1 ]
then
merge_base="$1"
shift
else
merge_base="$(git merge-base "$pr_commit" master)"
fi
xpath() {
set -euo pipefail
xmllint --nonet --noent --xpath "$2" "$1" --nowarning --dtdvalid xep.dtd
}
files_changed="$(git --no-pager diff --name-only "$pr_commit" "$merge_base")"
set +e
protoxep="$(echo "$files_changed" | grep -E '^inbox/[^.]+.xml$')"
num_protoxeps=$(echo "$protoxep" | grep -v '^$' | wc -l)
xeps_changed="$(echo "$files_changed" | grep -E '^xep-[0-9]{4}.xml$')"
xep_likes_changed="$(echo "$files_changed" | grep -E '^xep-[^.]+.xml$')"
num_xeps_changed=$(echo "$xeps_changed" | grep -v '^$' | wc -l)
set -e
if [ $num_protoxeps -ge 1 ]
then
if [ $num_xeps_changed -ne 0 ]
then
echo "error: cannot change xeps and add ProtoXEP in 1 PR"
exit 1
fi
# we are dealing with a protoxep here
echo "tag: protoxep"
if [ $num_protoxeps -ne 1 ]
then
echo "tag: split-pr"
echo "error: multiple ProtoXEPs cannot be created in 1 PR"
exit 1
fi
expected_title="ProtoXEP: $(xpath "$protoxep" '/xep/header/title/text()')"
if [ "$pr_title" != "$expected_title" ]
then
echo "tag: bad-title"
echo "warning: expected title '$expected_title' got title '$pr_title'"
fi
echo "tag: ready-to-merge"
echo "manual: be sure type '$(xpath "$protoxep" '/xep/header/type/text()')' is appropriate for XEP content"
exit 0
fi
# we are *not* dealing with a protoxep here
if [ "$xeps_changed" != "$xep_likes_changed" ]
then
echo "error: xep files created/changed but named incorrectly: $(echo "$xep_likes_changed" | tr '\n' ' ')"
exit 0
fi
if [ $num_xeps_changed -eq 0 ]
then
# some tag for this? tooling changes?
echo "manual: no XEPs changed"
exit 0
fi
if [ $num_xeps_changed -gt 1 ]
then
echo "manual: multiple XEPs changed, split?"
fi
all_approvers=""
# a super approver can approve this entire PR, because they are author on all XEPs touched
super_approvers=""
for xep in $xeps_changed
do
xep_num="XEP-$(echo "$xep" | grep -Eo '[0-9]{4}')"
if ! echo "$pr_title" | grep "$xep_num" &>/dev/null
then
echo "error: title did not include '$xep_num'"
exit 1
fi
status="$(xpath "$xep" '/xep/header/status/text()')"
approvers=""
if echo "$status" | grep -E '^(Experimental|Deferred)$' &>/dev/null
then
# Experimental or Deferred
if [ "$status" == 'Deferred' ]
then
echo "tag: needs-editor-action"
echo "manual: move $xep_num status to Experimental before or with merge"
fi
approvers="$(xpath "$xep" '/xep/header/author/email/text()' | sort -u)"
else
# *not* Experimental or Deferred
approvers="$(xpath "$xep" '/xep/header/approver/text()' 2>/dev/null || echo 'Unknown')"
fi
echo "info: $xep_num status '$status' needs approvers: '$(echo "$approvers" | tr '\n' ' ' | xargs)'"
new_all_approvers="$(echo -e "$all_approvers\n$approvers" | sort -u)"
if [ "$all_approvers" != "$new_all_approvers" ]
then
# this isn't technically a problem if they all have an approver in common, ie super_approvers is non-empty, suppress warning?
if [ "$all_approvers" != "" ]
then
echo "manual: multiple XEPs modified with different approvers, split?"
super_approvers="$(comm -12 <(echo "$super_approvers") <(echo "$approvers") | sort -u)"
else
super_approvers="$new_all_approvers"
fi
all_approvers="$new_all_approvers"
fi
# check revision block added and minor version bump
versions="$(xpath "$xep" '/xep/header/revision/version/text()')"
latest_num_versions="$(echo "$versions" | wc -l)"
latest_version="$(echo "$versions" | head -n1)"
# this git-cat-file usage assumes no entities etc are ever removed from xep.ent etc, this should be true
# but if it ever isn't, then we'll have to check out the entire repo as of $merge_base to do that
versions="$(git cat-file -p "$merge_base:./$xep" | xpath - '/xep/header/revision/version/text()')"
merge_base_num_versions="$(echo "$versions" | wc -l)"
merge_base_version="$(echo "$versions" | head -n1)"
if [ $latest_num_versions -gt $merge_base_num_versions ]
then
if ! echo "$latest_version" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' &>/dev/null
then
echo "error: version is not semver format: '$latest_version'"
exit 1
fi
if [ "$latest_version" == "$merge_base_version" ]
then
echo "tag: needs-version-block"
# todo: anyone have a fancy way to check semver is higher in $latest_version ?
# beware we have funky non-semver versions
# for xep in xep-*.xml; do xpath "$xep" '/xep/header/revision/version/text()'; done | sort -u > xep_versions.txt
fi
else
echo "tag: needs-version-block"
fi
done
if [ "$super_approvers" != "" ]
then
pr_authors="$(git --no-pager log --format="%aE" "$merge_base".."$pr_commit" | sort -u)"
pr_authors_super_approvers="$(comm -12 <(echo "$super_approvers") <(echo "$pr_authors") | sort -u)"
if [ "$pr_authors_super_approvers" != "" ]
then
echo "info: entire PR can be approved by one of the commit authors: '$(echo "$pr_authors" | tr '\n' ' ' | xargs)'"
fi
echo "info: entire PR can be approved by: '$(echo "$super_approvers" | tr '\n' ' ' | xargs)'"
fi
if echo "$all_approvers" | grep '^Council$' &>/dev/null
then
echo "tag: needs-council"
fi
if echo "$all_approvers" | grep '^Board$' &>/dev/null
then
echo "tag: needs-board"
fi
if echo "$all_approvers" | grep '^Unknown$' &>/dev/null
then
echo "tag: needs-unknown-approver"
echo "warning: approver is unknown, perhaps old XEP that needs fixed?"
fi
if echo "$all_approvers" | grep '@' &>/dev/null
then
echo "tag: needs-author"
fi
echo "manual: if only editorial changes, may not need approval"

View File

@ -0,0 +1,214 @@
#!/bin/bash
# Checks if provided file (filename to be provided as first argument) conforms to XEP-0001.
# See https://github.com/xsf/xeps/issues/1235
#
# Expected to be executed from the directory that holds all xep XML files.
# Requires one argument: the file name of the xep to be validated, eg:
#
# $ tools/validate-xep0001-conformance.sh xep-0010.xml
#
# exit status will be non-zero upon validation failure.
#
# requires: bash, xmllint, sort (supporting the '-V' argument)
set -euo pipefail
# ANSI color definitions
ANSI_INFO='\033[1;94m';
ANSI_PASS='\033[1;92m';
ANSI_FAIL='\033[1;91m';
ANSI_RESET='\033[0m';
validation_result=0
echo -e "Start validating file '$1'."
echo ""
# 1. Check DTD conformance against xep.dtd
xep_dtd="xep.dtd"
if xmllint --noout --dtdvalid "$xep_dtd" "$1"
then
echo -e "${ANSI_PASS}[PASS]${ANSI_RESET} DTD conformance against xep.dtd"
else
echo -e "${ANSI_FAIL}[FAIL]${ANSI_RESET} DTD conformance against xep.dtd"
validation_result=1;
fi
file_name=$(basename -- "$1")
# The test for exit code equalling 10 detects when the XPATH evaluation yields no results. In that case, the execution
# should not fail immediately, but use an empty value instead (which will likely cause a validation failure further down).
header_number=$(xmllint --xpath '/xep/header/number/text()' --nowarning --dtdvalid "$xep_dtd" "$1") || test $?=10
header_status=$(xmllint --xpath '/xep/header/status/text()' --nowarning --dtdvalid "$xep_dtd" "$1") || test $?=10
header_type=$(xmllint --xpath '/xep/header/type/text()' --nowarning --dtdvalid "$xep_dtd" "$1") || test $?=10
header_approver=$(xmllint --xpath '/xep/header/approver/text()' --nowarning --dtdvalid "$xep_dtd" "$1") || test $?=10
header_revisions=$(xmllint --xpath '/xep/header/revision/version/text()' --nowarning --dtdvalid "$xep_dtd" "$1") || test $?=10
processing_instructions=$(xmllint --xpath '/processing-instruction("xml-stylesheet")' --nowarning --dtdvalid "$xep_dtd" "$1") || test $?=10
if echo "$file_name" | grep -Eq "^xep-[0-9]{4}.xml$"
then
echo -e "${ANSI_INFO}[INFO]${ANSI_RESET} The filename ('$file_name') matches 'xep-[0-9]{4}.xml'."
# 2. If the filename matches xep-[0-9]{4}.xml, check:
# 2.1 that the number in the filename equals /xep/header/number (XPath)
if [ "$file_name" = "xep-$header_number.xml" ]
then
echo -e "${ANSI_PASS}[PASS]${ANSI_RESET} The number in the filename ('$file_name') equals XPATH value /xep/header/number/text() ('$header_number')."
else
echo -e "${ANSI_FAIL}[FAIL]${ANSI_RESET} The number in the filename ('$file_name') does not equals XPATH value /xep/header/number/text() ('$header_number') (but should)."
validation_result=1
fi
else
echo -e "${ANSI_INFO}[INFO]${ANSI_RESET} The filename ('$file_name') does not match 'xep-[0-9]{4}.xml'."
# 3. If the filename does not match xep-[0-9]{4}.xml, check:
# 3.1 That the /xep/header/status/text() (XPath) is ProtoXEP
if [ "$header_status" = "ProtoXEP" ]
then
echo -e "${ANSI_PASS}[PASS]${ANSI_RESET} XPATH value /xep/header/status/text() ('$header_status') equals 'ProtoXEP'."
else
echo -e "${ANSI_FAIL}[FAIL]${ANSI_RESET} XPATH value /xep/header/status/text() ('$header_status') does not equal 'ProtoXEP' (but should)."
validation_result=1
fi
# 3.2 That the /xep/header/number/text() (XPath) is literally XXXX or xxxx
if [ "$header_number" = "XXXX" ] || [ "$header_number" = "xxxx" ]
then
echo -e "${ANSI_PASS}[PASS]${ANSI_RESET} XPATH value /xep/header/number/text() ('$header_status') equals '$header_number'."
else
echo -e "${ANSI_FAIL}[FAIL]${ANSI_RESET} XPATH value /xep/header/number/text() ('$header_status') does not equal 'XXXX' or 'xxxx' (but should)."
validation_result=1
fi
# 3.3 That the name does not start with xep-[0-9]
if echo "$file_name" | grep -Eq "^xep-[0-9].*$"
then
echo -e "${ANSI_FAIL}[FAIL]${ANSI_RESET} The filename ('$file_name') starts with 'xep-[0-9]' (but should not)."
validation_result=1
else
echo -e "${ANSI_PASS}[PASS]${ANSI_RESET} The filename ('$file_name') does not start with 'xep-[0-9]'."
fi
fi
# 4. Check that /xep/header/status/text() (XPath) is a defined status (see tools/xeplib.py for an enum)
case $header_status in
ProtoXEP | Experimental | Proposed | Draft | Active | Final | Retracted | Obsolete | Deferred | Rejected | Deprecated )
echo -e "${ANSI_PASS}[PASS]${ANSI_RESET} XPATH value /xep/header/status/text() ('$header_status') equals a defined status."
;;
*)
echo -e "${ANSI_FAIL}[FAIL]${ANSI_RESET} XPATH value /xep/header/status/text() ('$header_status') does not equals a defined status (but should)."
validation_result=1
;;
esac
# 5. Check that /xep/header/type/text() (XPath) is defined in XEP-0001
# If the XEP number is less than 400, also accept some legacy values. To find which, see which you encounter in the XEP numbers below 400 :-).
# FIXME: lots of duplications here. Find a better solution.
case $file_name in
'xep-0001.xml' | 'xep-0002.xml' | 'xep-0019.xml' | 'xep-0053.xml' | 'xep-0143.xml' | 'xep-0182.xml' | 'xep-0345.xml' | 'xep-0381.xml' | 'xep-0429.xml' | 'xep-0458.xml' )
case $header_type in
Historical | Humorous | Informational | Organizational | 'Standards Track' | 'Procedural' )
echo -e "${ANSI_PASS}[PASS]${ANSI_RESET} XPATH value /xep/header/type/text() ('$header_type') equals a defined type."
;;
*)
echo -e "${ANSI_FAIL}[FAIL]${ANSI_RESET} XPATH value /xep/header/type/text() ('$header_type') does not equals a defined type (but should)."
validation_result=1
;;
esac
;;
'xep-0006.xml' | 'xep-0010.xml' | 'xep-0069.xml' | 'xep-0139.xml' )
case $header_type in
Historical | Humorous | Informational | Organizational | 'Standards Track' | 'SIG Formation' )
echo -e "${ANSI_PASS}[PASS]${ANSI_RESET} XPATH value /xep/header/type/text() ('$header_type') equals a defined type."
;;
*)
echo -e "${ANSI_FAIL}[FAIL]${ANSI_RESET} XPATH value /xep/header/type/text() ('$header_type') does not equals a defined type (but should)."
validation_result=1
;;
esac
;;
'xep-0007.xml' )
case $header_type in
Historical | Humorous | Informational | Organizational | 'Standards Track' | 'SIG Proposal' )
echo -e "${ANSI_PASS}[PASS]${ANSI_RESET} XPATH value /xep/header/type/text() ('$header_type') equals a defined type."
;;
*)
echo -e "${ANSI_FAIL}[FAIL]${ANSI_RESET} XPATH value /xep/header/type/text() ('$header_type') does not equals a defined type (but should)."
validation_result=1
;;
esac
;;
* )
case $header_type in
Historical | Humorous | Informational | Organizational | 'Standards Track' )
echo -e "${ANSI_PASS}[PASS]${ANSI_RESET} XPATH value /xep/header/type/text() ('$header_type') equals a defined type."
;;
*)
echo -e "${ANSI_FAIL}[FAIL]${ANSI_RESET} XPATH value /xep/header/type/text() ('$header_type') does not equals a defined type (but should)."
validation_result=1
;;
esac
;;
esac
# 6. Check that /xep/header/approver/text() (XPath) is either Board or Council
case $header_approver in
Board | Council )
echo -e "${ANSI_PASS}[PASS]${ANSI_RESET} XPATH value /xep/header/approver/text() ('$header_approver') equals either 'Board' or 'Council'."
;;
*)
echo -e "${ANSI_FAIL}[FAIL]${ANSI_RESET} XPATH value /xep/header/approver/text() ('$header_approver') does not equals 'Board' or 'Council' (but should)."
validation_result=1
;;
esac
# 7. Check that the version numbers in the revision blocks are descending (from top to bottom in the document)
expected_revision_order=$(echo "$header_revisions" | tr " " "\n" | sort -Vr)
if [ "$expected_revision_order" = "$header_revisions" ]
then
echo -e "${ANSI_PASS}[PASS]${ANSI_RESET} Version numbers in the revision blocks are descending."
else
echo -e "${ANSI_FAIL}[FAIL]${ANSI_RESET} Version numbers in the revision blocks are not ordered (descending from top to bottom in the document) (but should be)."
echo " Order found : $(echo $header_revisions)" # funky $() nesting to remove newlines.
echo " Expected was: $(echo $expected_revision_order)"
validation_result=1
fi
# 8. If the approver (see above) is Board, enforce that /xep/header/type is not Standards Track.
if [ "$header_approver" = "Board" ]
then
if [ "$header_type" = "Standards Track" ]
then
echo -e "${ANSI_FAIL}[FAIL]${ANSI_RESET} XPATH value /xep/header/approver/text() ('$header_approver') is 'Board' but XPATH value /xep/header/type/text() is 'Standards Track' (it should not be)."
validation_result=1
else
echo -e "${ANSI_PASS}[PASS]${ANSI_RESET} XPATH value /xep/header/approver/text() ('$header_approver') is 'Board' and XPATH value /xep/header/type/text() is not 'Standards Track'."
fi
fi
# 9. Check that it uses the xep.xsl XML stylesheet.
if echo "$processing_instructions" | grep -Eq "href=['\"]xep.xsl['\"]"
then
echo -e "${ANSI_PASS}[PASS]${ANSI_RESET} xep.xsl XML stylesheet is used."
else
echo -e "${ANSI_FAIL}[FAIL]${ANSI_RESET} xep.xsl XML stylesheet is not used (but should be)."
validation_result=1
fi
# 10. Check that it includes the correct legal notice (by checking for the entity reference)
if grep -q "&LEGALNOTICE;" "$1"
then
echo -e "${ANSI_PASS}[PASS]${ANSI_RESET} entity reference for the legal notice has been detected."
else
echo -e "${ANSI_FAIL}[FAIL]${ANSI_RESET} entity reference for the legal notice has not been detected (but it should have been)."
validation_result=1
fi
echo ""
if [ $validation_result = 0 ]
then
echo "No issues found."
else
echo "Issues found!"
fi
exit $validation_result

View File

@ -247,11 +247,21 @@ local header_schema = [[
supersededby , shortname , schemaloc* , registry? , discuss? ,
expires? , author+ , revision+ , councilnote?)
]];
for field in header_schema:gmatch("%w+") do
events.add_handler(field.."#text", function (event)
meta[field] = event.text:match("%S.*%S");
return true;
end);
for field, mod in header_schema:gmatch("(%w+)([*+?]?)") do
if mod == "" or mod == "?" then
events.add_handler(field .. "#text", function(event)
meta[field] = event.text:match("%S.*%S");
return true;
end);
elseif mod == "*" or mod == "+" then
events.add_handler(field .. "#text", function(event)
if not meta[field] then
meta[field] = {};
end
table.insert(meta[field], event.text:match("%S.*%S"));
return true;
end);
end
end
do

View File

@ -27,6 +27,12 @@
&jer;
&temas;
&stpeter;
<revision>
<version>2.13.1</version>
<date>2022-07-25</date>
<initials>ssw</initials>
<remark><p>Clarify elements allowed in multi-item data forms</p></remark>
</revision>
<revision>
<version>2.13.0</version>
<date>2022-01-21</date>
@ -318,9 +324,10 @@
<li>One and only one &lt;reported/&gt; element, which can be understood as a "table header" describing the data to follow.</li>
<li>Zero or more &lt;item/&gt; elements, which can be understood as "table cells" containing data (if any) that matches the request.</li>
</ol>
<p>The &lt;reported/&gt; element MUST appear before any &lt;item/&gt; element inside the &lt;x/&gt; element.</p>
<p>The &lt;reported/&gt; element MUST appear before any &lt;item/&gt; element inside the &lt;x/&gt; element. Forms of this type MUST NOT contain any top-level fields other than &lt;reported/&gt; and &lt;item/&gt;.</p>
<p class="box info">
Older revisions of this XEP (before 2.12.0) did not contain an explicit requirement for the ordering between &lt;reported&gt; and &lt;item&gt;. Implementations are therefore encouraged to be flexible when processing incoming data, as there might still be implementations which do not implement a strict ordering when generating reports.
Similarly, revisions of this XEP before 2.13.1 were ambiguous about whether &lt;reported/&gt; and &lt;item/&gt; elements could co-exist with other top level elements such as &lt;field/&gt; and &lt;title/&gt; and various implementations are known to have handled this in different ways.
</p>
<p>The syntax is as follows:</p>
<code><![CDATA[

View File

@ -19,6 +19,12 @@
<supersededby/>
<shortname>N/A</shortname>
&stpeter;
<revision>
<version>1.1</version>
<date>2022-11-03</date>
<initials>pep</initials>
<remark>Replaced shtml link.</remark>
</revision>
<revision>
<version>1.0</version>
<date>2002-03-20</date>
@ -72,6 +78,6 @@
<li>Continue to use the Standards SIG as the preferred forum for discussion of experimental specifications before they are submitted to the XMPP Council.</li>
<li>If the Standards SIG cannot reach a working consensus on a given topic, let the document author(s) continue to rework their proposal informally outside the context of the Standards SIG. <note>One option would be to send interested parties off to their own ad-hoc mailing list (e.g., on JabberStudio, <link url="http://www.jabberstudio.org/">http://www.jabberstudio.org/</link>). Unlike the current SIGs, such a list would be established on the initiative of the document author(s) and would not require any formal approval by the XMPP Council.</note></li>
</ol>
<p>There may be value in bringing back specialized SIGs in the future when the Jabber/XMPP community becomes larger. However, at this time I urge that we face the facts and proactively implement the solution I have outlined in this document. <note>Lest there be any concern that disbanding the SIGs is outside the power or purview of the XMPP Council, I note that Section 8.2 of the Bylaws of the XMPP Standards Foundation states in part that "The XMPP Council or the Members of the Corporation may, by resolution, ... terminate a Special Interest Group at any time for any reason." (An electronic copy of the Bylaws may be found at <link url="http://xmpp.org/xsf/docs/bylaws.shtml">http://www.jabber.org/bylaws.html</link>.)</note></p>
<p>There may be value in bringing back specialized SIGs in the future when the Jabber/XMPP community becomes larger. However, at this time I urge that we face the facts and proactively implement the solution I have outlined in this document. <note>Lest there be any concern that disbanding the SIGs is outside the power or purview of the XMPP Council, I note that Section 8.2 of the Bylaws of the XMPP Standards Foundation states in part that "The XMPP Council or the Members of the Corporation may, by resolution, ... terminate a Special Interest Group at any time for any reason." (An electronic copy of the Bylaws may be found at <link url="https://xmpp.org/about/xsf/bylaws/">http://www.jabber.org/bylaws.html</link>.)</note></p>
</section1>
</xep>

View File

@ -45,6 +45,18 @@
</schemaloc>
<registry/>
&stpeter;
<revision>
<version>1.34.5</version>
<date>2022-12-01</date>
<initials>NC</initials>
<remark><p>Add MUC service shut down example.</p></remark>
</revision>
<revision>
<version>1.34.4</version>
<date>2022-10-05</date>
<initials>pep</initials>
<remark><p>Remove more mentions of Group Chat 1.0.</p></remark>
</revision>
<revision>
<version>1.34.3</version>
<date>2022-03-08</date>
@ -4980,6 +4992,31 @@
and they are not linked to any user (e.g. moderator) action that the 307 code usually indicates. It is therefore recommended for the
client to ignore the 307 code if a 333 status code is present.</p>
</section2>
<section2 topic='Service removes user because of service shut down' anchor='service-shutdown-kick'>
<p>When a MUC service shuts downs, it SHOULD inform its participant by sending presences containing the 332 status code</p>
<example caption='MUC service removes user because of service shutdown'><![CDATA[
<presence
from='harfleur@chat.shakespeare.lit/pistol'
to='pistol@shakespeare.lit/client'
type='unavailable'>
<x xmlns='http://jabber.org/protocol/muc#user'>
<item affiliation='none' role='none' />
<status code='110'/>
<status code='332'/>
</x>
</presence>
<presence
from='harfleur@chat.shakespeare.lit/othello'
to='othello@shakespeare.lit/client'
type='unavailable'>
<x xmlns='http://jabber.org/protocol/muc#user'>
<item affiliation='none' role='none' />
<status code='110'/>
<status code='332'/>
</x>
</presence>
]]></example>
</section2>
</section1>
<section1 topic='Status Codes' anchor='statuscodes'>
@ -5708,7 +5745,6 @@ xmpp:coven@chat.shakespeare.lit?invite;jid=hecate@shakespeare.lit;password=cauld
<li><p>A MUC service SHOULD allow all other presence information to pass through, although it MAY choose to block extended presence information; see the <link url='#impl-service-traffic'>Allowable Traffic</link> section of this document.</p></li>
<li><p>In order to inform occupants of room roles and affiliations, and to make it easier for clients to track the current state of all users in the room, MUC service implementations MUST provide role and affiliation data (and, if allowed by the room configuration, full JID) in all presence stanzas, including presence stanzas of type "unavailable" sent when a user exits the room for any reason.</p></li>
<li><p>If a role or affiliation is revoked, the service MUST note that fact by sending an &lt;x/&gt; element qualified by the 'http://jabber.org/protocol/muc#user' namespace and containing an &lt;item/&gt; child element with the 'role' and/or 'affiliation' attributes set to a value that indicates the loss of the relevant status. All future presence stanzas for the occupant MUST include the updated role and affiliation, until and unless they change again.</p></li>
<li><p>A MUC service MUST include the MUC extensions even if the client did not send an empty &lt;x/&gt; element qualified by the 'http://jabber.org/protocol/muc' namespace on entering the room; naturally, a client MUST ignore such information if it does not understand it (in accordance with <cite>RFC 6120</cite>).</p></li>
<li><p>If the service includes an occupant's JabberID in the MUC presence extension, the value of the 'jid' attribute MUST be the full JID (not the bare JID).</p></li>
<li><p>A client MAY send a custom exit message if desired (as is often done in IRC channels) by including a &lt;status/&gt; element in the presence stanza of type "unavailable" sent when <link url='#exit'>exiting a room</link>.</p></li>
</ol>

View File

@ -21,6 +21,12 @@
<supersededby/>
<shortname>iq-iq</shortname>
&stpeter;
<revision>
<version>1.1</version>
<date>2022-11-03</date>
<initials>pep</initials>
<remark><p>Replace shtml link</p></remark>
</revision>
<revision>
<version>1.0</version>
<date>2005-04-01</date>
@ -191,7 +197,7 @@
<di><dt>Semantic Correlation and Observation of Truth in Conversation Handling (SCOTCH)</dt><dd>A person may seem intelligent to the casual observer, but his or her messages may actually not provide deep insights or even track reality in a useful or consistent fashion; this technique builds on early semantic web insights to determine the truth value of a given message within the context of a realtime conversation.</dd></di>
<di><dt>Webs of Intelligent Network Endpoints (WINE)</dt><dd>Any given person can engage in conversations with a large number of interlocutors, yet that person's status as an intelligent network endpoint is influenced by reputational factors across the full web of linguistic interactions, not just with any one person; this technique accounts for such reputational effects to paint a complete picture of the person's perceived intelligence across the network.</dd></di>
</dl>
<p>Naturally, because of the powerful and potentially unpredictable effects of these technologies, development of mod_iq was restricted to senior developers on the jabberd team, or at least (for developers in the U.S.) those over the age of 21. <note>See Title 23, Chapter 1, Subchapter 1, Section 158 of the United States federal legal code as enacted by the National Minimum Drinking Age Act of 1984 &lt;<link url='http://www.law.cornell.edu/uscode/23/158.shtml'>http://www.law.cornell.edu/uscode/23/158.shtml</link>&gt;.</note></p>
<p>Naturally, because of the powerful and potentially unpredictable effects of these technologies, development of mod_iq was restricted to senior developers on the jabberd team, or at least (for developers in the U.S.) those over the age of 21. <note>See Title 23, Chapter 1, Subchapter 1, Section 158 of the United States federal legal code as enacted by the National Minimum Drinking Age Act of 1984 &lt;<link url='https://www.law.cornell.edu/uscode/text/23/158'>https://www.law.cornell.edu/uscode/text/23/158</link>&gt;.</note></p>
</section2>
</section1>
<section1 topic='Internationalization Considerations' anchor='i18n'>

View File

@ -42,6 +42,12 @@
&seanegan;
&robmcqueen;
&diana;
<revision>
<version>1.2.2</version>
<date>2022-09-26</date>
<initials>melvo</initials>
<remark>Specify attribute 'name' of 'mute' and 'unmute' elements as optional in schema</remark>
</revision>
<revision>
<version>1.2.1</version>
<date>2020-09-29</date>
@ -1933,7 +1939,7 @@ Romeo Juliet
</xs:attribute>
<xs:attribute name='name'
type='xs:string'
use='required'/>
use='optional'/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>

View File

@ -27,6 +27,22 @@
&fippo;
&stpeter;
&tmolitor;
<revision>
<version>0.6.0</version>
<date>2022-01-29</date>
<initials>tm</initials>
<remark>
Port version 0.5 to :0 namespace and improve tie-breaking section
</remark>
</revision>
<revision>
<version>0.5.0</version>
<date>2022-01-05</date>
<initials>tm</initials>
<remark>
Recommend usage of UUID v4 for id attributes.
</remark>
</revision>
<revision>
<version>0.4.0</version>
<date>2021-11-27</date>
@ -98,12 +114,12 @@
<section1 topic='Use Cases' anchor='usecases'>
<p>All &MESSAGE; stanzas exchanged by this protocol MUST be of type="chat" and contain &xep0334; &lt;store/&gt; hints.</p>
<section2 topic='Indicating Intent to Start a Session' anchor='intent'>
<p>In order to prepare for sending a Jingle invitation, the initiator (e.g., Romeo) sends a &MESSAGE; stanza containing a &lt;propose/&gt; element qualified by the 'urn:xmpp:jingle-message:1' namespace. The &lt;propose/&gt; element MUST possess an 'id' attribute that will be used for the session invitation of &xep0166; and MUST contain one &lt;description/&gt; element for each media type associated with the intended session.</p>
<p>In order to prepare for sending a Jingle invitation, the initiator (e.g., Romeo) sends a &MESSAGE; stanza containing a &lt;propose/&gt; element qualified by the 'urn:xmpp:jingle-message:0' namespace. The &lt;propose/&gt; element MUST possess an 'id' attribute being a globally unique identifier. It therefore is RECOMMENDED to use UUIDv4. This id will also be used for the session invitation of &xep0166; later on. The &lt;propose/&gt; element MUST contain one &lt;description/&gt; element for each media type associated with the intended session.</p>
<example caption="Initiator Sends Intent Message"><![CDATA[
<message from='romeo@montague.example/orchard'
to='juliet@capulet.example'
type='chat'>
<propose xmlns='urn:xmpp:jingle-message:1' id='a73sjjvkla37jfea'>
<propose xmlns='urn:xmpp:jingle-message:0' id='ca3cf894-5325-482f-a412-a6e9f832298d'>
<description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'/>
</propose>
<store xmlns="urn:xmpp:hints"/>
@ -119,16 +135,29 @@
node='http://psi-im.org'
ver='q07IKJEyjvHSyhy//CH0CxmKi8w='/>
</presence>
]]></example>
</section2>
<section2 topic='Indicating a Ringing Device' anchor='ring'>
<p>Upon receiving the &lt;propose/&gt; message, the responder's various devices will start "ringing" and indicate so by sending a message to the bare JID of the initiator containing a &lt;ringing/&gt; element qualified by the 'urn:xmpp:jingle-message:0' namespace and specifying the session ID of the original &lt;propose/&gt; message.</p>
<p>This makes it possible to reflect the real state of the call in the UI and therefore comprises for better UX. It also somewhat compensates for the (intentionally) missing discovery of this protocol.</p>
<example caption="One of Responder's Resources Reports it is Ringing"><![CDATA[
<message from='juliet@capulet.example/phone'
to='romeo@montague.example'
type='chat'>
<ringing xmlns='urn:xmpp:jingle-message:0' id='ca3cf894-5325-482f-a412-a6e9f832298d'/>
<store xmlns="urn:xmpp:hints"/>
</message>
]]></example>
</section2>
<section2 topic='Disavowing Intent to Start a Session' anchor='retract'>
<p>It can happen that the initiator might want to disavow intent to send a session invitation (e.g., because the initiator has accepted another session). The initiator can do so by sending a message stanza containing a &lt;retract/&gt; element specifying the same session ID.</p>
<p>The &lt;retract/&gt; element MUST contain a &lt;reason/&gt; element as defined in &xep0166; section 7.4. This SHOULD use a condition of &lt;cancel/&gt;, but implementations MAY use other conditions if deemed more appropriate (see <link url="#security">Security Considerations</link> below for details and rationale).</p>
<example caption="Initiator Sends Stop Message"><![CDATA[
<p>It can happen that the initiator might want to disavow intent to send a session invitation (e.g., because the initiator has accepted another session). The initiator can do so by sending a message stanza containing a &lt;retract/&gt; element qualified by the 'urn:xmpp:jingle-message:0' namespace and specifying the session ID of the original &lt;propose/&gt; message.</p>
<p>The &lt;retract/&gt; element SHOULD contain a &lt;reason/&gt; element as defined in &xep0166; section 7.4. This SHOULD use a condition of &lt;cancel/&gt;, but implementations MAY use other conditions if deemed more appropriate (see <link url="#security">Security Considerations</link> below for details and rationale).</p>
<p>In conjunction with &xep0313; upon ending the catchup phase the responder SHOULD consider all sessions for which it received a &lt;propose/&gt; but no &lt;retract/&gt; or &lt;finish/&gt; message to be still active and allow the user to <link url="#proceed">accept the intent to start a session</link>.</p>
<example caption="Initiator Sends Retract Message"><![CDATA[
<message from='romeo@montague.example/orchard'
to='juliet@capulet.example'
type='chat'>
<retract xmlns='urn:xmpp:jingle-message:1' id='a73sjjvkla37jfea'>
<retract xmlns='urn:xmpp:jingle-message:0' id='ca3cf894-5325-482f-a412-a6e9f832298d'>
<reason xmlns="urn:xmpp:jingle:1">
<cancel/>
<text>Retracted</text>
@ -137,21 +166,20 @@
<store xmlns="urn:xmpp:hints"/>
</message>
]]></example>
<p>In conjunction with &xep0313; upon ending the catchup phase the responder SHOULD consider all sessions for which it received a &lt;propose/&gt; but no &lt;retract/&gt; or &lt;finish/&gt; message to be still active and allow the user to <link url="#accept">accept the intent to start a session</link>.</p>
</section2>
<section2 topic='Accepting Intent to Start a Session' anchor='accept'>
<p>Upon receiving the intent message, the responder's various devices will "ring" and the responder will answer the call on a particular device. Here we assume that since this is an audio-only call, Juliet chooses to take the call on the device associated with her "phone" resource.</p>
<p>Her "phone" resource informs all of her resources and all of the initiator's resources about accepting the call by sending a message to the bare JID of the initiator containing an &lt;accept/&gt; element specifying the session ID of the original &lt;propose/&gt; message.</p>
<example caption="One of Responder's Resources Accepts the Call"><![CDATA[
<section2 topic='Accepting Intent to Start a Session' anchor='proceed'>
<p>The responder will answer the call on a particular device. Here we assume that since this is an audio-only call, Juliet chooses to take the call on the device associated with her "phone" resource.</p>
<p>Her "phone" resource informs all of her resources and all of the initiator's resources about accepting the call by sending a message to the bare JID of the initiator containing an &lt;proceed/&gt; element qualified by the 'urn:xmpp:jingle-message:0' namespace and specifying the session ID of the original &lt;propose/&gt; message.</p>
<example caption="One of Responder's Resources Accepts the Call"><![CDATA[
<message from='juliet@capulet.example/phone'
to='romeo@montague.example'
type='chat'>
<accept xmlns='urn:xmpp:jingle-message:1' id='a73sjjvkla37jfea'/>
<proceed xmlns='urn:xmpp:jingle-message:0' id='ca3cf894-5325-482f-a412-a6e9f832298d'/>
<store xmlns="urn:xmpp:hints"/>
</message>
]]></example>
<p>Juliet's server broadcasts this accept message to all of her resources (as described in &xep0280;), which stop ringing, and to all of Romeo's resources (as described in &rfc6121;). Romeo's resources that did not send the &lt;propose/&gt; can use this &MESSAGE; stanza to update their UI or choose to ignore this &MESSAGE; stanza altogether.</p>
<p>Next, the device from which Juliet accepted the call sends directed presence to Romeo for the reasons described above.</p>
<p>Juliet's server broadcasts this accept message to all of her resources (as described in &xep0280;), which stop ringing, and to all of Romeo's resources (as described in &rfc6121;). Romeo's resources that did not send the &lt;propose/&gt; can use this &MESSAGE; stanza to update their UI or choose to ignore this &MESSAGE; stanza altogether.</p>
<p>Next, the device from which Juliet accepted the call SHOULD also send directed presence to Romeo if the two entities do not already share presence information, for the reasons described above.</p>
<example caption="Responder Sends Directed Presence"><![CDATA[
<presence from='juliet@capulet.example/phone'
to='romeo@montague.example/orchard'>
@ -163,14 +191,14 @@
]]></example>
</section2>
<section2 topic='Rejecting Intent to Start a Session' anchor='reject'>
<p>Instead of accepting the call, the responder might want to decline the call and tell all of her devices to stop ringing (e.g., perhaps because Romeo is getting to be a bit of a nuisance). She does this by rejecting the call on one of her devices and having that device tell all of the other devices to stop ringing by sending a &MESSAGE; stanza containing a &lt;reject/&gt; element specifying the session ID of the original &lt;propose/&gt; message to the bare JID of Romeo.</p>
<p>The &lt;reject/&gt; element MUST contain a &lt;reason/&gt; element as defined in &xep0166; section 7.4. The &lt;reason/&gt; element SHOULD use a condition of &lt;busy/&gt;, but implementations MAY use other conditions if deemed more appropriate (see <link url="#security">Security Considerations</link> below for details and rationale).</p>
<p>In Tie-Breaking scenarios it MUST also contain a &lt;tie-break/&gt; element as defined in <link url="#tie-break-1">Tie Breaking</link>.</p>
<example caption="One of Responder's Resources Rejects the Call"><![CDATA[
<p>Instead of accepting the call, the responder might want to decline the call and tell all of her devices to stop ringing (e.g., perhaps because Romeo is getting to be a bit of a nuisance). She does this by rejecting the call on one of her devices and having that device tell all of the other devices to stop ringing by sending a &MESSAGE; stanza containing a &lt;reject/&gt; element qualified by the 'urn:xmpp:jingle-message:0' namespace and specifying the session ID of the original &lt;propose/&gt; message to the bare JID of Romeo.</p>
<p>The &lt;reject/&gt; element SHOULD contain a &lt;reason/&gt; element as defined in &xep0166; section 7.4. If given, the &lt;reason/&gt; element SHOULD use a condition of &lt;busy/&gt;, but implementations MAY use other conditions if deemed more appropriate (see <link url="#security">Security Considerations</link> below for details and rationale).</p>
<p>In Tie-Breaking scenarios it MUST also contain a &lt;tie-break/&gt; element as defined in <link url="#tie-break-1">Tie Breaking</link>.</p>
<example caption="One of Responder's Resources Rejects the Call"><![CDATA[
<message from='juliet@capulet.example/phone'
to='romeo@montague.example'
type='chat'>
<reject xmlns='urn:xmpp:jingle-message:1' id='a73sjjvkla37jfea'>
<reject xmlns='urn:xmpp:jingle-message:0' id='ca3cf894-5325-482f-a412-a6e9f832298d'>
<reason xmlns="urn:xmpp:jingle:1">
<busy/>
<text>Busy</text>
@ -190,7 +218,7 @@
<jingle xmlns='urn:xmpp:jingle:1'
action='session-initiate'
initiator='romeo@montague.example/orchard'
sid='a73sjjvkla37jfea'>
sid='ca3cf894-5325-482f-a412-a6e9f832298d'>
<content creator='initiator' name='voice'>
<description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'>
<payload-type id='96' name='speex' clockrate='16000'/>
@ -232,14 +260,14 @@
]]></example>
</section2>
<section2 topic='Finishing a Started Session' anchor='finish'>
<p>This protocol in conjunction with &xep0280; and &xep0313; allows all devices of both involved parties to get synchronized about session start, rejection etc. To synchronize the ending of the session, both parties MUST send a message stanza containing a &lt;finish/&gt; element specifying the same session ID as in <link url='#accept'>Accept</link> to the bare jid of the other party.</p>
<p>This protocol in conjunction with &xep0280; and &xep0313; allows all devices of both involved parties to get synchronized about session start, rejection etc. To synchronize the ending of the session, both parties SHOULD send a message stanza containing a &lt;finish/&gt; element qualified by the 'urn:xmpp:jingle-message:0' namespace and specifying the same session ID as in <link url='#proceed'>proceed</link> to the bare jid of the other party.</p>
<p>Letting both involved parties send the &lt;finish/&gt; element makes sure we have the correct state in MAM archives etc. even if one client suddenly looses connectivity/power. It even makes possible for a client to determine if the call is still deemed "running" by the other party if it manages to recover from connectivity loss &mdash; before the other party runs into a timeout and sends a &lt;finish/&gt; &mdash; to recover the session or formally terminate the call (by ending the Jingle session and sending a &lt;finish/&gt; message itself). See <link url="#tie-break-2">Tie Breaking</link> for more infos on this and similar scenarios.</p>
<p>The &lt;finish/&gt; element MUST contain a &lt;reason/&gt; element as defined in &xep0166; section 7.4. This SHOULD use a condition of &lt;success/&gt;, but implementations MAY use other conditions if deemed more appropriate (see <link url="#security">Security Considerations</link> below for details and rationale).</p>
<p>The &lt;finish/&gt; element SHOULD contain a &lt;reason/&gt; element as defined in &xep0166; section 7.4. This SHOULD use a condition of &lt;success/&gt; or &lt;expired/&gt;, but implementations MAY use other conditions like &lt;connectivity-error/&gt; if deemed more appropriate (see <link url="#security">Security Considerations</link> below for details and rationale).</p>
<example caption="Initiator Sends Finish Message"><![CDATA[
<message from='romeo@montague.example/orchard'
to='juliet@capulet.example'
type='chat'>
<finish xmlns='urn:xmpp:jingle-message:1' id='a73sjjvkla37jfea'>
<finish xmlns='urn:xmpp:jingle-message:0' id='ca3cf894-5325-482f-a412-a6e9f832298d'>
<reason xmlns="urn:xmpp:jingle:1">
<success/>
<text>Success</text>
@ -252,7 +280,7 @@
<message from='juliet@capulet.example/phone'
to='romeo@montague.example'
type='chat'>
<finish xmlns='urn:xmpp:jingle-message:1' id='a73sjjvkla37jfea'>
<finish xmlns='urn:xmpp:jingle-message:0' id='ca3cf894-5325-482f-a412-a6e9f832298d'>
<reason xmlns="urn:xmpp:jingle:1">
<success/>
<text>Success</text>
@ -264,15 +292,17 @@
</section2>
</section1>
<section1 topic="Tie Breaking" anchor="tie-breaking">
<p>It is possible that a &lt;propose/&gt; message can be sent at the same time by both parties or a new session started while one is already running. Implementations of this specification MUST implement the following solutions to solve this. (This is loosely based upon section 7.2.16 of &xep0166;.)</p>
<p>It is possible that a &lt;propose/&gt; message can be sent at the same time by both parties or a new session started while one is already running. Implementations of this specification SHOULD implement the following solutions to solve this. (This is loosely based upon section 7.2.16 of &xep0166;.)</p>
<section2 topic='No existing session' anchor='tie-break-1'>
<p>In this case (e.g. no party answered the &lt;propose/&gt; message yet) the lower of the two session IDs MUST overrule the other action, where by "lower" is meant the session ID that is sorted first using "i;octet" collation as specified in Section 9.3 of &rfc4790; (in the unlikely event that the random session IDs are the same, the action sent by the lower of the JabberIDs MUST overrule the other action). The party that receives the &lt;propose/&gt; action with the lower of the two session IDs MUST respond with an &lt;accept/&gt; or &lt;reject/&gt; mesage like it would normally do for a &lt;propose/&gt; message, and the party that receives the &lt;propose/&gt; action with the higher of the two session IDs MUST return a &lt;reject/&gt; message to the other party with a &lt;tie-break/&gt; child element alongside of a &lt;reason/&gt; element carrying the condition &lt;expired/&gt;.</p>
<example caption="Tie break in propose state"><![CDATA[
<p>In this case (e.g. no party answered the &lt;propose/&gt; message yet) the lower of the two session IDs MUST overrule the other action, where by "lower" is meant the session ID that is sorted first using "i;octet" collation as specified in Section 9.3 of &rfc4790; (in the unlikely event that the random session IDs are the same, the action sent by the lower of the JabberIDs MUST overrule the other action).</p>
<p>The party that receives the &lt;propose/&gt; action with the lower of the two session IDs MUST send a &lt;retract/&gt; message for the higher session ID to the other party with a &lt;tie-break/&gt; child element alongside of a &lt;reason/&gt; element carrying the condition &lt;expired/&gt; and then eventually respond with an &lt;proceed/&gt; or &lt;reject/&gt; mesage like it would normally do for a received &lt;propose/&gt; message.</p>
<p>The party that receives the &lt;propose/&gt; action with the higher of the two session IDs MUST return a &lt;reject/&gt; message to the other party with a &lt;tie-break/&gt; child element alongside of a &lt;reason/&gt; element carrying the condition &lt;expired/&gt;.</p>
<example caption="Tie break in propose state"><![CDATA[
<!-- lower session ID -->
<message from='romeo@montague.example/orchard'
to='juliet@capulet.example'
type='chat'>
<propose xmlns='urn:xmpp:jingle-message:1' id='a73sjjvkla37jfea'>
<propose xmlns='urn:xmpp:jingle-message:0' id='ca3cf894-5325-482f-a412-a6e9f832298d'>
<description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'/>
</propose>
<store xmlns="urn:xmpp:hints"/>
@ -282,7 +312,7 @@
<message from='juliet@capulet.example/phone'
to='romeo@montague.example'
type='chat'>
<propose xmlns='urn:xmpp:jingle-message:1' id='b73sjjvkla37jfea'>
<propose xmlns='urn:xmpp:jingle-message:0' id='fecbea35-08d3-404f-9ec7-2b57c566fa74'>
<description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'/>
</propose>
<store xmlns="urn:xmpp:hints"/>
@ -292,7 +322,21 @@
<message from='romeo@montague.example/orchard'
to='juliet@capulet.example'
type='chat'>
<reject xmlns='urn:xmpp:jingle-message:1' id='b73sjjvkla37jfea'>
<reject xmlns='urn:xmpp:jingle-message:0' id='fecbea35-08d3-404f-9ec7-2b57c566fa74'>
<reason xmlns="urn:xmpp:jingle:1">
<expired/>
<text>Tie-Break</text>
</reason>
<tie-break/>
</reject>
<store xmlns="urn:xmpp:hints"/>
</message>
<!-- Juliet sent the higher ID and retracts the call -->
<message from='juliet@capulet.example/phone'
to='romeo@montague.example'
type='chat'>
<retract xmlns='urn:xmpp:jingle-message:0' id='fecbea35-08d3-404f-9ec7-2b57c566fa74'>
<reason xmlns="urn:xmpp:jingle:1">
<expired/>
<text>Tie-Break</text>
@ -306,21 +350,21 @@
<message from='juliet@capulet.example/phone'
to='romeo@montague.example'
type='chat'>
<accept xmlns='urn:xmpp:jingle-message:1' id='a73sjjvkla37jfea'/>
<proceed xmlns='urn:xmpp:jingle-message:0' id='ca3cf894-5325-482f-a412-a6e9f832298d'/>
<store xmlns="urn:xmpp:hints"/>
</message>
]]></example>
</section2>
<section2 topic='Existing session' anchor='tie-break-2'>
<p>If (from the perspective of the responder of the new session) there is already a session to the bare-jid of the initiator active (e.g. call already accepted but no &lt;finish/&gt; element received by the responder so far), the old session MUST be deemed an orphan and terminated by the responder of the new session in favor of the new one. The responder MUST transparently accept the new session and finish the old one, because it can be assumed that this new session is a transparent continuation of the old one.</p>
<p>She does so by first accepting the new session (sending an &lt;accept/&gt; message like she would do normally) and then sending a &lt;finish/&gt; message including a child element whose to-attribute refers to the old Jingle session id and including a &lt;reason/&gt; condition of &lt;expired/&gt;.</p>
<p>That makes it possible for the initiator of the new session to transparently switch devices (e.g. migrate the call to a new device) or resume an alreay running session after a sudden connectivity/power loss.</p>
<p>If (from the perspective of the responder of the new session) there is already a session to the bare-jid of the initiator active (e.g. call already accepted but no &lt;finish/&gt; element received by the responder so far), the old session MUST be deemed an orphan and terminated by the responder of the new session in favor of the new one. The responder SHOULD transparently accept the new session and finish the old one, because it can be assumed that this new session is a transparent continuation of the old one.</p>
<p>The responder does so by sending a &lt;finish/&gt; message including a &lt;reason/&gt; condition of &lt;expired/&gt; and having a &lt;migrated&gt; child element whose to-attribute refers to the new Jingle session id, and accepting the new session by sending an &lt;proceed/&gt; message like they would do normally.</p>
<p>That makes it possible for the initiator of the new session to transparently switch devices (e.g. migrate the call to a new device) or resume a still running session after a sudden connectivity/power loss.</p>
<example caption="Tie break in accept state"><![CDATA[
<!-- old session gets proposed... -->
<message from='romeo@montague.example/orchard'
to='juliet@capulet.example'
type='chat'>
<propose xmlns='urn:xmpp:jingle-message:1' id='a73sjjvkla37jfea'>
<propose xmlns='urn:xmpp:jingle-message:0' id='ca3cf894-5325-482f-a412-a6e9f832298d'>
<description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'/>
</propose>
<store xmlns="urn:xmpp:hints"/>
@ -330,7 +374,7 @@
<message from='juliet@capulet.example/phone'
to='romeo@montague.example'
type='chat'>
<accept xmlns='urn:xmpp:jingle-message:1' id='a73sjjvkla37jfea'/>
<proceed xmlns='urn:xmpp:jingle-message:0' id='ca3cf894-5325-482f-a412-a6e9f832298d'/>
<store xmlns="urn:xmpp:hints"/>
</message>
@ -340,42 +384,48 @@
<message from='juliet@capulet.example/tablet'
to='romeo@montague.example'
type='chat'>
<propose xmlns='urn:xmpp:jingle-message:1' id='x64sjjvkla37baka'>
<propose xmlns='urn:xmpp:jingle-message:0' id='989a46a6-f202-4910-a7c3-83c6ba3f3947'>
<description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'/>
</propose>
<store xmlns="urn:xmpp:hints"/>
</message>
<!-- Romeo accepts the call because it is assumed to be a continuation of the old session with id 'a73sjjvkla37jfea'... -->
<!-- Romeo finishes the old session with id 'ca3cf894-5325-482f-a412-a6e9f832298d' using reason <expired/> -->
<!-- because the new one is assumed to be the continuation of the old one. -->
<!-- This is including a <migrated/> element pointing to the new session id '989a46a6-f202-4910-a7c3-83c6ba3f3947'... -->
<message from='romeo@montague.example/orchard'
to='juliet@capulet.example'
type='chat'>
<accept xmlns='urn:xmpp:jingle-message:1' id='x64sjjvkla37baka'/>
<store xmlns="urn:xmpp:hints"/>
</message>
<!-- ...and finishes the old session with id 'a73sjjvkla37jfea' directly afterwards using reason <expired/> -->
<!-- and including a <migrated/> element pointing to the new session id 'x64sjjvkla37baka' -->
<message from='romeo@montague.example/orchard'
to='juliet@capulet.example'
type='chat'>
<finish xmlns='urn:xmpp:jingle-message:1' id='a73sjjvkla37jfea'>
<finish xmlns='urn:xmpp:jingle-message:0' id='ca3cf894-5325-482f-a412-a6e9f832298d'>
<reason xmlns="urn:xmpp:jingle:1">
<expired/>
<text>Session migrated</text>
</reason>
<migrated to='x64sjjvkla37baka'/>
<migrated to='989a46a6-f202-4910-a7c3-83c6ba3f3947'/>
</finish>
<store xmlns="urn:xmpp:hints"/>
</message>
<!-- ...and directly afterwards accepts the new call with id '989a46a6-f202-4910-a7c3-83c6ba3f3947'. -->
<message from='romeo@montague.example/orchard'
to='juliet@capulet.example'
type='chat'>
<proceed xmlns='urn:xmpp:jingle-message:0' id='989a46a6-f202-4910-a7c3-83c6ba3f3947'/>
<store xmlns="urn:xmpp:hints"/>
</message>
<!-- ...some more time passes... -->
<!-- the new session is termianted normally by Romeo... -->
<message from='romeo@montague.example/orchard'
to='juliet@capulet.example'
type='chat'>
<finish xmlns='urn:xmpp:jingle-message:1' id='x64sjjvkla37baka'/>
<finish xmlns='urn:xmpp:jingle-message:0' id='989a46a6-f202-4910-a7c3-83c6ba3f3947'>
<reason xmlns="urn:xmpp:jingle:1">
<success/>
<text>Success</text>
</reason>
</finish>
<store xmlns="urn:xmpp:hints"/>
</message>
@ -383,7 +433,12 @@
<message from='juliet@capulet.example/tablet'
to='romeo@montague.example'
type='chat'>
<finish xmlns='urn:xmpp:jingle-message:1' id='x64sjjvkla37baka'/>
<finish xmlns='urn:xmpp:jingle-message:0' id='989a46a6-f202-4910-a7c3-83c6ba3f3947'>
<reason xmlns="urn:xmpp:jingle:1">
<success/>
<text>Success</text>
</reason>
</finish>
<store xmlns="urn:xmpp:hints"/>
</message>
@ -393,12 +448,13 @@
<section1 topic='Business Rules' anchor="business-rules">
<p>Participants MUST use &xep0280; and &xep0313; to make sure all devices of initiator and responder receive all messages exchanged by this protocol.
Without &xep0280; implementations would need to send copies of outgoing messages to their own bare jid, to inform their own devices about an event (like it was done with the &lt;accept/&gt; message in the old urn:xmpp:jingle:jingle-message:0 specification).</p>
<p>In a &xep0313; (or &xep0198;) catchup scenario client developers MAY choose to not show an "incoming call" UI upon receiving a &lt;propose/&gt; message because they could receive another message for the same Jingle session id later in the catchup process invalidating the &lt;propose/&gt; received before. Showing the "incoming call" UI as soon as receiving an &lt;accept/&gt; might comprise bad UX.</p>
<p>In a &xep0313; (or &xep0198;) catchup scenario client developers MAY choose to not show an "incoming call" UI upon receiving a &lt;propose/&gt; message because they could receive another message for the same Jingle session id later in the catchup process invalidating the &lt;propose/&gt; received before. Showing the "incoming call" UI as soon as receiving a &lt;propose/&gt; might comprise bad UX.</p>
<p>In the rare case of missing &lt;finish/&gt; elements from both initiator and responder, sessions SHOULD be considered terminated after an appropriate timeframe (for example 24 hours) and indicated so in the UI.</p>
<p>All 'id' attributes MUST be globally unique to make sure they do not collide, and therefore it is RECOMMENDED to use UUIDv4.</p>
</section1>
<section1 topic='Security Considerations' anchor='security'>
<p>Because exchanging messages with other entities is effectively is a presence leak, an XMPP client that implements the receiving side of this specification MUST disable sending of accept messages by default and MUST enable the feature only as a result of explicit user confirmation. Such confirmation can be provided per request, by automatically allowing requests received from Jingle initiators in the responder's contact list, or through some other suitable means as long as sending accept messages does not occur by default.</p>
<p>Because sending of reasons other than the default ones (e.g. &lt;cancel/&gt; for &lt;retract/&gt;, &lt;busy/&gt; or &lt;expired/&gt; for &lt;reject/&gt; and &lt;success/&gt; or &lt;expired/&gt; for &lt;finish/&gt;) may leak privacy related information the user does not want to leak, sending of those non-default reasons should be carefully considered by client developers.</p>
<p>Because exchanging messages with other entities is effectively a presence leak, an XMPP client that implements the receiving side of this specification MUST disable sending of accept messages by default and MUST enable the feature only as a result of explicit user confirmation. Such confirmation can be provided per request, by automatically allowing requests received from Jingle initiators in the responder's contact list, or through some other suitable means as long as sending accept messages does not occur by default.</p>
<p>Because sending of reasons other than the default ones (e.g. &lt;cancel/&gt; for &lt;retract/&gt;, &lt;busy/&gt; or &lt;expired/&gt; for &lt;reject/&gt; and &lt;success/&gt; or &lt;expired/&gt; (or &lt;connectivity-error/&gt;) for &lt;finish/&gt;) may leak privacy related information the user does not want to leak, sending of those non-default reasons should be carefully considered by client developers.</p>
</section1>
<section1 topic='Acknowledgements' anchor='acks'>
<p>Thanks to Lance Stout, Holger Weiß and Daniel Gultsch for their feedback.</p>
@ -410,7 +466,7 @@
<section2 topic='Protocol Namespaces' anchor='registrar-ns'>
<p>This specification defines the following XML namespace:</p>
<ul>
<li>urn:xmpp:jingle:jingle-message:1</li>
<li>urn:xmpp:jingle:jingle-message:0</li>
</ul>
<p>The &REGISTRAR; includes the foregoing namespace to the registry located at &NAMESPACES;, as described in Section 4 of &xep0053;.</p>
</section2>
@ -418,6 +474,9 @@
&NSVER;
</section2>
</section1>
<section1 topic='Design Considerations' anchor='design'>
<p>Versions 0.4 and 0.5 of this specification define more or less the same protocol in the namespace urn:xmpp:jingle:jingle-message:1 (but in many places using MUST rather than SHOULD and removing &lt;proceed/&gt; in favor of &lt;accept/&gt;). To provide for greater backwards compatibility, version 0.6 of this document switched back to the old urn:xmpp:jingle:jingle-message:0 namespace. Future updates requiring a namespace bump should therefore directly bump the namespace version to :2 ans skip :1.</p>
</section1>
<section1 topic='XML Schema' anchor='schema'>
<code><![CDATA[
<?xml version='1.0' encoding='UTF-8'?>
@ -425,8 +484,8 @@
<xs:schema
xmlns:xs='http://www.w3.org/2001/XMLSchema'
xmlns:xml='http://www.w3.org/XML/1998/namespace'
targetNamespace='urn:xmpp:jingle-message:1'
xmlns='urn:xmpp:jingle-message:1'
targetNamespace='urn:xmpp:jingle-message:0'
xmlns='urn:xmpp:jingle-message:0'
elementFormDefault='qualified'>
<xs:element name='propose'>

View File

@ -13,19 +13,21 @@
</abstract>
&LEGALNOTICE;
<number>0426</number>
<status>Deferred</status>
<status>Experimental</status>
<type>Informational</type>
<sig>Standards</sig>
<approver>Council</approver>
<dependencies/>
<supersedes/>
<supersededby/>
<shortname>charcount</shortname>
<author>
<firstname>Marvin</firstname>
<surname>Wissfeld</surname>
<email>xsf@larma.de</email>
<jid>jabber@larma.de</jid>
</author>
&larma;
<revision>
<version>0.3.0</version>
<date>2022-12-27</date>
<initials>lmw</initials>
<remark>Added section about subsequences.</remark>
</revision>
<revision>
<version>0.2.0</version>
<date>2020-01-02</date>
@ -165,47 +167,80 @@
across platforms and as such should be used with care.
</p>
</section2>
<section2 topic='Rationale' anchor='rationale'>
<p>
The most obvious way of counting characters is to count them how humans
would. This sounds easy when only having western scripts in mind but becomes
more complicated in other scripts and most importantly is not well-defined
across Unicode versions. New unicode versions regularly added new
possibilities to build grapheme clusters, including from existing code
points. To be forward compatible, counting grapheme clusters, graphemes,
glyphs or similar is thus not an option.
This leaves basically the two options of using the number of code units of
the encoded string or the number of code points.
</p>
<p>
The main advantage of using the code units would be that those are native to
many programming languages, easing the task for developers.
However programming languages do not share a common encoding for their
string type (C/C++ use UTF-8, C#/Java use UTF-16, Python 3 hides the
internal encoding from the developer and only presents it in code points),
so there is no best pick here.
If one was to choose an encoding, the best choice would be UTF-8, the native
encoding of XMPP. However this makes counting bytes a more complex task for
programming languages that use a different encoding like UTF-16, as strings
would need to be transcoded first.
</p>
<p>
Counting code points has the advantage that offset counts cannot point
inside a code point. This could happen when using code units of any encoding
that may use more than one unit to represent a code point (such as UTF-8 and
UTF-16).
If an offset count points inside a code point, that would be an invalid
offset, raising more uncertainty of the correct behavior in such cases. Most
notably the opportunity of splitting (as it exists for grapheme cluster) is
not an option in that case, because splitting a code point would not create
any usable output.
Counting code points is widely supported in programming languages and can
easily be implemented for encoded strings when not.
The &w3xml; standard also defines a character as a unicode code point, thus
counting code points is equivalent to counting XML characters.
</p>
</section2>
</section1>
<section1 topic='Rationale' anchor='rationale'>
<section1 topic='Subsequences' anchor='subsequence'>
<p>
The most obvious way of counting characters is to count them how humans
would. This sounds easy when only having western scripts in mind but becomes
more complicated in other scripts and most importantly is not well-defined
across Unicode versions. New unicode versions regularly added new
possibilities to build grapheme clusters, including from existing code
points. To be forward compatible, counting grapheme clusters, graphemes,
glyphs or similar is thus not an option.
This leaves basically the two options of using the number of code units of
the encoded string or the number of code points.
</p>
<p>
The main advantage of using the code units would be that those are native to
many programming languages, easing the task for developers.
However programming languages do not share a common encoding for their
string type (C/C++ use UTF-8, C#/Java use UTF-16, Python 3 hides the
internal encoding from the developer and only presents it in code points),
so there is no best pick here.
If one was to choose an encoding, the best choice would be UTF-8, the native
encoding of XMPP. However this makes counting bytes a more complex task for
programming languages that use a different encoding like UTF-16, as strings
would need to be transcoded first.
</p>
<p>
Counting code points has the advantage that offset counts cannot point
inside a code point. This could happen when using code units of any encoding
that may use more than one unit to represent a code point (such as UTF-8 and
UTF-16).
If an offset count points inside a code point, that would be an invalid
offset, raising more uncertainty of the correct behavior in such cases. Most
notably the opportunity of splitting (as it exists for grapheme cluster) is
not an option in that case, because splitting a code point would not create
any usable output.
Counting code points is widely supported in programming languages and can
easily be implemented for encoded strings when not.
The &w3xml; standard also defines a character as a unicode code point, thus
counting code points is equivalent to counting XML characters.
When referencing a subsequence of the characters of a message body, the
begin and end of the subsequence should be provided by two numbers, denoting
the number of characters (counted as described above) before the begin of the
subsequence or before the end of the subsequence, respectively. In other
words, the begin is the index of the first character in the subsequence and
the end is the index following the last character in the subsequence. That
means, if a subsequence covers the full body, its begin should be given as
0 and its end should be given as the number of characters in the body.
</p>
<section2 topic='Developer notes' anchor='subsequence-developer-notes'>
<p>
Subsequence indexing in various programming languages match the convention
described here. When using Python, the subsequence created by
<tt>body[begin:end]</tt> matches all requirements of this document.
</p>
<p>
Some programming languages define subsequences by offset and length. In
this case, begin matchs the offset while end-begin matches the length.
</p>
</section2>
<section2 topic='Rationale' anchor='subsequence-rationale'>
<p>
The convention for subsequences was choosen because it has three main
advantages: It matches subsequence indexing in various programming
languages, end minus begin of a subsequence equal the length of the
subsequence and the end of the first of two adjacent subsequence matches the
begin of the second one.
</p>
</section2>
</section1>
<section1 topic='Glossary' anchor='glossary'>

View File

@ -22,6 +22,7 @@
<supersededby/>
<shortname>fallback</shortname>
&dcridland;
&larma;
<revision>
<version>0.1.1</version>
<date>2020-03-03</date>

View File

@ -43,6 +43,12 @@
<initials>NC</initials>
<remark>Add emoji rejection mechanism.</remark>
</revision>
<revision>
<version>0.1.1</version>
<date>2022-12-30</date>
<initials>egp</initials>
<remark>Add the XML Schema</remark>
</revision>
<revision>
<version>0.1.0</version>
<date>2020-10-13</date>
@ -324,4 +330,27 @@
</ul>
</section2>
</section1>
<section1 topic='XML Schema' anchor='schema'>
<section2 topic='urn:xmpp:reactions:0' anchor='schema-reactions'>
<code><![CDATA[
<?xml version='1.0' encoding='UTF-8'?>
<xs:schema
xmlns:xs='http://www.w3.org/2001/XMLSchema'
targetNamespace='urn:xmpp:reactions:0'
xmlns='urn:xmpp:reactions:0'
elementFormDefault='qualified'>
<xs:element name='reactions'>
<xs:complexType>
<xs:sequence minOccurs='0' maxOccurs='unbounded'>
<xs:element name='reaction' type='xs:string'/>
</xs:sequence>
<xs:attribute name='id' type='xs:string' use='required'/>
</xs:complexType>
</xs:element>
</xs:schema>]]></code>
</section2>
</section1>
</xep>

View File

@ -15,6 +15,7 @@
<status>Experimental</status>
<type>Standards Track</type>
<sig>Standards</sig>
<approver>Council</approver>
<dependencies/>
<supersedes/>
<supersededby/>
@ -30,6 +31,12 @@
<email>xsf@larma.de</email>
<jid>jabber@larma.de</jid>
</author>
<revision>
<version>0.2.0</version>
<date>2022-12-09</date>
<initials>nc</initials>
<remark>Fix example character counting. Add disco feature. Relax the 'to' attribute constraints.</remark>
</revision>
<revision>
<version>0.1.0</version>
<date>2022-01-25</date>
@ -58,11 +65,38 @@
</p>
</section1>
<section1 topic='Discovering support' anchor='disco'>
<p>
If a client implements message replies, it MUST specify the
'urn:xmpp:reply:0' feature in its service discovery information features
as specified in &xep0030; and the Entity Capabilities profile specified in &xep0115;.
</p>
<example caption='Client requests information about a chat partner&apos;s client'><![CDATA[
<iq type='get'
to='romeo@montague.lit/orchard'
from='juliet@capulet.lit/balcony'
id='info1'>
<query xmlns='http://jabber.org/protocol/disco#info'/>
</iq>]]></example>
<example caption='Partner&apos;s client advertises support for replies'><![CDATA[
<iq type='result'
to='juliet@capulet.lit/balcony'
from='romeo@montague.lit/orchard'
id='info1'>
<query xmlns='http://jabber.org/protocol/disco#info'>
...
<feature var='urn:xmpp:reply:0'/>
...
</query>
</iq>]]></example>
</section1>
<section1 topic='Use Cases' anchor='usecases'>
<p>
To indicate that a message is a reply, a &lt;reply&gt; element in the urn:xmpp:reply:0 namespace is placed in the
message stanza. The &lt;reply&gt; element has a 'to' attribute containing the full jid of the author of the
referenced message and an 'id' attribute containing the id of the referenced message.
message stanza. The &lt;reply&gt; element SHOULD have a 'to' attribute containing the full jid of the author of the
referenced message and MUST have an 'id' attribute containing the id of the referenced message.
In a 1:1 chat context, a bare jid MAY be used instead of a full jid.
</p>
<example caption="Max replies to Anna's message"><![CDATA[
<message to='max@example.com' from='anna@example.com/tablet' id='message-id1' type='chat'>
@ -78,6 +112,8 @@
<p>
To provide a fallback for non-supporting clients, the sending client MAY include fallback text in the body and
indicate it via Compatibility Fallback.
Note that the following example is formatted for readability and that the indentation, leading and trailing new lines
of the example body element should not be taken into account.
</p>
<example caption="Anna replies to a message and includes a fallback"><![CDATA[
<message to='anna@example.com' id='message-id3' type='chat'>
@ -88,7 +124,7 @@
</body>
<reply to='anna@example.com/laptop' id='message-id1' xmlns='urn:xmpp:reply:0' />
<fallback xmlns='urn:xmpp:feature-fallback:0' for='urn:xmpp:reply:0'>
<body start="0" end="36" />
<body start="0" end="38" />
</fallback>
</message>]]></example>

576
xep-0471.xml Normal file
View File

@ -0,0 +1,576 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE xep SYSTEM 'xep.dtd' [
<!ENTITY % ents SYSTEM 'xep.ent'>
%ents;
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
<xep>
<header>
<title>Events</title>
<abstract>This specification describe how to handle events with XMPP.</abstract>
&LEGALNOTICE;
<number>0471</number>
<status>Experimental</status>
<type>Standards Track</type>
<sig>Standards</sig>
<approver>Council</approver>
<dependencies>
<spec>XMPP Core</spec>
<spec>XEP-0001</spec>
<spec>XEP-0004</spec>
<spec>XEP-0060</spec>
<spec>XEP-0447</spec>
<spec>XEP-0470</spec>
</dependencies>
<supersedes/>
<supersededby/>
<shortname>events</shortname>
<author>
<firstname>Jérôme</firstname>
<surname>Poisson</surname>
<email>goffi@goffi.org</email>
<jid>goffi@jabber.fr</jid>
</author>
<revision>
<version>0.1.0</version>
<date>2022-12-13</date>
<initials>XEP Editor (jsc)</initials>
<remark>Accepted by vote of Council on 2022-09-28.</remark>
</revision>
<revision>
<version>0.0.1</version>
<date>2022-09-08</date>
<initials>jp</initials>
<remark><p>First draft.</p></remark>
</revision>
</header>
<section1 topic='Introduction' anchor='intro'>
<p>Nowadays, it is common to handle all kind of events through desktop computer or phone: it is useful to have them at hand, to easily share them and to have all kind of reminders.</p>
<p>XMPP is a good fit to handle events: it's a communication protocol, and as such it would be useful for it to have tools to handle and share events.</p>
<p>The only existing attempt at this point is &xep0097; which describe a way to wrap iCal<note>iCalendar <link url='https://datatracker.ietf.org/doc/html/rfc5545'>https://datatracker.ietf.org/doc/html/rfc5545</link></note> data. However, this XEP never got traction, is not taking advantage of XMPP features, doesn't handle thing such as invitees and RSVP, and it not easily extensible.</p>
<p>This XEP proposes an alternative which leverage existing tools such as &xep0060;.</p>
</section1>
<section1 topic='Requirements' anchor='reqs'>
<p>The design goals of this XEP are:</p>
<ul>
<li>use pubsub and its access model to be able to have events either private or public, and to take advantage of the subscription mechanism</li>
<li>being able to specify simple events with minimum metadata (e.g. doctor appointment, coffee with a friend)</li>
<li>provide optional tools such as RSVP or invitees list for events organization</li>
<li>it should be possible to optionally ask any kind of extra data in RSVP (e.g.: number of people attending, allergy information for dinner, etc.)</li>
<li>group several events of same kind in a pubsub node (e.g. personal agenda, work agenda, events linked to an organization)</li>
<li>flexible enough to specify all kind of extra metadata (e.g. description, classification tags, accessibility information) and media (e.g. main picture)</li>
<li>being able to optionally link to other pubsub features such as &xep0277; blog, or a way to share picture after the event is finished</li>
<li>be extensible</li>
</ul>
</section1>
<section1 topic='Glossary' anchor='glossary'>
<ul>
<li><strong>RSVP</strong>: "<link url='https://en.wikipedia.org/wiki/RSVP'>Répondez s'il vous plaît</link>", a way for event invitees to indicate whether they plan to attend the event</li>
</ul>
</section1>
<section1 topic='Use Cases' anchor='usecases'>
<section2 topic='Creating a Simple Event' anchor='simple-event'>
<p>Juliet and her nurse decide to have a coffee together. Juliet knows the usual place where they're going, and thus doesn't need to add much information, she creates an event for her agenda on her XMPP client. The client creates an item on Juliet's PEP node `urn:xmpp:events:0` as follow:</p>
<example caption="Minimal Event"><![CDATA[
<iq
type='set'
from='juliet@capulet.lit/chamber'
to='juliet@capulet.lit'
id='event1'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='urn:xmpp:events:0'>
<item>
<event xmlns='urn:xmpp:events:0'>
<name>Coffee with the nurse</name>
<start>2022-09-05T12:00:00Z</start>
<end>2022-09-05T13:00:00Z</end>
</event>
</item>
</publish>
</pubsub>
</iq>]]></example>
<section3 topic='explanation' anchor='simple-event-explanation'>
<p>An event is published on a &xep0060; item. Juliet publishes this event on her personal agenda, thus she uses the node 'urn:xmpp:events:0' (see <link url='#events_nodes'>events nodes</link>). The payload of an event is an &lt;event/&gt; element qualified by the namespace 'urn:xmpp:events:0'. Each event MUST have one or several &lt;name/&gt; elements containing a human readable short text describing the element. If several &lt;name/&gt; elements are used, they MUST have distinct 'xml:lang' attributes, to specify the same name in different languages. Each &lt;event/&gt; element MUST have a &lt;start/&gt; and an &lt;end/&gt; child elements specifying the expected start time and end time of the event by using the format explained in &xep0082;.</p>
<p>This is all for the minimum required elements of an event, everything else is optional. Thus, the only required elements of an event payload are &lt;name/&gt;, &lt;start/&gt; and &lt;end/&gt;.</p>
</section3>
</section2>
<section2 topic='Organizing an Event' anchor='originazing-event'>
<p>Juliet is organizing a ball, and to make things easier she uses her XMPP client to manage it. To make the event more appealing, she'll publish a nice image of the ball room as main picture of the event, and she'll publish the list of invitees. She'll also need RSVP to evaluate the number of people attending.</p>
<p>The event she's publishing looks as follows:</p>
<example caption="Organising an Event"><![CDATA[
<iq
type='set'
from='juliet@capulet.lit/chamber'
to='pubsub.capulet.lit'
id='event2'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='urn:xmpp:events:0/balls'>
<item id='2022_ball'>
<event xmlns='urn:xmpp:events:0'>
<name xml:lang='en'>Capulet's Ball</name>
<start>2022-12-15T20:00:00Z</start>
<end>2022-12-16T02:00:00Z</end>
<head-picture>
<file-sharing xmlns='urn:xmpp:sfs:0' disposition='inline'>
<file xmlns='urn:xmpp:file:metadata:0'>
<media-type>image/jpeg</media-type>
<name>ball_room.jpg</name>
<size>120354</size>
<dimensions>1920x1080</dimensions>
<hash xmlns='urn:xmpp:hashes:2' algo='sha3-256'>2XarmwTlNxDAMkvymloX3S5+VbylNrJt/l5QyPa+YoU=</hash>
<hash xmlns='urn:xmpp:hashes:2' algo='id-blake2b256'>2AfMGH8O7UNPTvUVAM9aK13mpCY=</hash>
<desc>Photo of the ball room.</desc>
<thumbnail xmlns='urn:xmpp:thumbs:1' uri='cid:sha1+ffd7c8d28e9c5e82afea41f97108c6b4@bob.capulet.lit' media-type='image/png' width='640' height='360'/>
</file>
<sources>
<url-data xmlns='http://jabber.org/protocol/url-data' target='https://download.capulet.lit/123abc-def-456-789/ball_room.jpg' />
<jinglepub xmlns='urn:xmpp:jinglepub:1' from='download.capulet.lit' id='123abc-def-456-789'>
<description xmlns='urn:xmpp:jingle:apps:file-transfer:5' />
</jinglepub>
</sources>
</file-sharing>
</head-picture>
<description type='text' xml:lang='en'>
The Capulet familly is organizing its great annual ball! Come and enjoy the event of the year…
</description>
<description type='xhtml' xml:lang='en'>
<div xmlns='http://www.w3.org/1999/xhtml'>
The Capulet familly is organizing its great <strong>annual ball!</strong> Come and enjoy the event of the year…
</div>
</description>
<category term='ball' wd='Q478515' xml:lang=en />
<category term='dance' wd='Q11639' xml:lang=en />
<category term='music' wd='Q638' xml:lang=en />
<location>
<geoloc xmlns='http://jabber.org/protocol/geoloc' xml:lang='en'>
<locality>Capulet's House</locality>
<country>Italy</country>
<lat>45.4181</lat>,
<lon>10.9637</lon>
<text>Code for entrance gate: 0123C</text>
</geoloc>
</location>
<rsvp xml:lang='en'>
<x xmlns="jabber:x:data" type="form">
<field var="FORM_TYPE" type="hidden">
<value>urn:xmpp:events:rsvp:0</value>
</field>
<field type='list-single' label='Attending' var='attending'>
<value>maybe</value>
<option label='maybe'><value>maybe</value></option>
<option label='yes'><value>yes</value></option>
<option label='no'><value>no</value></option>
<required/>
</field>
</x>
</rsvp>
<invitees jid='pubsub.capulet.lit' node='urn:xmpp:events:invitees:0/2022_ball' />
<comments jid='pubsub.capulet.lit' node='urn:xmpp:microblog:0:comments/2022_ball' />
<blog jid='pubsub.capulet.lit' node='2022_ball_blog' />
<schedule jid='pubsub.capulet.lit' node='urn:xmpp:events:0/2022_ball_schedule' />
<attachments>
<file-sharing xmlns='urn:xmpp:sfs:0' disposition='inline'>
<file xmlns='urn:xmpp:file:metadata:0'>
<media-type>application/pdf</media-type>
<name>dinner_menu.pdf</name>
<size>50123</size>
<hash xmlns='urn:xmpp:hashes:2' algo='sha3-256'>d7b7d858663d110761ac4c9b7dbc4d8408445b16be0b9cedb908a2c7b454335a</hash>
<desc>Menu for the ball dinner.</desc>
</file>
<sources>
<url-data xmlns='http://jabber.org/protocol/url-data' target='https://download.capulet.lit/789abc-def-123-456/dinner_menu.pdf' />
<jinglepub xmlns='urn:xmpp:jinglepub:1' from='download.capulet.lit' id='789abc-def-123-456'>
<description xmlns='urn:xmpp:jingle:apps:file-transfer:5' />
</jinglepub>
</sources>
</file-sharing>
</attachments>
<extra>
<x xmlns="jabber:x:data" type="result">
<field var="FORM_TYPE" type="hidden">
<value>urn:xmpp:events:extra:0</value>
</field>
<field var='website'>
<value>https://ball2022.capulet.lit</value>
</field>
<field var='accessibility:wheelchair'>
<value>full</value>
</field>
</x>
</extra>
</event>
</item>
</publish>
</pubsub>
</iq>]]></example>
<section3 topic='explanation' anchor='simple-event-explanation'>
<p>Juliet wants to be sure that this event will be a success, thus she provides a lot of information. The first 3 elements &lt;name/&gt;, &lt;start/&gt; and &lt;end/&gt; are the mandatory one as specified in <link url='#simple-event-explanation'>simple event explanation</link>, all other elements are optionals. The elements used are briefly explained below, and are more detailed in <link url='#events-data'>Events Data</link> section.</p>
<p>The &lt;head-picture/&gt; element indicate where to find the head picture, or in other terms the main image used to represent the event. This image is used by clients to nicely represent the event to end-user.</p>
<p>&lt;description/&gt; elements contain human readable text to explain what the event is about.</p>
<p>&lt;category/&gt; elements are used to classify the event. This is useful to quickly give an idea of what the event is about, and for events discovery.</p>
<p>&lt;location/&gt; specify where the event takes place. It may also be used for online events.</p>
<p>&lt;rsvp/&gt; contains the form that invitees will answer to indicate if they plan to attend the event.</p>
<p>The 4 following elements &lt;invitees/&gt;, &lt;comments/&gt;, &lt;blog/&gt; and &lt;schedule/&gt; link to pubsub nodes respectively handling list of invitees, comments on the events, blog talking about the event, and event schedule. They are described in <link url='#linked_nodes'>Linked Pubsub Nodes</link> section.</p>
<p>&lt;attachments/&gt; elements provide any kind of files that can be useful to the event. It's used here to provide the menu for the dinner.</p>
<p>Finally, the &lt;extra/&gt; element contains a data form for any useful extra information.</p>
</section3>
</section2>
</section1>
<section1 topic='Events Nodes' anchor='events_nodes'>
<p>Events are published to pubsub nodes. Each user may have a personal agenda on its &xep0163; service, by using the 'urn:xmpp:events:0' node. This node should have an access model of "whitelist" by default, however it is up to the entity holding the PEP node to use an other access model (a JID linked to an organisation may want to make public all its events from the personal agenda by using an "open" access model).</p>
<p>Otherwise, a node may be published on any pubsub service. An events node SHOULD be prefixed with 'urn:xmpp:events:0/', which SHOULD be followed by an unique identifier.</p>
<p>A pubsub node can contain any kind of events, and it is up to the publisher to decide what to put inside. While a personal agenda will hold events related to the owning entity, an events node can be used to keep events related to a school or other organisation, to a room (e.g. to show when and by whom a room is booked), to a team, to professional appointments, etc.</p>
</section1>
<section1 topic='Events Data' anchor='events-data'>
<p>This section describe the various optional elements usable as children of an &lt;event/&gt; element. The 3 mandatory elements &lt;name/&gt;, &lt;start/&gt; and &lt;end/&gt; are specified in <link url='#simple-event-explanation'>Simple Event Explanation</link>.</p>
<section2 topic='Head Picture' anchor='head-picture'>
<p>&lt;head-picture/&gt; element describe the image to use to represent the event to end-user. It is recommended to include it for public events as it may help to give a rough idea of the event, and to represent nicely a summary of the event. Keep in mind that the picture may be resized or cropped to fit end-user display and client's UI choices.</p>
<p>The element MUST contain a child &lt;file-sharing/&gt; element as described &xep0447;. The image SHOULD be published in JPEG format due to its widespread support and the fact that mostly photos are expected to be used as head pictures.</p>
<p>It is strongly recommended to include thumbnails if the head picture is large, as the event may be displayed on any screen size.</p>
</section2>
<section2 topic='Description' anchor='description'>
<p>The &lt;description/&gt; element is used to give an human readable text explaining the event. It is the main presentation of the event, usually highlighted below the head picture.</p>
<p>The description may be in plain text, in this case the &lt;description/&gt; MUST have a 'type' attribute with a value of "text". The element then contains the plain text description.</p>
<p>XHTML may also be used to provide rich description. To do so, the "xhtml" value must be used for the 'type' attribute, and the first child element of the &lt;description/&gt; element MUST be a &lt;div/&gt; element qualified by the 'http://www.w3.org/1999/xhtml' namespace. Note that the content MUST be sanitized before being shown to end-user, please check <link url='#security'>Security Considerations</link> for some advices.</p>
<p>The "xml:lang" attribute SHOULD be present on each description element.</p>
<p>Several &lt;description/&gt; elements MAY be present, as long as they have distinct "type"/"xml:lang" combination. It is not mandatory to provide a text or XHTML description, and providing only one of them is valid.</p>
</section2>
<section2 topic='Categories' anchor='categories'>
<p>It is possible to give categories to the event with the &lt;category/&gt; element. This is specially useful for event discovery, and to give a rought idea of what the event is about. A &lt;category/&gt; MUST have a 'term' attribute with a human readable word or short words combination describing the category, and SHOULD have a "xml:lang" attribute set.</p>
<p>Whenever possible, the &lt;category/&gt; SHOULD have a "wd" attribute whose value is the <link url='https://www.wikidata.org/wiki/Wikidata:Identifiers'>Wikidata Entity ID</link>
<note>to find the ID corresponding to the term, you can either <link url='https://www.wikidata.org/wiki/Special:Search'>search on Wikidata itself</link>, or <link url='https://www.wikidata.org/wiki/Wikidata:Identifiers'>check it via Wikipedia</link>. An item entity identifier is needed, thus it should start with a "Q". IDs can also be found via <link url='https://www.mediawiki.org/wiki/API:Main_page'>Wikipedia API</link> or <link url='https://www.wikidata.org/wiki/Wikidata:Data_access'>Wikidata API</link>.</note>.
Wikidata is an open and collaborative database with over 100 million items. By specifying the Wikidata entity ID corresponding to the term, the category becomes machine readable and can be easily translated, associated to similar terms, linked to corresponding Wikipedia page in end-user language, and so on.</p>
</section2>
<section2 topic='Location' anchor='location'>
<p>It is often important to indicate the place where the event happens. This is done by using a &lt;location/&gt; element which is wrapping zero or one &xep0080; &lt;geoloc/&gt; element and any number of &lt;online/&gt; elements (described below).</p>
<p>&lt;online/&gt; element is used for virtual meeting using a computer. If is it the under the same &lt;location/&gt; element than a &lt;geoloc/&gt; element, the online meeting is done in parallel to the physical meeting.</p>
<p>There may be several &lt;location&gt; elements if the meeting happens in several places (either at the same time, or one after the other). If several locations are used, each &lt;location/&gt; element MUST have an 'id' attribute with an unique identifier. At least one of the &lt;location/&gt; SHOULD have an 'id' with a value of "main", indicating that it is the main meeting place (which can then be used to discover events by geographical coordinates). When the event is presented to end-user using HTML, the rendering software SHOULD set an 'id' attribute to the element showing the location with the value "location_&lt;LOCATION_ID&gt;" (e.g. for the "main" location, the 'id' attribute would have a value of "location_main"), this way location may then be linked in the XHTML description.</p>
<section3 topic="Online Location" anchor='online_location'>
<p>If the meeting is virtual or if a virtual meeting happens in parallel for those who can't go physically to the event, one or more &lt;online/&gt; elements can be used to give the instructions.</p>
<p>The only mandatory &lt;online/&gt; child element is &lt;instructions/&gt; which contains a human readable text explaining how to join the online meeting. The &lt;instructions/&gt; element SHOULD have a 'xml:lang' attribute, and several &lt;instructions/&gt; elements MAY be present if they have distinct 'xml:lang' attributes.</p>
<p>&lt;online/&gt; MAY have an optional &lt;name/&gt; child with a human readable text, this is notably useful if several online locations are used at the same time for different purpose (e.g.: global announces, lost and found, etc.). The &lt;name/&gt; element SHOULD have a 'xml:lang' attribute.</p>
<p>If the online location is on an XMPP MUC, an &lt;x/&gt; element qualified by the 'jabber:x:conference' namespace as described in &xep0249; can be used.</p>
<p>It may be useful to indicate which software is used for the meeting. This is done with the &lt;software/&gt; element which MUST have a 'name' attribute with the software name, SHOULD have a 'wd' attribute with Wikidata entity ID when available (see <link url='#categories'>Categories section</link> for explanation on Wikidata) as it provides a lot of machine readable useful information such as where it can be found, on which platforms it is running, etc. The &lt;software/&gt; SHOULD also have an 'url' attribute with the URL to the official software website as value. The 'need_install' attribute MAY be used with a value of either 'true' if the software needs to be installed or 'false' if it's not necessary (i.e. if it's accessible directly via a web resource).</p>
<p>The &lt;url-data/&gt; provide the main URL to be used to join the online meeting. It is specified in &xep0103;</p>
<example caption="Online Location"><![CDATA[
<iq
type='set'
from='juliet@capulet.lit/chamber'
to='pubsub.capulet.lit'
id='event3'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='urn:xmpp:events:0/ball_organisation'>
<item>
<event xmlns='urn:xmpp:events:0'>
<!---->
<location>
<online>
<name xml:lang="en">Ball organisation</name>
<software name='Jitsi Meet' wd='Q87849488' url='https://meet.jit.si/' need_install='false' />
<url-data xmlns='http://jabber.org/protocol/url-data' target='https://jitsi.capulet.lit/ball_2022_organisation' />
<instructions xml:lang='en'>
Just click on the link to access the room. We'll be discussion about organisation of the Capulet ball.
</instructions>
</online>
<online>
<x xmlns='jabber:x:conference' jid='ball_talks@muc.capulet.lit' />
<instructions xml:lang='en'>
Join this room for any king of discussions which need to be written, and to share files.
</instructions>
</online>
</location>
<!---->
</event>
</item>
</publish>
</pubsub>
</iq>]]></example>
</section3>
</section2>
<section2 topic='RSVP' anchor='RSVP'>
<p>RSVP is a major tools when an event is organized: it helps to check if invitees have seen the event, and to evaluate the total number of people attending. The &lt;rsvp&gt; element MUST contain form as specified in &xep0004; and &xep0068;. The form must be specified as explained in &xep0068; with &lt;field/&gt; having a 'type' attribute with a value of "hidden", a 'var' with a value of "FORM_TYPE", and the field value MUST be "urn:xmpp:events:rsvp:0".</p>
<p>The form is the one which has to be answered by invitees, it SHOULD contain a field with a 'type' attribute of value "list-single" and a 'var' attribute of value "attending" with 3 options of respective value "maybe", "yes" and "no". This is the main field and it's the one which will be used to estimate the number of attendees. However, an event organizer MAY decide to modify the available options, for instance if the "maybe" option is not desired. This element SHOULD have a &lt;required/&gt; child element.</p>
<p>An optional field named "participants_number" MAY be used to indicate the number of attendees, including the person answering. This field has the default type of "text-single". If present, it will be used to summarize the expected number of persons participating to the event, otherwise one person per attending invitee will be assumed.</p>
<p>Any other field can be added to request extra information to invitees. For instance, it may be used to ask if attendees have allergies, or who is bringing what to a picnic. If a new field is added, &xep0068; MUST be followed, and the 'var' attribute MUST be namespaced using &clark;.</p>
<p>The answer is provided by attendees using &xep0470;: an &lt;rsvp/&gt; element qualified by the 'urn:xmpp:events:0' namespace is attached to the event item, containing the submitted data.</p>
<p>&lt;rsvp/&gt; element SHOULD have a 'xml:lang' attribute set to the language of the labels. Several &lt;rsvp/&gt; elements MAY be present, in which case they MUST have distinct 'xml:lang' attributes.</p>
<example caption="RSVP Form"><![CDATA[
<iq
type='set'
from='juliet@capulet.lit/chamber'
to='pubsub.capulet.lit'
id='event4'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='urn:xmpp:events:0/picnics'>
<item id='picnic_ab123'>
<event xmlns='urn:xmpp:events:0'>
<!---->
<rsvp>
<x xmlns="jabber:x:data" type="form">
<field var="FORM_TYPE" type="hidden">
<value>urn:xmpp:events:rsvp:0</value>
</field>
<field type='list-single' label='Attending' var='attending'>
<value>maybe</value>
<option label='maybe'><value>maybe</value></option>
<option label='yes'><value>yes</value></option>
<option label='no'><value>no</value></option>
<required/>
</field>
<field label='Number of persons comming (including you)' var='participants_number'>
<value>1</value>
</field>
<field
label='Do you have any allergy or food restriction?'
var='{https://example.org/some_software}restrictions'
type='text-multi' />
</x>
</rsvp>
<!---->
</event>
</item>
</publish>
</pubsub>
</iq>]]></example>
<example caption="Romeo Submit his RSVP Answer"><![CDATA[
<iq from='romeo@montague.lit/123'
id='events_5'
to='pubsub.capulet.lit'
type='set'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='xmpp:pubsub.capulet.lit?;node=urn%3Axmpp%3Aevents%3A0%2Fpicnics;item=picnic_ab123'>
<item id='romeo@montague.lit'>
<attachments>
<rsvp xmlns='urn:xmpp:events:0'>
<x xmlns="jabber:x:data" type="submit">
<field var='FORM_TYPE'>
<value>>urn:xmpp:events:rsvp:0</value>
</field>
<field var='attending'>
<value>yes</value>
</field>
<field var='{https://example.org/some_software}restrictions'>
<value>no</value>
</field>
</x>
</rsvp>
</attachments>
</item>
</publish>
</pubsub>
</iq>
]]></example>
<section3 topic='RSVP Summarizing' anchor='rsvp_summarizing'>
<p>To summarize RSVP answers, as explained in &xep0470;, the number of attendees is counted with 2 values: "confirmed" which are attendees coming for sure, and "max" which is the maximum number of persons expected.</p>
<p>For each &lt;rsvp/&gt; element attached, the count is done like this:</p>
<ul>
<li>the increment is equal to the value of the 'participants_number' field, or 1 if
<ol>
<li>the 'participants_number' field is not used or not present in submitted values</li>
<li>the value doesn't cast to an int</li>
<li>the int value is lower than 1</li>
</ol>
</li>
<li>if the value of 'attending' field is not set or "no", then nothing is done</li>
<li>if the value of 'attending' field is "yes", both "confirmed" and "max" are increased by the increment value</li>
<li>if the value of 'attending' field is "maybe", only "max" is increased by the increment value</li>
</ul>
<p>The summary is done in an &lt;attendees/&gt; element qualified by the 'urn:xmpp:events:0' namespace, with a 'confirmed' attribute whose value is the number of confirmed invitees, and a 'max' attribute with the maximum number of invitees expected. If 'max' is the same number as 'confirmed' (meaning that nobody has answered "maybe"), then it may be omitted.</p>
<example caption="Juliet Check Current Summary of RSVP"><![CDATA[
<iq from='pubsub.capulet.lit'
id='events_6'
to='juliet@capulet.lit/chamber'
type='result'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<items node='urn:xmpp:pubsub-attachments:summary:1/urn:xmpp:events:0/picnics'>
<item id='picnic_ab123'>
<summary xmlns='urn:xmpp:pubsub-attachments:summary:1'>
<!---->
<attendees xmlns='urn:xmpp:events:0' confirmed='5' max='7' />
<!---->
</summary>
</item>
</items>
</pubsub>
</iq>
]]></example>
</section3>
<section3 topic='Private RSVP' anchor='private_rsvp'>
<p>Due to the way &xep0470; is working, the normal way to answer RSVP is visible to everybody which can see the event. This is normally not a problem as people which attend the event can see by themselves who is there or not, however some persons may not want to have their RSVP or JID exposed to other participants. In this case the RSVP MAY be sent through a &MESSAGE; stanza directed to the JID of the event publisher. The RSVP is then simply put as a child of the stanza, with an optional &lt;body/&gt;. If not &lt;body/&gt; is provided or if the body in empty, The &MESSAGE; SHOULD include a &lt;store&gt; hint as specified in &xep0334;.</p>
<p>Note that sending an RSVP with a &MESSAGE; may complicate the organisation: it's then not counted automatically in the attachments summary, and if several persons are organizing the event, they may not all check easily the participation.</p>
<example caption="Romeo Submit a Private RSVP Answer"><![CDATA[
<message from='romeo@montague.lit/123' to='juliet@.capulet.lit' >
<rsvp xmlns='urn:xmpp:events:0'>
<x xmlns="jabber:x:data" type="submit">
<field var='FORM_TYPE'>
<value>>urn:xmpp:events:rsvp:0</value>
</field>
<field var='attending'>
<value>yes</value>
</field>
<field var='{https://example.org/some_software}restrictions'>
<value>no</value>
</field>
</x>
</rsvp>
<store xmlns="urn:xmpp:hints"/>
</message>
]]></example>
</section3>
</section2>
<section2 topic='Linked Pubsub Nodes' anchor='linked_nodes'>
<p>Some useful external pubsub nodes can be linked to the event. Those nodes are linked through elements which always have a 'jid' attribute specifying the JID of the pubsub or &xep0163; service, and a 'node' attribute specifying the pubsub node used. The supported elements are described below.</p>
<section3 topic='invitees' anchor='linked_invitees'>
<p>&lt;invitees/&gt; element links to a node containing one item per invitee. This node access model MAY be different to the one of the event itself: it can for instance have a "whitelist" access model to restrict the list of invitees only to organisers. In other words, it's not because an user has access to the event item that they have necessarily access to the list of invitees. Each item of the invitees node has a simple payload with an &lt;invitee/&gt; element qualified by the 'urn:xmpp:events:0' namespace and whose attributes are the mandatory 'jid' with the JID of the invitee, and an optional 'name' attribute with a human readable name.</p>
</section3>
<example caption="Pubsub Service Returns the List of Invitees to Juliet"><![CDATA[
<iq type='result'
from='pubsub.capulet.lit'
to='juliet@capulet.lit/chamber'
id='invitees_123'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<items node='urn:xmpp:events:invitees:0/2022_ball'>
<item id='abcdef'>
<invitee jid='nurse@capulet.lit' name='Nurse' />
</item>
<item id='123456'>
<invitee jid='tybalt@capulet.lit' name='Tybalt' />
</item>
<!---->
</items
</pubsub>
</iq>
]]></example>
<section3 topic='comments' anchor='linked_comments'>
<p>The &lt;comments/&gt; element link to a &xep0277; comments node holding comments to the event iself.</p>
</section3>
<section3 topic='blog' anchor='linked_blog'>
<p>The &lt;blog/&gt; element link to a &xep0277; node with a blog about the event. It is useful to keep people updated about any news or preparation information.</p>
</section3>
<section3 topic='schedule' anchor='linked_schedule'>
<p>The &lt;schedule/&gt; element link to an events node (i.e. a node using this specification) describing the programation which will happens during the main event. Put another way, it's were information such as dinner time, talks, workshop, etc. can be added.</p>
<p>Several events in the schedule MAY happen at the same time or overlapping time (for instance: various talks happening in parallel in a conference), in which case the locations SHOULD be specified (e.g. in which room each talk is taking place). Schedule MAY include events with RSVP (e.g. for a workshop needing inscription).</p>
</section3>
</section2>
<section2 topic='Attachments' anchor='attachments'>
<p>The &lt;attachments/&gt; elements is used to attach all kinds of files which may be useful to the event (menu, map, badge template, and so forth). It contains one or more &lt;file-sharing/&gt; elements as specified by &xep0447;.</p>
</section2>
<section2 topic='Extra Data' anchor='extra'>
<p>The &lt;extra/&gt; element hold a data form containing any relevant extra data. The form must be specified by using a FORM_TYPE field with the value "urn:xmpp:events:extra:0" and a 'type' with the value "hidden". Below some fields are specified, a software MAY add additional field. Any new field MUST follow &xep0068; and be namespaced using &clark;. All field and the form itself are optional.</p>
<p>The following fields may be used, if not specified otherwise their type is "text-single":</p>
<ul>
<li><strong>website</strong>: the value links to a website dedicated to the event</li>
<li><strong>status</strong>: indicate if the event will happen for sure or if it's a tentative. The possible values are "confirmed" if the event will happen for sure, "tentative" if the event may happen dependant on some condition (e.g. number of participants, convenient date found), and "cancelled" if the event won't happen. Note that "tentative" events may be moved to another time<note>technically any event can be moved to a different time, the "tentative" status just make it a stronger possibility</note>.</li>
<li><strong>languages</strong>: indicate the main languages that will be used during the event. The field is of type "list-multi", and each language value is an <link url='https://en.wikipedia.org/wiki/ISO_639'>ISO 639</link> language code.</li>
<li><strong>accessibility:wheelchair</strong>: indicates if the event is accessible to wheelchairs. The possible values are "full" for an event totally accessible to wheelchair, "partial" when some zones may be difficult to access, and "no" when the zone is not adapted for wheelchairs.</li>
</ul>
</section2>
<section2 topic='External Event' anchor='external'>
<p>An event may link to an other one. This is often useful when ones want to participate to an event and add it to their own personal agenda</p>
<p>To link an external event, an &lt;external/&gt; element is used which MUST have the 3 following attributes: 'jid' with the JID of the pubsub service of the linked event, 'node' with the name of the pubsub node and 'item' with the ID of the linked event item.</p>
<p>Generally, only the 3 mandatory &lt;name/&gt;, &lt;start/&gt; and &lt;end/&gt; elements are specified in addition to the &lt;external/&gt; one, the reason being that all data of the events SHOULD be retrieved from the original event itself. The start and end time are still specified through to be sure that the event won't be automatically moved to an unapproved time spot if the original event is modified.</p>
<example caption="Romeo Link Capulet's Ball in His Personal Agenda"><![CDATA[
<iq
type='set'
from='romeo@montague.lit/123'
to='romeo@montague.lit'
id='event_link_123'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='urn:xmpp:events:0'>
<item>
<event xmlns='urn:xmpp:events:0'>
<name xml:lang='en'>Capulet's Ball</name>
<start>2022-12-15T20:00:00Z</start>
<end>2022-12-16T02:00:00Z</end>
<external jid='pubsub.capulet.lit' node='urn:xmpp:events:0/balls' item='2022_ball' />
</event>
</item>
</publish>
</pubsub>
</iq>]]></example>
</section2>
</section1>
<section1 topic='Business Rules' anchor='rules'>
<p>TODO</p>
</section1>
<section1 topic='Discovering Support' anchor='disco'>
<p>If a client supports the Events protocol specified in this XEP, it must advertize it by including the "urn:xmpp:events:0" discovery feature in response to a &xep0030; information request:</p>
<example caption="Service Discovery information request"><![CDATA[
<iq type='get'
from='juliet@example.org/balcony'
to='romeo@example.org/orchard'
id='disco1'>
<query xmlns='http://jabber.org/protocol/disco#info'/>
</iq>]]></example>
<example caption="Service Discovery information response"><![CDATA[
<iq type='result'
from='romeo@example.org/orchard'
to='juliet@example.org/balcony'
id='disco1'>
<query xmlns='http://jabber.org/protocol/disco#info'>
...
<feature var='urn:xmpp:events:0'/>
...
</query>
</iq>]]></example>
<p>Similarly, if a PEP/Pubsub service implements the summarizing of RSVP as described in <link url='#rsvp_summarizing'>RSVP Summarizing</link>, it MUST advertise that fact by including the "urn:xmpp:events:0" discovery feature in response to a &xep0030; information request:</p>
<example caption="Service Discovery information request"><![CDATA[
<iq type='get'
from='juliet@example.org/balcony'
to='pubsub.capulet.lit'
id='disco2'>
<query xmlns='http://jabber.org/protocol/disco#info'/>
</iq>]]></example>
<example caption="Service Discovery information response"><![CDATA[
<iq type='result'
from='pubsub.capulet.lit'
to='juliet@example.org/balcony'
id='disco2'>
<query xmlns='http://jabber.org/protocol/disco#info'>
...
<feature var='urn:xmpp:events:0'/>
...
</query>
</iq>]]></example>
</section1>
<section1 topic='Security Considerations' anchor='security'>
<p>TODO</p>
</section1>
<section1 topic='IANA Considerations' anchor='iana'>
<p>TODO</p>
</section1>
<section1 topic='XMPP Registrar Considerations' anchor='registrar'>
<p>TODO</p>
</section1>
<section1 topic='XML Schema' anchor='schema'>
<p>TODO</p>
</section1>
<section1 topic='Acknowledgements' anchor='acks'>
<p>Thanks to JC Brand for spelling corrections.</p>
</section1>
</xep>

358
xep-0472.xml Normal file
View File

@ -0,0 +1,358 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE xep SYSTEM 'xep.dtd' [
<!ENTITY % ents SYSTEM 'xep.ent'>
%ents;
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
<xep>
<header>
<title>Pubsub Social Feed</title>
<abstract>This specification defines a way of publishing social content over XMPP.</abstract>
&LEGALNOTICE;
<number>0472</number>
<status>Experimental</status>
<type>Standards Track</type>
<sig>Standards</sig>
<approver>Council</approver>
<dependencies>
<spec>XMPP Core</spec>
<spec>XMPP IM</spec>
<spec>XEP-0060</spec>
<spec>RFC 4287</spec>
</dependencies>
<supersedes>
<spec>XEP-0277</spec>
</supersedes>
<supersededby />
<shortname>psf</shortname>
<author>
<firstname>Timothée</firstname>
<surname>Jaussoin</surname>
<email>edhelas@movim.eu</email>
<jid>edhelas@movim.eu</jid>
<uri>https://edhelas.movim.eu</uri>
</author>
<revision>
<version>0.1.1</version>
<date>2022-12-24</date>
<initials>tj</initials>
<remark>
<ul>
<li>Change the specified pubsub#type profiles to be more consistent</li>
<li>Rephrase some paragraphs</li>
<li>Fix examples formating</li>
</ul>
</remark>
</revision>
<revision>
<version>0.1.0</version>
<date>2022-12-13</date>
<initials>XEP Editor (jsc)</initials>
<remark>Accepted by vote of Council on 2022-10-19.</remark>
</revision>
<revision>
<version>0.0.1</version>
<date>2022-09-26</date>
<initials>tj</initials>
<remark>Initial version.</remark>
</revision>
</header>
<section1 topic='Introduction' anchor='intro'>
<p>Social Networking plaftorms are often built around the concept of feeds. XMPP offers, through &xep0060;, a really generic way of Publishing and Subscribing elements on XMPP nodes. This extension defines a way to publish social content on Pubsub nodes using &rfc4287;</p>
<p>Social features in XMPP were historically built on the &xep0277; specifications. However, in practice, Microblogging was not clearly defined in more common cases such as on generic Pubsub nodes and it was not easy to differentiate social nodes from the other ones. The current XEP defines a more generic way of handling Social Feeds on XMPP by declaring a secific pubsub#type for those Pubsub nodes and by keeping &xep0277; as a subset of it.</p>
</section1>
<section1 topic='Glossary' anchor='glossary'>
<dl>
<di>
<dt>Profile</dt>
<dd>
Defined by a specific Pubsub type (pubsub#type) a profile is a Pubsub Social Feed with some constraints. See the
<link url="#profiles">Profiles</link>
section.
</dd>
</di>
</dl>
</section1>
<section1 topic='Protocol' anchor='protocol'>
<section2 topic='Location' anchor='location'>
<p>
A Pubsub Social Feed can be located on any Pubsub node on the XMPP network. Some specific use cases, such as the personal eventing (PEP) node Microblog is defined in the
<link url="#profiles">Profiles</link>
section.
</p>
</section2>
<section2 topic='Publishing a Post' anchor='publish'>
<p>The publication of a Post consist of a valid &rfc4287; entry embeded in a &xep0060; item.</p>
<p>The post content itself can be either text (content element without "type" attribute or with "type" attribute with "text" value) or XHTML ("content" element "type" attribute with "xhtml" value). If Romeo publishes XHTML content, his client MUST publish two "content" elements: a text one, and a XHTML one. For XHTML publishing, see &xep0060;.</p>
<example caption="Publishing a post"><![CDATA[
<iq from='romeo@montague.lit/pda'
id='pub1'
to='new.montague.lit'
type='set'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='montague-family'>
<item id='1cb57d9c-1c46-11dd-838c-001143d5d5db'>
<entry xmlns='http://www.w3.org/2005/Atom'>
<title type='text'>hanging out at the Caf&amp;#233; Napolitano</title>
<id>tag:montague.lit,2008-05-08:posts-1cb57d9c-1c46-11dd-838c-001143d5d5db</id>
<published>2008-05-08T18:30:02Z</published>
<updated>2008-05-08T18:30:02Z</updated>
</entry>
</item>
</publish>
</pubsub>
</iq>
]]></example>
<p>Note: The "title" element is required to be included in an "atom:entry" element according to &rfc4287;. An implementation MAY provide also "atom:summary" and/or "atom:content" elements too if it needs.</p>
<section3 topic="Publishing a Post with Rich Content" anchor="rich_content">
<p>It's possible to insert some rich content in the post. It can be some text formatting, images, etc. Only "xhtml" content type is supported for the moment by this document but possibly it will be extended later.</p>
<example caption="Publishing a post with rich content"><![CDATA[
<iq from='romeo@montague.lit/pda'
id='pub2'
to='news.montague.lit'
type='set'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='montague-family'>
<item id='1cb57d9c-1c46-11dd-838c-001143d5d5db'>
<entry xmlns='http://www.w3.org/2005/Atom'>
<title type='xhtml'>
<div xmlns="http://www.w3.org/1999/xhtml">
<p>hanging out at the <strong>Caf&amp;#233; Napolitano</strong></p>
</div>
</title>
<id>tag:montague.lit,2008-05-08:posts-1cb57d9c-1c46-11dd-838c-001143d5d5db</id>
<published>2008-05-08T18:30:02Z</published>
<updated>2008-05-08T18:30:02Z</updated>
<generator uri='https://capu.chat' version='42'>CapuChat</generator>
</entry>
</item>
</publish>
</pubsub>
</iq>
]]></example>
</section3>
</section2>
<section2 topic='Receiving a Post' anchor='receive'>
<p>
Because Juliet is subscribed to some Romeo's family Pubsub service nodes. Romeo's XMPP server will send a Pubsub notification to Juliet. The notification can include an XMPP message body for backwards-compatibility with Jabber clients that are not pubsub-capable (see
<link url="#body">Message Body</link>
).
</p>
<example caption="Receiving a post"><![CDATA[
<message from='news.montague.lit'
to='juliet@capulet.lit'
type='headline'>
<body>hanging out at the Caf&amp;#233; Napolitano</body>
<event xmlns='http://jabber.org/protocol/pubsub#event'>
<items node='montague-family'>
<item id='1cb57d9c-1c46-11dd-838c-001143d5d5db' publisher='romeo@montague.lit'>
<entry xmlns='http://www.w3.org/2005/Atom'>
<title type='text'>hanging out at the Caf&amp;#233; Napolitano</title>
<link rel='alternate'
type='text/html'
href='http://montague.lit/romeo/posts/1cb57d9c-1c46-11dd-838c-001143d5d5db'/>
<link rel='alternate'
href='xmpp:news.montague.lit?;node=montague-family;item=1cb57d9c-1c46-11dd-838c-001143d5d5db'/>
<id>tag:montague.lit,2008-05-08:posts-1cb57d9c-1c46-11dd-838c-001143d5d5db</id>
<published>2008-05-08T18:30:02Z</published>
<updated>2008-05-08T18:30:02Z</updated>
<generator uri='https://capu.chat' version='42'>CapuChat</generator>
</entry>
</item>
</items>
</event>
</message>
]]></example>
<p>Note: these alternate links were not posted by the original client because some clients can't compute them themselves. These things SHOULD be inserted at server side though.</p>
</section2>
<section2 topic='Replying to a Post' anchor='reply'>
<p>Anyone can publish a post in reply to Romeo's post. Here we assume that a reply comes from Benvolio.</p>
<p>Note: Inclusion of the "thr:in-reply-to" element defined in &rfc4685; indicates the post to which the user is replying. This reply includes two such elements (one pointing to the HTTP URL for the post and the other pointing to the XMPP URI for the post.</p>
<p>Note: The post can be a reply to more than the only one another.</p>
<example caption="Publishing a reply"><![CDATA[
<iq from='benvolio@montague.lit/mobile'
id='uv2x37s5'
to='news.montague.lit'
type='set'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='montague-family'>
<item id='c4145006-1c53-11dd-b2d5-000bcd82471e'>
<entry xmlns='http://www.w3.org/2005/Atom'
xmlns:thr='http://purl.org/syndication/thread/1.0'>
<author>
<name>Benvolio Montague</name>
<uri>xmpp:romeo@montague.lit</uri>
</author>
<title type='text'>@romeo cappuccino this late in the day?</title>
<link rel='alternate'
type='text/html'
href='http://montague.lit/benvolio/posts/c4145006-1c53-11dd-b2d5-000bcd82471e'/>
<link rel='alternate'
href='xmpp:news.montague.lit?;
node=montague-family;
item=c4145006-1c53-11dd-b2d5-000bcd82471e'/>
<id>tag:montague.lit,2008-05-08:posts-c4145006-1c53-11dd-b2d5-000bcd82471e</id>
<published>2008-05-08T18:31:21Z</published>
<updated>2008-05-08T18:31:21Z</updated>
<thr:in-reply-to
ref='tag:montague.lit,2008-05-08:posts-1cb57d9c-1c46-11dd-838c-001143d5d5db'
type='application/xhtml+xml'
href='http://montague.lit/romeo/posts/1cb57d9c-1c46-11dd-838c-001143d5d5db'/>
<thr:in-reply-to
ref='tag:montague.lit,2008-05-08:posts-1cb57d9c-1c46-11dd-838c-001143d5d5db'
href='xmpp:news.montague.lit?;node=montague-family;item=1cb57d9c-1c46-11dd-838c-001143d5d5db'/>
</entry>
</item>
</publish>
</pubsub>
</iq>
]]></example>
<p>Assuming that Romeo has also subscribed to the same node he will receive the reply that Benvolio sent.</p>
</section2>
<section2 topic='Repeating a Post' anchor='repeat'>
<p>When Benvolio wants to repeat a Romeo's post, his client publishes the same post under a different name. But to be able to track the repeated post original author, Benvolio's client MAY use specific "atom:author" child node, "atom:name" and "atom:uri", containing, respectively, the name of the original post author, and his XMPP URI (JID).</p>
<p>The client SHOULD also put an "atom:link" element with "rel" attribute set to "via" and point it to the original post.</p>
<example caption="Repeating a Post"><![CDATA[
<iq from='benvolio@montague.lit/mobile'
id='pub2'
to='news.montague.lit'
type='set'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='montague-family'>
<item id='1re57d3c-1q46-11dd-748r-024943d2d5rt'>
<entry xmlns='http://www.w3.org/2005/Atom'>
<author>
<name>Romeo Montague</name>
<uri>xmpp:romeo@montague.lit</uri>
</author>
<title type='text'>hanging out at the Caf&amp;#233; Napolitano</title>
<link rel='alternate'
type='text/html'
href='http://montague.lit/benvolio/posts/1re57d3c-1q46-11dd-748r-024943d2d5rt'/>
<link rel='alternate'
href='xmpp:news.montague.lit?;node=montague-family;item=1re57d3c-1q46-11dd-748r-024943d2d5rt'/>
<link rel='via'
href='xmpp:rnews.montague.lit?;node=montague-family;item=1cb57d9c-1c46-11dd-838c-001143d5d5db'
ref='tag:montague.lit,2008-05-08:posts-1cb57d9c-1c46-11dd-838c-001143d5d5db'/>
<id>tag:montague.lit,2008-05-08:posts-1re57d3c-1q46-11dd-748r-024943d2d5rt</id>
<published>2008-05-08T18:30:02Z</published>
<updated>2008-05-08T18:32:02Z</updated>
</entry>
</item>
</publish>
</pubsub>
</iq>
]]>
</example>
<p>Thus, a different author JID value lets the client know the item has been repeated from another one.</p>
<p>It's also possible for Benvolio to add his own thougths to the repost. To do this he SHOULD wrap the original content in the "xhtml:blockquote" element and after it add his own content. Also, the client MAY post reply without quotation to the original thread to inform users about the repost.</p>
</section2>
<section2 topic='Atom and XMPP integration' anchor='atom_xmpp_integration'>
<section3 topic="Pubsub Item ID vs. Atom Entry id" anchor="pubsub_id_vs_atom_id">
<p>There are two different things that carry a similar sense: the XMPP Pubsub Item ID and the "atom:id" element. This section is devoted to make a separation between them.</p>
<p>The pubsub Item ID MUST be used when linking to an entry with an XMPP channel (i.e. by including it in the URI with the "xmpp" schema). the Atom entry ID MUST be built according to &rfc4287; and used in aggregators with the aim of revealing of post duplicates, reposts, mentions, syndications, etc.</p>
<p>Note that the rules of comparing, building and security notes for "atom:id" are listed in the &rfc4287;.</p>
</section3>
<section3 topic='Message Body' anchor='body'>
<p>Depending on service policies and the value of the "pubsub#include_body" node configuration option, Pubsub Social Feed notifications SHOULD include a message "body" element for backwards-compatibility with Jabber clients that are not pubsub-capable. It is RECOMMENDED for the XML character value of the "body" element to be the same as that of the "atom:title" child of the "atom:entry".</p>
</section3>
<section3 topic='Geotagging' anchor='geotagging'>
<p>Juliet may want to know which places are Romeo's notices related to. That's why Romeo's client MAY geotag microblog entries, using the &xep0080; protocol for storing geolocation information.</p>
<p>Romeo's client MUST create a "geoloc" element, with the &xep0080; reference namespace: "http://jabber.org/protocol/geoloc".</p>
<example caption="Geotagging a Post"><![CDATA[
<iq from='romeo@montague.lit/mobile'
id='pub7'
to='romeo@montague.lit'
type='set'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='urn:xmpp:microblog:0'>
<item id='1zr23z8a-3g12-34fh-750b-120867gjc1sqh'>
<entry xmlns='http://www.w3.org/2005/Atom'>
<author>
<name>Romeo Montague</name>
<uri>xmpp:romeo@montague.lit</uri>
</author>
<title type='text'>Is lost in the forest. Need help!</title>
<id>tag:montague.lit,2008-05-08:posts-1zr23z8a-3g12-34fh-750b-120867gjc1sqh</id>
<published>2008-05-08T18:43:01Z</published>
<updated>2008-05-08T18:43:01Z</updated>
<geoloc xmlns="http://jabber.org/protocol/geoloc">
<lat>48.171761</lat>
<lon>-3.3667986</lon>
<country>France</country>
<countrycode>FR</countrycode>
<region>Brittany</region>
</geoloc>
</entry>
</item>
</publish>
</pubsub>
</iq>
]]></example>
</section3>
</section2>
</section1>
<section1 topic="Profiles" anchor="profiles">
<p>Pubsub Social feeds are specified under profiles. Those profiles are constraints applied to nodes and defined by a specific Pubsub type (see &xep0060;#registrar-formtypes-metadata)</p>
<p>
All the profiles MUST base their default configuration on the
<link url="#profile_base">Base profile</link>
.
</p>
<section2 topic="Base profile" anchor="profile_base">
<p>This profile is specified by the Pubsub type "urn:xmpp:pubsub-social-feed:0" and define a generic Pubsub Social Feed that can be hosted on any Pubsub service node or &xep0163; node.</p>
<p>Those restrictions MUST be used by all the other profiles defined bellow and in other XEPs based on Pubsub Social Feed.</p>
<section3 topic="Pubsub Node Configuration" anchor="profile_base_node_config">
<ol>
<li>The "pubsub#notify_retract" MUST be set to "true" to provide clients the ability to track if some items were retracted and reflect such changes in the UI correctly.</li>
<li>The "pubsub#max_items" MUST be set to the "max" value, as defined in the &xep0060;.</li>
<li>The "pubsub#persist_items" MUST be set to "true".</li>
<li>The "pubsub#send_last_published_item" SHOULD be set to "never".</li>
<li>The "pubsub#deliver_payloads" SHOULD be set to "false". The social content can be quite large so it is advised to let the clients to manually query the content if it is not already cached.</li>
</ol>
</section3>
</section2>
<section2 topic="Microblog profile" anchor="profile_microblog">
<p>This profile is defined by the Pubsub type "urn:xmpp:microblog:0" as defined in &xep0277; and MUST be created and configured under the PEP "urn:xmpp:microblog:0" node.</p>
</section2>
<section2 topic="Gallery profile" anchor="profile_gallery">
<p>This profile is defined by the Pubsub type "urn:xmpp:pubsub-social-gallery:0" and can be hosted on any Pubsub service.</p>
<p>All the items published in a gallery node MUST only have at least one attached picture. This picture MUST be of type "enclosure" as specified in &rfc4287;.</p>
<example caption="An Atom attached picture"><![CDATA[
<link rel='enclosure' href='https://capulet.lit/upload/romeo.jpg' type='image/jpeg' title='Romeo Portrait'/>
]]></example>
</section2>
</section1>
<section1 topic='Security Considerations' anchor='security'>
<p>There are no security features or concerns related to this proposal.</p>
</section1>
<section1 topic='IANA Considerations' anchor='iana'>
<p>This document requires no interaction with &IANA;.</p>
</section1>
<section1 topic='XMPP Registrar Considerations' anchor='registrar'>
<p>The &REGISTRAR; is requested to issue an initial namespace of "urn:xmpp:social:0" and "urn:xmpp:gallery:0".</p>
</section1>
<section1 topic='XML Schema' anchor='schema'>
<p>
This specification re-uses the schema for the Atom content format, i.e., the 'http://www.w3.org/2005/Atom' namespace (see
<cite>RFC 4287</cite>
).
</p>
</section1>
</xep>

268
xep-0473.xml Normal file
View File

@ -0,0 +1,268 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE xep SYSTEM 'xep.dtd' [
<!ENTITY % ents SYSTEM 'xep.ent'>
%ents;
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
<xep>
<header>
<title>OpenPGP for XMPP Pubsub</title>
<abstract>Specifies an OpenPGP for XMPP (XEP-0373) profile for the pubsub use case.</abstract>
&LEGALNOTICE;
<number>0473</number>
<status>Experimental</status>
<type>Standards Track</type>
<sig>Standards</sig>
<approver>Council</approver>
<dependencies>
<spec>XMPP Core</spec>
<spec>XEP-0001</spec>
<spec>XEP-0004</spec>
<spec>XEP-0060</spec>
<spec>XEP-0373</spec>
</dependencies>
<supersedes/>
<supersededby/>
<shortname>oxps</shortname>
<author>
<firstname>Jérôme</firstname>
<surname>Poisson</surname>
<email>goffi@goffi.org</email>
<jid>goffi@jabber.fr</jid>
</author>
<revision>
<version>0.1.0</version>
<date>2022-12-13</date>
<initials>XEP Editor (jsc)</initials>
<remark>Accepted by vote of Council on 2022-10-19.</remark>
</revision>
<revision>
<version>0.0.6</version>
<date>2022-10-12</date>
<initials>jp</initials>
<remark>
<ul>
<li>add forgotten "jid" and "node" attribute to &lt;revoke/&gt;</li>
<li>clarify that &lt;openpgp/&gt; wrapper is used</li>
</ul>
</remark>
</revision>
<revision>
<version>0.0.5</version>
<date>2022-10-12</date>
<initials>jp</initials>
<remark>
<ul>
<li>add forgotten "timestamp" in example</li>
<li>add implementation node on double encryption</li>
<li>add clarification that sender should be a node owner</li>
</ul>
</remark>
</revision>
<revision>
<version>0.0.4</version>
<date>2022-10-11</date>
<initials>jp</initials>
<remark>
<ul>
<li>add a security note to indicate that &lt;shared-secret/&gt; and &lt;revoke/&gt; sender must be checked.</li>
</ul>
</remark>
</revision>
<revision>
<version>0.0.3</version>
<date>2022-10-10</date>
<initials>jp</initials>
<remark>
<ul>
<li>Base64 is not needed for the key (it's a passphrase)</li>
<li>Specify that as least on &MESSAGE; should be encrypted for sender other devices</li>
<li>Recommend minimum length for shared secret</li>
</ul>
</remark>
</revision>
<revision>
<version>0.0.2</version>
<date>2022-10-10</date>
<initials>jp</initials>
<remark><p>Remove useless references to XEP-0374 + acknowledgements</p></remark>
</revision>
<revision>
<version>0.0.1</version>
<date>2022-10-09</date>
<initials>jp</initials>
<remark><p>First draft.</p></remark>
</revision>
</header>
<section1 topic='Introduction' anchor='intro'>
<p>&xep0060; and &xep0163; are widely used XMPP features. However, items are published in plain text, making them readable by server administrators or anybody having administrator level access on the pubsub/PEP services.</p>
<p>Although this is not a problem for data intended to be published publicly, there are many cases where it may be desirable to make the data inaccessible to anybody but the selected recipients, or in other words to end-to-end encrypt the data.</p>
<p>This specification aims to provide an easy way to e2e encrypt items of a pubsub node, and to share access with other entities. It is compatible with all existing pubsub/PEP features, which makes it possible to use securily features such a geolocation, private blogs, private calendar events, data forms, etc.</p>
</section1>
<section1 topic='Requirements' anchor='reqs'>
<p>The design goals of this XEP are:</p>
<ul>
<li>work with basic standard pubsub/PEP service, no extra feature needed;</li>
<li>be generic and work with any protocol using pubsub: once decrypted, the items should be parsable as if they were plain text;</li>
<li>be able to share with other entities the means to decipher the elements;</li>
<li>be able to easily share the means of decrypting items with new entities, even after the items have been published;</li>
<li>be able to modify the means of decryption to make the new elements inaccessible to certain entities even if they have had access to the previous elements;</li>
</ul>
</section1>
<section1 topic='Glossary' anchor='glossary'>
<ul>
<li><strong>e2ee</strong>: end-to-end encryption</li>
<li><strong>Shared Secret</strong>: a cryptographically strong random string used to symmetrically encrypt items</li>
<li><strong>Encrypted Node</strong>: pubsub node whose items are end-2-end encrypted using this protocol.</li>
</ul>
</section1>
<section1 topic='Overview' anchor='overview'>
<p>To encrypt a pubsub node, each item is symmetrically encrypted with a shared secret using OpenPGP symmetric encryption. The secret is shared with other entities using e2e encrypted messages with &xep0373;. If an entity's access is revoked or a shared secret may have been compromised, a new shared secret is generated and new items are encrypted with it.</p>
</section1>
<section1 topic='Use Cases' anchor='usecases'>
<section2 topic='Encrypting Pubsub Item' anchor='encrypt'>
<p>Juliet wants to create a private blog (using &xep0277;) that she only share with her confidante and her lover. To make sure that her family, who manages her XMPP server, can't read the content, she want to use end-to-end encryption.</p>
<p>To do so, her client creates a "shared secret" by generating a cryptographically strong key that will be used to symmetrically encrypt new items. This key MUST be associated with an ID, which MUST be an unique sequence of characters usable in an XML attribute. She will later share this key with entities allowed to access or publish on the blog as explained below.</p>
<p>From now on, all items that Juliet publishes on the node SHOULD be symmetrically encrypted with the shared secret by using OpenPGP symmetric encryption.</p>
<p>To publish an encrypted item, an &lt;encrypted/&gt; element qualified by the 'urn:xmpp:openpgp:pubsub:0' namespace MUST be used as payload. This element MUST contain a 'secret' attribute whose value is the ID of the shared secret used. The content of the element is a base64 encoded Symmetric-Key Encrypted Session Key Packet as specified at <cite>RFC 4880</cite> <link url='http://tools.ietf.org/html/rfc4880#section-5.3'>§ 5.3</link> (in a similar way as <link url='https://xmpp.org/extensions/xep-0373.html#backup-encryption'>secret key backup is encoded in XEP-0373</link>). The encrypted content is the item payload that would normally be used.</p>
<p>The encrypted node SHOULD have a "whitelist" access model as specified in &xep0060;. Juliet's client ensure that either by creating a new node with suitable access model, or by changing the access model of existing node.</p>
<example caption="Juliet publish an encrypted item"><![CDATA[
<iq
type='set'
from='juliet@capulet.lit/chamber'
to='pubsub.capulet.lit'
id='encrypted1'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='123abc'>
<item id="encrypt_123">
<encrypted xmlns='urn:xmpp:openpgp:pubsub:0' key='1234-abcd-5678-efgh'>
<!-- BASE64_OPENPGP_SYMMETRICALLY_ENCRYPTED_ITEM -->
</encrypted>
</item>
</publish>
</pubsub>
</iq>]]></example>
</section2>
<section2 topic='Transmit Shared Secret' anchor='transmit_secret'>
<p>Now that Juliet has started to publish encrypted items on a blog, she wants to share the secret key with her confidante and her lover. To do so she uses a e2ee &MESSAGE; stanza by using an &lt;openpgp/&gt; element wrapping a &lt;signcrypt/&gt; as specified in <link url='https://xmpp.org/extensions/xep-0373.html#exchange'>XEP-0373 "Exchanging OpenPGP Encrypted and Signed Data"</link>. The encrypted payload of the &lt;signcrypt/&gt; MUST contain a &lt;shared-secret/&gt; element qualified by the 'urn:xmpp:openpgp:pubsub:0' namespace. This element MUST have the following attributes:</p>
<ul>
<li>a 'timestamp' attribute whose value is the datetime of the shared key generation. Datetime format is specified in &xep0082;.</li>
<li>a 'jid' attribute with bare JID of the pubsub/PEP service;</li>
<li>a 'node' attribute with the name of the encrypted node;</li>
<li>an 'id' attribute with the ID of the shared secret;</li>
<li>if the key is revoked (due to <link url='#revocation_rotation'>shared secret rotation</link>), it must have a 'revoked' attribute with the value "true".</li>
</ul>
<p>The &lt;shared-secret/&gt; SHOULD have a 'type' attribute whose value is the pubsub#type that the node would have if it were plain text (i.e. the semantic type information of decrypted data in the node, usually the namespace of the decrypted payload). </p>
<p>The content of the &lt;shared-secret/&gt; element MUST be the shared secret (i.e. the passphrase used to symmetrically encode items).</p>
<p>She send messages with the encrypted shared secret to her nurse, Romeo and herself (so her other devices get the shared secret too).</p>
<p>Entities MUST always use the most recently generated shared secret to encrypt new items (the 'timestamp' attribute is used to check generation date and time).</p>
<p>
Following example only show the &lt;shared-secret/&gt; element, as it is normally put as an encrypted payload of &xep0373; &lt;signcrypt/&gt; payload.
</p>
<example caption="shared-secret element (normally encrypted as part of XEP-0373's signcrypt payload)"><![CDATA[
<shared-secret
xmlns='urn:xmpp:openpgp:pubsub:0'
jid='pubsub.capulet.lit'
node='123abc'
id='1234-abcd-5678-efgh'
timestamp='2022-10-10T13:24:31Z'
type='http://www.w3.org/2005/Atom'
>
ZSRD5lK9mz-5VHNyu2N1XLiJZ8I87jkv85ceZkVrOGA
</shared-secret>
]]></example>
<p><strong>note:</strong> we use &MESSAGE; instead of PEP or Pubsub to transmit the shared secret for several reasons:</p>
<ul>
<li>Shared secret would have to be encrypted for all entities allowed to decrypt the items, and re-encrypted each time there is a new entity. While acceptable for a small number of entities, this doesn't scale as well as separated &MESSAGE;;</li>
<li>The item containing the shared secret would need to keep all previous shared secrets in case of secret rotation (see <link url='#revocation_rotation'>below</link>). At some point, there would be a risk to reach stanza maximum size limit of one server;</li>
<li>Using a well-known pubsub node or pubsub item id would mean than the location of the encrypted shared secret would be known. While not enough to get the secret, that's better to hide it in encrypted messages flow;</li>
</ul>
</section2>
<section2 topic='Revocation and Shared Secret Rotation' anchor='revocation_rotation'>
<p>If there is any doubt about the compromise of a shared secret or if access to the encrypted node is revoked for an entity, the shared secret SHOULD BE rotated.</p>
<p>To rotate a key, a &MESSAGE; must be sent to all people which got the shared secret. The &MESSAGE; MUST contain a XEP-0373 &lt;openpgp/&gt; element with a &lt;signcrypt/&gt; element whose payload is an encrypted &lt;revoke/&gt; element qualified by the 'urn:xmpp:openpgp:pubsub:0' namespace, which MUST have a 'jid' attribute whose value is the JID of the pubsub/PEP service where the node is, a 'node' attribute whose value is the name of the node, and an 'id' attribute whose value is the shared secret ID.</p>
<p>Optionally, the &lt;revoke/&gt; element MAY have one or more &lt;reason/&gt; child element(s) which contain a human readable message explaining the reason of the revocation. The &lt;reason/&gt; element MAY contain an 'xml:lang' attribute with the language code of the text, and there MAY be several &lt;reason/&gt; elements if and only if they have distinct xml:lang. A revoked key MUST NOT be used to encrypt new items.</p>
<p>Then a new shared secret MUST be generated and transmitted to all participants (excluding those who have seen their access revoked) as explained in <link url='#transmit_secret'>Transmit Shared Secret.</link></p>
<p>Note that if an entity's access is revoked, it SHOULD also be removed from the node's whitelist (if "whitelist" has been used as access model as recommended).</p>
<p>
Following example only show the &lt;revoke/&gt; element, as it is normally put as an encrypted payload of &xep0373; &lt;signcrypt/&gt; payload.
</p>
<example caption="revoke element (normally encrypted as part of XEP-0373's signcrypt payload)"><![CDATA[
<revoke xmlns='urn:xmpp:openpgp:pubsub:0' jid='pubsub.capulet.lit' node='123abc' id='1234-abcd-5678-efgh'>
<reason>Revoked access from an entity</reason>
</revoke>
]]></example>
<p>Items published before the key rotation SHOULD NOT be re-encrypted as it would be resource intensive, and revoked entities may have made a copy anyway.</p>
<p>When access to the shared secret is granted to a new entity, all previously used keys SHOULD be transmitted (with their 'revoked' attribute set to "true" as explained in <link url='#transmit_secret'>Transmit Shared Secret.</link>) along with the currently used shared secret. This allows the new entity to decrypt the items encrypted with the old keys. The &lt;shared-secret/&gt; elements can either be sent in the same encrypted payload of a single &MESSAGE;, or split into multiple encrypted &MESSAGE;, it's up to the implementation to decide which is better (keep in mind that too many shared secrets in a single message may reach the maximum stanza size limit at some point, even if this limit is not likely to be reached for most usual cases).</p>
</section2>
</section1>
<section1 topic='Business Rules' anchor='rules'>
<p>The shared secret and revocation SHOULD be generated by node owner.</p>
<p>&MESSAGE; with encrypted &lt;shared-secret/&gt; or &lt;revoke/&gt; elements MUST be sent to everybody who must have access to the node. At least one of the encrypted payload SHOULD be encrypted for the sender themselves (either by sending the &MESSAGE; directly to the sender, or to decrypt a copy received with &xep0280;), so other devices of the sender can get the shared secret too.</p>
<p>When &xep0470; are used, the attachment node SHOULD have the same access model (i.e. whitelist as recommended in <link url="#security">Security Considerations</link>) as the encrypted node, with authorized entities synchronized (this should be done automatically for <link url='https://xmpp.org/extensions/xep-0470.html#full-compliance'>fully compliant services</link>). The items published to attachment node itself MUST be encrypted using this protocol. Due to <link url='https://xmpp.org/extensions/xep-0470.html#validity-check'>validity check of attachment items</link>, the encrypted element MUST be a child of a XEP-0470's &lt;attachments/&gt; element, instead of being the &lt;item/&gt; payload as usual. Note that this will prevent the <link url="https://xmpp.org/extensions/xep-0470.html#summary-node">summary feature</link> to work with encrypted elements, and the end-user client will have to do the summary itself, this is an inevitable trade-off when using e2ee.</p>
<p>The "pubsub#type" of an encrypted item is always "urn:xmpp:openpgp:pubsub:0", thus no information is leaked on the content of the node, and all encrypted nodes can easily be retrieved by using &xep0462;.</p>
<p>Note that encrypted items MAY be mixed with plain text items: for instance if a blog is public, but some of its items are private. However the proper handling of this use case is out of scope of this specification.</p>
</section1>
<section1 topic='Implementation Notes' anchor='impl'>
<p>This specification uses &xep0373; independently of &xep0374;, implementations SHOULD avoid double encryption (e.g. by excluding &lt;openpgp/&gt; element qualified by 'urn:xmpp:openpgp:0' namespace from encryption by XEP-0374 implementation), and MUST ensure that element is correctly decrypted. Double encryption should be checked, and the &lt;openpgp/&gt; element MUST be decrypted even if OXIM (XEP-0374) is not being used.</p>
</section1>
<section1 topic='Discovering Support' anchor='disco'>
<p>If a client supports the protocol specified in this XEP, it MUST advertise it by including the "urn:xmpp:openpgp:pubsub:0" discovery feature in response to a &xep0030; information request:</p>
<example caption="Service Discovery information request"><![CDATA[
<iq type='get'
from='juliet@example.org/balcony'
to='romeo@example.org/orchard'
id='disco1'>
<query xmlns='http://jabber.org/protocol/disco#info'/>
</iq>]]></example>
<example caption="Service Discovery information response"><![CDATA[
<iq type='result'
from='romeo@example.org/orchard'
to='juliet@example.org/balcony'
id='disco1'>
<query xmlns='http://jabber.org/protocol/disco#info'>
...
<feature var='urn:xmpp:openpgp:pubsub:0'/>
...
</query>
</iq>]]></example>
</section1>
<section1 topic='Security Considerations' anchor='security'>
<ul>
<li>When receiving a &lt;shared-secret/&gt; or a &lt;revoke/&gt; element, the receiving client MUST ensure that the signing sender is the same as the one for all known shared secrets of this pubsub node (usually a node owner). This prevents a malicious actor for misleading the client into using a non-legitimate secret.</li>
<li>To limit the surface of attack, the access model of an encrypted node should be set to "whitelist" and only people having the shared key should be allowed to retrieve encrypted items.</li>
<li>If the shared key is compromised, or a user access is revoked, the key MUST be rotated. However, only new items are encrypted with the new key, any previous item should be considered as compromised too.</li>
<li>Sometimes client may use metadata to construct item ID, this is notably the case for some &xep0277; implementation, as the resulting item ID is used to generate user friendly URLs. To avoid metadata leakage, clients SHOULD NOT derivate the item ID from any data of the item when pubsub encryption is used.</li>
<li>Some protocols define prefixes for nodes, this is for instance the case for <link url='https://xmpp.org/extensions/xep-0277.html#comments'>XEP-0277 Comments</link>. If the prefix is not essential to make the feature work (which is the case for XEP-0277 comments), the client SHOULD NOT use the usual prefix to avoid leaking informations on the content of the node. The prefix defined in &xep0470; MUST be used as usually, as it is essential to retrieve the attachment node, and it's generic and thus doesn't leak information on the node content.</li>
<li>To decrypt archives and future items, clients most probably cache plain text version of items, and shared secret. If one device with access to an encrypted node is compromised, all items from the node should be considered compromised, and shared secret should be rotated.</li>
<li>For the same reason, client SHOULD encrypt data at rest (even if the device is stolen, data should not be accessible without some cryptographic key).</li>
<li>Note that only the shared key sender is authenticated (by &xep0373;'s &lt;signcrypt/&gt;), not the items publishers, meaning that encrypted items could be published by anybody in possession of the shared secret. Pubsub items authentication will be treated in a separated XEP.</li>
<li>The shared secret should be long enough to avoid brute force attacks. A secret of at least 32 characters is recommended.</li>
</ul>
</section1>
<section1 topic='IANA Considerations' anchor='iana'>
<p>TODO</p>
</section1>
<section1 topic='XMPP Registrar Considerations' anchor='registrar'>
<p>TODO</p>
</section1>
<section1 topic='XML Schema' anchor='schema'>
<p>TODO</p>
</section1>
<section1 topic='Acknowledgements' anchor='acks'>
<p>Thanks to Tim Henkes for his advices and NLNet foundation/NGI0 Discovery for funding.</p>
</section1>
</xep>

227
xep-0474.xml Normal file
View File

@ -0,0 +1,227 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE xep SYSTEM 'xep.dtd' [
<!ENTITY % ents SYSTEM 'xep.ent'>
%ents;
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
<xep>
<header>
<title>SASL SCRAM Downgrade Protection</title>
<abstract>This specification provides a way to secure the SASL and SASL2 handshakes against method and channel-binding downgrades.</abstract>
&LEGALNOTICE;
<number>0474</number>
<status>Experimental</status>
<type>Standards Track</type>
<sig>Standards</sig>
<approver>Council</approver>
<dependencies>
<spec>XMPP Core</spec>
<spec>RFC 5802</spec>
<spec>XEP-0388</spec>
</dependencies>
<supersedes/>
<supersededby/>
<shortname>SSDP</shortname>
&tmolitor;
<revision>
<version>0.2.0</version>
<date>2023-01-14</date>
<initials>tm</initials>
<remark>
<ul>
<li>Add description of attack model</li>
<li>Add section defining IETF interaction</li>
</ul>
</remark>
</revision>
<revision>
<version>0.1.0</version>
<date>2022-12-13</date>
<initials>XEP Editor (jsc)</initials>
<remark>Accepted by vote of Council on 2022-10-19.</remark>
</revision>
<revision>
<version>0.0.1</version>
<date>2022-10-11</date>
<initials>tm</initials>
<remark>Initial version.</remark>
</revision>
</header>
<section1 topic='Introduction' anchor='intro'>
<p>&rfc6120; and &xep0388; define a way to negotiate SASL mechanisms. When used together with SCRAM mechanisms (&rfc5802;) and channel-binding (&xep0440;) the mechanism selection is protected against downgrade attacks by an active MITM tampering with the TLS channel and advertised SASL mechanisms, while the negotiation of the channel-binding types is still not protected against such downgrade attacks.</p>
<p>&xep0440; tries to mitigate this by making the "tls-server-end-point" (&rfc5929;) channel-binding mandatory to implement for servers. But that leaves clients not able to implement this type, or any channel-binding at all, vulnerable to downgrades of channel-binding types and SASL mechanisms. Furthermore "tls-server-end-point" provides weaker security guarantees than other channel-bindings like for example "tls-exporter" (defined in &rfc5705; and &rfc9266;).</p>
<p>This specification aims to solve this issue by spcifying a downgrade protection for both SASL mechanisms and channel-binding types using an optional SCRAM attribute (see &rfc5802;). This specification can be used for SASL1 (&rfc6120;) and SASL2 (&xep0388;) profiles as well as any other SASL profile.</p>
<p>Note: In the long term the author strives to publish this as an RFC rather than a XEP to also make this protection available to other protocols, after gaining implementation experience.</p>
</section1>
<section1 topic='Glossary' anchor='glossary'>
<p>This specification uses some abbreviations:</p>
<ul>
<li>MITM: man-in-the-middle</li>
<li>CA: Certificate Authority</li>
<li>SASL1: the XMPP SASL profile specified in &rfc6120;</li>
<li>SASL2: the XMPP SASL profile specified in &xep0388;</li>
</ul>
</section1>
<section1 topic='Requirements' anchor='reqs'>
<p>This protocol was designed with the following requirements in mind:</p>
<ul>
<li>Allow detection of SASL mechanism downgrades even if no channel-binding is in use.</li>
<li>Allow detection of downgrades of channel-binding types.</li>
<li>Support all currently defined and future SCRAM mechanisms (&rfc5802; and &rfc7677;)</li>
</ul>
<p>Note that this specification intentionally leaves out support for SASL PLAIN. If server and client support PLAIN, no protection against SASL method or channel-binding downgrades is possible and the security relies solely on the underlying TLS channel. As explained in § 13.8.3 of &rfc6120;, servers and clients SHOULD NOT support SASL PLAIN unless it is required by the authentication backend.</p>
<p>A compromise might be to use pinning not for concrete SASL mechanisms, but instead pin that something better than SASL PLAIN was previously supported. Thus pinning will ensure that authentication won't fall back to SASL-PLAIN in the future, but also won't hinder protocol agility for the SCRAM family of SASL mechanisms etc..</p>
<section2 topic="Attack model 1 (list of channel-binding types)">
<p><strong>Scenario:</strong> Bob connects to Alice's XMPP server using a client of his choice supporting SCRAM and channel-binding, Eve wants to MITM this connection. Neither Alice's server nor Bob's client support SASL PLAIN, but only the SCRAM family of SASL mechanisms.</p>
<p><strong>Prerequisites:</strong> Eve, the MITM attacker, managed to either steal the cert+key of Alice's XMPP server or to convince some CA to give out a cert+key for Alice's XMPP domain. Maybe Bob even installed a CA of his employer/school and now gets MITMed by his employer/school.</p>
<p>Given this scenario and prerequisites, Eve now can passively MITM the XMPP connection, but Bob and Alice are using channel-binding and this allows them to detect Eve and abort authentication. This forces Eve to be an active attacker, manipulating the data in the XMPP stream to get rid of the channel-binding. Eve does so by changing the list of server-advertised channel-bindings to only include some (fictional) channel-binding types she is sure the client does not support. Bob's client now has the following choices (see also the Security Considerations of &xep0440;):</p>
<ol>
<li>Authenticate without using channel-binding and signal to the server that the client <em>does not</em> support channel-binding ("n" GS2-flag)</li>
<li>Authenticate without using channel-binding and signal to the server that the client <em>does</em> support channel-binding ("y" GS2-flag)</li>
<li>Try to authenticate using <em>some</em> channel-binding type</li>
<li>Try to authenticate using the <em>pinned</em> channel-binding type</li>
<li>Fall back to use the lowest denominator: "tls-server-end-point"</li>
</ol>
<p><strong>Case 1</strong> is a successful downgrade from channel-binding to non-channel-binding authentication, Eve "wins".</p>
<p><strong>Case 2</strong> will always fail the authentication if the server supports channel-binding, Eve does not "win". But authentication will fail even if there is no MITM present but server and client simply happen to have no mutually supported channel-binding type.</p>
<p><strong>Case 3</strong> can result in a successful or failed authentication, depending on wether the server supports the type randomly selected by the client. Unfortunately a failed authentication due to selecting the wrong channel-binding type can not be distinguished from a failed authentication because of invalid credentials etc. Thus authentication using <em>some</em> channel-binding type will slow down authentication speed, because the client has to cycle through all channel-binding types it supports until it finds one the server supports (and eventually fall back to no channel-binding, if all channel-binding types have been tried). So, if server and client have mutually supported channel-binding types, Eve won't "win", but authentication will potentially need many roundtrips. If they don't have mutually supported channel-bindig types, Eve wouldn't have had to manipulate the channel-binding list in the first place.</p>
<p><strong>Case 4</strong> does not help on first authentication. This could be neglected, but since channel-binding types aren't that easily ordered by percieved strength and could legitimately change, this could effectively lead to a Denial of Service. For example Alice might want to offload TLS termination because of higher server load and now her server does not support "tls-exporter" anymore but only "tls-server-end-point". A client pinning "tls-exporter" would not be able to connect to Alice's server anymore after the TLS offloading is in place.</p>
<p><strong>Case 5</strong> won't help if Eve managed to steal the cert+key (or the server either somehow does not support the "tls-server-end-point" type).</p>
<p><em>This specification solves the problems outlined above by adding an optional SCRAM attribute containing the hash of the client-perceived list of channel-binding types that can be checked by the server and will be cryptographically signed by the authentication password used for SCRAM.</em></p>
</section2>
<section2 topic="Attack model 2 (SASL mechanism list)">
<p><strong>Scenario:</strong> Bob connects to Alice's XMPP server using a client of his choice supporting SCRAM but <strong>no</strong> channel-binding, Eve wants to MITM this connection. Neither Alice's server nor Bob's client support SASL PLAIN, but only the SCRAM family of SASL mechanisms. Eve wants to downgrade the used SCRAM mechanism to something weak that she is able to break in X hours/days (For example some time in the future SCRAM-SHA-1 might be broken that way and the underlying password could be recovered investing X hours/days of computing time. But SCRAM-SHA-1 might still be supported by servers for backwards compatibility with older clients only supporting SCRAM-SHA-1 but not SCRAM-SHA-256 etc.).</p>
<p><strong>Prerequisites:</strong> Eve, the MITM attacker, managed to either steal the cert+key of Alice's XMPP server or to convince some CA to give out a cert+key for Alice's XMPP domain. Maybe Bob even installed a CA of his employer/school and now gets MITMed by his employer/school.</p>
<p>Given this scenario and prerequisites, Eve now can passively MITM the XMPP connection, but if Eve wants to actively downgrade the SASL mechanism used by Bob, he has to actively change the server-advertised SASL mechanism list. In this scenario Eve actively removes all SCRAM mechanisms but SCRAM-SHA-1 from the server-advertised list to force Bob's client to use SCRAM-SHA-1. Neither Alice nor Bob would detect that.</p>
<p>Pinning of SASL mechanisms could be used for that, but in doing this, Alice would loose some flexibility. She might have briefly activated SCRAM-SHA-512 and deactivated it again. Now Bob's client can not authenticate using SCRAM-SHA-512 anymore and authentication will always fail, if pinning is used. Pinning won't help on first connection either. See above for a pinning + SSDP compromise when still supporting SASL PLAIN.</p>
<p><em>This specification solves this problem by adding an optional SCRAM attribute containing the hash of the client-perceived SASL mechanism list that can be checked by the server and will be cryptographically signed by the authentication password used for SCRAM.</em></p>
</section2>
</section1>
<section1 topic='Protocol' anchor='protocol'>
<p>Sections 5.1 and 7 of &rfc5802; allow for arbitrary optional attributes inside SCRAM messages. This specification uses those optional attribute to implement a downgrade protection.</p>
<section2 topic="Server Indicates Support" anchor="support">
<p>The server uses the optional attribute "d" with the value "ssdp" in its server-first-message to indicate support for this specification.</p>
<p>A client supporting this specification but not seeing this attribute advertised by the server MAY abort the authentication. It is RECOMMENDED to wait until the whole SCRAM flow hash been completed to distinguish the case of a server not supporting this specification from a MITM stripping out this optional SCRAM attribute.</p>
</section2>
<section2 topic="Client Sends Downgrade Protection Hash" anchor="hash">
<p>If the server indicated support for this spec in the server-first-message and the client supports it, the client calculates a hash for the server-advertised list of SASL mechanisms and channel-binding types as follows.</p>
<p>Note: All sorting operations MUST be performed using "i;octet" collation as specified in Section 9.3 of &rfc4790;.</p>
<ol>
<li>Initialize an empty ASCII string S</li>
<li>Sort all server-advertised SASL mechanisms and append them to string S joined by delimiter "," (%x2C)</li>
<li>If the server used &xep0440; to advertise channel-bindings, append "|" (%x7C) to S</li>
<li>If the server used &xep0440; to advertise channel-bindings, sort all server-advertised channel-binding types and append them to string S joined by delimiter "," (%x2C)</li>
<li>Hash S using the same hash mechanism as used for the SCRAM mechanism currently in use and encode the result using base64</li>
</ol>
<p>The client then adds the optional attribute "d" with the base64 encoded hash obtained in step 5 to its client-final-message. The client MAY send this attribute even if the server did not advertise support.</p>
<p>Note: If the server simultaneously advertises SASL1 and SASL2, only the mechanism list of the SASL protocol the client uses for authentication MUST be considered for hashing.</p>
</section2>
<section2 topic="Server Verifys The Downgrade Protection Hash" anchor="verification">
<p>Upon receiving the client-final-message the server calculates its own base64 encoded hash using the list of SASL mechanisms and channel-binding types it advertised using SASL1 or SASL2 and &xep0440; by applying the same algorithm as defined in <link url="#hash">Client Sends Downgrade Protection Hash</link>.</p>
<p>The server then extracts the base64 encoded hash presented by the client in the optional attribute "d" and compares it to its own hash. If the hashes match, the list of SASL mechanisms and channel-binding types has not been changed by an active MITM.</p>
<p>If the hashes do not match, the server MUST fail the authentication as specified in &rfc6120; section 6.5 or &xep0388; section 2.6.2 using the "aborted" error-condition. If &xep0388; is used, the application-specific error-condition "downgrade-detected" in the namespace "urn:xmpp:ssdp:0" MUST be added, too. It MAY further include an optional descriptive text to further clarify this error as specified in &xep0388; section 6.2.6 or &rfc6120; section 6.5. If additional SCRAM data is provided, the used SCRAM "server-error-value" MUST be "downgrade-detected".</p>
<p>Non-XMPP implementations MAY use a SCRAM "server-error-value" of "downgrade-detected" alongside any protocol specific error-condition.</p>
</section2>
<section2 topic="Full Example" anchor="example">
<p>This sections contains an example based on the ones provided in &xep0388;.</p>
<example caption="Full SCRAM-SHA-1-PLUS authentication flow using the optional attribute defined in this spec"><![CDATA[
<!--
Client sending stream header
-->
<stream:stream
from='user@example.org'
to='example.org'
version='1.0'
xml:lang='en'
xmlns='jabber:client'
xmlns:stream='http://etherx.jabber.org/streams'>
<!--
Server responding with stream header and features
-->
<stream:stream
from='example.org'
id='++TR84Sm6A3hnt3Q065SnAbbk3Y='
to='user@example.org'
version='1.0'
xml:lang='en'
xmlns='jabber:client'
xmlns:stream='http://etherx.jabber.org/streams'>
<stream:features>
<authentication xmlns='urn:xmpp:sasl:2'>
<mechanism>SCRAM-SHA-1</mechanism>
<mechanism>SCRAM-SHA-1-PLUS</mechanism>
<inline xmlns='urn:xmpp:sasl:2'>
<!-- Server indicates that XEP-0198 can be negotiated "inline" -->
<enable xmlns='urn:xmpp:sm:3'/>
<!-- Server indicates support for XEP-0386 Bind 2 -->
<bind xmlns='urn:xmpp:bind2:1'/>
</inline>
</authentication>
<!-- Channel-binding information provided by XEP-0440 -->
<sasl-channel-binding xmlns='urn:xmpp:sasl-cb:0'>
<channel-binding type='tls-server-end-point'/>
<channel-binding type='tls-exporter'/>
</sasl-channel-binding>
</stream:features>
<!--
Client initiates authentication using SCRAM-SHA-1-PLUS and channel-binding type "tls-exporter"
-->
<authenticate xmlns='urn:xmpp:sasl:2' mechanism='SCRAM-SHA-1-PLUS'>
<!-- Base64 of: 'p=tls-exporter,,n=user,r=12C4CD5C-E38E-4A98-8F6D-15C38F51CCC6' -->
<initial-response>cD10bHMtZXhwb3J0ZXIsLG49dXNlcixyPTEyQzRDRDVDLUUzOEUtNEE5OC04RjZELTE1QzM4RjUxQ0NDNg==</initial-response>
<user-agent id='d4565fa7-4d72-4749-b3d3-740edbf87770'>
<software>AwesomeXMPP</software>
<device>Kiva's Phone</device>
</user-agent>
</authenticate>
<!--
SCRAM-SHA-1-PLUS challenge issued by the server as defined in RFC 5802
but including the optional attribute indicating support for this specification.
Base64 of: 'r=12C4CD5C-E38E-4A98-8F6D-15C38F51CCC6a09117a6-ac50-4f2f-93f1-93799c2bddf6,s=QSXCR+Q6sek8bf92,i=4096,d=ssdp'
-->
<challenge xmlns='urn:xmpp:sasl:2'>
cj0xMkM0Q0Q1Qy1FMzhFLTRBOTgtOEY2RC0xNUMzOEY1MUNDQzZhMDkxMTdhNi1hYzUwLTRmMmYtOTNmMS05Mzc5OWMyYmRkZjYscz1RU1hDUitRNnNlazhiZjkyLGk9NDA5NixkPXNzZHA=
</challenge>
<!--
The client responds with the base64 encoded SCRAM-SHA-1-PLUS client-final-message (password: 'pencil')
including the base64 encoded SHA-1 hash of the mechanism and channel-binding lists.
Attribute "d" contains base64 encoded SHA-1 hash of 'SCRAM-SHA-1,SCRAM-SHA-1-PLUS|tls-exporter,tls-server-end-point'
Base64 of: 'c=cD10bHMtZXhwb3J0ZXIsLMcoQvOdBDePd4OswlmAWV3dg1a1Wh1tYPTBwVid10VU,r=12C4CD5C-E38E-4A98-8F6D-15C38F51CCC6a09117a6-ac50-4f2f-93f1-93799c2bddf6,p=UApo7xo6Pa9J+Vaejfz/dG7BomU=,d=dRc3RenuSY9ypgPpERowoaySQZY='
The c-attribute contains the GS2-header and channel-binding data blob (32 bytes) as defined in RFC 5802.
-->
<response xmlns='urn:xmpp:sasl:2'>
Yz1jRDEwYkhNdFpYaHdiM0owWlhJc0xNY29Rdk9kQkRlUGQ0T3N3bG1BV1YzZGcxYTFXaDF0WVBUQndWaWQxMFZVLHI9MTJDNENENUMtRTM4RS00QTk4LThGNkQtMTVDMzhGNTFDQ0M2YTA5MTE3YTYtYWM1MC00ZjJmLTkzZjEtOTM3OTljMmJkZGY2LHA9VUFwbzd4bzZQYTlKK1ZhZWpmei9kRzdCb21VPSxkPWRSYzNSZW51U1k5eXBnUHBFUm93b2F5U1FaWT0=
</response>
<!--
The server accepted this authentication, no tampering with the advertised SASL mechanisms or channel-bindings was detected.
-->
<success xmlns='urn:xmpp:sasl:2'>
<!-- Base64 of: 'v=sQq8A1dePL5DxWX22Sz4TJMD7t4=' -->
<additional-data>
dj1zUXE4QTFkZVBMNUR4V1gyMlN6NFRKTUQ3dDQ9
</additional-data>
<authorization-identifier>user@example.org</authorization-identifier>
</success>]]></example>
</section2>
</section1>
<section1 topic='Security Considerations' anchor='security'>
<p>Using SCRAM attributes makes them part of the HMAC signatures used in the SCRAM protocol flow efficiently protecting them against any MITM attacker not knowing the password used.</p>
</section1>
<section1 topic='IETF Interaction' anchor='ietf'>
<p>This protocol shall be superseded by any IETF RFC providing some or all of the functionality provided by this specification. If such a specification exists implementations SHOULD NOT implement this XEP and SHOULD implement the superseding RFC.</p>
</section1>
<section1 topic='IANA Considerations' anchor='iana'>
<p>This document requires no interaction with &IANA;.</p>
</section1>
<section1 topic='XMPP Registrar Considerations' anchor='registrar'>
<p>This specification does not need any interaction with the &REGISTRAR;.</p>
</section1>
<section1 topic='XML Schema' anchor='schema'>
<p>This specification does not specify any new XML elements.</p>
</section1>
</xep>

233
xep-0475.xml Normal file
View File

@ -0,0 +1,233 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE xep SYSTEM 'xep.dtd' [
<!ENTITY % ents SYSTEM 'xep.ent'>
%ents;
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
<xep>
<header>
<title>Pubsub Signing</title>
<abstract>Specifies a mechanism to sign pubsub items</abstract>
&LEGALNOTICE;
<number>0475</number>
<status>Experimental</status>
<type>Standards Track</type>
<sig>Standards</sig>
<approver>Council</approver>
<dependencies>
<spec>XMPP Core</spec>
<spec>XEP-0001</spec>
<spec>XEP-0004</spec>
<spec>XEP-0060</spec>
<spec>XEP-0470</spec>
</dependencies>
<supersedes/>
<supersededby/>
<shortname>pubsub-signing</shortname>
<author>
<firstname>Jérôme</firstname>
<surname>Poisson</surname>
<email>goffi@goffi.org</email>
<jid>goffi@jabber.fr</jid>
</author>
<revision>
<version>0.1.0</version>
<date>2022-12-20</date>
<initials>XEP Editor (jsc)</initials>
<remark>Accepted by vote of Council on 2022-11-30.</remark>
</revision>
<revision>
<version>0.0.2</version>
<date>2022-10-20</date>
<initials>jp</initials>
<remark>
<ul>
<li>replaced "signatory" term with the more commonly used "signer"</li>
<li>added &lt;to/&gt; and &lt;time/&gt; elements (similar to XEP-0373)</li>
</ul>
</remark>
</revision>
<revision>
<version>0.0.1</version>
<date>2022-10-17</date>
<initials>jp</initials>
<remark><p>First draft.</p></remark>
</revision>
</header>
<section1 topic='Introduction' anchor='intro'>
<p>There are few ways to authenticate items published via &xep0060;, and none of them are secure: the <link url='https://xmpp.org/extensions/xep-0060.html#publisher-publish-success-publisher'>publish attribute</link> defined by the pubsub service is not mandatory and can be spoofed by the service itself, and some XEPs such as &xep0277; have their own mechanism (like &lt;author/&gt; qualified by "http://www.w3.org/2005/Atom" namespace) that is even easier to spoof.</p>
<p>This specification proposes a framework for attaching cryptographic signatures to pubsub items, allowing strong authentication of item authors. This specification only defines the framework, it is designed to be extended by other specifications to use various cryptographic algorithms.</p>
</section1>
<section1 topic='Glossary' anchor='glossary'>
<ul>
<li><strong>wrapper element</strong>: element wrapping the item to sign, and containing extra metadata</li>
<li><strong>signed data</strong>: normalized and serialized wrapped element</li>
<li><strong>signing profile</strong>: a specialisation of this specification for a specific cryptographic algorithm.</li>
<li><strong>signature</strong>: element containing the signature itself (which is detached from the signed data).</li>
<li><strong>C14N</strong>: <link url='https://www.w3.org/TR/xml-c14n2/'>Canonical XML (version 2.0 is used in this specification)</link>, a way to normalize XMP to have the same data to sign.</li>
</ul>
</section1>
<section1 topic='Requirements' anchor='reqs'>
<p>The design goals of this XEP are:</p>
<ul>
<li>it must be possible to sign plain text items as well as end-to-end encrypted items;</li>
<li>it must be backwards compatible: attaching a signature must work with existing specifications so that clients that do not support pubsub signatures can continue to work as usual;</li>
<li>it must be possible to sign an item by several authors;</li>
<li>it should be possible to have different signers from the item publisher;</li>
</ul>
</section1>
<section1 topic='Overview' anchor='overview'>
<p>To sign a pubsub item, the signature and the signed data are separated. Signed data is a wrapper element comprising essential data such as signers, and the item to be signed. The wrapper element is then normalized, serialized and signed. The signature and additional data of the wrapper element are then publised as &xep0470;. In case of multiple signers, each signer publish their own signature as an attachment.</p>
<p>To verify a signature, the process is similiar: the receiving client builds the same wrapper element, normalize and serialize it, and uses it to validate the given signature(s).</p>
</section1>
<section1 topic='Signing a Pubsub Item' anchor='signing'>
<p>To sign a pubsub item, a &lt;sign-data/&gt; wrapper element qualified by the 'urn:xmpp:pubsub-signature:0' namespace is created. This element MUST contain at least one 'to' element which MUST have a 'jid' attribute whose value is the intended recipient's XMPP address. The XMPP address found in the 'to' element's 'jid' attribute SHOULD be without Resourcepart (i.e., a bare JID).</p>
<p>The &lt;sign-data/&gt; element MUST contain exactly one &lt;time/&gt; element. The &lt;time/&gt; element MUST have a 'stamp' attribute which contains the timestamp of the moment when the element is being signed in the DateTime format as specified in &xep0082;</p>
<p>The &lt;sign-data/&gt; element MUST contain one or more &lt;signer/&gt; element(s) which MUST possess a 'jid' attribute whose value is the bare JID of the signer.</p>
<p>One or more external elements specified by signing profile MAY be added</p>
<p>The item to sign MUST be added as a child of the &lt;sign-data/&gt; element. If the wrapped &lt;item/&gt; element possesses a 'publisher' attribute, it MUST be removed when added to the wrapper element. As item ID can be added or modified by the Pubsub/PEP service, if the &lt;item/&gt; has an 'id' attribute, it MUST be removed too when added to the wrapper element, thus the item ID is not part of the signed data.</p>
<p>Then the resulting item is put to canonical form by applying <link url='https://www.w3.org/TR/xml-c14n2/'>C14N v2.0</link> specification.</p>
<p>The resulting element in canonical form is then serialized and signed.</p>
<p>Below is an example of wrapper element:</p>
<example caption="Wrapper Element (Before Normalization)"><![CDATA[
<sign-data>
<to jid='juliet@capulet.lit' />
<time stamp='2022-10-16T18:39:03Z' />
<signer>juliet@capulet.lit</signer>
<item>
<entry xmlns='http://www.w3.org/2005/Atom'>
<author>
<name>Juliet Capulet</name>
<uri>xmpp:juliet@capulet.lit</uri>
</author>
<title type='text'>She is so pretty! </title>
<published>2022-10-16T18:39:02Z</published>
</entry>
</item>
</sign-data>
]]></example>
<p>The normalized form is as follow:</p>
<example caption="Wrapper Element (After Normalization)"><![CDATA[<sign-data><to jid="juliet@capulet.lit"></to><time stamp="2022-10-16T18:39:03Z"></time><signer>juliet@capulet.lit</signer><item><entry xmlns="http://www.w3.org/2005/Atom"><author><name>Juliet Capulet</name><uri>xmpp:juliet@capulet.lit</uri></author><title type="text">She is so pretty!</title><published>2022-10-16T18:39:02Z</published></entry></item></sign-data>]]></example>
<p>The signature is then put as an &xep0470;. The attachment is a &lt;signature/&gt; element qualified by the 'urn:xmpp:pubsub-signing:0' namespace. The attachment MUST contain the same &lt;time/&gt; and &lt;signer/&gt; elements in the same order as in the &lt;sign-data/&gt; element. If any signing profile extra elements have been used in &lt;sign-data/&gt;, they MUST be added too in the same order as in &lt;sign-data/&gt;. Then the signature is added in an element specified in the signing profile specification.</p>
<p>Each signer entity MUST publish a &lt;signature/&gt; attachment signed with their own encryption keys.</p>
<p>If the pubsub item is encrypted, the signature MUST be done on the plain text version of the item <strong>before</strong> the encryption of the item. The &lt;signature/&gt; attachment SHOULD be encrypted too.</p>
<example caption="Juliet Publish Her Signature as an Attachment"><![CDATA[
<iq from='juliet@capulut.lit/chamber'
id='signature_1'
to='juliet@capulet.lit'
type='set'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='urn:xmpp:pubsub-attachments:1/xmpp:juliet@capulet.lit?;node=urn%3Axmpp%3Amicroblog%3A0;item=random-thoughts-12bd'>
<item id='juliet@capulet.lit'>
<attachments>
<signature xmlns='urn:xmpp:pubsub-signing:0' timestamp="2022-10-16T18:39:04Z">
<time stamp='2022-10-16T18:39:03Z' />
<signer>juliet@capulet.lit</signer>
<example-signature xmlns='https://example.org/signature'>
<!-- SOME PAYLOAD -->
</example-signature>
</signature>
</attachments>
</item>
</publish>
</pubsub>
</iq>
]]></example>
<section2 topic='rationales' anchor='signing-rationales'>
<p>The reason we use &xep0470; instead of directly signing the target item is that we need to be backwards compatible, so we cannot replace the target item with another element, nor is it possible to add a sibling element to item's payload (this would not be compliant with &xep0060; specification). This requires detaching the signature from the &lt;item/&gt; element itself, and &xep0470; are dedicated to attaching data to items, so a viable solution.</p>
</section2>
<section2 topic='Summarizing' anchor='summarizing'>
<p>To summarize signatures as explained in &xep0470; the &lt;signer/&gt; elements are grouped into a &lt;signature/&gt; element qualified by the 'urn:xmpp:pubsub-signing:0' namespace. This allows a client to easily know that an item is signed, and to obtain the IDs of attachments that need to be retrieved to validate signatures.</p>
<example caption="Juliet Get Summary of Signatures of an Item"><![CDATA[
<iq from='juliet@capulet.lit'
id='summary_123'
to='juliet@capulet.lit/chamber'
type='result'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<items node='urn:xmpp:pubsub-attachments:summary:1/urn:xmpp:microblog:0'>
<item id='some-post-with-several-signatures-0adf'>
<summary xmlns='urn:xmpp:pubsub-attachments:summary:1'>
<!---->
<signature xmlns='urn:xmpp:pubsub-signing:0' >
<signer>juliet@capulet.lit</signer>
<signer>romemo@montague.lit</signer>
</signature>
<!---->
</summary>
</item>
</items>
</pubsub>
</iq>
]]></example>
</section2>
<section2 topic='Signature Validation' anchor='signature-validation'>
<p>Once one or more signatures have been found in an item attachment, a client SHOULD validate them. To do this, it builds a wrapper element with the target item as explained in <link url='#signing'>Signing a Pubsub Item</link>, and validate it with each signature. Validation mechanism depends of the signing profile.</p>
</section2>
</section1>
<section1 topic='Business Rules' anchor='rules'>
<p>C14N 2.0 defines <link url='https://www.w3.org/TR/xml-c14n2/#sec-Canonicalization-Parameters'>parameters</link> for the algorithm. For this specification, default values MUST be used, i.e. <em>IgnoreComments</em> is true, <em>TrimTextNodes</em> is true, <em>PrefixRewrite</em> is none, and <em>QNameAware</em> is the empty set. In other terms: there must be no comments, text nodes must be trimmed, prefixes are left unchanged, and no nodes must be processed as QName-valued.</p>
<p>Once the signature has been validated, it's the original item which MUST be used, as usual, not the normalized form. The original item has attributes missing from the normalized form ('published' and 'id' attribute), and spaces are trimmed, but they may be significant (e.g. in a dataform &lt;value/&gt;).</p>
<p>It is essential to use the same &lt;to/&gt;, &lt;time/&gt;, &lt;signer/&gt; and signing profile extra elements in the &lt;signature/&gt; element put in attachment and in wrapper &lt;sign-data/&gt; element used for signed data, as it is necessary for receiving client to re-build the wrapper element and then validate the signature.</p>
</section1>
<section1 topic='Implementation Notes' anchor='impl'>
<p>The client validating signatures should display a message or indicator depending on the validation result:</p>
<ul>
<li>If one of the signatures doesn't validate, the client SHOULD display a prominent warning message explicitely stating that the signature is not validated and that the message is probably spoofed.</li>
<li>If the signature is validated but at least one of the signers's fingerprints is not trusted, the client SHOULD display a warning message stating that the signature is validated but unreliable, and that the message may be forged.</li>
<li>If all signatures are validated <strong>and</strong> all signers' fingerprints are trusted, the client SHOULD display an information message or indication that the item is signed by one or more trusted signers.</li>
</ul>
</section1>
<section1 topic='Discovering Support' anchor='disco'>
<p>If a client supports the protocol specified in this XEP, it MUST advertise it by including the "urn:xmpp:pubsub-signing:0" discovery feature in response to a &xep0030; information request:</p>
<example caption="Service Discovery information request"><![CDATA[
<iq type='get'
from='juliet@example.org/chamber'
to='romeo@example.org/orchard'
id='disco1'>
<query xmlns='http://jabber.org/protocol/disco#info'/>
</iq>]]></example>
<example caption="Service Discovery information response"><![CDATA[
<iq type='result'
from='romeo@example.org/orchard'
to='juliet@example.org/chamber'
id='disco1'>
<query xmlns='http://jabber.org/protocol/disco#info'>
...
<feature var='urn:xmpp:pubsub-signing:0'/>
...
</query>
</iq>]]></example>
</section1>
<section1 topic='Security Considerations' anchor='security'>
<p>Signature is intimely linked to the trust in the fingerprint of the encryption keys. A warning SHOULD be displayed by a client if a signature is valid but the signing entity's fingerprints are not trusted. Trust should be done through an external channel (outside of XMPP), preferably face-to-face.</p>
<p>Security considerations of the signing profile applies.</p>
</section1>
<section1 topic='IANA Considerations' anchor='iana'>
<p>TODO</p>
</section1>
<section1 topic='XMPP Registrar Considerations' anchor='registrar'>
<p>TODO</p>
</section1>
<section1 topic='XML Schema' anchor='schema'>
<p>TODO</p>
</section1>
<section1 topic='Acknowledgements' anchor='acks'>
<p>Thanks to NLnet foundation/NGI0 Discovery for funding.</p>
</section1>
</xep>

111
xep-0476.xml Normal file
View File

@ -0,0 +1,111 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE xep SYSTEM 'xep.dtd' [
<!ENTITY % ents SYSTEM 'xep.ent'>
%ents;
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
<xep>
<header>
<title>Pubsub Signing: OpenPGP Profile</title>
<abstract>Specifies a pubsub signing profile for OpenPGP</abstract>
&LEGALNOTICE;
<number>0476</number>
<status>Experimental</status>
<type>Standards Track</type>
<sig>Standards</sig>
<approver>Council</approver>
<dependencies>
<spec>XMPP Core</spec>
<spec>XEP-0001</spec>
<spec>XEP-0004</spec>
<spec>XEP-0060</spec>
<spec>XEP-0373</spec>
</dependencies>
<supersedes/>
<supersededby/>
<shortname>pss-ox</shortname>
<author>
<firstname>Jérôme</firstname>
<surname>Poisson</surname>
<email>goffi@goffi.org</email>
<jid>goffi@jabber.fr</jid>
</author>
<revision>
<version>0.1.0</version>
<date>2022-12-20</date>
<initials>XEP Editor (jsc)</initials>
<remark>Accepted by vote of Council on 2022-11-30.</remark>
</revision>
<revision>
<version>0.0.1</version>
<date>2022-10-29</date>
<initials>jp</initials>
<remark><p>First draft.</p></remark>
</revision>
</header>
<section1 topic='Introduction' anchor='intro'>
<p>This XMPP extension protocol specifies a profile of Pubsub Signing to use OpenPGP for signature.</p>
</section1>
<section1 topic='Signing a Pubsub Item With OpenPGP' anchor='signing'>
<p>Signing an item with OpenPGP requires to have &xep0373; implemented to handle keys, however this specification uses its own &lt;sign/&gt; element because it uses wrapper element from Pubsub Signing XEP, and signed data MUST NOT be included with the signature.</p>
<p>To sign an element, a client process as explained in XEP-0XXX <link url='https://xmpp.org/extensions/inbox/pubsub-signing.html#signing'>§ Signing a Pubsub Item</link> where the "signing profile" element used is a &lt;sign/&gt; element qualified by the 'urn:xmpp:pubsub-signing:openpgp:0' namespace. This element MUST contain a Base64 encoded (&rfc4648; <link url='https://tools.ietf.org/html/rfc4648#section-4'>§ 4</link>) OpenPGP message as specified in &rfc4880; which MUST contain a <strong>detached signature</strong> as defined in &rfc4880; <link url='https://www.rfc-editor.org/rfc/rfc4880#section-11.4'>§ 11.4</link> of the signed data as specified in XEP-0XXX <link url='https://xmpp.org/extensions/inbox/pubsub-signing.html#signing'>§ Signing a Pubsub Item</link>.</p>
<example caption="Juliet Publishes Her Signature as an Attachment With OpenPGP Signing Profile"><![CDATA[
<iq xmlns="jabber:client" from="juliet@capulet.lit/chamber" to="juliet@capulet.lit" id="signature_1" type="set">
<pubsub xmlns="http://jabber.org/protocol/pubsub">
<items node="urn:xmpp:pubsub-attachments:1/xmpp:juliet@capulet.lit?;node=urn%3Axmpp%3Amicroblog%3A0;item=random-thoughts-12bd">
<item id="juliet@capulet.lit">
<attachments xmlns="urn:xmpp:pubsub-attachments:1">
<signature xmlns="urn:xmpp:pubsub-signing:0">
<time stamp="2022-10-16T18:39:03Z"/>
<signer>juliet@capulet.lit</signer>
<sign xmlns="urn:xmpp:pubsub-signing:openpgp:0">iQGzBAABCAAdFiEEyTOMos/ZmE//ikYkAzNxB0kY9CIFAmNaomUACgkQAzNxB0kY9CJQcAv9HjIIrzIhtmWvf2IoHBUgY7hUFPZ3TKZ0Ltc6uz+CR4K1GHQB842/vjPSHwo5qfVgaVEUK3Liw8eXawOZ4SJeSZdmd1KUjjuZ+SLlB1SKKEoap3KFhidT9XYA2OU4tkWOwVI2cyBIWE3JRxD0YFh5YMJObZrOoyMiobwaMaGCHt60T71rl1wPb399l9aU6sYu2HHIRnM5pDgVljIMZe0n1LnY5pH5jzN67JgxlFAfl0Q4BO81pBycNnbk0VPb78Ki4001S7uoFftkN3j6euYf8KhtTH+Yaw1BdYzjO8o2Nw/9ledMrwO652Ud4hLGpmSpIJI1NTOjmy5crfhEHMA5ERYDbGbaB/IoaHxje+8occlI78xChoz7xCQlwVVyHARvuotEbYRimY78s2Ozae+uG/8wQZmeLnrvwCrzDiJbEkW4MbiOWUC1QcApNoW8lriLcb+ZfNGMeENSSMqMRfi3wL6WOovM2IR8O97/1DkGFiYAZ414CVZV2ZT+xxE64pMM</sign>
</signature>
</attachments>
</item>
</items>
</pubsub>
</iq>
]]></example>
</section1>
<section1 topic='Discovering Support' anchor='disco'>
<p>If a client supports the protocol specified in this XEP, it MUST advertise it by including the "urn:xmpp:pubsub-signing:openpgp:0" discovery feature in response to a &xep0030; information request:</p>
<example caption="Service Discovery information request"><![CDATA[
<iq type='get'
from='juliet@example.org/chamber'
to='romeo@example.org/orchard'
id='disco1'>
<query xmlns='http://jabber.org/protocol/disco#info'/>
</iq>]]></example>
<example caption="Service Discovery information response"><![CDATA[
<iq type='result'
from='romeo@example.org/orchard'
to='juliet@example.org/chamber'
id='disco1'>
<query xmlns='http://jabber.org/protocol/disco#info'>
...
<feature var='urn:xmpp:pubsub-signing:openpgp:0'/>
...
</query>
</iq>]]></example>
</section1>
<section1 topic='Security Considerations' anchor='security'>
<p>Security considerations of &xep0373; and <link url='https://xmpp.org/extensions/inbox/pubsub-signing.html'>XEP-0XXX</link> apply.</p>
</section1>
<section1 topic='IANA Considerations' anchor='iana'>
<p>TODO</p>
</section1>
<section1 topic='XMPP Registrar Considerations' anchor='registrar'>
<p>TODO</p>
</section1>
<section1 topic='XML Schema' anchor='schema'>
<p>TODO</p>
</section1>
<section1 topic='Acknowledgements' anchor='acks'>
<p>Thanks to NLnet foundation/NGI0 Discovery for funding.</p>
</section1>
</xep>

127
xep-0477.xml Normal file
View File

@ -0,0 +1,127 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE xep SYSTEM 'xep.dtd' [
<!ENTITY % ents SYSTEM 'xep.ent'>
%ents;
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
<xep>
<header>
<title>Pubsub Targeted Encryption</title>
<abstract>Specifies a way to encrypt pubsub items for a restricted set of entities</abstract>
&LEGALNOTICE;
<number>0477</number>
<status>Experimental</status>
<type>Standards Track</type>
<sig>Standards</sig>
<approver>Council</approver>
<dependencies>
<spec>XMPP Core</spec>
<spec>XEP-0001</spec>
<spec>XEP-0004</spec>
<spec>XEP-0060</spec>
<spec>XEP-0384</spec>
</dependencies>
<supersedes/>
<supersededby/>
<shortname>pte</shortname>
<author>
<firstname>Jérôme</firstname>
<surname>Poisson</surname>
<email>goffi@goffi.org</email>
<jid>goffi@jabber.fr</jid>
</author>
<revision>
<version>0.1.0</version>
<date>2022-12-20</date>
<initials>XEP Editor (jsc)</initials>
<remark>Accepted by vote of Council on 2022-11-30.</remark>
</revision>
<revision>
<version>0.0.1</version>
<date>2022-10-31</date>
<initials>jp</initials>
<remark><p>First draft.</p></remark>
</revision>
</header>
<section1 topic='Introduction' anchor='intro'>
<p>While it is nowadays possible to encrypt pubsub items with OpenPGP for XMPP Pubsub, this specification is designed for pubsub nodes were all items are end-to-end encrypted, and it is using symmetric encryption with a system of key sharing, meaning that if a key is available, it can decrypt all items encrypted with it.</p>
<p>This is fine for most use cases, however it may be desirable to only encrypt a few items with properties such as Perfect Forward Secrecy. This specification describes a way on how to do that by adapting existing end-to-end encryption algorithms used in instant messaging to pubsub items. This may be used to implement restricted items (a feature known is some other software such as "aspects" or "circles") or for transient nodes.</p>
</section1>
<section1 topic='Requirements' anchor='reqs'>
<p>The design goal of this specification is do adapt simply existing e2e encryption algorithms used for messages to pubsub items.</p>
</section1>
<section1 topic='Use Cases' anchor='usecases'>
<section2 topic='Encrypting a Pubsub Item' anchor='encrypt'>
<p>Juliet holds a public blog using &xep0277;. However, she wants to publish a new items that should be visible only to some well targeted users. To do so she encrypt the payload in the same way as she encrypt messages with algorithm such as &xep0384;. She wrap the encrypted payload in an &lt;encrypted/&gt; element qualified by the 'urn:xmpp:pte:0' namespace which MUST have a 'by' attribute with its own bare jid as value, and which MUST have a 'type' attribute whose value is the namespace of the algorithm used.</p>
<p>She decides to use &xep0384; to encrypt her items, her client publish an item like this:</p>
<example caption="Juliet Publish a Targeted Encrypted Item"><![CDATA[
<iq xmlns="jabber:client" id="pte_1" type="set" from="juliet@capulet.lit/chamber" to="juliet@capulet.lit">
<pubsub xmlns="http://jabber.org/protocol/pubsub">
<items node="urn:xmpp:microblog:0">
<item id="secret_blog_post" publisher="juliet@capulet.lit/chamber">
<encrypted xmlns="urn:xmpp:pte:0" by="juliet@capulet.lit" type="urn:xmpp:omemo:2">
<encrypted xmlns="urn:xmpp:omemo:2">
<header sid="878841001">
<keys jid="juliet@capulet.lit">
<key rid="673880319">ChDRqSBLTR+RtRIH8io7kf22EmgIARACGiCasIYfB6Zfe5SNyT8twIa+mEYA8h7uEQIjQ64dJx4vXiJAZSpXPRW+sVVSC7gc4lDEiTA4DT7AIh/woa82PFjgFdL0A8HTyBe7yh3UWThZGuTp5A3zmjXH7pAwKX85oxQ8XA==</key>
</keys>
</header>
<payload>DWmAVvrKlPPh23OmvmIrJmQXj5hVtgAnY8IOGZNqJc59T93hzsTen7tw7Kea5KfM3btfS25xd6RRWe0ZrqdvdGtKfHJFc77k5pQ052br4Qxw9kLWCVGqpNkrpwoBUshqs5mwA1WRLGdUfEsMaePwZv4m9xvXZSrxNIf9vQNX/GJM2GAT55exZSRU0Px8/E8j0XMtHCuZ4j3z0EBk1NZin0suQv8rVy1liWACPNuVrnU7h8LpdWmUggYztqL9l1yoxzEOFRrpdFkDqcZDLbO8bWAcYQNpWYoefaYvnvLV4zkW4dELQydSC2KkGMN/LmdYspVUPzPpQt7OmAKAndFWXTsAV5wmbtVsr15TzxI4NVDZyp7G70TYyTHlhG2gAq7StVj09bJi6IHa59L1BgNrNKT/ZG8pbe/GXUoPg4q9ZfuDiOYBHUugUxNsVFactRp6UocaQT/RogrqKY3o6NlTvnqVYpMJsi72cp8uQWTPtqwBpxyhAY0jKp1D+y7m2wzbeD2SZCw5+FryXulQhCKJ0dLI00PJr4dELWdu+uQLdyHl5FxG4D8mLQVOnY/TMa0vXUxsMAQI8g8LEHdJIhKU4GyVt125WhrbMrbcBu8iKCYmiz820siZeD8i5iZa1eQ69hnA9iCqMRS2DsqieUeI1Y4I7+0pHcyzpNC8408B7LhkgwxOEopExdOfv1NFwamsN5zXhCqj386oGRl9Ry0Gw+QSv9jlW4FB0rM8r+GF5gB66p0nYU/U5W8efXgNI/W1yAdUxgXc9FiQMmzIauTmR4m5WUxPjBggVYz1q3TkeZHQJpWy47EWZPnM9leWKNqC</payload>
</encrypted>
</encrypted>
</item>
</items>
</pubsub>
</iq>
]]></example>
</section2>
</section1>
<section1 topic='Business Rules' anchor='rules'>
<p>The properties of the encryption algorithm applies. For instance in the case of &xep0384;, there Perfect Forward Secrecy, meaning that once an item has been decrypted once by a targeted entity, it can't be decrypted anymore. Client shoud then handle pubsub caching of the decrypted item when necessary.</p>
</section1>
<section1 topic='Discovering Support' anchor='disco'>
<p>If a client supports the protocol specified in this XEP, it MUST advertise it by including the "urn:xmpp:pte:0" discovery feature in response to a &xep0030; information request, Then the supported encryption algorithms are announced as explained in their respective XEPs.</p>
<example caption="Service Discovery information request"><![CDATA[
<iq type='get'
from='juliet@example.org/balcony'
to='romeo@example.org/orchard'
id='disco1'>
<query xmlns='http://jabber.org/protocol/disco#info'/>
</iq>]]></example>
<example caption="Service Discovery information response"><![CDATA[
<iq type='result'
from='romeo@example.org/orchard'
to='juliet@example.org/balcony'
id='disco1'>
<query xmlns='http://jabber.org/protocol/disco#info'>
...
<feature var='urn:xmpp:pte:0'/>
<feature var='urn:xmpp:omemo:2'/>
...
</query>
</iq>]]></example>
</section1>
<section1 topic='Security Considerations' anchor='security'>
<p>Security Considerations of used encryption specifications apply.</p>
</section1>
<section1 topic='IANA Considerations' anchor='iana'>
<p>TODO</p>
</section1>
<section1 topic='XMPP Registrar Considerations' anchor='registrar'>
<p>TODO</p>
</section1>
<section1 topic='XML Schema' anchor='schema'>
<p>TODO</p>
</section1>
<section1 topic='Acknowledgements' anchor='acks'>
<p>Thanks to NLNet foundation/NGI0 Discovery for funding.</p>
</section1>
</xep>

View File

@ -22,6 +22,9 @@
<supersedes/>
<supersededby/>
<shortname>NOT_YET_ASSIGNED</shortname>
<tags>
<tag>template</tag>
</tags>
<author>
<firstname>Peter</firstname>
<surname>Saint-Andre</surname>

View File

@ -27,7 +27,7 @@ THE SOFTWARE.
<!ELEMENT xep ( header, section1* ) >
<!ATTLIST xep
xmlns CDATA '' >
<!ELEMENT header ( title, abstract, legal, number, status, lastcall*, interim*, type, sig, approver*, dependencies, supersedes, supersededby, shortname, schemaloc*, registry?, discuss?, expires?, author+, revision+, councilnote? ) >
<!ELEMENT header ( title, abstract, legal, number, status, lastcall*, interim*, type, sig, approver*, dependencies, supersedes, supersededby, shortname, tags?, schemaloc*, registry?, discuss?, expires?, author+, revision+, councilnote?) >
<!ELEMENT title (#PCDATA)* >
<!ELEMENT abstract (#PCDATA)* >
<!ELEMENT legal ( copyright, permissions, warranty, liability, conformance ) >
@ -68,6 +68,8 @@ THE SOFTWARE.
<!ELEMENT initials (#PCDATA)* >
<!ELEMENT remark (#PCDATA | p | ul)* >
<!ELEMENT councilnote (#PCDATA)* >
<!ELEMENT tags ( tag* ) >
<!ELEMENT tag (#PCDATA)* >
<!ELEMENT section1 ( div | p | section2 | example | code | cve | ul | ol | dl | table )* >
<!ATTLIST section1
topic CDATA ''

View File

@ -1666,3 +1666,10 @@ IANA Service Location Protocol, Version 2 (SLPv2) Templates</link></span> <note>
<!ENTITY xep0468 "<span class='ref'><link url='https://xmpp.org/extensions/xep-0468.html'>WebSocket S2S (XEP-0468)</link></span> <note>XEP-0468: WebSocket S2S &lt;<link url='https://xmpp.org/extensions/xep-0468.html'>https://xmpp.org/extensions/xep-0468.html</link>&gt;.</note>" >
<!ENTITY xep0469 "<span class='ref'><link url='https://xmpp.org/extensions/xep-0469.html'>Bookmark Pinning (XEP-0469)</link></span> <note>XEP-0469: Bookmark Pinning &lt;<link url='https://xmpp.org/extensions/xep-0469.html'>https://xmpp.org/extensions/xep-0469.html</link>&gt;.</note>" >
<!ENTITY xep0470 "<span class='ref'><link url='https://xmpp.org/extensions/xep-0470.html'>Pubsub Attachments (XEP-0470)</link></span> <note>XEP-0470: Pubsub Attachments &lt;<link url='https://xmpp.org/extensions/xep-0470.html'>https://xmpp.org/extensions/xep-0470.html</link>&gt;.</note>" >
<!ENTITY xep0471 "<span class='ref'><link url='https://xmpp.org/extensions/xep-0471.html'>Events (XEP-0471)</link></span> <note>XEP-0471: Events &lt;<link url='https://xmpp.org/extensions/xep-0471.html'>https://xmpp.org/extensions/xep-0471.html</link>&gt;.</note>" >
<!ENTITY xep0472 "<span class='ref'><link url='https://xmpp.org/extensions/xep-0472.html'>PubSub Social Feed (XEP-0472)</link></span> <note>XEP-0472: PubSub Social Feed &lt;<link url='https://xmpp.org/extensions/xep-0472.html'>https://xmpp.org/extensions/xep-0472.html</link>&gt;.</note>" >
<!ENTITY xep0473 "<span class='ref'><link url='https://xmpp.org/extensions/xep-0473.html'>OpenPGP for XMPP Pubsub (XEP-0473)</link></span> <note>XEP-0473: OpenPGP for XMPP Pubsub &lt;<link url='https://xmpp.org/extensions/xep-0473.html'>https://xmpp.org/extensions/xep-0473.html</link>&gt;.</note>" >
<!ENTITY xep0474 "<span class='ref'><link url='https://xmpp.org/extensions/xep-0474.html'>SASL SCRAM Downgrade Protection (XEP-0474)</link></span> <note>XEP-0474: SASL SCRAM Downgrade Protection &lt;<link url='https://xmpp.org/extensions/xep-0474.html'>https://xmpp.org/extensions/xep-0474.html</link>&gt;.</note>" >
<!ENTITY xep0475 "<span class='ref'><link url='https://xmpp.org/extensions/xep-0475.html'>Pubsub Signing (XEP-0475)</link></span> <note>XEP-0475: Pubsub Signing &lt;<link url='https://xmpp.org/extensions/xep-0475.html'>https://xmpp.org/extensions/xep-0475.html</link>&gt;.</note>" >
<!ENTITY xep0476 "<span class='ref'><link url='https://xmpp.org/extensions/xep-0476.html'>Pubsub Signing: OpenPGP Profile (XEP-0476)</link></span> <note>XEP-0476: Pubsub Signing: OpenPGP Profile &lt;<link url='https://xmpp.org/extensions/xep-0476.html'>https://xmpp.org/extensions/xep-0476.html</link>&gt;.</note>" >
<!ENTITY xep0477 "<span class='ref'><link url='https://xmpp.org/extensions/xep-0477.html'>Pubsub Targeted Encryption (XEP-0477)</link></span> <note>XEP-0477: Pubsub Targeted Encryption &lt;<link url='https://xmpp.org/extensions/xep-0477.html'>https://xmpp.org/extensions/xep-0477.html</link>&gt;.</note>" >

View File

@ -70,6 +70,7 @@ THE SOFTWARE.
<xs:element ref='supersedes'/>
<xs:element ref='supersededby'/>
<xs:element name='shortname' type='xs:NCName'/>
<xs:element ref='tags' minOccurs='0'/>
<xs:element ref='schemaloc' minOccurs='0' maxOccurs='unbounded'/>
<xs:element name='registry' minOccurs='0' type='empty'/>
<xs:element name='discuss' minOccurs='0' type='xs:string'/>
@ -196,6 +197,14 @@ THE SOFTWARE.
</xs:complexType>
</xs:element>
<xs:element name='tags'>
<xs:complexType>
<xs:sequence minOccurs='1' maxOccurs='unbounded'>
<xs:element name='tag' type='xs:string'/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name='remark'>
<xs:complexType>
<xs:choice>

View File

@ -476,7 +476,7 @@ content: "XEP-<xsl:value-of select='/xep/header/number'/>";
</xsl:when>
<xsl:otherwise>
<p class='indent'>The primary venue for discussion of XMPP Extension Protocols is the &lt;<a href="https://mail.jabber.org/mailman/listinfo/standards">standards@xmpp.org</a>&gt; discussion list.</p>
<p class='indent'>Discussion on other xmpp.org discussion lists might also be appropriate; see &lt;<a href='https://xmpp.org/about/discuss.shtml'>https://xmpp.org/about/discuss.shtml</a>&gt; for a complete list.</p>
<p class='indent'>Discussion on other xmpp.org discussion lists might also be appropriate; see &lt;<a href='https://xmpp.org/community/'>https://xmpp.org/community/</a>&gt; for a complete list.</p>
<xsl:if test='contains(/xep/header/dependencies,"RFC")'>
<p class='indent'>Given that this XMPP Extension Protocol normatively references IETF technologies, discussion on the &lt;<a href="https://mail.jabber.org/mailman/listinfo/xsf-ietf">xsf-ietf@xmpp.org</a>&gt; list might also be appropriate.</p>
</xsl:if>