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

Merge branches 'feature/editor-tooling', 'feature/xep-0045', 'feature/xep-0060', 'feature/xep-0234', 'feature/xep-0321', 'feature/xep-0369', 'feature/xep-0388', 'feature/xep-0390', 'feature/protoxep-jet' and 'feature/protoxep-pubsub-cap'

This commit is contained in:
Jonas Wielicki 2017-08-24 10:03:47 +02:00
64 changed files with 2467 additions and 1550 deletions

View File

@ -4,10 +4,12 @@
FROM xmppxsf/xeps-base:latest
ARG NCORES=1
ARG TARGETS="html pdf"
ARG TARGETS="html inbox-html inbox-xml pdf xeplist"
COPY *.xml xep.* *.css *.xsl *.js *.xsl Makefile /src/
COPY resources/*.pdf /src/resources/
COPY tools/*.py /src/tools/
COPY inbox/*.xml inbox/*.ent inbox/*.dtd /src/inbox/
WORKDIR /src
RUN OUTDIR=/var/www/html/extensions/ make -j$NCORES $TARGETS

View File

@ -12,6 +12,22 @@ JSTARGETS=$(OUTDIR)/prettify.js
DO_XELATEX=cd $(OUTDIR); xelatex --interaction=nonstopmode -no-shell-escape "$(notdir $(basename $@)).tex" >/dev/null
xeps=$(wildcard *.xml)
proto_xeps=$(wildcard inbox/*.xml)
all_xeps=$(xeps) $(proto_xeps)
xep_xmls=$(patsubst %.xml,$(OUTDIR)/%.xml,$(xeps))
proto_xep_xmls=$(patsubst %.xml,$(OUTDIR)/%.xml,$(proto_xeps))
all_xep_xmls=$(xep_xmls) $(proto_xep_xmls)
xep_htmls=$(patsubst %.xml,$(OUTDIR)/%.html,$(xeps))
proto_xep_htmls=$(patsubst %.xml,$(OUTDIR)/%.html,$(proto_xeps))
all_xep_htmls=$(xep_htmls) $(proto_xep_htmls)
xep_pdfs=$(patsubst %.xml,$(OUTDIR)/%.pdf,$(xeps))
xep_refs=$(patsubst xep-%.xml, $(REFSDIR)/reference.XSF.XEP-%.xml, $(xeps))
xep_examples=$(patsubst xep-%.xml, $(EXAMPLESDIR)/%.xml, $(xeps))
.PHONY: help
help:
@ -33,17 +49,29 @@ help:
.PHONY: all
all: html
.PHONY: xeplist
xeplist: $(OUTDIR)/xeplist.xml
.PHONY: html
html: $(patsubst %.xml, $(OUTDIR)/%.html, $(wildcard *.xml))
html: $(xep_htmls)
.PHONY: xml
xml: $(xep_xmls)
.PHONY: inbox-html
inbox-html: $(proto_xep_htmls)
.PHONY: inbox-xml
inbox-xml: $(proto_xep_xmls)
.PHONY: pdf
pdf: $(patsubst %.xml, $(OUTDIR)/%.pdf, $(wildcard *.xml))
pdf: $(xep_pdfs)
.PHONY: refs
refs: $(patsubst xep-%.xml, $(REFSDIR)/reference.XSF.XEP-%.xml, $(wildcard *.xml))
refs: $(xep_refs)
.PHONY: examples
examples: $(patsubst xep-%.xml, $(EXAMPLESDIR)/%.xml, $(wildcard *.xml))
examples: $(xep_examples)
.PHONY: xep-%
xep-%: $(OUTDIR)/xep-%.html $(REFSDIR)/reference.XSF.XEP-%.xml $(OUTDIR)/xep-%.pdf $(EXAMPLESDIR)/%.xml;
@ -54,19 +82,29 @@ xep-%.html: $(OUTDIR)/xep-%.html ;
.PHONY: xep-%.pdf
xep-%.pdf: $(OUTDIR)/xep-%.pdf ;
$(all_xep_xmls): $(OUTDIR)/%.xml: %.xml
cp $< $@
$(OUTDIR)/xeplist.xml: $(wildcard *.xml) $(wildcard inbox/*.xml)
./tools/extract-metadata.py > $@
$(EXAMPLESDIR)/%.xml: xep-%.xml $(XMLDEPS) examples.xsl $(EXAMPLESDIR)
xsltproc --path $(CURDIR) examples.xsl "$<" > "$@" && echo "Finished building $@"
$(REFSDIR)/reference.XSF.XEP-%.xml: xep-%.xml $(XMLDEPS) ref.xsl $(REFSDIR)
xsltproc --path $(CURDIR) ref.xsl "$<" > "$@" && echo "Finished building $@"
$(OUTDIR)/%.html: %.xml $(XMLDEPS) $(HTMLDEPS)
$(all_xep_htmls): $(OUTDIR)/%.html: %.xml $(XMLDEPS) $(HTMLDEPS)
# we dont put it as a dependency to avoid a rebuild due to a timestamp
# change on the directory
mkdir -p $(OUTDIR)/inbox
xmllint --nonet --noout --noent --loaddtd --valid "$<"
# Check for non-data URIs
! xmllint --nonet --noout --noent --loaddtd --xpath "//img/@src[not(starts-with(., 'data:'))]" $< 2>/dev/null && true
# Actually build the HTML
xsltproc --path $(CURDIR) xep.xsl "$<" > "$@" && echo "Finished building $@"
xsltproc --path $(CURDIR) --param htmlbase "$(if $(findstring inbox,$<),'../','./')" xep.xsl "$<" > "$@" && echo "Finished building $@"
$(OUTDIR)/xmpp.pdf $(OUTDIR)/xmpp-text.pdf: $(OUTDIR)
cp "resources/$(notdir $@)" "$@"

56
all.sh
View File

@ -1,56 +0,0 @@
#!/bin/sh
# for all XEPs, generates HTML files and IETF-style reference, then copies XML file
# usage: ./all.sh
## LICENSE ##
#
# Copyright (c) 1999 - 2013 XMPP Standards Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
## END LICENSE ##
xeppath=/var/www/vhosts/xmpp.org/extensions
ls xep-0*.xml > tmp1.txt
sed s/^xep-// tmp1.txt > tmp2.txt
sed s/.xml$// tmp2.txt > nums.txt
rm tmp*.txt
while read f
do
xsltproc xep.xsl xep-$f.xml > $xeppath/xep-$f.html
xsltproc ref.xsl xep-$f.xml > $xeppath/refs/reference.XSF.XEP-$f.xml
xsltproc examples.xsl xep-$f.xml > $xeppath/examples/$f.xml
./gen.py $f
cp xep-$f.xml $xeppath/
./gen.py $f
done < nums.txt
rm nums.txt
xsltproc xep.xsl xep-README.xml > $xeppath/README.html
xsltproc xep.xsl xep-template.xml > $xeppath/template.html
cp *.dtd $xeppath/
cp *.ent $xeppath/
cp *.shtml $xeppath/
cp *.xsd $xeppath/
# END

View File

@ -1,196 +0,0 @@
#!/usr/bin/env python
# File: announce.py
# Version: 0.9
# Description: a script for announcing XEPs
# Last Modified: 2016-10-03
# Author: Peter Saint-Andre (stpeter@jabber.org)
# License: public domain
# HowTo: ./announce.py xepnum
## LICENSE ##
#
# Copyright (c) 1999 - 2010 XMPP Standards Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
## END LICENSE ##
# IMPORTS:
#
import glob
import os
from select import select
import smtplib
import socket
from string import split,strip,join,find
import sys
import time
from xml.dom.minidom import parse,parseString,Document
def getText(nodelist):
thisText = ""
for node in nodelist:
if node.nodeType == node.TEXT_NODE:
thisText = thisText + node.data
return thisText
# get the seconds in the Unix era
now = int(time.time())
# READ IN ARGS:
#
# 1. XEP number
xepnum = sys.argv[1];
xepfile = 'xep-' + xepnum + '.xml'
# PARSE XEP HEADERS:
#
# - title
# - abstract
# - version
# - date
# - initials
# - remark
thexep = parse(xepfile)
xepNode = (thexep.getElementsByTagName("xep")[0])
headerNode = (xepNode.getElementsByTagName("header")[0])
titleNode = (headerNode.getElementsByTagName("title")[0])
title = getText(titleNode.childNodes)
abstractNode = (headerNode.getElementsByTagName("abstract")[0])
abstract = getText(abstractNode.childNodes)
statusNode = (headerNode.getElementsByTagName("status")[0])
xepstatus = getText(statusNode.childNodes)
typeNode = (headerNode.getElementsByTagName("type")[0])
xeptype = getText(typeNode.childNodes)
revNodes = headerNode.getElementsByTagName("revision")
revNode = revNodes[0]
versionNode = (revNode.getElementsByTagName("version")[0])
version = getText(versionNode.childNodes)
dateNode = (revNode.getElementsByTagName("date")[0])
date = getText(dateNode.childNodes)
initialsNode = (revNode.getElementsByTagName("initials")[0])
initials = getText(initialsNode.childNodes)
remNode = (revNode.getElementsByTagName("remark")[0])
# could be <p> or <ul>
testRemarkNode = remNode.firstChild.nodeName
# print testRemarkNode
if (testRemarkNode == "p"):
remarkNode = (remNode.getElementsByTagName("p")[0])
remark = getText(remarkNode.childNodes)
else:
remark = "[See revision history]"
# what kind of action are we taking?
xepflag = ""
if (version == "0.1" or version == "0.1.0"):
xepflag = "new"
elif ((version == "1.0" or version == "1.0.0") and xeptype == "Standards Track"):
xepflag = "draft"
elif ((version == "1.0" or version == "1.0.0") and xeptype != "Standards Track"):
xepflag = "active"
elif (version == "2.0" or version == "2.0.0"):
xepflag = "final"
elif (xepstatus == "Retracted"):
xepflag = "retract"
elif (xepstatus == "Deprecated"):
xepflag = "deprecate"
elif (xepstatus == "Obsolete"):
xepflag = "obsolete"
elif (xepstatus == "Deferred"):
xepflag = "defer"
# generate the diffs URL
if len(revNodes) > 1:
prevRevNode = revNodes[1]
prevVersionNode = (prevRevNode.getElementsByTagName("version")[0])
prevVersion = getText(prevVersionNode.childNodes)
diffs = 'https://xmpp.org/extensions/diff/api/xep/' + xepnum + '/diff/' + prevVersion + '/vs/' + version
else:
diffs = 'N/A'
## SEND MAIL:
#
# From: editor@xmpp.org
# To: standards@xmpp.org
# Subject: UPDATED: XEP-$xepnum ($title)
# [or "NEW..." if version 0.1]
# Body:
# Version $version of XEP-$xepnum ($title) is now available.
# Abstract: $abstract
# Changelog: $remark ($initials)
# Diff: $diffs ### no longer in use
# URL: https://xmpp.org/extensions/xep-$xepnum.html
fromaddr = "editor@xmpp.org"
# for testing...
# toaddrs = "stpeter@jabber.org"
# for real...
toaddrs = "standards@xmpp.org"
if xepflag == "new":
thesubject = 'NEW: XEP-'
elif xepflag == "draft":
thesubject = 'DRAFT: XEP-'
elif xepflag == "final":
thesubject = 'FINAL: XEP-'
elif xepflag == "active":
thesubject = 'ACTIVE: XEP-'
elif xepflag == "retract":
thesubject = 'RETRACTED: XEP-'
elif xepflag == "deprecate":
thesubject = 'DEPRECATED: XEP-'
elif xepflag == "obsolete":
thesubject = 'OBSOLETE: XEP-'
elif xepflag == "defer":
thesubject = 'DEFERRED: XEP-'
else:
thesubject = 'UPDATED: XEP-'
thesubject = thesubject + xepnum + ' (' + title + ')'
versionline = 'Version ' + version + ' of XEP-' + xepnum + ' (' + title + ') has been released.'
abstractline = 'Abstract: ' + abstract
changelogline = 'Changelog: ' + remark + ' (' + initials + ')'
diffsline = 'Diff: ' + diffs
urlline = 'URL: https://xmpp.org/extensions/xep-' + xepnum + '.html'
msg = "From: XMPP Extensions Editor <%s>\r\n" % fromaddr
msg = msg + "To: %s\r\n" % toaddrs
msg = msg + "Subject: %s\r\n" % thesubject
msg = msg + versionline
msg = msg + "\r\n\n"
msg = msg + abstractline
msg = msg + "\r\n\n"
msg = msg + changelogline
msg = msg + "\r\n\n"
msg = msg + diffsline
msg = msg + "\r\n\n"
msg = msg + urlline
msg = msg + "\r\n\n"
server = smtplib.SMTP('localhost')
server.set_debuglevel(1)
server.sendmail(fromaddr, toaddrs, msg)
server.quit()
# END

432
gen.py
View File

@ -1,432 +0,0 @@
#!/usr/bin/env python
# File: gen.py
# Version: 0.2
# Description: a renewed XEP compilation tool
# Last Modified: 2009
# Author: Tobias Markmann (tm@ayena.de)
# HowTo: ./gen.py xep-####.xml
## LICENSE ##
#
# Copyright (c) 1999 - 2010 XMPP Standards Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
## END LICENSE ##
import pickle
import commands
import os
import re
import sys
import getopt
import glob
import tempfile
from xepinfo import XEPInfo
from xeputil import getLatestXEPFilename
from xml.dom.minidom import parse,parseString,Document,getDOMImplementation
# for serializing inline images
import base64
import urlparse
import urllib
XEPPATH = "/var/www/vhosts/xmpp.org/extensions"
CONFIGPATH = "/var/local/xsf"
verbose = False
fast = False
last_build = {}
files_to_delete = [];
def serializeInlineImage(output_dir, xep_nr, no, attrValue):
up = urlparse.urlparse(attrValue)
if up.scheme == 'data':
head, data = up.path.split(',')
bits = head.split(';')
mime_type = bits[0] if bits[0] else 'text/plain'
charset, b64 = 'ASCII', False
for bit in bits[1]:
if bit.startswith('charset='):
charset = bit[8:]
elif bit == 'base64':
b64 = True
# Do something smart with charset and b64 instead of assuming
plaindata = base64.b64decode(data)
# Do something smart with mime_type
if mime_type in ('image/png', 'image/jpeg'):
file_ext = mime_type.split('/')[1]
f = open(output_dir + '/' + 'inlineimage-' + xep_nr + '-' + str(no) + '.' + file_ext, 'wb')
f.write(plaindata)
elif up.scheme == 'http':
file_name, file_ext = os.path.splitext(up.path)
urllib.urlretrieve(attrValue, output_dir + '/' + 'inlineimage-' + xep_nr + '-' + str(no) + file_ext)
def serializeXEPInlineImages(output_dir, xep_nr, filename):
dom = parse(filename)
imgs = dom.getElementsByTagName('img')
for (no, img) in enumerate(imgs):
serializeInlineImage(output_dir, xep_nr, no, img.attributes["src"].value)
def getText(nodelist):
thisText = ""
for node in nodelist:
if node.nodeType == node.TEXT_NODE:
thisText = thisText + node.data
return thisText
def executeCommand( cmd ):
error, desc = commands.getstatusoutput( cmd )
return error, desc + "\n" + "executed cmd: " + cmd
## creates a HTML table (for the human reader) and XML table (for bots)
class XEPTable:
def __init__(self, filename, shortXMLfilename):
self.filename = filename
self.shortXMLfilename = shortXMLfilename
try:
self.tableFile = parse(filename)
except:
impl = getDOMImplementation()
self.tableFile = impl.createDocument(None, "table", None)
self.tableFile.getElementsByTagName("table")[0].setAttribute("class", "sortable")
self.tableFile.getElementsByTagName("table")[0].setAttribute("id", "xeplist")
self.tableFile.getElementsByTagName("table")[0].setAttribute("cellspacing", "0")
self.tableFile.getElementsByTagName("table")[0].setAttribute("cellpadding", "3")
self.tableFile.getElementsByTagName("table")[0].setAttribute("border", "1")
header = parseString(
'''<tr class='xepheader'>
<th align='left'>Number</th>
<th align='left'>Name</th>
<th align='left'>Type</th>
<th align='left'>Status</th>
<th align='left'>Date</th>
</tr>''')
self.tableFile.getElementsByTagName("table")[0].appendChild(header.getElementsByTagName("tr")[0])
try:
self.botsFile = parse(shortXMLfilename)
except:
impl = getDOMImplementation()
self.botsFile = impl.createDocument(None, "xeps", None)
def save(self):
f = open(self.filename, "wb")
self.tableFile.getElementsByTagName("table")[0].normalize()
f.write(self.tableFile.toxml())
f.close()
f = open(self.shortXMLfilename, "wb")
self.botsFile.getElementsByTagName("xeps")[0].normalize()
f.write(self.botsFile.toxml())
f.close()
def setXEP(self, info):
## set for HTML table
rows = self.tableFile.getElementsByTagName("tr")
xeprow = 0
for row in rows:
if row.getAttribute("id") == "xep" + info.getNr():
xeprow = row
break
if xeprow == 0:
xeprow = self.tableFile.createElement("tr")
self.tableFile.getElementsByTagName("table")[0].appendChild(xeprow)
self.tableFile.getElementsByTagName("table")[0].appendChild(self.tableFile.createTextNode('''
'''))
xeprow.setAttribute("id", "xep" + info.getNr())
xeprow.setAttribute("class", "tablebody XEP-" + info.getStatus())
else:
xeprow.setAttribute("class", "tablebody XEP-" + info.getStatus())
while(xeprow.hasChildNodes()):
xeprow.removeChild(xeprow.firstChild)
col = parseString('''<td valign='top'><a href='/extensions/xep-''' + info.getNr() + ".html'>XEP-" + info.getNr() + '''</a> <a href='/extensions/xep-''' + info.getNr() + '''.pdf'>(PDF)</a></td>''')
xeprow.appendChild(col.getElementsByTagName("td")[0])
col = parseString("<td valign='top'>" + info.getTitle() + "</td>")
xeprow.appendChild(col.getElementsByTagName("td")[0])
col = parseString("<td valign='top'>" + info.getType() + "</td>")
xeprow.appendChild(col.getElementsByTagName("td")[0])
col = parseString("<td valign='top'>" + info.getStatus() + "</td>")
xeprow.appendChild(col.getElementsByTagName("td")[0])
col = parseString("<td valign='top'>" + info.getDate() + "</td>")
xeprow.appendChild(col.getElementsByTagName("td")[0])
## set for bots file
xeps = self.botsFile.getElementsByTagName("xep")
xep = 0
for xeps_xep in xeps:
if xeps_xep.getElementsByTagName("number")[0].firstChild.data == info.getNr():
xep = xeps_xep
break
if xep == 0:
xep = self.botsFile.createElement("xep")
self.botsFile.getElementsByTagName("xeps")[0].appendChild(xep)
self.botsFile.getElementsByTagName("xeps")[0].appendChild(self.botsFile.createTextNode('''
'''))
else:
while(xep.hasChildNodes()):
xep.removeChild(xep.firstChild)
child = parseString("<number>" + info.getNr() + "</number>")
xep.appendChild(child.getElementsByTagName("number")[0])
child = parseString("<name>" + info.getTitle() + "</name>")
xep.appendChild(child.getElementsByTagName("name")[0])
child = parseString("<type>" + info.getType() + "</type>")
xep.appendChild(child.getElementsByTagName("type")[0])
child = parseString("<status>" + info.getStatus() + "</status>")
xep.appendChild(child.getElementsByTagName("status")[0])
child = parseString("<updated>" + info.getDate() + "</updated>")
xep.appendChild(child.getElementsByTagName("updated")[0])
child = parseString("<shortname>" + info.getShortname() + "</shortname>")
xep.appendChild(child.getElementsByTagName("shortname")[0])
child = parseString("<abstract>" + info.getAbstract() + "</abstract>")
xep.appendChild(child.getElementsByTagName("abstract")[0])
def filebase( filename ):
return os.path.splitext(os.path.basename(filename))[0]
def checkError( error, desc):
global verbose
if error != 0:
if verbose:
print "Error: ", desc
return False
return True
def fileHash( filename ):
f = open(filename, "rb")
import hashlib
h = hashlib.sha1()
h.update(f.read())
hash = h.hexdigest()
f.close()
return hash
def loadDict( filename ):
try:
f = open(filename, "rb")
di = pickle.load(f)
f.close()
return di
except:
print "failed loading dict."
return {}
def saveDict( filename, di ):
f = open(filename, "w")
pickle.dump(di, f)
f.close()
def buildXHTML( file, nr ):
error, desc = executeCommand("xsltproc xep.xsl " + file + " > " + XEPPATH + "/xep-" + nr + ".html")
if not checkError(error, desc):
return False
error, desc = executeCommand("xsltproc ref.xsl xep-" + nr + ".xml > " + XEPPATH + "/refs/reference.XSF.XEP-" + nr + ".xml")
if not checkError(error, desc):
return False
error, desc = executeCommand("xsltproc examples.xsl xep-" + nr + ".xml > " + XEPPATH + "/examples/" + nr + ".xml")
if not checkError(error, desc):
return False
error, desc = executeCommand(" cp xep-" + nr + ".xml " + XEPPATH + "/")
if not checkError(error, desc):
return False
return True
def buildPDF( file, nr ):
serializeXEPInlineImages("/tmp/xepbuilder", nr, file)
error, desc = executeCommand("xsltproc -o /tmp/xepbuilder/xep-" + nr + ".tex.xml xep2texml.xsl " + file)
if not checkError(error, desc):
return False
error, desc = executeCommand("texml -e utf8 /tmp/xepbuilder/xep-" + nr + ".tex.xml /tmp/xepbuilder/xep-" + nr + ".tex")
if not checkError(error, desc):
return False
#detect http urls and escape them to make them breakable
# this should match all urls in free text; not the urls in xml:ns or so..so no " or ' in front.
error, desc = executeCommand('''sed -i 's|\([\s"]\)\([^"]http://[^ "]*\)|\1\\path{\2}|g' /tmp/xepbuilder/xep-''' + nr + ".tex")
if not checkError(error, desc):
return False
#adjust references
error, desc = executeCommand('''sed -i 's|\\hyperref\[#\([^}]*\)\]|\\hyperref\[\1\]|g' /tmp/xepbuilder/xep-''' + nr + ".tex")
if error != 0:
if verbose == 1:
print "Error: ", desc
return False
error, desc = executeCommand('''sed -i 's|\\pageref{#\([^}]*\)}|\\pageref{\1}|g' /tmp/xepbuilder/xep-''' + nr + ".tex")
if not checkError(error, desc):
return False
olddir = os.getcwd()
os.chdir("/tmp/xepbuilder")
error, desc = executeCommand("xelatex -interaction=batchmode xep-" + nr + ".tex")
#if not checkError(error, desc):
# os.chdir(olddir)
# return False
#error, desc = executeCommand("xelatex -interaction=batchmode xep-" + nr + ".tex")
#if not checkError(error, desc):
# os.chdir(olddir)
# return False
os.chdir(olddir)
error, desc = executeCommand("cp /tmp/xepbuilder/xep-" + nr + ".pdf " + XEPPATH + "/")
if not checkError(error, desc):
return False
return True
def buildXEP( filename ):
nr = re.match("xep-(\d\d\d\d).xml", filename).group(1)
xepfilepath = getLatestXEPFilename("./", nr);
if not xepfilepath:
print "getLatestXEPContent (ERROR)"
return
files_to_delete.append(xepfilepath)
if not fast:
print "Building " + filename + ": ",
if buildXHTML( xepfilepath, nr ):
print "XHTML(OK) / ",
else:
print "XHTML(ERROR) / ",
if buildPDF( xepfilepath, nr ):
print "PDF(OK)"
else:
print "PDF(ERROR)"
else:
print "Building " + filename + " (FAST MODE)"
x = XEPTable(CONFIGPATH + "/extensions.xml", XEPPATH + "/xeps.xml")
xinfo = XEPInfo(xepfilepath, False)
x.setXEP( xinfo )
x.save()
def buildAll():
files = glob.glob('xep-????.xml')
files.sort(key=lambda x: x.lower())
for file in files:
buildXEP( file )
def makeBundle():
print "Creating the bundle...",
executeCommand("mkdir /tmp/xepbundle")
executeCommand("cp " + XEPPATH + "/*.pdf " + "/tmp/xepbundle")
executeCommand("tar -cf /tmp/xepbundle.tar -C /tmp xepbundle")
executeCommand("pbzip2 -f -9 /tmp/xepbundle.tar")
executeCommand("mv -f /tmp/xepbundle.tar.bz2 " + XEPPATH + "/xepbundle.tar.bz2")
executeCommand("rm -rfd /tmp/xepbundle")
print "DONE"
def usage():
print "gen.py: generate nice XHTML and beautiful PDF out of the XEP XML files"
print ""
print "Usage:"
print "gen.py xep-####.xml"
print ""
print "Options:"
print "-v Enable verbose output for debugging."
print "-a Build all available XEPs."
print "-f Fast; means no actual compiling is done."
def main(argv):
global verbose
global CONFIGPATH
global fast
buildall = False
try:
options, remainder = getopt.gnu_getopt(argv, "vaf")
except getopt.GetoptError:
usage()
sys.exit(2)
for opt, arg in options:
if opt in ('-v'):
verbose = True
elif opt in ('-a'):
buildall = True
elif opt in ('-f'):
fast = True
if len(remainder) > 0:
try:
xep = int(remainder[0])
xep = "xep-%04d.xml" % xep
except:
xep = remainder[0]
executeCommand("mkdir /tmp/xepbuilder")
executeCommand("cp ../images/xmpp.pdf /tmp/xepbuilder/xmpp.pdf")
executeCommand("cp ../images/xmpp-text.pdf /tmp/xepbuilder/xmpp-text.pdf")
executeCommand("cp -r deps/* /tmp/xepbuilder/")
executeCommand("cp xep.ent /tmp/xep.ent")
files_to_delete.append("/tmp/xep.ent")
if buildall:
buildAll()
else:
buildXEP( xep )
# remove xep temporary files
for filename in files_to_delete:
executeCommand("rm " + filename)
executeCommand("sed -e '1s/<?[^?]*?>//' " + CONFIGPATH + "/extensions.xml > " + XEPPATH + "/../includes/xeplist.txt")
executeCommand("rm -rfd /tmp/xepbuilder")
makeBundle()
if __name__ == "__main__":
main(sys.argv[1:])

View File

@ -23,7 +23,7 @@
<dependencies>
<spec>XMPP Core</spec>
</dependencies>
<supersedes>XEP-0077</supersedes>
<supersedes><spec>XEP-0077</spec></supersedes>
<supersededby/>
<shortname>NOT_YET_ASSIGNED</shortname>
<author>
@ -72,11 +72,11 @@
<di>
<dt>Account Management</dt>
<dd>Gestion of a client XMPP account on a given server deployment. An account is being defined by the locale part of the JID, and by the authentication mechanisms available for this account.</dd>
<dt>In-Band</dt>
<dd>Capacity of acting directly through a XMPP stream. As a consequence, an In-Band Account Management MAY allow users to bootstrap the existence of their account, and oppositely to end it, or modify it, without ever having to use another medium (like the web for instance), or without the existence of a previous account.</dd>
<dt>Storage Mechanism</dt>
<dd>The internal logics of a server to store authentication data.</dd>
</di>
<di><dt>In-Band</dt>
<dd>Capacity of acting directly through a XMPP stream. As a consequence, an In-Band Account Management MAY allow users to bootstrap the existence of their account, and oppositely to end it, or modify it, without ever having to use another medium (like the web for instance), or without the existence of a previous account.</dd></di>
<di><dt>Storage Mechanism</dt>
<dd>The internal logics of a server to store authentication data.</dd></di>
</dl>
</section1>
<section1 topic='Use Cases' anchor='usecases'>
@ -481,13 +481,13 @@
<li>For a better user experience, it is important to provide &lt;challenge/> fallbacks rather than directly fail with a &lt;failure/> on the first user error. <cite>XEP-0158</cite> for instance proposes to fail directly on a wrong answer to a CAPTCHA challenge, while it is well known that many actual human users regularly fails, sometimes even several, captchas before succeeding one. As a consequence, in such a case or other similar challenge, it is better to return a new challenge (a new CAPTCHA for instance) rather than cancelling the negotiation, doing so eventually only after a few retries.</li>
<li>The storage mechanism does not mean necessarily that credentials have to be stored in the given form, in particular when the server estimates a storage mechanism being stronger than the one desired by the user, and still without losing any authentication possibility. For instance if a client was to exchange credentials in PLAIN, and if the server usually provides SCRAM-SHA1, SCRAM-SHA-256 and PLAIN authentication mechanisms, then it would be wise to store it as both SCRAM-SHA-1 and SCRAM-SHA-256 instead of PLAIN. This way the security of the password is highly renforced in the case of the database being stolen and the three authentication mechanisms are still available to this user. Of course it would have been even more secure for the client itself to exchange the credentials as SCRAM-SHA-1 and SCRAM-SHA-256 from the start, because by exchanging PLAIN data, possibility is given to a man-in-the-middle attack to steal directly the password during this one-time account registration.</li>
<li>Security may have a price. If you were to store credentials with SCRAM-SHA-256 only, and later you change to a client which supports only PLAIN and SCRAM-SHA-1, you may fall in a case where you force yourself to log in using PLAIN. For this reason, a good client implementation SHOULD be able to determine such edge case. In the previous case, if possible, it SHOULD have stored both SCRAM-SHA-1 and SCRAM-SHA-256 on registration or silently modify later its storage.</li>
<li>When registering a new account, considering that the user has obviously not been authenticated yet, the server MUST NOT rely on the 'from' value of the initiating stream. In particular:</li>
<li>When registering a new account, considering that the user has obviously not been authenticated yet, the server MUST NOT rely on the 'from' value of the initiating stream. In particular:
<ul>
<li>the server MUST NOT decide whether or not to propose the &lt;registration/> feature based on the existence of the JID filled in 'from'. Doing so would leak away information about the existence of a JID which could therefore be sent undesirable messages. Being consistent on showing the feature forces to try to register which can already eliminates part of the risk if the challenge provides some bot protection (for instance CAPTCHAs).
<br />A perfectly valid alternative would be to always provide the &lt;registration/> feature when no "from" is filled but never provide it when a "from is filled" (no matter it is an existing JID or not). This consistent logics does not leak information.</li>
<li>Do not modify the SASL authentication's mechanisms listed in the &lt;mechanisms/> feature depending on the 'from'. Even though a given JID might not be able to connect with some mechanisms because the credentials storage is incompatible, this would leak information on the kind of storage mechanism used for this user. This information would allow attackers to determine, then target, users whose storage would be weaker.
<br/>Of course this particular point might cause issues for users regularly changing their clients or log in from various computer. For instance the SCRAM-SHA-1 and SCRAM-SHA-256 storage are incompatible. If you first registered by specifying the SCRAM-SHA-256 storage, then on another client which does not support SCRAM-SHA-256 or even who supports it, but for some reason always try and gives priority to SCRAM-SHA-1, the user could be found in a situation where he never manages to authenticate while providing the right password. For this reason, it could be wiser for server deployments to choose compatible mechanisms, when possible. On client side, if they are provided a raw password, instead of pre-computed data for a specific mechanism, then they should intelligently try the various mechanisms, starting from the one they consider the stronger. Hence try SCRAM-SHA-256, then SCRAM-SHA-1 if the first failed, then only if both failed, tell the user that authentication failed (note that the client should not try PLAIN as a last fallback, because we remind that any SCRAM-* storage is compatible with the SASL PLAIN mechanism. Trying PLAIN would therefore be a security risk.</li>
</ul>
<li><p>the server MUST NOT decide whether or not to propose the &lt;registration/> feature based on the existence of the JID filled in 'from'. Doing so would leak away information about the existence of a JID which could therefore be sent undesirable messages. Being consistent on showing the feature forces to try to register which can already eliminates part of the risk if the challenge provides some bot protection (for instance CAPTCHAs).</p>
<p>A perfectly valid alternative would be to always provide the &lt;registration/> feature when no "from" is filled but never provide it when a "from is filled" (no matter it is an existing JID or not). This consistent logics does not leak information.</p></li>
<li><p>Do not modify the SASL authentication's mechanisms listed in the &lt;mechanisms/> feature depending on the 'from'. Even though a given JID might not be able to connect with some mechanisms because the credentials storage is incompatible, this would leak information on the kind of storage mechanism used for this user. This information would allow attackers to determine, then target, users whose storage would be weaker.</p>
<p>Of course this particular point might cause issues for users regularly changing their clients or log in from various computer. For instance the SCRAM-SHA-1 and SCRAM-SHA-256 storage are incompatible. If you first registered by specifying the SCRAM-SHA-256 storage, then on another client which does not support SCRAM-SHA-256 or even who supports it, but for some reason always try and gives priority to SCRAM-SHA-1, the user could be found in a situation where he never manages to authenticate while providing the right password. For this reason, it could be wiser for server deployments to choose compatible mechanisms, when possible. On client side, if they are provided a raw password, instead of pre-computed data for a specific mechanism, then they should intelligently try the various mechanisms, starting from the one they consider the stronger. Hence try SCRAM-SHA-256, then SCRAM-SHA-1 if the first failed, then only if both failed, tell the user that authentication failed (note that the client should not try PLAIN as a last fallback, because we remind that any SCRAM-* storage is compatible with the SASL PLAIN mechanism. Trying PLAIN would therefore be a security risk.</p></li>
</ul></li>
</ul>
</section1>
<section1 topic='IANA Considerations' anchor='iana'>

View File

@ -1,6 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE xep SYSTEM 'xep.dtd' [
<!ENTITY % ents SYSTEM 'xep.ent'>
<!ENTITY rfc3920bis "<span class='ref'><link url='http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis'>rfc3920bis</link></span> <note>RFC 3920: Extensible Messaging and Presence Protocol (XMPP): Core &lt;<link url='http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis'>http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis</link>&gt;.</note>" >
%ents;
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>

View File

@ -8,78 +8,15 @@
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
<xep>
<header xml:base="sections/header.xml">
<header>
<title>Buddycloud Channels</title>
<abstract>This document describes a profile and conventions for usage of the PubSub protocol in the context of a new type of communication.</abstract>
&LEGALNOTICE;
<number>xxxx</number>
<status>ProtoXEP</status>
<type>Standards Track</type>
<sig>Standards</sig>
<approver>Council</approver>
<revision>
<version>0.0.2</version>
<date>2014-04-29</date>
<initials>sdt</initials>
<remark>
<p>First draft.</p>
</remark>
</revision>
<shortname>NOT_YET_ASSIGNED</shortname>
<legal>
<copyright>This XMPP Extension Protocol is copyright (c) 1999 - 2014
by the XMPP Standards Foundation (XSF).
</copyright>
<permissions> Permission is hereby granted, free of charge, to any
person obtaining a copy of this specification (the
"Specification"), to make use of the Specification without
restriction, including without limitation the rights to implement
the Specification in a software program, deploy the Specification in
a network service, and copy, modify, merge, publish, translate,
distribute, sublicense, or sell copies of the Specification, and to
permit persons to whom the Specification is furnished to do so,
subject to the condition that the foregoing copyright notice and
this permission notice shall be included in all copies or
substantial portions of the Specification. Unless separate
permission is granted, modified works that are redistributed shall
not contain misleading information regarding the authors, title,
number, or publisher of the Specification, and shall not claim
endorsement of the modified works by the authors, any organization
or project to which the authors belong, or the XMPP Standards
Foundation.
</permissions>
<warranty> ## NOTE WELL: This Specification is provided on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, express or implied, including, without limitation, any
warranties or conditions of TITLE, NON-INFRINGEMENT,
MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. In no event
shall the XMPP Standards Foundation or the authors of this
Specification be liable for any claim, damages, or other liability,
whether in an action of contract, tort, or otherwise, arising from,
out of, or in connection with the Specification or the
implementation, deployment, or other use of the Specification. ##
</warranty>
<liability> In no event and under no legal theory, whether in tort
(including negligence), contract, or otherwise, unless required by
applicable law (such as deliberate and grossly negligent acts) or
agreed to in writing, shall the XMPP Standards Foundation or any
author of this Specification be liable for damages, including any
direct, indirect, special, incidental, or consequential damages of
any character arising out of the use or inability to use the
Specification (including but not limited to damages for loss of
goodwill, work stoppage, computer failure or malfunction, or any and
all other commercial damages or losses), even if the XMPP Standards
Foundation or such author has been advised of the possibility of
such damages.
</liability>
<conformance>
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 &lt;
<link url="http://xmpp.org/extensions/ipr-policy.shtml">http://xmpp.org/extensions/ipr-policy.shtml</link>
&gt; or obtained by writing to XSF, P.O. Box 1641, Denver, CO 80201
USA).
</conformance>
</legal>
<dependencies>
<spec>XMPP Core</spec>
<spec>XEP-0059</spec>
@ -90,26 +27,35 @@
</dependencies>
<supersedes/>
<supersededby/>
<author xml:base="authors/simon-tennant.xml">
<shortname>NOT_YET_ASSIGNED</shortname>
<author>
<firstname>Simon</firstname>
<surname>Tennant</surname>
<email>simon@buddycloud.com</email>
<jid>simon@buddycloud.com</jid>
</author>
<author xml:base="authors/lloyd-watkin.xml">
<author>
<firstname>Lloyd</firstname>
<surname>Watkin</surname>
<email>lloyd@evilprofessor.co.uk</email>
<jid>lloyd@evilprofessor.co.uk</jid>
</author>
<author xml:base="authors/ashley-ward.xml">
<author>
<firstname>Ashley</firstname>
<surname>Ward</surname>
<email>ashley.ward@surevine.com</email>
<jid>ashley.ward@surevine.com</jid>
</author>
<revision>
<version>0.0.2</version>
<date>2014-04-29</date>
<initials>sdt</initials>
<remark>
<p>First draft.</p>
</remark>
</revision>
</header>
<section1 topic="Buddycloud Introduction" anchor="Buddycloud Introduction" xml:base="sections/10.intro.xml">
<section1 topic="Buddycloud Introduction" anchor="Buddycloud Introduction">
<section2 topic="About Buddycloud" anchor="about-buddycloud">
<p>The Buddycloud project is a set of independently deployable services, that
inter-operate to create a rich collaboration service.
@ -188,7 +134,7 @@
</dl>
</section2>
</section1>
<section1 topic="Service Discovery" anchor="Finding-the-right-Buddycloud-server" xml:base="sections/30.discovery.xml">
<section1 topic="Service Discovery" anchor="Finding-the-right-Buddycloud-server">
<p>Each XMPP domain can have one Buddycloud server that serves user's channels.
Buddycloud clients and servers need to be able to discover the authoratative
Buddycloud server. find the
@ -196,7 +142,7 @@
<section2 topic="Discovery order" anchor="DISCOthenDNS">
<p>
To find the correct remote Buddycloud service for a domain, the Buddycloud
server should:
server should:</p>
<ol>
<li>Use a disco#items query against the XMPP service for the remote
Buddycloud domain.
@ -206,7 +152,6 @@
discovery method.
</li>
</ol>
</p>
</section2>
<section2 topic="Discovery using Disco" anchor="disco-discovery">
<p>The Buddycloud service first sends an items discovery request to the domain
@ -274,12 +219,12 @@
<p>
This example delegates all the Buddycloud service to an XMPP component
running the Buddycloud named
<i>buddycloud-component.verona.lit</i>
<em>buddycloud-component.verona.lit</em>
.
</p>
</section2>
</section1>
<section1 topic="Register" anchor="register" xml:base="sections/40.register.xml">
<section1 topic="Register" anchor="register">
<p>Upon connection to the buddycloud server a user should send a register
stanza.</p>
@ -300,15 +245,16 @@
</p>
</section1>
<section1 topic="Channel and Node Configuration" anchor="channel-config" xml:base="sections/50.node-config.xml">
<section1 topic="Channel and Node Configuration" anchor="channel-config">
<p>Node metadata is used to describe the channel to users. All nodes in a
channel have the same metadata and permission.
</p>
<section2 topic="Get Node Configuration" anchor="get-node-config"> - using disco-info
with the node specified - using <cite>XEP-0060</cite> 5.4 Discover Node Metadata
<section2 topic="Get Node Configuration" anchor="get-node-config">
<p>- using disco-info
with the node specified - using &xep0060; 5.4 Discover Node Metadata</p>
</section2>
<section2 topic="Set Node Configuration" anchor="set-node-config"> set Not sure what
goes here?
<section2 topic="Set Node Configuration" anchor="set-node-config"><p> set Not sure what
goes here?</p>
</section2>
<section2 topic="Default roles" anchor="default-roles">
<p> minimum setting/optional recommended fallbacks
@ -401,7 +347,6 @@
<p>Channel owners and moderators can also set the default affiliation for the
channel
</p>
<p>
<table caption="Channel Types">
<tr>
<th>Channel Type</th>
@ -429,8 +374,6 @@
</td>
</tr>
</table>
</p>
<p>
<table caption="Channel Access Models">
<tr>
<th>Access Model</th>
@ -455,7 +398,6 @@
</td>
</tr>
</table>
</p>
</section2>
<section2 topic="Well known nodes" anchor="well-known-nodes">
<p>Buddycloud is designed to be extended with new node and content types. To
@ -523,16 +465,14 @@
</table>
</section2>
</section1>
<section1 topic="Business Logic" anchor="biz-logic" xml:base="sections/55.application-logic.xml">
<section1 topic="Business Logic" anchor="biz-logic">
<section2 topic="PubSub for Humans" anchor="PubSub-for-humans">
<p> Buddycloud adapts <cite>XEP-0060</cite>'s machine-to-machine design goals with logic
and presets that work better in a social person-to-person and person-to-group
environment. For example, to discourage "glorifying the wicked", the list of
banned users is only presented to the channel's moderators.
</p>
<p>
<table caption="channel read permissions">
<thead>
<tr>
<th>Property</th>
<th>Access model</th>
@ -544,8 +484,6 @@
<th>Anonymous (e.g. web)</th>
<th>Banned users</th>
</tr>
</thead>
<tbody>
<tr>
<td>channel name</td>
<td>all</td>
@ -665,12 +603,8 @@
<td>no</td>
<td>no</td>
</tr>
</tbody>
</table>
</p>
<p>
<table caption="channel write permissions">
<thead>
<tr>
<th>Property</th>
<th>Producer</th>
@ -680,8 +614,6 @@
<th>Anonymous (e.g. web)</th>
<th>Banned users</th>
</tr>
</thead>
<tbody>
<tr>
<td>change channel name</td>
<td>only at creation time</td>
@ -745,9 +677,7 @@
<td>no</td>
<td>no</td>
</tr>
</tbody>
</table>
</p>
</section2>
<section2 topic="Maintain Similar Affiliations across Channel Nodes" anchor="rules-nodeaffiliations">
<p>A Buddycloud server MUST maintain similar affiliations and permissions for a subscribed
@ -762,7 +692,7 @@
</p>
</section2>
</section1>
<section1 topic="Pubsub Items" anchor="items" xml:base="sections/60.items.xml">
<section1 topic="Pubsub Items" anchor="items">
<p>Many of the item use cases follow those from <cite>XEP-0060</cite>. This section notes
the departures from the parent XEP and specific requirements.
@ -864,8 +794,8 @@
<iq from="buddycloud.capulet.lit" to="juliet@capulet.lit/bc-app" type="result" id="retractitem:32"/>
]]>
</example>
A retraction message is sent to all online clients, with an Atom tombstone to
replace the deleted post
<p>A retraction message is sent to all online clients, with an Atom tombstone to
replace the deleted post</p>
<example caption="The Buddycloud server sends retractions out to online clients">
<![CDATA[
<message from="buddycloud.capulet.lit" id="bc:MGV3B" to="benvolio@montague.lit">
@ -900,7 +830,7 @@
<strong>review</strong>
; extensions.
</p>
<section3 topic="Publishing" anchor="item-publishing"/>
<section3 topic="Publishing" anchor="item-publishing">
<p>The minimal payload for a publish request must be formatted as follows:
</p>
<example caption="The Entity publishes to a node">
@ -962,11 +892,11 @@
</li>
</ul>
</section4>
<section3 topic="Threading" anchor="item-threading"/>
</section3>
<section3 topic="Threading" anchor="item-threading">
<p>
Posts in Buddycloud can be formed into threads consisting of a parent post
and comments to a maximum thread depth of 1. Posts follow the
<a href="http://tools.ietf.org/html/rfc4685">ATOM threading specification</a>
and comments to a maximum thread depth of 1. Posts follow the &rfc4685;
and utilise the &amp;
<strong>thread</strong>
; namespace with the 'ref' attribute referring to the full global ID of the
@ -992,7 +922,7 @@
</entry>
]]>
</example>
<section4 topic="Error Cases" anchor="item-threading-errorcases"/>
<section4 topic="Error Cases" anchor="item-threading-errorcases">
<ul>
<li>
<em>parent-item-not-found</em>
@ -1003,7 +933,9 @@
: An attempt to comment on a comment will result in this error response
</li>
</ul>
<section3 topic="Referencing" anchor="item-referencing"/>
</section4>
</section3>
<section3 topic="Referencing" anchor="item-referencing">
<p>Within a single thread comments can reference other comments or the parent
item. This is for the purpose of making a comment to a post further back in
the thread.
@ -1052,6 +984,7 @@
</li>
</ul>
</section4>
</section3>
<section3 topic="Rating" anchor="item-rating">
<p>By
making use of the &amp;
@ -1119,13 +1052,13 @@
</section3>
</section2>
</section1>
<section1 topic="Channel subscriptions" anchor="subscriptions" xml:base="sections/70.subscriptions.xml">
<section1 topic="Channel subscriptions" anchor="subscriptions">
<p>Buddycloud clients follow <cite>XEP-0060</cite> subscription mechanisms for following and unfollowing a channel.</p>
</section1>
<section1 topic="Channel affiliations" anchor="affiliations" xml:base="sections/80.affiliations.xml">
<section1 topic="Channel affiliations" anchor="affiliations">
<section2 topic="Buddycloud to XEP-0060 mappings" anchor="affiliation-to-xep-0060-mappings">
<p>
Buddycloud channels build on XEP-0060's node affiliations.
Buddycloud channels build on XEP-0060's node affiliations.</p>
<table caption="Channel Affiliations">
<tr>
<th>XEP-0060 Affiliation</th>
@ -1183,10 +1116,9 @@
<td>RECOMMENDED</td>
</tr>
</table>
</p>
</section2>
</section1>
<section1 topic="Federation" anchor="federation" xml:base="sections/90.federation.xml">
<section1 topic="Federation" anchor="federation">
<section2 topic="Inbox" anchor="inbox">
</section2>
<section2 topic="Interaction With Other Services" anchor="Interaction-With-Other-Services">
@ -1204,7 +1136,7 @@
</p>
</section2>
</section1>
<section1 topic="Security Considerations" anchor="security-considerations" xml:base="sections/95.security.xml">
<section1 topic="Security Considerations" anchor="security-considerations">
<section2 topic="Server Trust" anchor="server-trust">
<p>
The Buddycloud server should make sure that the remote server

169
inbox/cap.xml Normal file
View File

@ -0,0 +1,169 @@
<?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>Atomically Compare-And-Publish PubSub Items</title>
<abstract>This specification provides a mechanism to atomically Compare-And-Publish items to a PubSub node.</abstract>
&LEGALNOTICE;
<number>xxxx</number>
<status>ProtoXEP</status>
<type>Standards Track</type>
<sig>Standards</sig>
<approver>Council</approver>
<dependencies>
<spec>XEP-0030</spec>
<spec>XEP-0060</spec>
</dependencies>
<supersedes/>
<supersededby/>
<shortname>cap</shortname>
&flow;
<revision>
<version>0.0.1</version>
<date>2017-04-20</date>
<initials>fs</initials>
<remark><p>First draft.</p></remark>
</revision>
</header>
<section1 topic='Introduction' anchor='intro'>
<p>This specification provides a mechanism to atomically publish
items to a PubSub node depending on the item ID of the node's latest
item. This allows to prevent race conditions and avoids data
loss in certain situations.</p>
</section1>
<section1 topic='Discoverying Support' anchor='disco'>
<p>If an entity supports the Compared-And-Publish feature it MUST
advertise the fact by returning a &lt;feature/&gt; with the 'var'
attribute set to 'urn:xmpp:pubsub:cap:0' in response to a &xep0030;
query for information.</p>
</section1>
<section1 topic='Compare-And-Publish PubSub Items' anchor='cap'>
<p>In order to atomically compare-and-publish an item, a client
sends an &IQ; with a 'pubsub' element qualified by the
'urn:xmpp:pubsub:cap:0' namespace. The element MUST contain the same
attributes and elements as the &lt;publish/&gt; element defined in
&xep0060; <em>and</em> it MUST contain a previd attribute containing
an item ID.</p>
<p>The PubSub service MUST only publish the item if the node's
latest item ID is equal to the ID found in the 'previd'
attribute.</p>
<example caption='Publisher publishes an item using Compare-And-Publish'><![CDATA[
<iq type='set'
from='hamlet@denmark.lit/blogbot'
to='pubsub.shakespeare.lit'
id='compare-and-publish1'>
<pubsub xmlns='urn:xmpp:pubsub:cap:0'>
<compare-and-publish
node='princely_musings'
previd='1'>
<item>
<entry xmlns='http://www.w3.org/2005/Atom'>
<title>Soliloquy</title>
<summary>
To be, or not to be: that is the question:
Whether 'tis nobler in the mind to suffer
The slings and arrows of outrageous fortune,
Or to take arms against a sea of troubles,
And by opposing end them?
</summary>
<link rel='alternate' type='text/html'
href='http://denmark.lit/2003/12/13/atom03'/>
<id>tag:denmark.lit,2003:entry-32397</id>
<published>2003-12-13T18:30:02Z</published>
<updated>2003-12-13T18:30:02Z</updated>
</entry>
</item>
</publish>
</pubsub>
</iq>
]]></example>
<section2 topic='Successfully published an item using Compare-And-Publish'>
<p>If the 'previd' matched the latest item's ID and if the service
was able to successfully process the request then the protocol
continues as defined in <cite>XEP-0060 7.1.2</cite>.</p>
</section2>
<section2 topic='Could not publish because newest item ID did not match'>
<p>In case the Compare-And-Publish operation failed because the
latest node id is not the same as given in the 'previd' attribute
in the request, the server returns an &IQ; result with 'pubsub'
element qualified by the 'urn:xmpp:pubsub:cap:0' namespace which
contains a &lt;compare-and-publish-failed/&gt; element. The
element MUST have a 'id' attribute with the ID of the lastest
item.</p>
<example caption='Service returns IQ response notifying of failed Compare-And-Publish operation'><![CDATA[
<iq type='result'
from='pubsub.shakespeare.lit'
to='hamlet@denmark.lit/blogbot'
id='compare-and-ublish1'>
<pubsub xmlns='urn:xmpp:pubsub:cap:0'>
<compare-and-publish-failed id='2'/>
</pubsub>
</iq>
]]></example>
</section2>
<section2 topic='Error cases'>
<p>All other error cases are handled as specified in
<cite>XEP-0060 § 7.1.3</cite></p>
</section2>
</section1>
<section1 topic='Security Considerations' anchor='security'>
<p>This extension protocol does not add any further security
considerations to the ones mentioned in <cite>XEP-0060 §
14.</cite>.</p>
</section1>
<section1 topic='IANA Considerations' anchor='iana'>
<p>This document requires no interaction with the Internet Assigned
Numbers Authority (IANA).</p>
</section1>
<section1 topic='XMPP Registrar Considerations' anchor='registrar'>
<p>This specification defines the following XML namespaces:</p>
<ul>
<li>urn:xmpp:pubsub:cap:0</li>
</ul>
<code caption='Registry Submission'><![CDATA[
<var>
<name>urn:xmpp:pubsub:cap:0</name>
<desc>Indicates support for Compare-And-Publish</desc>
<doc>XEP-XXXX</doc>
</var>]]></code>
</section1>
<section1 topic='XML Schema' anchor='schema'>
<p>TODO: Add after the XEP leaves the 'experimental' state.</p>
</section1>
</xep>

View File

@ -1,6 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE xep SYSTEM 'xep.dtd' [
<!ENTITY % ents SYSTEM 'xep.ent'>
<!ENTITY rfc3921bis "<span class='ref'><link url='http://tools.ietf.org/html/draft-ietf-saintandre-rfc3921bis'>rfc3921bis</link></span> <note>RFC 3921: Extensible Messaging and Presence Protocol (XMPP): Instant Messaging and Presence &lt;<link url='http://tools.ietf.org/html/draft-ietf-saintandre-rfc3921bis'>http://tools.ietf.org/html/draft-ietf-saintandre-rfc3921bis</link>&gt;.</note>" >
%ents;
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>

View File

@ -117,7 +117,7 @@ Examples for balancing algorithms include:
<section1 topic='Protocol' anchor='protocol'>
<section2 topic='Discovering Support'>
An entity advertises support for this protocol by including the 'urn:xmpp:cmr:0' feature in its service discovery information features as specified in Service Discovery (XEP-0030) or section 6.3 of Entity Capabilities (XEP-0015).
<p>An entity advertises support for this protocol by including the 'urn:xmpp:cmr:0' feature in its service discovery information features as specified in Service Discovery (XEP-0030) or section 6.3 of Entity Capabilities (XEP-0015).</p>
<example caption='Service discovery information request'><![CDATA[
<iq xmlns='jabber:client'
@ -217,7 +217,7 @@ If the server is unable to change the message routing algorithm, then an error &
<section2 topic='Message Routing Hints'>
If allowed and supported by the server, clients are able to annotate message stanza with a routing hint, that SHOULD affect the used message routing algorithm for the annotated stanza.
<p>If allowed and supported by the server, clients are able to annotate message stanza with a routing hint, that SHOULD affect the used message routing algorithm for the annotated stanza.</p>
<section3 topic='Determing support'>
@ -306,7 +306,7 @@ The CMR state, ie. the used routing algorithm, is identical for every session of
<p>
<strong>Algorithm Namespace:</strong> 'urn:xmpp:cmr:all'
</p>
Deliver to all non-negative resources with share the same maximum priority. And if message type is 'chat', only to those that have opted in to receive chat messages.
<p>Deliver to all non-negative resources with share the same maximum priority. And if message type is 'chat', only to those that have opted in to receive chat messages.</p>
</section3>
@ -314,7 +314,7 @@ Deliver to all non-negative resources with share the same maximum priority. And
<p>
<strong>Algorithm Namespace:</strong> 'urn:xmpp:cmr:mostactive'
</p>
Deliver the message to the "most available" resource or resources, depending on the server's implementation.
<p>Deliver the message to the "most available" resource or resources, depending on the server's implementation.</p>
</section3>
@ -322,7 +322,7 @@ Deliver the message to the "most available" resource or resources, depending on
<p>
<strong>Algorithm Namespace:</strong> 'urn:xmpp:cmr:roundrobin'
</p>
Deliver the message to the next resource selected by a round-robin algorithm.
<p>Deliver the message to the next resource selected by a round-robin algorithm.</p>
</section3>
@ -330,7 +330,7 @@ Deliver the message to the next resource selected by a round-robin algorithm.
<p>
<strong>Algorithm Namespace:</strong> 'urn:xmpp:cmr:weighted'
</p>
Deliver the message to a resource selected by a weighted round-robin algorithm. The weight of a resource is determined by its priority.
<p>Deliver the message to a resource selected by a weighted round-robin algorithm. The weight of a resource is determined by its priority.</p>
</section3>
</section2>

View File

@ -149,15 +149,20 @@
<p>To signal the type of communication that is desired, the entity that first decloaks MAY include a 'reason' attribute on the &lt;decloak/&gt; element. The following values for the 'reason' attribute are defined:</p>
<dl>
<di>
<dt>media</dt>
<dd>Presence is requested for a voice and/or video call, e.g. via &xep0167;.</dd>
</di>
<di>
<dt>text</dt>
<dd>Presence is requested for a plaintext or &xep0071; conversation, e.g. with end-to-end encryption (which requires capabilities to be disclosed).</dd>
</di>
<di>
<dt>file</dt>
<dd>Presence is requested for one or more file transfers, e.g. via &xep0234; or &xep0095;.</dd>
</di>
</dl>
<p>Inclusion of the 'reason' attribute can be interpreted by the receiving client as a signal that communication is about to start; for instance, a call accept/reject dialog could double as a UI for accepting or rejecting a decloaking request.</p>

View File

@ -357,7 +357,7 @@
</section1>
<section1 topic='Determining Support' anchor='support'>
<p>If a MUC service supports distributed rooms, it MUST return a feature of "urn:xmpp:dmuc:0" &NSVER; in response to &xep0030; information requests.</p>
<p>If a MUC service supports distributed rooms, it MUST return a feature of "urn:xmpp:dmuc:0" in response to &xep0030; information requests.</p>
</section1>
<section1 topic='Security Considerations' anchor='security'>

View File

@ -54,7 +54,7 @@
</p>
</section2>
<section2 topic='Requirements' anchor='reqs'>
<p>The following is a list of goals for the design of this extension:
<p>The following is a list of goals for the design of this extension:</p>
<ul>
<li>DMUC should be transparent to the end user</li>
<li>DMUC should be transparent to the client program</li>
@ -63,35 +63,33 @@
<li>Mirrors of the master room will not communicate directly with each other</li>
<li>If the S2S link is broken, it will appear to a user as if other users have left the room</li>
<li>Users in the same mirror can communicate with each other until the link is re-established with the master</li>
<li>DMUC will improve upon the &xep0033; concept</li> by eliminating the need for &lt;addresses/&gt;
<li>DMUC will improve upon the &xep0033; concept by eliminating the need for &lt;addresses/&gt;</li>
</ul>
</p>
</section2>
</section1>
<section1 topic='Terminology' anchor='terms'>
<section2 topic='General Terms' anchor='genterms'>
<dl>
<dt>master</dt>
<dd>The the actual MUC server</dd>
<dt>mirror</dt>
<dd>A mirror for a master MUC room on another machine</dd>
<di><dt>master</dt>
<dd>The the actual MUC server</dd></di>
<di><dt>mirror</dt>
<dd>A mirror for a master MUC room on another machine</dd></di>
</dl>
</section2>
<section2 topic='Actors' anchor='actors'>
<p>The following JIDs are used in this document.</p>
<dl>
<dt>fairfax.tridsys.com</dt><dd>XMPP server where the master MUC room is located</dd>
<dt>conference.fairfax.tridsys.com</dt><dd>MUC service on fairfax.tridsys.com.</dd>
<dt>chatroom@conference.fairfax.tridsys.com</dt><dd>MUC room.</dd>
<dt>kevin@fairfax.tridsys.com</dt><dd>User on fairfax.tridsys.com</dd>
<dt>scott@fairfax.tridsys.com</dt><dd>Another user on fairfax.tridsys.com</dd>
<br/>
<dt>raleigh.tridsys.com</dt><dd>A remote service, connected to fairfax.tridsys.com over constrained link</dd>
<dt>mirror.raleigh.tridsys.com</dt><dd>DMUC service on raleigh.tridsys.com</dd>
<dt>wayne@raleigh.tridsys.com</dt><dd>User on raleigh.tridsys.com</dd>
<dt>keith@raleigh.tridsys.com</dt><dd>Another user on raleigh.tridsys.com</dd>
<di><dt>fairfax.tridsys.com</dt><dd>XMPP server where the master MUC room is located</dd></di>
<di><dt>conference.fairfax.tridsys.com</dt><dd>MUC service on fairfax.tridsys.com.</dd></di>
<di><dt>chatroom@conference.fairfax.tridsys.com</dt><dd>MUC room.</dd></di>
<di><dt>kevin@fairfax.tridsys.com</dt><dd>User on fairfax.tridsys.com</dd></di>
<di><dt>scott@fairfax.tridsys.com</dt><dd>Another user on fairfax.tridsys.com</dd></di>
<di><dt>raleigh.tridsys.com</dt><dd>A remote service, connected to fairfax.tridsys.com over constrained link</dd></di>
<di><dt>mirror.raleigh.tridsys.com</dt><dd>DMUC service on raleigh.tridsys.com</dd></di>
<di><dt>wayne@raleigh.tridsys.com</dt><dd>User on raleigh.tridsys.com</dd></di>
<di><dt>keith@raleigh.tridsys.com</dt><dd>Another user on raleigh.tridsys.com</dd></di>
</dl>
<p></p>
</section2>
@ -105,7 +103,7 @@ Support for Distributed MUC in a given server instance SHOULD be determined usin
A conforming server MUST respond to disco#info requests.
</p>
<section3 topic='Disco to determine support' anchor='disco2'>
To determine if a server or service supports Distributed MUC, the requesting entity SHOULD send a disco#info request to it.
<p>To determine if a server or service supports Distributed MUC, the requesting entity SHOULD send a disco#info request to it.</p>
<example caption='Disco request for distributed MUC support'><![CDATA[
<iq type='get'
from='raleigh.tridsys.com'

View File

@ -2,6 +2,7 @@
<!DOCTYPE xep SYSTEM 'xep.dtd' [
<!ENTITY % ents SYSTEM 'xep.ent'>
%ents;
<!ENTITY rfc3920bis "<span class='ref'><link url='http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis'>rfc3920bis</link></span> <note>RFC 3920: Extensible Messaging and Presence Protocol (XMPP): Core &lt;<link url='http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis'>http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis</link>&gt;.</note>" >
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
<xep>

View File

@ -5,6 +5,7 @@
<!ENTITY DATETIME "<span class='ref'><link url='http://tools.ietf.org/html/rfc3339'>DATETIME</link></span> <note>RFC 3339: Date and Time on the Internet Timestamps &lt;<link url='http://tools.ietf.org/html/rfc3339'>http://tools.ietf.org/html/rfc3339</link>&gt;.</note>" >
<!ENTITY XMLDSIG "<span class='ref'><link url='http://www.w3.org/TR/xmldsig-core/'>XMLDSIG</link></span> <note>XML Signature Syntax and Processing, W3C Recommendation, 10 June 2008 &lt;<link url='http://www.w3.org/TR/xmldsig-core/'>http://www.w3.org/TR/xmldsig-core/</link>&gt;.</note>" >
<!ENTITY E2EEncrypt "<span class='ref'><link url='http://datatracker.ietf.org/doc/draft-miller-3923bis'>E2EEncrypt</link></span> <note>End-to-End Object Encryption for the Extensible Messaging and Presence Protocol (XMPP), Miller, M. and P. Saint-Andre, work in progress &lt;<link url='http://datatracker.ietf.org/doc/draft-miller-3923bis'>http://datatracker.ietf.org/doc/draft-miller-3923bis</link>&gt;.</note>" >
<!ENTITY rfc3920bis "<span class='ref'><link url='http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis'>rfc3920bis</link></span> <note>RFC 3920: Extensible Messaging and Presence Protocol (XMPP): Core &lt;<link url='http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis'>http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis</link>&gt;.</note>" >
%ents;
]>
<?xml-stylesheet type='text/xsl' href='../xep.xsl'?>

View File

@ -13,8 +13,8 @@
<number>xxxx</number>
<status>ProtoXEP</status>
<type>Standards Track</type>
<approver>Council</approver>
<sig>Standards</sig>
<approver>Council</approver>
<dependencies>
<spec>XMPP Core</spec>
<spec>XEP-0096</spec>

View File

@ -20,6 +20,7 @@
<header>
<title>Instant Gaming</title>
<abstract>This document defines an XMPP protocol extension for serverless instant gaming in a one-to-one context.</abstract>
&LEGALNOTICE;
<number>xxxx</number>
<status>ProtoXEP</status>
<type>Standards Track</type>
@ -53,7 +54,6 @@
<initials>tg</initials>
<remark><p>First draft.</p></remark>
</revision>
&LEGALNOTICE;
</header>
<section1 topic='Introduction' anchor='intro'>
<p>

View File

@ -367,7 +367,7 @@
</tr>
</table>
</section2>
<section2 topic='Unsubscribing a subscription' anhor='unsubscribe'>
<section2 topic='Unsubscribing a subscription' anchor='unsubscribe'>
<p>
To unsubscribe a subscription, send the <strong>unsubscribe</strong> element in a request to the Thing with the <strong>seqnr</strong> sequence number corresponding to the
subscription. The Thing responds with an empty response to acknowledge the un-subscription, regardless if the subscription existed or not.

242
inbox/jet.xml Normal file
View File

@ -0,0 +1,242 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE xep SYSTEM 'xep.dtd' [
<!ENTITY secret "&lt;secret/&gt;">
<!ENTITY % ents SYSTEM 'xep.ent'>
%ents;
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
<xep>
<header>
<title>Jingle Encrypted Transports</title>
<abstract>This specification defines a method that allows to use established encryption schemes like OpenPGP or OMEMO for end-to-end encryption of Jingle transports.</abstract>
&LEGALNOTICE;
<number>XXXX</number>
<status>ProtoXEP</status>
<type>Standards Track</type>
<sig>Standards</sig>
<approver>Council</approver>
<dependencies>
<spec>XEP-0234</spec>
</dependencies>
<supersedes/>
<supersededby/>
<shortname>jet</shortname>
<schemaloc>
<ns>jingle</ns>
<url>http://xmpp.org/schemas/jingle.xsd</url>
</schemaloc>
<schemaloc>
<ns>jingle:errors</ns>
<url>http://xmpp.org/schemas/jingle-errors.xsd</url>
</schemaloc>
<registry/>
<discuss>jingle</discuss>
<author>
<firstname>Paul</firstname>
<surname>Schaub</surname>
<email>vanitasvitae@riseup.net</email>
<jid>vanitasvitae@jabberhead.tk</jid>
</author>
<revision>
<version>0.0.1</version>
<date>2017-06-12</date>
<initials>vv</initials>
<remark><p>First draft</p></remark>
</revision>
</header>
<section1 topic='Introduction' anchor='intro'>
<p>Jingle Encrypted Transports (JET) strives to provide a modular and easily extensible way to wrap Jingle Transports in an additional end-to-end encryption layer. The focus of this specification lays on being modular. It should be possible to extend existing Jingle use scenarios with end-to-end encryption by simply adding a JET element to the negotiation.</p>
</section1>
<section1 topic='Terminology' anchor='terminology'>
<p>JET uses multiple encryption layers, so it is necessary to declare a distinct denomination for the different keys involved.</p>
<table caption='Denomination of keys used in the protocol'>
<tr>
<th>Designation</th>
<th>Abbrevation</th>
<th>Usage</th>
</tr>
<tr>
<td>Transport Key</td>
<td>TK</td>
<td>(Symmetric) key that is used to encrypt/decrypt the bytestreams sent/received through Jingle transports. This key encrypts the data two entities want to exchange. Examples for TK can be found under <link url='#ciphers'>"Ciphers"</link>.</td>
</tr>
<tr>
<td>Initialization Vector</td>
<td>IV</td>
<td>Initialization vector that is used together with TK.</td>
</tr>
<tr>
<td>Transport Secret</td>
<td>TS</td>
<td>Serialization of TK and TI.</td>
</tr>
<tr>
<td>Envelope Element</td>
<td>EE</td>
<td>Output of an established end-to-end encryption methods when encrypting TS. Examples for such methods could be &xep0384; or &xep0374;.</td>
</tr>
</table>
</section1>
<section1 topic='Principle' anchor='principle'>
<p>Lets assume Romeo wants to initiate an encrypted Jingle session with Juliet. Prior to the Jingle session initiation, an already existing, established and (ideally) authenticated end-to-end encryption session between Romeo and Juliet MUST exist. Examples for suitable encryption sessions are &xep0384; and &xep0374;. This session is needed to transfer the Transport Secret from Romeo to Juliet.</p>
<p>When this precondition is met, Romeo initially generates a transport key (TK) and associated initialization vector (IV). These will later be used by the sender to encrypt, and respectively by the recipient to decrypt data that is exchanged. This protocol defines a set of usable <link url='#ciphers'>ciphers</link> from which Romeo might choose. TK and IV are serialized to create the transport secret (TS).</p>
<p>Next Romeo uses her established encryption session with Juliet to encrypt TS. The resulting envelope element (EE) will be part of the Jingle session initiation as child of the JET &secret; element.</p>
<p>When Juliet receives Romeos session request, she decrypts EE to retrieve TS, from which she can deserialize TK and IV. Now she and Romeo can go on with the session negotiation. Once the session is established, data can be encrypted and exchanged.</p>
</section1>
<section1 topic='Encrypted Jingle File Transfer using JET' anchor='jft'>
<p>&xep0234; has the disadvantage, that transmitted files are not encrypted (aside from regular TLS transport encryption), which means that intermediate nodes like XMPP/proxy server(s) have access to the transferred data. Considering that end-to-end encryption becomes more and more important to protect free speech and personal expression, this is a major flaw that needs to be addressed.</p>
<p>In order to initiate an encrypted file transfer, the initiator includes a JET &secret; in the Jingle file transfer request.</p>
<section2 topic='File offer'>
<p>In this scenario Romeo wants to send an encrypted text file over to Juliet. He chooses to use their existing &xep0384; session to do so. First, he generates a fresh AES-256 transport key and IV. TK and IV are serialized into TS which is then encrypted using Romeos OMEMO session with Juliet.</p>
<p>The resulting OMEMO element (EE) is sent as part of the security element along with the rest of the jingle stanza over to Juliet.</p>
<example caption="Romeo initiates an encrypted file offer"><![CDATA[
<iq from='romeo@montague.example/dr4hcr0st3lup4c'
id='nzu25s8'
to='juliet@capulet.example/yn0cl4bnw0yr3vym'
type='set'>
<jingle xmlns='urn:xmpp:jingle:1'
action='session-initiate'
initiator='romeo@montague.example/dr4hcr0st3lup4c'
sid='851ba2'>
<content creator='initiator' name='a-file-offer' senders='initiator'>
<description xmlns='urn:xmpp:jingle:apps:file-transfer:5'>
<file>
<date>1969-07-21T02:56:15Z</date>
<desc>This is a test. If this were a real file...</desc>
<media-type>text/plain</media-type>
<name>test.txt</name>
<range/>
<size>6144</size>
<hash xmlns='urn:xmpp:hashes:2'
algo='sha-1'>w0mcJylzCn+AfvuGdqkty2+KP48=</hash>
</file>
</description>
<transport xmlns='urn:xmpp:jingle:transports:s5b:1'
mode='tcp'
sid='vj3hs98y'>
<candidate cid='hft54dqy'
host='192.168.4.1'
jid='romeo@montague.example/dr4hcr0st3lup4c'
port='5086'
priority='8257636'
type='direct'/>
</transport>
<security xmlns='urn:xmpp:jingle:jet:0'
name='a-file-offer'
cipher='urn:xmpp:ciphers:aes-256-gcm-nopadding'
type='urn:xmpp:omemo:0'>
<encrypted xmlns='urn:xmpp:omemo:0'>
<header sid='27183'>
<key rid='31415'>BASE64ENCODED...</key>
<key rid='12321'>BASE64ENCODED...</key>
<iv>BASE64ENCODED...</iv>
</header>
<payload>BASE64-ENCODED-ENCRYPTED-SECRET</payload>
</encrypted>
</security>
</content>
</jingle>
</iq>]]></example>
<p>Juliet decrypts the OMEMO element (EE) using her session with Romeo to retrieve TS from which she deserializes TK and IV. Both Juliet and Romeo then carry on with the session negotiation as described in &xep0234;. Before Romeo starts transmitting the file, he encrypts it using TK and IV. He then transmitts the encrypted file over to Juliet.</p>
<p>When Juliet received the file, she uses the TK and IV to decrypt the received file.</p>
</section2>
<section2 topic='File Request'>
<p>Juliet might want to request a file transfer from Romeo. This can be the case, when Romeo hosts the file. In order to do so, she sends generates TK and IV, creates TS from those and encrypts TS with an encryption method of her choice to get EE. TK and IV will be used by Romeo to encrypt the requested file before sending it to Juliet. In this example we assume, that Romeo and Juliet secured their communications using &xep0374;.</p>
<example caption="Juliet initiates an encrypted file request"><![CDATA[
<iq from='juliet@capulet.example/yn0cl4bnw0yr3vym'
id='wsn361c3'
to='romeo@montague.example/dr4hcr0st3lup4c'
type='set'>
<jingle xmlns='urn:xmpp:jingle:1'
action='session-initiate'
initiator='juliet@capulet.example/yn0cl4bnw0yr3vym'
sid='uj3b2'>
<content creator='initiator' name='a-file-request' senders='responder'>
<description xmlns='urn:xmpp:jingle:apps:file-transfer:5'>
<file>
<hash xmlns='urn:xmpp:hashes:2'
algo='sha-1'>w0mcJylzCn+AfvuGdqkty2+KP48=</hash>
</file>
</description>
<transport xmlns='urn:xmpp:jingle:transports:s5b:1'
mode='tcp'
sid='xig361fj'>
<candidate cid='ht567dq'
host='192.169.1.10'
jid='juliet@capulet.example/yn0cl4bnw0yr3vym'
port='6539'
priority='8257636'
type='direct'/>
</transport>
<security xmlns='urn:xmpp:jingle:jet:0'
name='a-file-request'
cipher='urn:xmpp:ciphers:aes-256-gcm-nopadding'
type='urn:xmpp:openpgp:0'>
<signcrypt xmlns='urn:xmpp:openpgp:0'>
<to jid='romeo@montague.example'/>
<time stamp='2014-07-10T17:06:00+02:00'/>
<rpad>f0rm1l4n4-mT8y33j!Y%fRSrcd^ZE4Q7VDt1L%WEgR!kv</rpad>
<payload>
<body xmlns='jabber:client'>BASE64-ENCODED-ENCRYPTED-SECRET</body>
</payload>
</signcrypt>
</security>
</content>
</jingle>
</iq>]]></example>
</section2>
</section1>
<section1 topic='Ciphers' anchor='ciphers'>
<p>In order to encrypt the transported bytestream, the initiator must transmit a cipher key to the responder. There are multiple options available:</p>
<table caption='Available ciphers, configurations and their namespaces'>
<tr>
<th>Namespace</th>
<th>Type</th>
<th>Length (bits)</th>
<th>Parameters</th>
<th>Serialization</th>
</tr>
<tr>
<td>urn:xmpp:ciphers:aes-128-gcm-nopadding:0</td>
<td>AES</td>
<td>128</td>
<td>GCM/NoPadding</td>
<td>128BitKey::96BitIV</td>
</tr>
<tr>
<td>urn:xmpp:ciphers:aes-256-gcm-nopadding:0</td>
<td>AES</td>
<td>256</td>
<td>GCM/NoPadding</td>
<td>256BitKey::96BitIV</td>
</tr>
</table>
<p>The column 'serialization' describes, how the key and iv are serialized. "::" means plain concatenation of byte arrays.</p>
</section1>
<section1 topic='Security Considerations' anchor='security'>
<p>The initiator SHOULD NOT use the generated key TK as IV, but instead generate a seperate random IV.</p>
<p>Instead of falling back to unencrypted transfer in case something goes wrong, implementations MUST instead abort the Jingle session, informing the user.</p>
<p>IMPORTANT: This approach does not deal with metadata. In case of &xep0234;, an attacker with access to the sent stanzas can for example still see the name of the file and other information included in the &lt;file/&gt; element.</p>
<p>When using OX as encryption method, clients might want to protect against replay attacks</p>
<p>The responder MUST check, whether the envelope element belongs to the initiator to prevent MitM attacks</p>
</section1>
<section1 topic='Open Questions'>
<p>This is only a rough draft and there is still a ton of questions left to be answered. Here is a small non-exhaustive list of things I can think of:</p>
<ul>
<li>How exactly are interrupted transfers resumed? How (long) are keys/IVs cached?</li>
<li>May it be desirable to split data into chunks?</li>
<li>Please add to this list :)</li>
</ul>
</section1>
<section1 topic='TODO'>
<ul>
<li>Service discovery</li>
</ul>
</section1>
</xep>

View File

@ -1,6 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE xep SYSTEM 'xep.dtd' [
<!ENTITY % ents SYSTEM 'xep.ent'>
<!ENTITY rfc3920bis "<span class='ref'><link url='http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis'>rfc3920bis</link></span> <note>RFC 3920: Extensible Messaging and Presence Protocol (XMPP): Core &lt;<link url='http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis'>http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis</link>&gt;.</note>" >
%ents;
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
@ -35,7 +36,7 @@
</section1>
<section1 topic='Protocol'>
<para>The basic flow is as follows.</para>
<p>The basic flow is as follows.</p>
<code><![CDATA[
Initiator Responder
| |

View File

@ -31,7 +31,7 @@
</dependencies>
<supersedes/>
<supersededby/>
<shortname/>Jingle Nodes <author>
<shortname>Jingle Nodes</shortname> <author>
<firstname>Thiago</firstname>
<surname>Camargo</surname>
<email>thiago@xmppjingle.com</email>
@ -120,7 +120,7 @@ All signalling, request, response and publishing is done via XMPP, not requiring
<tracker policy='public' address='capulet.lit' protocol='udp'/>
</services>
</iq> ]]></example>
<em>In this example 'montague.lit' XMPP Domain a Relay Service and a Tracker Service. The Relay Service can be contacted in order to retrieve Relay Channels. The Tracker Service can be contacted in order to retrieve its known services.</em>
<p><em>In this example 'montague.lit' XMPP Domain a Relay Service and a Tracker Service. The Relay Service can be contacted in order to retrieve Relay Channels. The Tracker Service can be contacted in order to retrieve its known services.</em></p>
</section2>
<section2 topic="Jingle Client Searches for Services on a Retrieved Tracker Service" anchor="clientcheckownserver">
<p>A Jingle Client MAY NOT be satisfied with only one Relay Service entry found. So it keeps the search on the known Tracker Services.</p>
@ -139,7 +139,7 @@ All signalling, request, response and publishing is done via XMPP, not requiring
type='result'>
<services xmlns='http://jabber.org/protocol/jinglenodes'/>
</iq> ]]></example>
<em>In this example 'capulet.lit' returned an empty service list, meaning that it does NOT known ANY Relay or Tracker Services.</em>
<p><em>In this example 'capulet.lit' returned an empty service list, meaning that it does NOT known ANY Relay or Tracker Services.</em></p>
</section2>
<section2 topic="Jingle Client Searches for Services on online Roster Entries" anchor="clientcheckownserver">
<p>A Jingle Client MAY NOT be satisfied with only one Relay Service entry found. So it keeps the search on his Roster Items until find the desired amount of Relay Services, or while it does NOT exceed a search depth or ANY other Client implementation policy. The Client SHOULD keep a list of visited Tracker Services in order to avoid searching twice in same Service Entity.</p>
@ -161,7 +161,7 @@ All signalling, request, response and publishing is done via XMPP, not requiring
</services>
</iq> ]]></example>
<p>In this example 'juliet@capulet.lit/balcony' returned a Relay Service entry that is restricted to its roster. This Service is usable as the requester has 'juliet@capulet.lit/balcony' on its roster. Although, services with policy 'roster' MUST NOT be listed in Tracker Responses expects in Tracker Responses that comes from the Service Entity itself, in this case 'juliet@capulet.lit/balcony'.</p>
<em>In the presented example 'romeo@montague.lit/orchard' knows that 'juliet@capulet.lit/balcony' provides Relay Service, but if another entity requests 'romeo@montague.lit/orchard' its known services, it MUST NOT include 'juliet@capulet.lit/balcony' as it is a roster restricted entry.</em>
<p><em>In the presented example 'romeo@montague.lit/orchard' knows that 'juliet@capulet.lit/balcony' provides Relay Service, but if another entity requests 'romeo@montague.lit/orchard' its known services, it MUST NOT include 'juliet@capulet.lit/balcony' as it is a roster restricted entry.</em></p>
</section2>
<section2 topic="Jingle Client Consuming the Relay Service" anchor="clientconsumingrelay">
<p>A Jingle Client with direct access to a public IP can potentially provide the Relay Service becaming itself a Jingle Relay Node. The service can intend to provide a public service, or a restricted services based on user preferences, like buddylist, whitelist, blacklist, domain, etc...</p>
@ -372,15 +372,9 @@ All signalling, request, response and publishing is done via XMPP, not requiring
<p>Relay Channels auto expires MUST expire on traffic inactivity. The inactivity timeout recommended is 60 seconds.</p>
<p>It is heavily recommended that the Super Node implements throttle:</p>
<ul>
<p>
<li>Based on JID, allowing the control of how many concurrent channels an specific JID can have.</li>
</p>
<p>
<li>Based on JID, allowing the control of how many channel requests an specific JID can request in a time period.</li>
</p>
<p>
<li>Based on Bandwidth, allowing the control of how much bandwidth a channel can use. The maximum bandwidth SHOULD be included on the candidate element provided by a Super Node on the attribute maxkbps. If no attribute is present, it means that it has no bandwidth control.</li>
</p>
<li>Based on Bandwidth, allowing the control of how much bandwidth a channel can use. The maximum bandwidth SHOULD be included on the candidate element provided by a Super Node on the attribute maxkbps. If no attribute is present, it means that it has no bandwidth control.
<example caption="Channel Returned by a Node with bandwidth throttle (stub)"><![CDATA[
<channel component='1'
id='el0747fg11'
@ -389,7 +383,7 @@ All signalling, request, response and publishing is done via XMPP, not requiring
remoteport='35802'
protocol='udp'
maxkbps='120'/>
]]></example>
]]></example></li>
</ul>
</section1>
<section1 topic='XML Schema' anchor='schema'>

View File

@ -80,7 +80,7 @@
</tr>
<tr>
<td>Good quality; optimized for voice; can be used for wide-band audio.</td>
<td>See &rtpspeex;.</td>
<td>See &rfc5574;.</td>
<td>Freely downloadable under a revised BSD license at &lt;<link url='http://speex.org/'>http://speex.org/</link>&gt; and commonly deployed on Internet (VoIP) systems; not commonly deployed on non-Internet systems.</td>
<td>Designed to be patent-clear.</td>
</tr>

View File

@ -64,7 +64,7 @@
</tr>
<tr>
<td>Good quality; optimized for voice; can be used for wide-band audio.</td>
<td>See &rtpspeex;.</td>
<td>See &rfc5574;.</td>
<td>Widely available and freely downloadable under a revised BSD license at &lt;<link url='http://speex.org/'>http://speex.org/</link>&gt;.</td>
<td>Designed to be patent-free.</td>
</tr>

View File

@ -54,7 +54,7 @@
</section1>
<section1 topic='Protocol' anchor='protocol'>
<para>The basic flow is as follows.</para>
<p>The basic flow is as follows.</p>
<code><![CDATA[
Romeo Juliet
| |

View File

@ -1,6 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE xep SYSTEM 'xep.dtd' [
<!ENTITY % ents SYSTEM 'xep.ent'>
<!ENTITY rfc3920bis "<span class='ref'><link url='http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis'>rfc3920bis</link></span> <note>RFC 3920: Extensible Messaging and Presence Protocol (XMPP): Core &lt;<link url='http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis'>http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis</link>&gt;.</note>" >
%ents;
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>

View File

@ -40,7 +40,7 @@
</header>
<section1 topic='Protocol' anchor='protocol'>
<p>&xep0167; recommends the use of the Secure Real-time Transport Protocol (SRTP) for end-to-end encryption of RTP sessions negotiated using &xep0166;. An alternative approach to end-to-end encryption of RTP traffic is provided by &zrtp;. Although negotiation of ZRTP mainly occurs in the media channel rather than the signalling channel, the ZRTP specification defines one SDP attribute called "zrtp-hash" (this communicates the ZRTP version supported as well as a hash of the Hello message).</p>
<p>&xep0167; recommends the use of the Secure Real-time Transport Protocol (SRTP) for end-to-end encryption of RTP sessions negotiated using &xep0166;. An alternative approach to end-to-end encryption of RTP traffic is provided by &rfc6189;. Although negotiation of ZRTP mainly occurs in the media channel rather than the signalling channel, the ZRTP specification defines one SDP attribute called "zrtp-hash" (this communicates the ZRTP version supported as well as a hash of the Hello message).</p>
<p>The SDP format is shown below.</p>
<code>
a=zrtp-hash:zrtp-version zrtp-hash-value

View File

@ -48,13 +48,11 @@
</section1>
<section1 topic='Requirements' anchor='reqs'>
<p>The following design requirements reflect the need to offer performance as close as possible to standard XMPP-based stanza handling.</p>
<p>
<ol>
<li>JSON default character set must be UTF-8</li>
<li>JSON stanza must contain (or retain) all XMPP stanza content and hierarchy</li>
<li>Server must support both XML and JSON content-types.</li>
</ol>
</p>
</section1>
<section1 topic='Use Cases' anchor='usecases'>
<p>Intent for following use-cases is to support JavaScript-based clients which typically start XMPP-session from HTTP-dialog, and then depending on network environment and run-time support end using BOSH or C2S through Web Sockets.</p>
@ -69,23 +67,23 @@
<section1 topic='Implementation Notes' anchor='impl'>
<p>Client (and server) implementation needs to take care of using such JSON object format which retains all structure of all XMPP XML stanzas.</p>
<section2 topic='HTTP Header' anchor='http-header'>
<p>Following http-header is used to communicate with server using JSON playload:
<section3 topic='Request' anchor='c-header'><pre>
<p>Following http-header is used to communicate with server using JSON playload:</p>
<section3 topic='Request' anchor='c-header'><code>
POST /http-bind HTTP/1.1
Host: httpcm.jabber.org
Accept-Encoding: gzip, deflate
Content-Type: application/jsonrequest
Content-Length: 230
</pre></section3>
<section3 topic='Response' anchor='s-header'><pre>
</code></section3>
<section3 topic='Response' anchor='s-header'><code>
HTTP/1.1 200 OK
Content-Type: application/jsonrequest
Content-Length: 513
</pre></section3></p>
</code></section3>
</section2>
<section2 topic='Initial BOSH request/response in JSON' anchor='init-payload'>
<p>In following example server name is modified so content length is not accurate. Also JSON payload is modified for better clarity of its structure.
<section3 topic='Client request' anchor='c-req'><pre>
<p>In following example server name is modified so content length is not accurate. Also JSON payload is modified for better clarity of its structure.</p>
<section3 topic='Client request' anchor='c-req'><code>
POST /http-bind HTTP/1.1
Host: httpcm.jabber.org
Accept-Encoding: gzip, deflate
@ -106,8 +104,8 @@ Content-Length: 230
"@xmpp" : "urn:xmpp:xbosh" }
}
}
</pre></section3>
<section3 topic='Server response' anchor='s-resp'><pre>
</code></section3>
<section3 topic='Server response' anchor='s-resp'><code>
HTTP/1.1 200 OK
Content-Type: application/jsonrequest
Content-Length: 513
@ -141,140 +139,139 @@ Content-Length: 513
}
}
}
</pre></section3>
</code></section3>
<section3 topic='JSON syntax explained' anchor='json-syntax'>
<ul>
<li>Tag with text value</li>
<em>XMPP-XML:</em><pre>
<li>Tag with text value
<em>XMPP-XML:</em><code>
&lt;tag&gt;txt-value&lt;/tag&gt;
</pre>
<em>JSON:</em><pre>
</code>
<em>JSON:</em><code>
{ "tag" : "txt-value" }
</pre>
<li>Tag with another tag</li>
<em>XMPP-XML:</em><pre>
</code></li>
<li>Tag with another tag
<em>XMPP-XML:</em><code>
&lt;tag&gt;
&lt;tag2&gt;txt-value&lt;/tag2&gt;
&lt;/tag&gt;
</pre>
<em>JSON:</em><pre>
</code>
<em>JSON:</em><code>
{ "tag" : {
"$" : {
"tag2" : "txt-value" }
}
}
</pre>
<li>Multiple text value tags as array</li>
<em>XMPP-XML:</em><pre>
</code></li>
<li>Multiple text value tags as array
<em>XMPP-XML:</em><code>
&lt;tag&gt;
&lt;tag2&gt;txt-value1&lt;/tag2&gt;
&lt;tag2&gt;txt-value2&lt;/tag2&gt;
&lt;/tag&gt;
</pre>
<em>JSON:</em><pre>
</code>
<em>JSON:</em><code>
{ "tag" : {
"$" : {
"tag2" : [ "txt-value1", "txt-value2" ] }
}
}
</pre>
<li>Tag with attribute, no value</li>
<em>XMPP-XML:</em><pre>
</code></li>
<li>Tag with attribute, no value
<em>XMPP-XML:</em><code>
&lt;tag attr="attr-value" /&gt;
</pre>
<em>JSON:</em><pre>
</code>
<em>JSON:</em><code>
{ "tag" : { "attr" : "attr-value" } }
</pre>
<li>Tag with multiple attributes as array, no value</li>
<em>XMPP-XML:</em><pre>
</code></li>
<li>Tag with multiple attributes as array, no value
<em>XMPP-XML:</em><code>
&lt;tag attr="attr-value1" attr="attr-value2" /&gt;
</pre>
<em>JSON:</em><pre>
</code>
<em>JSON:</em><code>
{ "tag" : {
"attr" : [ "attr-value1", "attr-value2" ] }
}
</pre>
<li>Tags as array with unique attributes, no value</li>
<em>XMPP-XML:</em><pre>
</code></li>
<li>Tags as array with unique attributes, no value
<em>XMPP-XML:</em><code>
&lt;tag&gt;
&lt;tag2 attr="attr-value1" /&gt;
&lt;tag2 attr="attr-value2" /&gt;
&lt;/tag&gt;
</pre>
<em>JSON:</em><pre>
</code>
<em>JSON:</em><code>
{ "tag" : {
"tag2" : [
{ "attr" : "attr-value1" },
{ "attr" : "attr-value2" } ]
}
}
</pre>
<li>Tag with namespace attribute, no value</li>
<em>XMPP-XML:</em><pre>
</code></li>
<li>Tag with namespace attribute, no value
<em>XMPP-XML:</em><code>
&lt;tag xmlns:ns="ns-value" /&gt;
</pre>
<em>JSON:</em><pre>
</code>
<em>JSON:</em><code>
{ "tag" : {
"xmlns" : {
"@ns" : "attr-value" }
}
}
</pre>
<li>Tag with many attributes to namespace, no value</li>
<em>XMPP-XML:</em><pre>
</code></li>
<li>Tag with many attributes to namespace, no value
<em>XMPP-XML:</em><code>
&lt;tag xmlns="root-value" xmlns:ns="ns-value" /&gt;
</pre>
<em>JSON:</em><pre>
</code>
<em>JSON:</em><code>
{ "tag" : {
"xmlns" : {
"$" : "root-value",
"@ns" : "attr-value" }
}
}
</pre>
<li>Tag with namespace attribute, no value</li>
<em>XMPP-XML:</em><pre>
</code></li>
<li>Tag with namespace attribute, no value
<em>XMPP-XML:</em><code>
&lt;ns:tag attr="attr-value" /&gt;
</pre>
<em>JSON:</em><pre>
</code>
<em>JSON:</em><code>
{ "tag" : {
"$$" : "ns",
"attr" : "attr-value" }
}
</pre>
<li>Tag with attribute and text value</li>
<em>XMPP-XML:</em><pre>
</code></li>
<li>Tag with attribute and text value
<em>XMPP-XML:</em><code>
&lt;tag attr="attr-value"&gt;txt-value&lt;/tag&gt;
</pre>
<em>JSON:</em><pre>
</code>
<em>JSON:</em><code>
{ "tag" : {
"attr" : "attr-value",
"$" : "txt-value" }
}
</pre>
<li>Namespace tag with attribute and text value</li>
<em>XMPP-XML:</em><pre>
</code></li>
<li>Namespace tag with attribute and text value
<em>XMPP-XML:</em><code>
&lt;ns:tag attr="attr-value"&gt;txt-value&lt;/tag&gt;
</pre>
<em>JSON:</em><pre>
</code>
<em>JSON:</em><code>
{ "tag" : {
"$$" : "ns",
"attr" : "attr-value",
"$" : "txt-value" }
}
</pre>
</code></li>
<li>Complex combination</li>
<li>Tag name conversions</li>
<p>JSON data is typically converted to JS-object in browser client. Practically this means that <em>tag string name</em> / <em>value string</em> pairs are converted to <em>tag name</em> / <em>value string</em> pairs. Example:<pre>
<li>Tag name conversions
<p>JSON data is typically converted to JS-object in browser client. Practically this means that <em>tag string name</em> / <em>value string</em> pairs are converted to <em>tag name</em> / <em>value string</em> pairs. Example:</p><code>
var s = '{ "key" : "value" }';
var sObj = JSON.parse(s); // sObj = { key : "value" };
var sStr = JSON.stringify(sObj); // sStr = '{"key":"value"}';
</pre></p>
</code>
<p>Javascript variable naming doesn't support full colon characters '<em>:</em>'. Intented conversion between JSON and JS-objects is based on native JavaScript class <em>JSON</em>, more spesifically methods <em>JSON.stringify()</em> for converting object to JSON, and <em>JSON.parse()</em> from JSON to object.<br/>
Because of this namespace definitions are constructed hiearchically and their scope is within tag it is defined. Currently only reserved namespace name is '<em>xml</em>'.</p>
Because of this namespace definitions are constructed hiearchically and their scope is within tag it is defined. Currently only reserved namespace name is '<em>xml</em>'.</p></li>
</ul>
</section3>
</p>
</section2>
</section1>
<section1 topic='Security Considerations' anchor='security'>

View File

@ -66,12 +66,12 @@
<section1 topic='Introduction' anchor='intro'>
<p>
Linked Process is a protocol for Internet-scale, general-purpose distributed computing. With an implementation of this protocol, any computing device with an Internet connection can contribute computing resources to a user-generated compute cloud.
</p>
<ul>
<li>The term <strong>computing device</strong> is broad and spans particulars such as cell phones, laptops, desktops, servers, supercomputers, etc. In Linked Process, a computing device is anything that maintains a central processing unit (CPU) that can be programmed to execute any desired computation.</li>
<li>The term <strong>computing resources</strong> is broad and spans particulars such as clock cycles, data sets, software application programming interfaces (APIs), or specialized hardware componets such as cell phone cameras, field-programmable gate array (FPGA) circuits, etc.</li>
<li>The term <strong>compute cloud</strong> is the collection of all Linked Process enabled devices, their resources, and the Linked Process specific software components defined later in this specification.</li>
</ul>
</p>
<p>
Within the category of computing devices, Linked Process makes a distinction between resource consumers (devices making use of non-local computing resources) and a resource providers (devices offering computing resources)<note>Nothing prevents the same device from being a resource consumer in one context and being a resource provider in another.</note>. Linked Process allows a resource consumer to leverage the computing resources offered by a resource provider in anyway deemed appropriate by the resource consumer. This is accomplished by the resource consumer providing/migrating/sending code (i.e. software instructions) to a computer language interpreter maintained by the resource provider. As such, it is up to the resource consumer to define the instructions to be executed by the provider. Given this architecture, resource providing devices in a Linked Process cloud are general-purpose computing sandboxes (i.e. they can be leveraged for computational ends that are defined by a resource consumer).
</p>
@ -84,18 +84,18 @@
Linked Process was developed to address the following two distributed computing requirements: <em>Internet-scale</em> and <em>general-purpose</em>. These requirements imply yet more requirements which accompany their description below.
</p>
<ul>
<li><strong>Internet-scale</strong>: it is required that any device with an Internet connection (from a cell phone to a supercomputer) be able provide/contribute and consume/leverage computing resources in a Linked Process cloud.</li>
<li><strong>Internet-scale</strong>: it is required that any device with an Internet connection (from a cell phone to a supercomputer) be able provide/contribute and consume/leverage computing resources in a Linked Process cloud.
<ul>
<li><strong>Decentralized</strong>: it is required that the computing resources are not necessarily centralized or controlled by any one party.</li>
<li><strong>Discoverable</strong>: it is required that resource providers be discoverable by resources consumers.</li>
<li><strong>Transient</strong>: it is required that devices coming online and offline are gracefully incoporated and removed from the cloud.</li>
</ul>
<li><strong>General-purpose</strong>: It is required that consumers be able to utilize provided resources for any desired purpose.</li>
</ul></li>
<li><strong>General-purpose</strong>: It is required that consumers be able to utilize provided resources for any desired purpose.
<ul>
<li><strong>Language-agnostic</strong>: it is required that the protocol support the migration of code written in any computer language.</li>
<li><strong>Safe</strong>: it is required that the execution of consumer code be confined by permissions clearly specified by the resource provider<note>There is a tradeoff between "general-purpose" and "safety." It is important to ensure that the integrity of resource providers are not compomised due to malicious or poorly written code.</note>.</li>
<li><strong>Accessible</strong>: it is required that computing resources be accessible when permissions allow by ensuring the supported language interpreters provide necessary "low-level" manipulations of such resources.</li>
</ul>
</ul></li>
</ul>
</section1>
<section1 topic='Glossary' anchor='glossary'>
@ -161,18 +161,18 @@
A <tt>&lt;spawn_vm/&gt;</tt> element is wrapped by an <tt>&lt;iq/&gt;</tt> element. The purpose of <tt>&lt;spawn_vm/&gt;</tt> is to have a farm create a new virtual machine. It is through a virtual machine that a villein is able to access the computing resources of the physical device that hosts the farm (i.e. the resource provider). A virtual machine will maintain a state throughout a villein "session" with that virtual machine. The only way to alter the state of a virtual machine is through submitting jobs and updating its variable bindings<note>This is an important concept to understand. During the life of a virtual machine, the virtual machine has a state that changes as jobs are submitted and bindings are managed. In other words, a virtual machine is not a "one-job" machine.</note>.
</p>
<ul>
<li>Villein generated <tt>&lt;iq type="get"&gt;</tt> <tt>&lt;spawn_vm/&gt;</tt>:</li>
<li>Villein generated <tt>&lt;iq type="get"&gt;</tt> <tt>&lt;spawn_vm/&gt;</tt>:
<ul>
<li><tt>xmlns</tt> attribute: <tt>http://linkedprocess.org/2009/06/Farm#</tt>.</li>
<li><tt>vm_species</tt> attribute: the language of the virtual machine to be spawned (values are implementation dependent).</li>
<li><tt>farm_password</tt> attribute: the password of the farm<note>This is an OPTIONAL attribute. Farm passwords are useful for creating private farms in order, for example, to allow "looser" permissions with known villeins. If no password is required (e.g. a public farm), then no <tt>farm_password</tt> attribute SHOULD be provided.</note>.</li>
</ul>
<li>Farm generated <tt>&lt;iq type="result"&gt;</tt> or <tt>&lt;iq type="error"&gt;</tt> <tt>&lt;spawn_vm/&gt;</tt>:</li>
</ul></li>
<li>Farm generated <tt>&lt;iq type="result"&gt;</tt> or <tt>&lt;iq type="error"&gt;</tt> <tt>&lt;spawn_vm/&gt;</tt>:
<ul>
<li><tt>xmlns</tt> attribute: <tt>http://linkedprocess.org/2009/06/Farm#</tt>.</li>
<li><tt>vm_id</tt> attribute: a farm-internal unique identifier for the newly created virtual machine. This MUST be provided if <tt>&lt;iq type="result"/&gt;</tt>.</li>
<li><tt>vm_species</tt> attribute: the species of the newly created virtual machine. This MUST be provided if <tt>&lt;iq type="result"/&gt;</tt>.</li>
<li>One of these error conditions MUST be provided if <tt>&lt;iq type="error"/&gt;</tt>.</li>
<li>One of these error conditions MUST be provided if <tt>&lt;iq type="error"/&gt;</tt>.
<ul>
<li><tt>&lt;species_not_supported/&gt;</tt></li>
<li><tt>&lt;farm_is_busy/&gt;</tt></li>
@ -180,8 +180,8 @@
<li><tt>&lt;internal_error/&gt;</tt></li>
<li><tt>&lt;wrong_farm_password/&gt;</tt></li>
<li>if an error occurred, the farm SHOULD provide some implementation specific human-readable information detailing the error in <tt>&lt;text/&gt;</tt>. Error responses extend the requirements set forth by the <link url="http://xmpp.org/rfcs/rfc3920.html">Core</link> XMPP specification.</li>
</ul>
</ul>
</ul></li>
</ul></li>
</ul>
<example caption="A successful &lt;spawn_vm/&gt; request."><![CDATA[<iq from="lp1@linkedprocess.org/villein"
@ -218,18 +218,18 @@
A <tt>&lt;submit_job/&gt;</tt> element is wrapped by an <tt>&lt;iq/&gt;</tt> element. The purpose of <tt>&lt;submit_job/&gt;</tt> is to send code (i.e. expressions, statements, instructions) to a virtual machine for execution (i.e. evaluation, interpretation). The expression SHOULD be respective of the virtual machine's language (i.e. the virtual machine's species). If they are not, then evaluation errors SHOULD occur. The expression submitted through a <tt>&lt;submit_job/&gt;</tt> stanza can be short (e.g. set a variable value, get a variable value) or long (e.g. define a class/method, execute a long running body of statements). The submitted expression is called a <strong>job</strong> in Linked Process and is assigned a <tt>job_id</tt> as specified by the <tt>&lt;iq/&gt;</tt> <tt>id</tt> attribute value. That is, the staza id of the <tt>&lt;submit_job/&gt;</tt> is the job's id.
</p>
<ul>
<li>Villein generated <tt>&lt;iq type="get"&gt;</tt> <tt>&lt;submit_job/&gt;</tt>:</li>
<li>Villein generated <tt>&lt;iq type="get"&gt;</tt> <tt>&lt;submit_job/&gt;</tt>:
<ul>
<li><tt>xmlns</tt> attribute: <tt>http://linkedprocess.org/2009/06/Farm#</tt>.</li>
<li><tt>vm_id</tt> attribute: the farm-internal unique identifier of the virtual machine.</li>
<li><tt>&lt;submit_job/&gt;</tt> text body: the expression for the virtual machine to evaluate. If no text body is provided, the expression to be evaluated can be interpreted as a blank string or a null expression. The behavior of such an evaluation is up to the virtual machine implementation.</li>
</ul>
<li>Farm generated <tt>&lt;iq type="result"&gt;</tt> or <tt>&lt;iq type="error"&gt;</tt> <tt>&lt;submit_job/&gt;</tt>:</li>
</ul></li>
<li>Farm generated <tt>&lt;iq type="result"&gt;</tt> or <tt>&lt;iq type="error"&gt;</tt> <tt>&lt;submit_job/&gt;</tt>:
<ul>
<li><tt>xmlns</tt> attribute: <tt>http://linkedprocess.org/2009/06/Farm#</tt>.</li>
<li><tt>vm_id</tt> attribute: the farm-internal unique identifier of the virtual machine.</li>
<li><tt>&lt;submit_job/&gt;</tt> text body: the result of the expression evaluated.</li>
<li>One of these error conditions MUST be provided if <tt>&lt;iq type="error"/&gt;</tt><note>Note that, according to XMPP Core, it is RECOMMENDED that an <tt>&lt;iq type="error"/&gt;</tt> return the the query provided by the villein. In the example above, only the tag name is provided without the full body. The reason for this is that for <tt>&lt;submit_job/&gt;</tt>, the length of the text body of the tag is unrestricted and thus could be a very large piece of code. Thus, returning the original <tt>&lt;submit_job/&gt;</tt> stanza in the error response could lead to excessive communication overhead.</note>.</li>
<li>One of these error conditions MUST be provided if <tt>&lt;iq type="error"/&gt;</tt><note>Note that, according to XMPP Core, it is RECOMMENDED that an <tt>&lt;iq type="error"/&gt;</tt> return the the query provided by the villein. In the example above, only the tag name is provided without the full body. The reason for this is that for <tt>&lt;submit_job/&gt;</tt>, the length of the text body of the tag is unrestricted and thus could be a very large piece of code. Thus, returning the original <tt>&lt;submit_job/&gt;</tt> stanza in the error response could lead to excessive communication overhead.</note>.
<ul>
<li><tt>&lt;malformed_packet/&gt;</tt></li>
<li><tt>&lt;internal_error/&gt;</tt></li>
@ -240,8 +240,8 @@
<li><tt>&lt;vm_not_found/&gt;</tt></li>
<li><tt>&lt;job_timed_out/&gt;</tt></li>
<li>if an error occurred, the farm SHOULD provide some implementation specific human-readable information detailing the error in <tt>&lt;text/&gt;</tt>. Error responses extend the requirements set forth by the <link url="http://xmpp.org/rfcs/rfc3920.html">Core</link> XMPP specification.</li>
</ul>
</ul>
</ul></li>
</ul></li>
</ul>
<example caption="A successful &lt;submit_job/&gt; request."><![CDATA[<iq from="lp1@linkedprocess.org/villein"
@ -306,30 +306,30 @@
A <tt>&lt;ping_job/&gt;</tt> element is wrapped by an <tt>&lt;iq/&gt;</tt> element. The purpose of <tt>&lt;ping_job/&gt;</tt> is to determine the status (i.e. progress, state) of a previously submitted <tt>&lt;submit_job/&gt;</tt> stanza (i.e. job) that has yet to complete.
</p>
<ul>
<li>Villein generated <tt>&lt;iq type="get"&gt;</tt> <tt>&lt;ping_job/&gt;</tt>:</li>
<li>Villein generated <tt>&lt;iq type="get"&gt;</tt> <tt>&lt;ping_job/&gt;</tt>:
<ul>
<li><tt>xmlns</tt> attribute: <tt>http://linkedprocess.org/2009/06/Farm#</tt>.</li>
<li><tt>vm_id</tt> attribute: the farm-internal unique identifier of the virtual machine.</li>
<li><tt>job_id</tt> attribute: the job identifier (the job identifier is the stanza identifier of the respective <tt>&lt;submit_job/&gt;</tt>).</li>
</ul>
<li>Farm generated <tt>&lt;iq type="result"&gt;</tt> or <tt>&lt;iq type="error"&gt;</tt> <tt>&lt;ping_job/&gt;</tt>:</li>
</ul></li>
<li>Farm generated <tt>&lt;iq type="result"&gt;</tt> or <tt>&lt;iq type="error"&gt;</tt> <tt>&lt;ping_job/&gt;</tt>:
<ul>
<li><tt>xmlns</tt> attribute: <tt>http://linkedprocess.org/2009/06/Farm#</tt>.</li>
<li><tt>vm_id</tt> attribute: the farm-internal unique identifier of the virtual machine.</li>
<li><tt>status</tt> attribute: the job's status. This MUST be provided if <tt>&lt;iq type="result"/&gt;</tt>.</li>
<li><tt>status</tt> attribute: the job's status. This MUST be provided if <tt>&lt;iq type="result"/&gt;</tt>.
<ul>
<li><tt>in_progress</tt>: the job is in progress.</li>
</ul>
</ul></li>
<li><tt>job_id</tt> attribute: the job identifier for the status being reported.</li>
<li>One of these error conditions MUST be provided if <tt>&lt;iq type="error"/&gt;</tt>.</li>
<li>One of these error conditions MUST be provided if <tt>&lt;iq type="error"/&gt;</tt>.
<ul>
<li><tt>&lt;malformed_packet/&gt;</tt></li>
<li><tt>&lt;vm_not_found/&gt;</tt></li>
<li><tt>&lt;internal_error/&gt;</tt></li>
<li><tt>&lt;job_not_found/&gt;</tt></li>
<li>if an error occurred, the farm SHOULD provide some implementation specific human-readable information detailing the error in <tt>&lt;text/&gt;</tt>. Error responses extend the requirements set forth by the <link url="http://xmpp.org/rfcs/rfc3920.html">Core</link> XMPP specification.</li>
</ul>
</ul>
</ul></li>
</ul></li>
</ul>
<example caption="A successful &lt;ping_job/&gt; request."><![CDATA[<iq from="lp1@linkedprocess.org/villein"
to="lp2@linkedprocess.org/farm" type="get" id="xxxx">
@ -348,26 +348,26 @@
An <tt>&lt;abort_job/&gt;</tt> element is wrapped by an <tt>&lt;iq/&gt;</tt> element. The purpose of <tt>&lt;abort_job/&gt;</tt> is to cancel (i.e. quit, stop, halt) a previously submitted, yet not completed <tt>&lt;submit_job/&gt;</tt> stanza (i.e. job).
</p>
<ul>
<li>Villein generated <tt>&lt;iq type="get"&gt;</tt> <tt>&lt;abort_job/&gt;</tt>:</li>
<li>Villein generated <tt>&lt;iq type="get"&gt;</tt> <tt>&lt;abort_job/&gt;</tt>:
<ul>
<li><tt>xmlns</tt> attribute: <tt>http://linkedprocess.org/2009/06/Farm#</tt>.</li>
<li><tt>vm_id</tt> attribute: the farm-internal unique identifier of the virtual machine.</li>
<li><tt>job_id</tt> attribute: the job identifier (the job identifier is the stanza identifier of the respective <tt>&lt;submit_job/&gt;</tt>).</li>
</ul>
</ul></li>
<li>Farm generated <tt>&lt;iq type="result"&gt;</tt> or <tt>&lt;iq type="error"&gt;</tt> <tt>&lt;abort_job/&gt;</tt>:</li>
<li>Farm generated <tt>&lt;iq type="result"&gt;</tt> or <tt>&lt;iq type="error"&gt;</tt> <tt>&lt;abort_job/&gt;</tt>:
<ul>
<li><tt>xmlns</tt> attribute: <tt>http://linkedprocess.org/2009/06/Farm#</tt>.</li>
<li><tt>vm_id</tt> attribute: the farm-internal unique identifier of the virtual machine.</li>
<li>One of these error conditions MUST be provided if <tt>&lt;iq type="error"/&gt;</tt>.</li>
<li>One of these error conditions MUST be provided if <tt>&lt;iq type="error"/&gt;</tt>.
<ul>
<li><tt>&lt;malformed_packet/&gt;</tt></li>
<li><tt>&lt;vm_not_found/&gt;</tt></li>
<li><tt>&lt;internal_error/&gt;</tt></li>
<li><tt>&lt;job_not_found/&gt;</tt></li>
<li>if an error occurred, the farm SHOULD provide some implementation specific human-readable information detailing the error in <tt>&lt;text/&gt;</tt>. Error responses extend the requirements set forth by the <link url="http://xmpp.org/rfcs/rfc3920.html">Core</link> XMPP specification.</li>
</ul>
</ul>
</ul></li>
</ul></li>
</ul>
<example caption="A successful &lt;abort_job/&gt; request."><![CDATA[<iq from="lp1@linkedprocess.org/villein"
@ -403,31 +403,31 @@
A <tt>&lt;manage_bindings/&gt;</tt> element is wrapped by an <tt>&lt;iq/&gt;</tt> element. The purpose of <tt>&lt;manage_bindings/&gt;</tt> is to allow a villein to get and set variables in the variable space of a virtual machine. The definition of the "variable space" is up to the implementation of the virtual machine. In general, this is the set of all global variables for the virtual machine.
</p>
<ul>
<li>Villein generated <tt>&lt;iq type="get"&gt;</tt> or <tt>&lt;iq type="set"&gt;</tt> <tt>&lt;manage_bindings/&gt;</tt>:</li>
<li>Villein generated <tt>&lt;iq type="get"&gt;</tt> or <tt>&lt;iq type="set"&gt;</tt> <tt>&lt;manage_bindings/&gt;</tt>:
<ul>
<li><tt>xmlns</tt> attribute: <tt>http://linkedprocess.org/2009/06/Farm#</tt></li>
<li><tt>vm_id</tt> attribute: the farm-internal unique identifier of the virtual machine.</li>
<li><tt>&lt;binding/&gt;</tt> child tag of <tt>&lt;manage_bindings/&gt;</tt> for <tt>&lt;iq type="get"/&gt;</tt></li>
<li><tt>&lt;binding/&gt;</tt> child tag of <tt>&lt;manage_bindings/&gt;</tt> for <tt>&lt;iq type="get"/&gt;</tt>
<ul>
<li><tt>name</tt> attribute: the name of the variable.</li>
</ul>
<li><tt>&lt;binding/&gt;</tt> child tag of <tt>&lt;manage_bindings/&gt;</tt> for <tt>&lt;iq type="set"/&gt;</tt></li>
</ul></li>
<li><tt>&lt;binding/&gt;</tt> child tag of <tt>&lt;manage_bindings/&gt;</tt> for <tt>&lt;iq type="set"/&gt;</tt>
<ul>
<li><tt>name</tt> attribute: the name of the variable.</li>
<li><tt>value</tt> attribute: the value of the variable.</li>
<li><tt>datatype</tt> attribute: the datatype of the variable (specified using <link url="http://www.w3.org/TR/xmlschema-2/">XML schema for datatypes</link>).</li>
</ul>
</ul>
<li>Farm generated <tt>&lt;iq type="result"&gt;</tt> or <tt>&lt;iq type="error"&gt;</tt> <tt>&lt;manage_bindings/&gt;</tt>:</li>
</ul></li>
</ul></li>
<li>Farm generated <tt>&lt;iq type="result"&gt;</tt> or <tt>&lt;iq type="error"&gt;</tt> <tt>&lt;manage_bindings/&gt;</tt>:
<ul>
<li><tt>xmlns</tt> attribute: <tt>http://linkedprocess.org/2009/06/Farm#</tt>.</li>
<li><tt>vm_id</tt> attribute: the farm-internal unique identifier of the virtual machine.</li>
<li><tt>&lt;binding/&gt;</tt> child tag of <tt>&lt;manage_bindings/&gt;</tt> for <tt>&lt;iq type="get"/&gt;</tt></li>
<li><tt>&lt;binding/&gt;</tt> child tag of <tt>&lt;manage_bindings/&gt;</tt> for <tt>&lt;iq type="get"/&gt;</tt>
<ul>
<li><tt>name</tt> attribute: the name of the variable.</li>
<li><tt>value</tt> attribute: the value of the variable.</li>
</ul>
<li>One of these error conditions MUST be provided if <tt>&lt;iq type="error"/&gt;</tt>.</li>
</ul></li>
<li>One of these error conditions MUST be provided if <tt>&lt;iq type="error"/&gt;</tt>.
<ul>
<li><tt>&lt;malformed_packet/&gt;</tt></li>
<li><tt>&lt;vm_not_found/&gt;</tt></li>
@ -435,8 +435,8 @@
<li><tt>&lt;unknown_datatype/&gt;</tt></li>
<li><tt>&lt;invalid_value/&gt;</tt></li>
<li>if an error occurred, the farm SHOULD provide some implementation specific human-readable information detailing the error in <tt>&lt;text/&gt;</tt>. Error responses extend the requirements set forth by the <link url="http://xmpp.org/rfcs/rfc3920.html">Core</link> XMPP specification.</li>
</ul>
</ul>
</ul></li>
</ul></li>
</ul>
<example caption="A successful &lt;manage_bindings/&gt; set request."><![CDATA[<iq from="lp1@linkedprocess.org/villein"
to="lp2@linkedprocess.org/farm" type="set" id="xxxx">
@ -468,11 +468,11 @@
</iq>
]]></example>
<p>
After the previous <tt>&lt;manage_bindings/&gt;</tt> stanza has been processed by the virtual machine, it is possible to use the bindings in a statement. For example, in JavaScript
After the previous <tt>&lt;manage_bindings/&gt;</tt> stanza has been processed by the virtual machine, it is possible to use the bindings in a statement. For example, in JavaScript</p>
<code>var fact = name + " knows josh and peter";</code>
will set <tt>fact</tt> to the value "marko knows josh and peter" as well as make it an accessible binding.
<p>will set <tt>fact</tt> to the value "marko knows josh and peter" as well as make it an accessible binding.
</p>
<example caption="A successful &lt;manage_bindings/&gt; get request."><![CDATA[<iq from="lp1@linkedprocess.org/villein"
to="lp2@linkedprocess.org/farm" type="get" id="zzzz">
@ -490,11 +490,11 @@
</iq>
]]></example>
<p>
A useful aspect of <tt>&lt;manage_bindings/&gt;</tt> is that it can be used to track the state of a variable during the execution of a job. For example, suppose the following job is submitted to a JavaScript virtual machine.<code>var x = 1.0;
A useful aspect of <tt>&lt;manage_bindings/&gt;</tt> is that it can be used to track the state of a variable during the execution of a job. For example, suppose the following job is submitted to a JavaScript virtual machine.</p><code>var x = 1.0;
while(true) {
x = x + 0.0001;
}</code>
This job will continue indefinitely (or until it is timed out by the virtual machine). However, during its execution, it is possible to determine the current state of <tt>x</tt> using <tt>&lt;manage_bindings/&gt;</tt>. Each get-based <tt>&lt;manage_bindings/&gt;</tt> call should return a larger <tt>x</tt> value.
<p>This job will continue indefinitely (or until it is timed out by the virtual machine). However, during its execution, it is possible to determine the current state of <tt>x</tt> using <tt>&lt;manage_bindings/&gt;</tt>. Each get-based <tt>&lt;manage_bindings/&gt;</tt> call should return a larger <tt>x</tt> value.
</p>
</section3>
<section3 topic="Terminating a Virtual Machine">
@ -502,23 +502,23 @@ while(true) {
A <tt>&lt;terminate_vm/&gt;</tt> element is wrapped by an <tt>&lt;iq/&gt;</tt> element. The purpose of a <tt>&lt;terminate_vm/&gt;</tt> is to shutdown (i.e. quit, exit, halt) the virtual machine. Upon termination, the virtual machine will lose its state and will no longer be able to be communicated with.
</p>
<ul>
<li>Villein generated <tt>&lt;iq type="get"&gt;</tt> <tt>&lt;terminate_vm/&gt;</tt>:</li>
<li>Villein generated <tt>&lt;iq type="get"&gt;</tt> <tt>&lt;terminate_vm/&gt;</tt>:
<ul>
<li><tt>xmlns</tt> attribute: <tt>http://linkedprocess.org/2009/06/Farm#</tt>.</li>
<li><tt>vm_id</tt> attribute: the farm-internal unique identifier of the virtual machine.</li>
</ul>
<li>Farm generated <tt>&lt;iq type="result"&gt;</tt> or <tt>&lt;iq type="error"&gt;</tt> <tt>&lt;terminate_vm/&gt;</tt>:</li>
</ul></li>
<li>Farm generated <tt>&lt;iq type="result"&gt;</tt> or <tt>&lt;iq type="error"&gt;</tt> <tt>&lt;terminate_vm/&gt;</tt>:
<ul>
<li><tt>xmlns</tt> attribute: <tt>http://linkedprocess.org/2009/06/Farm#</tt>.</li>
<li><tt>vm_id</tt> attribute: the farm-internal unique identifier of the virtual machine.</li>
<li>One of these error conditions MUST be provided if <tt>&lt;iq type="error"/&gt;</tt>.</li>
<li>One of these error conditions MUST be provided if <tt>&lt;iq type="error"/&gt;</tt>.
<ul>
<li><tt>&lt;malformed_packet/&gt;</tt></li>
<li><tt>&lt;vm_not_found/&gt;</tt></li>
<li><tt>&lt;internal_error/&gt;</tt></li>
<li>if an error occurred, the farm SHOULD provide some implementation specific human-readable information detailing the error in <tt>&lt;text/&gt;</tt>. Error responses extend the requirements set forth by the <link url="http://xmpp.org/rfcs/rfc3920.html">Core</link> XMPP specification.</li>
</ul>
</ul>
</ul></li>
</ul></li>
</ul>
<example caption="A successful &lt;terminate_vm/&gt; request."><![CDATA[<iq from="lp1@linkedprocess.org/LoPVillein/EFGH"
to="lp2@linkedprocess.org/farm" type="get" id="xxxx">
@ -928,7 +928,7 @@ while(true) {
</p>
</section1>
<section1 topic='XMPP Registrar Considerations' anchor='registrar'>
The following namespaces are defined by Linked Process:
<p>The following namespaces are defined by Linked Process:</p>
<ul>
<li><tt>http://linkedprocess.org/2006/06/Farm#</tt></li>
<li><tt>http://linkedprocess.org/2006/06/Registry#</tt></li>

View File

@ -1,6 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE xep SYSTEM 'xep.dtd' [
<!ENTITY % ents SYSTEM 'xep.ent'>
<!ENTITY rfc3920bis "<span class='ref'><link url='http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis'>rfc3920bis</link></span> <note>RFC 3920: Extensible Messaging and Presence Protocol (XMPP): Core &lt;<link url='http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis'>http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis</link>&gt;.</note>" >
%ents;
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
@ -107,27 +108,27 @@
<section1 topic='Conclusions'>
<p>As with anything, there are no hard and fast rules. If there were, they might look like these. First, for devices:</p>
<dl>
<dt>Transmit no data.</dt>
<dd>Transmitting costs significant power, and moreover raises the radio state. Not transmitting will allow it to maximize the time spent in the low-cost Idle state.</dd>
<dt>If you must transmit, then transmit only a small volume.</dt>
<dd>If there is only a small amount of data transmitted - less than 128 octets typically - the radio will only raise to FACH, which is significantly cheaper than DCH.</dd>
<dt>If you must transmit, then compress as hard as possible.</dt>
<dd>Since individual octets have an associate power - and often financial - cost, it's worth maximizing the compression algorithm, even if the volume of traffic will raise to DCH.</dd>
<dt>If you have transmit a lot, then do a lot</dt>
<dd>If the radio is raised to DCH anyway, then you may as well go fetch that avatar you were missing, since you're chewing through power anyway.</dd>
<dt>If you receive, then transmit</dt>
<dd>If your peer raises the radio state, you may as well use it.</dd>
<di><dt>Transmit no data.</dt>
<dd>Transmitting costs significant power, and moreover raises the radio state. Not transmitting will allow it to maximize the time spent in the low-cost Idle state.</dd></di>
<di><dt>If you must transmit, then transmit only a small volume.</dt>
<dd>If there is only a small amount of data transmitted - less than 128 octets typically - the radio will only raise to FACH, which is significantly cheaper than DCH.</dd></di>
<di><dt>If you must transmit, then compress as hard as possible.</dt>
<dd>Since individual octets have an associate power - and often financial - cost, it's worth maximizing the compression algorithm, even if the volume of traffic will raise to DCH.</dd></di>
<di><dt>If you have transmit a lot, then do a lot</dt>
<dd>If the radio is raised to DCH anyway, then you may as well go fetch that avatar you were missing, since you're chewing through power anyway.</dd></di>
<di><dt>If you receive, then transmit</dt>
<dd>If your peer raises the radio state, you may as well use it.</dd></di>
</dl>
<p>And for servers, similar rules apply:</p>
<dl>
<dt>Send no data.</dt>
<dd>Sending data will cause the handset to be raised out of Idle. This immediately costs massively higher power.</dd>
<dt>If you must send, send tiny bits.</dt>
<dd>Sending small enough data maximizes the likelyhood that the devices radio will only be raised to FACH levels.</dd>
<dt>If you receive, then send anything you have.</dt>
<dd>Receiving data indicates that the radio is active - it'll stay active for some time, so sending data doesn't incur the overhead of raising the radio state, and won't increase power drain on the handset.</dd>
<dt>If you must send when not receiving, send plenty.</dt>
<dd>Sending data will raise the radio's state - unless you can tell this will only raise it to FACH, it's worth sending as much as possible.</dd>
<di><dt>Send no data.</dt>
<dd>Sending data will cause the handset to be raised out of Idle. This immediately costs massively higher power.</dd></di>
<di><dt>If you must send, send tiny bits.</dt>
<dd>Sending small enough data maximizes the likelyhood that the devices radio will only be raised to FACH levels.</dd></di>
<di><dt>If you receive, then send anything you have.</dt>
<dd>Receiving data indicates that the radio is active - it'll stay active for some time, so sending data doesn't incur the overhead of raising the radio state, and won't increase power drain on the handset.</dd></di>
<di><dt>If you must send when not receiving, send plenty.</dt>
<dd>Sending data will raise the radio's state - unless you can tell this will only raise it to FACH, it's worth sending as much as possible.</dd></di>
</dl>
<p>Finally, protocol designers should aim to minimize any responses required from the handset, and ensure keepalive traffic, if any, fits inside FACH wherever possible.</p>
</section1>

View File

@ -2,6 +2,7 @@
<!DOCTYPE xep SYSTEM 'xep.dtd' [
<!ENTITY % ents SYSTEM 'xep.ent'>
<!ENTITY MOVED "&lt;moved/&gt;">
<!ENTITY rfc3920bis "<span class='ref'><link url='http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis'>rfc3920bis</link></span> <note>RFC 3920: Extensible Messaging and Presence Protocol (XMPP): Core &lt;<link url='http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis'>http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis</link>&gt;.</note>" >
%ents;
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
@ -111,10 +112,10 @@
user@example.com.</p>
<dl>
<dt><strong>original JID</strong></dt>
<dd>user@example.com</dd>
<dt><strong>new JID</strong></dt>
<dd>user2@example2.com</dd>
<di><dt>original JID</dt>
<dd>user@example.com</dd></di>
<di><dt>new JID</dt>
<dd>user2@example2.com</dd></di>
</dl>
<section2 topic='Unsubscribing the original JID from outbound subscriptions'
@ -285,7 +286,7 @@
the user to subscribe to the new JID listed in the &MOVED; element.</p>
<p>Because of the ability to spoof the &MOVED; element, the client SHOULD
NOT automatically subscribe to the &MOVED; element target</p>.
NOT automatically subscribe to the &MOVED; element target.</p>
</section3>
<section3 topic='Roster state and action table' anchor='actions'>

View File

@ -531,13 +531,12 @@
<p>The client MAY include initial configuration and occupant list (the list MUST NOT include the creator). The server MAY allow sending incomplete configuration form. In such case the server MUST use default values for missing fields. The server MAY enforce a minimal occupant list length.</p>
<p>The service MAY either give the creator the 'owner' or 'member' status. In the latter case all users are equal.</p>
<p>Upon room creation success, the service MUST reply with an empty IQ result.</p>
<p>The following rules (similar to the ones relevant to the affiliation change request) apply to the occupant list:
<p>The following rules (similar to the ones relevant to the affiliation change request) apply to the occupant list:</p>
<ul>
<li>'none' affiliation cannot be used.</li>
<li>All user bare JIDs must be unique</li>
<li>At most one owner can be chosen. In such case the room creator will become "just" a 'member'.</li>
</ul>
</p>
<p>After the room is created (but before receiving IQ result), new occupants (including creator) receive &MESSAGE; from the room with their affiliations (stanza MUST include only recipient's affiliation) and initial room version. &lt;prev-version /&gt; element MUST NOT be included.</p>
<example caption='Client requests room creation'><![CDATA[
<iq from='crone1@shakespeare.lit/desktop'
@ -770,7 +769,7 @@
<li>All changes must be meaningful, e.g. setting member's affiliation to 'member' is considered a bad request.</li>
<li>Server MAY allow members to add new members but they still cannot make anyone an 'owner' or remove other users from the room.</li>
</ol>
<p>On success the server will reply with result IQ with all changed items. <b>BEFORE</b> returning the IQ result, the service MUST route a message with affiliation change to all relevant users.</p>
<p>On success the server will reply with result IQ with all changed items. <strong>BEFORE</strong> returning the IQ result, the service MUST route a message with affiliation change to all relevant users.</p>
<p>Newcomers, i.e. users that were not occupants before the change, SHOULD receive only their own affiliation and SHOULD NOT receive &lt;prev-version /&gt; element.</p>
<p>The notifications must include both the new and old room version (&lt;version /&gt; and &lt;prev-version /&gt; respectively) string (except for the ones directed to users that have been removed from the room).</p>
<p>The notifications contain a list of items. The item list may be different from the list in IQ set, because some of the changes may require additional operations, e.g. choosing new owner when the old one leaves. Users, that are still in the room after change, will receive full change list. Users, that have been removed from the room with the request, will get only one item: themselves with affiliation 'none'.</p>
@ -1007,13 +1006,12 @@
</section2>
<section2 topic='Request sender has insufficient privileges' anchor='insufficient-privileges'>
<p>If the request sender does not have sufficient privileges (but is a room occupant), the service MUST reply with a 'not-allowed' error.</p>
<p>It occurs in the following cases:
<p>It occurs in the following cases:</p>
<ul>
<li>A member tries to change the configuration but the service is not configured to allow it. It does not apply to the subject change, although it has to be performed by sending &MESSAGE; with &SUBJECT;, not configuration &IQ;.</li>
<li>A member tries to change anyone's affiliation to 'none' or 'owner'.</li>
<li>A member tries to change someone's affiliation to 'member' but the service is not configured to allow it.</li>
</ul>
</p>
<example caption='Prohibited IQ'><![CDATA[
<iq from='minion@shakespeare.lit/desktop'
id='privileges1'
@ -1483,7 +1481,6 @@
<section2 topic='Service limits and configuration' anchor='limits-and-config'>
<p>MUC Light service may be abused by malicious users, e.g. due to replicating single message for every room occupant. The list below contains suggested configurable limits that SHOULD be implemented.</p>
<p>The service features that might vary depending on specific application are included as well.</p>
<p>
<ul>
<li>Maximal count of rooms the user occupies.</li>
<li>Blocking feature enabled/disabled.</li>
@ -1493,7 +1490,6 @@
<li>New members can be invited by owner/occupants.</li>
<li>Maximal room size.</li>
</ul>
</p>
</section2>
</section1>
<section1 topic='Security Considerations' anchor='security'>

View File

@ -49,25 +49,25 @@
</header>
<section1 topic='Introduction' anchor='intro'>
Jingle <cite>XEP-0166</cite> is used to negotiate peer to peer media sessions.
<p>Jingle <cite>XEP-0166</cite> is used to negotiate peer to peer media sessions.
Muji is a way to coordinate Jingle sessions between a group of people.
Muji conferences are held in <cite>XEP-0045</cite> rooms.
Muji conferences are held in <cite>XEP-0045</cite> rooms.</p>
</section1>
<section1 topic="How it works" anchor="howitworks">
A Muji conference has a number of contents, each of which has unique name.
<p>A Muji conference has a number of contents, each of which has unique name.
content type, and an encoding. Each participant may provide a stream for each
content, and communicates which contents they are willing to provide streams
for, along with encoding information, in their MUC presence. This serves two
purposes. Firstly, so that each participant knows which contents every other
participant provides. Secondly, so that there is a global payload type (PT)
mapping for the various contents, so that clients only need to encode and
payload each content that they provide once.
payload each content that they provide once.</p>
Participants are not required to participate all the contents that are
<p>Participants are not required to participate all the contents that are
available. For example, a Muji client might choose to only request audio
streams.
streams.</p>
</section1>
<section1 topic='Joining a conference' anchor='joining'>
@ -75,7 +75,7 @@ streams.
Joining a conference is done in two stages. The first step is to
declare that preparations are being done to either join or start a muji
session inside the MUC. This is indicated by the client sending a presence
stanza to the MUC with a preparing element in muji section.
stanza to the MUC with a preparing element in muji section.</p>
<code><![CDATA[
<presence from='wiccarocks@shakespeare.lit/laptop'
@ -90,11 +90,11 @@ streams.
</presence>
]]></code>
The client MUST then wait until the MUC rebroadcasts its presence message,
<p>The client MUST then wait until the MUC rebroadcasts its presence message,
after which it MUST wait for all other participants that had a preparing
element in their presence to finish preparation. Afterwards it should finish
it's own preparation by updating its presence with the contents it wants to
take part in.
take part in.</p>
<code><![CDATA[
<presence from='wiccarocks@shakespeare.lit/laptop'
@ -118,11 +118,8 @@ streams.
</muji>
</presence>
]]></code>
</p>
<p>
When a client adds a payload ID to a content description, it MUST have the
<p>When a client adds a payload ID to a content description, it MUST have the
same codec name and receiving parameters as the corresponding entries in
other participants' payload maps for that content. For instance, if Alice
defines a payload type with ID 98, codec Speex and a a clock rate of 8000
@ -170,7 +167,7 @@ streams.
<p>
Adding a stream follows a process similar to the joining a conference. As a
first step an updated presence stanza MUST be send which contains a preparing
element as part of the Muji section.
element as part of the Muji section.</p>
<code><![CDATA[
<presence from='wiccarocks@shakespeare.lit/laptop'
@ -191,13 +188,13 @@ streams.
</presence>
]]></code>
The client MUST then wait until the MUC rebroadcasts its presence message,
<p>The client MUST then wait until the MUC rebroadcasts its presence message,
after which it MUST wait for all other participants that had a preparing
element in their presence to finish their changes.
element in their presence to finish their changes.</p>
Afterwards the client should add the new content to the muji section of its
<p>Afterwards the client should add the new content to the muji section of its
presence and add the content to all the jingle sessions it had with
participants it shared the content with.
participants it shared the content with.</p>
<code><![CDATA[
<presence from='wiccarocks@shakespeare.lit/laptop'
@ -221,7 +218,6 @@ streams.
</muji>
</presence>
]]></code>
</p>
</section1>
<section1 topic='Removing a content' anchor='removecontent'>

View File

@ -23,6 +23,7 @@
<header>
<title>Multi-User Gaming</title>
<abstract>This document defines an XMPP protocol extension for multi-user gaming.</abstract>
&LEGALNOTICE;
<number>xxxx</number>
<status>ProtoXEP</status>
<type>Standards Track</type>
@ -74,7 +75,6 @@
<initials>tg</initials>
<remark><p>First draft.</p></remark>
</revision>
&LEGALNOTICE;
</header>
<section1 topic='Introduction' anchor='intro'>
<p>
@ -197,8 +197,8 @@
</section2>
<section2 topic='Dramatis Personae' anchor='terms-personae'>
Most of the examples in this document use the scenario of Miranda and Ferdinand playing chess in Act V, Scene I of Shakespeare's The Tempest,
represented here as the "island-chess@games.shakespeare.lit" room. The characters are as follows:
<p>Most of the examples in this document use the scenario of Miranda and Ferdinand playing chess in Act V, Scene I of Shakespeare's The Tempest,
represented here as the "island-chess@games.shakespeare.lit" room. The characters are as follows:</p>
<table caption='Dramatis Personae'>
<tr>
<th>Room Nickname</th><th>Full JID</th><th>Affiliation</th><th>Game Role</th>
@ -216,7 +216,7 @@
</section1>
<section1 topic='Affiliations' anchor='affiliations'>
The following affiliations are defined:
<p>The following affiliations are defined:</p>
<ol>
<li>Member</li>
<li>Owner</li>
@ -239,10 +239,10 @@
</p>
<section2 topic='Privileges' anchor='privileges'>
Owners are allowed to do what they like (saving/loading, change match options, etc.)
<p>Owners are allowed to do what they like (saving/loading, change match options, etc.)
except in unmoderated matches. This match type restricts the use of owner privileges to specific room statuses.
Users with no affiliation SHALL NOT enter members-only matches.
Besides that, these users have the same privileges as members.
Besides that, these users have the same privileges as members.</p>
<table caption='Owner Privileges Overview'>
<tr>
<th>Room Type</th>
@ -275,11 +275,11 @@
</section2>
<section2 topic='Changing Affiliations' anchor='changing-affi'>
The ways in which a user's affiliation changes are well-defined.
<p>The ways in which a user's affiliation changes are well-defined.
Sometimes the change results from the user's own action (e.g., registering as a member of the match),
whereas sometimes the change results from an action taken by an owner.
If a user's affiliation changes, a MUG service implementation MUST change the user's affiliation to reflect the change
and communicate that to all occupants.
and communicate that to all occupants.</p>
</section2>
</section1>
@ -762,10 +762,10 @@
<section1 topic="Occupant Use Cases" anchor='occupantusecases'>
<section2 topic='Invitation' anchor='mug-invite'>
It can be useful to invite other users to a room in which one is an occupant.
<p>It can be useful to invite other users to a room in which one is an occupant.
To do this, a MUG client sends XML of the following form to the &ROOM; itself
adding an &INVITE; element for every invitee.
(the reason is OPTIONAL and the message MUST be explicitly or implicitly of type "normal"):
(the reason is OPTIONAL and the message MUST be explicitly or implicitly of type "normal"):</p>
<example caption="Occupant Sends an Invitation by Way of Room"><![CDATA[
<message
from='ferdinand@shakespeare.lit/desktop'
@ -2039,7 +2039,7 @@
<p>
If the room creation fails because the specified room configuration options violate
one or more service policies (e.g., because the password for a password-protected room is blank),
the service MUST return a <not-acceptable/> error.
the service MUST return a &lt;not-acceptable/&gt; error.
</p>
<example caption='Service Informs Owner that Requested Configuration Options Are Unacceptable'><![CDATA[

View File

@ -94,7 +94,7 @@
</section2>
<section2 topic='Redirection' anchor='usecases-redirection'>
<p>A given deployment MAY wish to redirect users to another medium (e.g., a website) for further stages of registration, rather than allowing in-band registration. The recommended approach is to include only the <instructions/> element rather than the required fields or a data form in the IQ result, as well as a URL encoded using &xep0066;</p>
<p>A given deployment MAY wish to redirect users to another medium (e.g., a website) for further stages of registration, rather than allowing in-band registration. The recommended approach is to include only the &lt;instructions/&gt; element rather than the required fields or a data form in the IQ result, as well as a URL encoded using &xep0066;</p>
<example caption='Host Redirects Entity to Web Registration'><![CDATA[
<iq type='result'
from='sms.shakespeare.lit'

View File

@ -19,7 +19,6 @@
<supersedes/>
<supersededby/>
<shortname>inbox</shortname>
<schemaloc/>
<author>
<firstname>Valerian</firstname>
<surname>Saliou</surname>

View File

@ -13,8 +13,9 @@
<status>Experimental</status>
<type>Informational</type>
<sig>Standards</sig>
<supersedes>None</supersedes>
<supersededby>None</supersededby>
<dependencies/>
<supersedes/>
<supersededby/>
<shortname>namespace</shortname>
&dcridland;
&stpeter;

View File

@ -22,7 +22,7 @@
<spec>XEP-0114</spec>
<spec>XEP-0225</spec>
</supersedes>
<supersededby>None</supersededby>
<supersededby/>
<shortname>comp-s2s</shortname>
&dcridland;
<revision>

216
inbox/sasl2.xml Normal file
View File

@ -0,0 +1,216 @@
<?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>Extensible SASL Profile</title>
<abstract>This document describes a replacement for the SASL profile documented in RFC 6120 which allows for greater extensibility.</abstract>
&LEGALNOTICE;
<number>XXXX</number>
<status>ProtoXEP</status>
<type>Standards Track</type>
<sig>Standards</sig>
<dependencies>
<spec>XMPP Core</spec>
</dependencies>
<supersedes/>
<supersededby/>
<shortname>sasl2</shortname>
&dcridland;
<revision>
<version>0.0.1</version>
<date>2017-02-07</date>
<initials>dwd</initials>
<remark>
<ul>
<li>Initial Revision</li>
</ul>
</remark>
</revision>
</header>
<section1 topic='Introduction' anchor='intro'>
<p>While SASL provides an excellent framework that has served us well over the past 18 years, a number of shortcomings in the profile - the syntax binding to XMPP - that is in use.</p>
<p>This specification addresses a number of shortfalls:</p>
<ul>
<li>Number of round trips</li>
<li>Extensibility</li>
<li>Support for second factor</li>
<li>Support for mandatory password changes</li>
</ul>
<p>The new SASL profile documented herein is primarily a syntactic change to allow extensibility, combined with removal of the (largely) redundant stream restart, and additional results beyond total success or abject failure.</p>
<section2 topic="Terminology">
<p>Although initiating entities, in general, use SASL, and receiving entities offer it, the SASL specification and common parlance both use "Client " and "Server"; this specification uses Client and Server and assumes C2S links. This is not intended to preclude use of this SASL profile on S2S links. The term "SASL2" is used to mean the new SASL profile specified in this document; however the same RFC 4422 definition of SASL (and SASL profiles) applies.</p>
<p>Examples often use hypothetical SASL mechanisms and sub-extensions; this specification does not intend to make a position on any particular SASL mechanism, and the Mandatory To Implement mechanisms are unaffected.</p>
</section2>
</section1>
<section1 topic='Overview' anchor="overview">
<section2 topic="Discovering Support" anchor="feature">
<p>Servers capable of SASL2 offer a stream feature of &lt;mechanisms/>, qualified by the "urn:xmpp:sasl:0" namespace. This in turn contains one or more &lt;mechanism/> elements in the same namespace, and potentially other elements (for example, the &lt;hostname/> element defined within XEP-0233).</p>
<p>Note that SASL2 is impossible for clients to initiate without at least one mechanism being available, and therefore MUST NOT be offered.</p>
<p>The feature so advertised, and its child content, SHOULD be stable for the given stream to and from attributes and encryption state, and therefore MAY be cached by clients for later connections.</p>
<p>The Service Name used by XMPP is unchanged from RFC 6120.</p>
</section2>
<section2 topic="SASL Data Encoding">
<p>In all cases, both Clients and Servers encode SASL exchanges using Base 64 encoding. This SHOULD NOT include any line wrapping or other whitespace. As the form &lt;element/> is equivalent to &lt;element>&lt;/element>, these both indicate an empty string, which is used to indicate no data (ie, the absence of the data). In order to explicitly transmit a zero-length SASL challenge or response, the sending party sends a single equals sign character ("=").</p>
</section2>
<section2 topic="Initiation">
<p>Clients, upon observing this stream feature, initiate the authentication by the use of the &lt;authenticate/> top-level element, within the same namespace. The nature of this element is to inform the server about properties of the final stream state, as well as initiate authentication itself. To achieve the latter, it has a single mandatory attribute of "mechanism", with a string value of a mechanism name offered by the Server in the stream feature, and an optional child element of &lt;initial-response/>, containing a base64-encoded SASL Initial Response.</p>
<p>On subsequent connections, if a Client has previously cache the stream feature, the Client MAY choose to send it before seeing the stream features - sending it "pipelined" with the Stream Open tag for example.</p>
<example caption="An authentication request"><![CDATA[
<authenticate xmlns='urn:xmpp:sasl:0' mechanism="BLURDLYBLOOP">
<initial-response>SW1wcm92ZWQgZW5jYXNwdWxhdGlvbiBvZiBvcHRpb25hbCBTQVNMLUlSIGRhdGE=</initial-response>
</authenticate>
]]>
</example>
<p>In order to provide support for other desired stream states beyond authentication, additional child elements are used. For example, a hypothetical XEP-0198 session resumption element might be included, and/or Resource Binding requests.</p>
<example caption="An authentication request with a (hypothetical) bind request"><![CDATA[
<authenticate xmlns='urn:xmpp:sasl:0' mechanism='BLURDYBLOOP'>
<initial-response>
U0FTTC1JUiBlbmNvZGVkIGFsb25nc2lkZSBiaW5kIHJlcXVlc3Q=
</initial-response>
<bind xmlns='urn:xmpp:bind:example'/>
</authenticate>
]]>
</example>
</section2>
<section2 topic="Challenges and Responses" anchor="challenge">
<p>Server Challenges MAY then be sent. Each Challenge MUST be responded to by a Client in a Client Response. These are not extensible, and contain the corresponding base64 encoded SASL data:</p>
<example caption="A challenge and response exchange"><![CDATA[
<!-- A server might send: -->
<challenge xmlns='urn:xmpp:sasl:0'>
QmFzZSA2NCBlbmNvZGVkIFNBU0wgY2hhbGxlbmdlIGRhdGE=
</challenge>
<!-- A client might respond: -->
<response xmlns='urn:xmpp:sasl:0'>
QmFzZSA2NCBlbmNvZGVkIFNBU0wgcmVzcG9uc2UgZGF0YQ==
</response>
]]>
</example>
</section2>
<section2 topic="During Authentication">
<p>At any time while authentication is in progress, neither Client nor Server sends any element (including stanzas) or other data except the top-level elements defined herein. Clients MUST NOT send whitespace, and MUST send only &lt;response/> elements as appropriate or an &lt;abort/> element to immediately cause an error. Servers MUST disconnect Clients immediately if any other traffic is received. Servers are similarly REQUIRED to send no whitespace, and only the &lt;response/> and completion elements from the section below.</p>
</section2>
<section2 topic="Completing Authentication">
<p>Authentication may complete in one of three ways. It may complete successfully, in which case the client is authenticated. It may also fail, in which case the client is not authenticated and the stream and session state remain entirely unchanged.</p>
<p>Finally, it may have completed successfully, but further interaction is required - for example, a password change or second-factor authentication.</p>
<section3 topic="Success">
<p>If the Client is now authenticated, the Server sends a &lt;success/> element, which contains an OPTIONAL &lt;additional-data/> element containing SASL additional data. It also contains a &lt;authorization-identity/> element containing the negotiated identity - this is a bare JID, unless resource binding has occurred, in which case it is a full JID.</p>
<example caption="Successful authentication"><![CDATA[
<success xmlns='urn:xmpp:sasl:0'>
<success-data>
T3B0aW9uYWwgQmFzZSA2NCBlbmNvZGVkIFNBU0wgc3VjY2VzcyBkYXRh
</success-data>
<authorization-identifier>juliet@montague.example/Balcony/a987dsh9a87sdh</authorization-identifier>
</success>
]]></example>
<p>Other extension elements MAY also be contained by the &lt;success/> element.</p>
<example caption="Successful re-authentication and resumption"><![CDATA[
<success xmlns='urn:xmpp:sasl:0'>
<additional-data>
T3B0aW9uYWwgQmFzZSA2NCBlbmNvZGVkIFNBU0wgc3VjY2VzcyBkYXRh
</additional-data>
<authorization-identifier>juliet@montague.example/Balcony/a987dsh9a87sdh</authorization-identifier>
<sm:resumed xmlns='urn:xmpp:sm:3:example' h='345' previd='124'/>
</success>
]]></example>
<p>Any security layer negotiated SHALL take effect after the ">" octet of the closing tag (ie, immediately after "&lt;/success>").</p>
</section3>
<section3 topic="Failure">
<p>A &lt;failure/> element is used by the server to terminate the authentication attempt. It MAY contain application-specific error codes, and MAY contain a textual error. It MUST contain one of the SASL error codes from RFC 6120 Section 6.5.</p>
<example caption="Failure"><![CDATA[
<failure xmlns='urn:xmpp:sasl:0'>
<aborted xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>
<optional-application-specific xmlns='urn:something:else'/>
<text>This is a terrible example.</text>
</failure>
]]></example>
</section3>
<section3 topic="Continue" anchor="continue">
<p>A &lt;continue/> element is used to indicate that while the SASL exchange was successful, it is insufficient to allow authentication at this time.</p>
<p>This can be used to indicate that the Client needs to perform a Second Factor Authentication ("2FA"), or is required to change password. These are conducted as additional SASL mechanisms. Such SASL mechanisms MUST NOT change the authorization identifier, or introduce any security layer. The authorization identifer transmitted during the subsequent &lt;success/>, and any security layer which comes into effect after the eventual &lt;success/>, therefore MUST be that of the first mechanism.</p>
<p>The element contains a &lt;mechanisms/> element, as defined above as a stream feature, containing suitable mechanisms. It MAY contain an &lt;additional-data/> element, as the &lt;success/> element does.</p>
<p>Finally, it MAY contain a &lt;text/> element, which can contain human-readable data explaining the nature of the step required.</p>
<example caption="Continue Required"><![CDATA[
<continue xmlns='urn:xmpp:sasl:0'>
<additional-data>
T3B0aW9uYWwgQmFzZSA2NCBlbmNvZGVkIFNBU0wgc3VjY2VzcyBkYXRh
</additional-data>
<mechanisms>
<mechanism>HOTP-EXAMPLE</mechanism>
<mechanism>TOTP-EXAMPLE</mechanism>
<mechanisms>
<text>This account requires 2FA</text>
</continue>
]]></example>
<p>Clients respond with a &lt;next-authenticate/> element, which has a single mandatory attribute of "mechanism", containing the selected mechanism name, and contains an OPTIONAL base64 encoded initial response.</p>
<example caption="Client Continues"><![CDATA[
<next-authenticate xmlns='urn:xmpp:sasl' mechanism='TOTP-EXAMPLE'>
MkZBIG9yIHBhc3N3b3JkIGNoYW5nZSBvciBzb21ldGhpbmc=
</next-authenticate>
]]></example>
</section3>
</section2>
</section1>
<section1 topic="SASL Profile Definition">
<p>This provides pointers and/or clarifications to the <link url="#overview"/> in the order and manner defined in RFC 4422, section 4.</p>
<section2 topic="Service Name">
<p>The service name SHALL be "xmpp", as defined by RFC 6120.</p>
</section2>
<section2 topic="Mechanism negotiation">
<p>Servers list mechanisms during stream features (See <link url="#features"/>) and within the &lt;continue/> element (See <link url="#continue"/>).</p>
<p>TODO: Neither this specification nor RFC 6120 allow clients access to the mechanism list after SASL negotiation...?</p>
</section2>
<section2 topic="Message Definitions">
<section3 topic="Initiation">
<p>Clients initiate using the &lt;authenticate/> top level element (See <link url="#auth"/>, and after any &lt;continue/> with the &lt;next-authenticate/> message (See <link url="#continue"/>).</p>
</section3>
<section3 topic="Server Challenges and Client Responses">
<p>See <link url="#challenge"/>.</p>
</section3>
<section3 topic="Outcome">
<p>See <link url="#outcome"/>.</p>
</section3>
</section2>
<section2 topic="Non-Empty Authorization Strings">
<p>If a Client specifies an authorization string which is non-empty, the identifier is normalized by treating it as a JID, and performing normalization as described in RFC 7622.</p>
</section2>
<section2 topic="Aborting">
<p>Clients MAY abort unilaterally by sending &lt;abort/> as specified in <link url="#abort"/>.</p>
<p>Servers MAY abort unliterally by sending &lt;failure/> with the &lt;aborted/> error code as defined in <link url="#failure"/>.</p>
</section2>
<section2 topic="Security Layer Effect">
<p>See <link url="#success"/>.</p>
</section2>
<section2 topic="Security Layer Order">
<p>Option (a) is used - any SASL Security Layer is applied first to data being sent, and TLS applied last.</p>
</section2>
<section2 topic="Multiple Authentication">
<p>Although the &lt;continue/> concept does use multiple SASL sequences, only the first SASL mechanism used is considered an authentication, and only the first can negotiate a security layer.</p>
<p>In particular, once &lt;success/> has been sent by the server, any further &lt;authenticate/> element MUST result in a stream error.</p>
</section2>
</section1>
<section1 topic='Security Considerations' anchor='security'>
<p>Relative to the SASL profile documented in RFC 6120, this introduces more data unprotected by any security layer negotiated by SASL itself.</p>
</section1>
<section1 topic='IANA Considerations' anchor='iana'>
<p>This XEP requires no interaction with &IANA;. </p>
</section1>
<section1 topic='XMPP Registrar Considerations' anchor='registrar'>
<p>None.</p>
</section1>
<section1 topic='Acknowledgements' anchor='ack'>
<p>The author wishes to share any credit with many members of the community, including Lance Stout, Ralph Meijer, and Florian Schmaus.</p>
</section1>
</xep>

View File

@ -244,7 +244,7 @@ Thus, for the meta data, the node id would be UUID_meta and the data value node
</section2>
<section2 topic='Device Metadata' anchor='devicem'>
Adapter publishes device meta data:
<p>Adapter publishes device meta data:</p>
<code><![CDATA[
<iq type='set'
to='pubsub.capulet.lit'
@ -315,7 +315,6 @@ If the meta node is configured to include payloads, the subscribers will receive
</message>
]]></code>
<table caption='Device Attributes'>
<tbody>
<tr>
<th>
Attribute
@ -373,11 +372,9 @@ If the meta node is configured to include payloads, the subscribers will receive
A serial number or other unique identifier for the physical device
</td>
</tr>
</tbody>
</table>
<table caption='Transducer Attributes'>
<tbody>
<tr>
<th>
Attribute
@ -507,13 +504,11 @@ The tuple (UUID X, transducer id Y) MUST be unique such that a publish operation
The accuracy of the values reported by this transducer
</td>
</tr>
</tbody>
</table>
<section3 topic='Types' anchor='types'>
<p>To make it easier for agents to sort through available devices and seonsors, it is desirable for implementations to use a common set of types. The following device types are defined:
</p>
<table caption='Device Types'>
<tbody>
<tr>
<th>
Type
@ -610,7 +605,6 @@ The tuple (UUID X, transducer id Y) MUST be unique such that a publish operation
Other type that isn't listed above
</td>
</tr>
</tbody>
</table>
</section3>
<section3 topic='Units' anchor='units'>
@ -618,7 +612,7 @@ The tuple (UUID X, transducer id Y) MUST be unique such that a publish operation
SI conventions as shown in the <link url='http://aurora.regenstrief.org/~ucum/ucum.html'>The Unified Code For Units of Measurement</link>.
</p>
<p>
After specifying the units of the transducer device, you can then also specify an SI scalar value as powers of 10. The following example shows how to specify a sensor in centimeters.
After specifying the units of the transducer device, you can then also specify an SI scalar value as powers of 10. The following example shows how to specify a sensor in centimeters.</p>
<code><![CDATA[
<device id='01020301' type='other'>
<transducer name='inchworm movement' id='0001'
@ -626,7 +620,7 @@ After specifying the units of the transducer device, you can then also specify a
</device>
]]></code>
The following example shows how to specify a sensor in kilograms.
<p>The following example shows how to specify a sensor in kilograms.</p>
<code><![CDATA[
<device id='xyzzy' type='scale'>
<transducer name='bathroom scale' id='0001'
@ -634,7 +628,7 @@ The following example shows how to specify a sensor in kilograms.
</device>
]]></code>
The following example shows how to specify a sensor in kilowatt-second with a resolution to the nearest 0.1 kWh.
<p>The following example shows how to specify a sensor in kilowatt-second with a resolution to the nearest 0.1 kWh.</p>
<code><![CDATA[
<device id='windmill087' type='resource generation'>
<transducer name='home wind generator' id='0001'
@ -644,12 +638,12 @@ The following example shows how to specify a sensor in kilowatt-second with a re
</device>
]]></code>
If no unitScaler value is specified, then a unitScaler of 0 (aka 10**0 = 1) is assumed.
<p>If no unitScaler value is specified, then a unitScaler of 0 (aka 10**0 = 1) is assumed.
</p>
</section3>
</section2>
<section2 topic='Transducer Values' anchor='transducervalues'>
Values for a transducer are published via the data value node:
<p>Values for a transducer are published via the data value node:</p>
<code><![CDATA[
<iq type='set'
to='pubsub.capulet.lit'
@ -700,7 +694,6 @@ If the data value node is configured to include payloads, the subscribers will r
</message>
]]></code>
<table caption='Transducer Value Attributes'>
<tbody>
<tr>
<th>
Attribute
@ -744,7 +737,6 @@ The tuple (UUID X, transducer id Y) MUST be unique such that a publish operation
The raw value as seen by the transducer. The rawValue can be used to record a non-unit converted value for record keeping (e.g. a raw ADC value before calibration).
</td>
</tr>
</tbody>
</table>
<p>OPTIONAL: Instead of putting all of the transducer values into a single data value node, an adapter MAY want to break up the transducer values into multiple nodes.
For example, an adapter may want to do this for reasons of security (allow some entities to subscribe/publish to transducer Y1 and a different set of entities to subscribe/publish to transducer Y2).
@ -804,7 +796,7 @@ The information in the meta node is used by consumers to determine which node th
</p>
</section2>
<section2 topic='Setting Transducer Values' anchor='transducerset'>
Values for a transducer can also be set by publishing to the data value node.
<p>Values for a transducer can also be set by publishing to the data value node.</p>
<code><![CDATA[
<iq type='set'
to='pubsub.capulet.lit'
@ -886,7 +878,6 @@ If the fan node is configured to include payloads, the subscribers will receive
</message>
]]></code>
<table caption='Transducer Set Attributes'>
<tbody>
<tr>
<th>
Attribute
@ -922,7 +913,6 @@ The tuple (UUID X, transducer id Y) MUST be unique such that a publish operation
If the adapter can verify that the raw value is an allowable value for the transducer, it SHOULD allow the raw value to take precedence over the typedValue if provided.
</td>
</tr>
</tbody>
</table>
<section3 topic='Actuation' anchor='actuation'>
<p> Actuation takes place as a split-phase operation with an action signal (publish) followed by a completion callback (subscribed message).
@ -1153,12 +1143,11 @@ Event Node ID: 4d4335b5-4134-11e0-9207-0800200c9a66_data
</iq>
]]></code>
<p>Two things to note:
<p>Two things to note:</p>
<ol>
<li>The tuple ('4d4335b5-4134-11e0-9207-0800200c9a66_data', 'tid1') uniquely identifies the motion sensor for this camera adapter.</li>
<li>It is not relevant to the subscriber of this node (the consumer of information) whether the camera has motion detection built in or whether the adapter is capturing images from the camera and using its own methodology for determining motion.</li>
</ol>
</p>
<p>
To continue this example further, let's assume an agent is subscribed to the data value node and can also publish to the tid2 node which controls the light.
In this case, an agent will receive notification that movement was sensed and can take action.
@ -1302,7 +1291,7 @@ If an adapter chooses to publish a subset of transducer data (for example, only
the changed values), it is possible for consumers who are off line or recently
activated to miss older values.
There are a variety of ways to handle this depending on the needs of the
implementor including (but not limited to):
implementor including (but not limited to):</p>
<ul>
<li>
Increase the history size of the node in the xmpp server so old entries can be obtained
@ -1317,7 +1306,7 @@ Put infrequent events in their own nodes and use data value node for frequent ev
Put frequent events in their own nodes and use data value node for infrequent events
</li>
</ul>
If an implementaion chooses to put some transducers values into their own nodes
<p>If an implementaion chooses to put some transducers values into their own nodes
(instead of putting them all into the data value node), remember that a transducer value MUST appear in either the data value node or its own node, but not both.
The meta node indicates to consumers which node they should subscribe to in order to be notified when new data is available for their chosen transducer.
</p>

View File

@ -162,10 +162,10 @@
<dl>
<di>
<dt>iq-sift</dt>
<dd>The server enables the client to sift all &IQ; stanzas or ones that match the specified criteria.</dd>
<dt>message-sift</dt>
<dd>The server enables the client to sift all &MESSAGE; stanzas or ones that match the specified criteria.</dd>
<dt>presence-sift</dt>
<dd>The server enables the client to sift all &IQ; stanzas or ones that match the specified criteria.</dd></di>
<di><dt>message-sift</dt>
<dd>The server enables the client to sift all &MESSAGE; stanzas or ones that match the specified criteria.</dd></di>
<di><dt>presence-sift</dt>
<dd>The server enables the client to sift all &PRESENCE; stanzas or ones that match the specified criteria.</dd>
</di>
</dl>
@ -175,14 +175,14 @@
<dl>
<di>
<dt>all</dt>
<dd>The server shall sift this kind of stanza no matter who the sender is. This is the <strong>default</strong>.</dd>
<dt>local</dt>
<dd>The server shall sift this kind of stanza only from entities associated with the same local domain as the user itself (not from remote domains).</dd>
<dt>others</dt>
<dd>The server shall sift this kind of stanza only from other entities (not from the user itself).</dd>
<dt>remote</dt>
<dd>The server shall sift this kind of stanza only from entities associated with remote domains (not from the same local domain as the user itself).</dd>
<dt>self</dt>
<dd>The server shall sift this kind of stanza no matter who the sender is. This is the <strong>default</strong>.</dd></di>
<di><dt>local</dt>
<dd>The server shall sift this kind of stanza only from entities associated with the same local domain as the user itself (not from remote domains).</dd></di>
<di><dt>others</dt>
<dd>The server shall sift this kind of stanza only from other entities (not from the user itself).</dd></di>
<di><dt>remote</dt>
<dd>The server shall sift this kind of stanza only from entities associated with remote domains (not from the same local domain as the user itself).</dd></di>
<di><dt>self</dt>
<dd>The server shall sift this kind of stanza only from the user itself (not from other entities).</dd>
</di>
</dl>
@ -193,10 +193,10 @@
<dl>
<di>
<dt>all</dt>
<dd>The server shall sift this kind of stanza if the recipient is the bare JID &LOCALBARE; of the user or the full JID &LOCALFULL; of the particular resource. This is the <strong>default</strong>.</dd>
<dt>bare</dt>
<dd>The server shall sift this kind of stanza only if the recipient is the bare JID &LOCALBARE; of the user.</dd>
<dt>full</dt>
<dd>The server shall sift this kind of stanza if the recipient is the bare JID &LOCALBARE; of the user or the full JID &LOCALFULL; of the particular resource. This is the <strong>default</strong>.</dd></di>
<di><dt>bare</dt>
<dd>The server shall sift this kind of stanza only if the recipient is the bare JID &LOCALBARE; of the user.</dd></di>
<di><dt>full</dt>
<dd>The server shall sift this kind of stanza only if the recipient is the full JID &LOCALFULL; of the particular resource.</dd>
</di>
</dl>

View File

@ -43,14 +43,14 @@
</revision>
</header>
<section1 topic='Introduction' anchor='intro'>
<p>There are various spim protection methods exist in XMPP: &xep0016;, &xep0158;, &xep0191;, &xep0268; and &xep0275;. But they may not be sufficient enough:
<p>There are various spim protection methods exist in XMPP: &xep0016;, &xep0158;, &xep0191;, &xep0268; and &xep0275;. But they may not be sufficient enough:</p>
<ul>
<li>&xep0016; and &xep0191; define blocking mechanism only which is not always appropriate.</li>
<li>&xep0158; interacts badly with automated software such as gateways.</li>
<li>&xep0268; implies trusted network of servers.</li>
<li>&xep0275; concentrates on ranking only.</li>
</ul>
Service administrators might want to deploy server-based spim recognition software to fill in the gaps. However, every automated spim recognition suffers from <em>false positives</em> - situations where a stanza incorrectly qualified as spim. To avoid them, a spim filter doesn't block suspicious stanza, but marks it and sends to a client in a regular manner. A client software doesn't need to interrupt a user when processing such marked stanzas: for example, it may put them silently in "SPAM" folder, so a user can look through them at any time later. Furthermore, a spim filter may take user's experience into account. When a user receives an unsolicited stanza, he or she can mark it as spim. In this case a client software sends an automatic complaint to a server-based spim filter. This specification deals with both cases. Thus, in contrast to &xep0159;, it doesn't introduce any spim blocking techniques. Also, the various spim recognition procedures that may be employed by the server are beyond the scope of this document.
<p>Service administrators might want to deploy server-based spim recognition software to fill in the gaps. However, every automated spim recognition suffers from <em>false positives</em> - situations where a stanza incorrectly qualified as spim. To avoid them, a spim filter doesn't block suspicious stanza, but marks it and sends to a client in a regular manner. A client software doesn't need to interrupt a user when processing such marked stanzas: for example, it may put them silently in "SPAM" folder, so a user can look through them at any time later. Furthermore, a spim filter may take user's experience into account. When a user receives an unsolicited stanza, he or she can mark it as spim. In this case a client software sends an automatic complaint to a server-based spim filter. This specification deals with both cases. Thus, in contrast to &xep0159;, it doesn't introduce any spim blocking techniques. Also, the various spim recognition procedures that may be employed by the server are beyond the scope of this document.
</p>
</section1>
<section1 topic='Requirements' anchor='reqs'>
@ -143,13 +143,12 @@
</section1>
<section1 topic='Business Rules' anchor='rules'>
<p>A filtering entity SHOULD only add &lt;mark/&gt; or &lt;report/&gt; elements and a receiving entity SHOULD only process those elements if the corresponding stanza envolves an interaction with a human user: subscription requests, messages, conference invites, voice calls, etc. For example, it doesn't make a lot of sense to mark &xep0232; stanzas.</p>
<p>To avoid obvious false positives and user confusions, a filtering entity SHOULD NOT add &lt;mark/&gt; or &lt;report/&gt; elements to a stanza and a receiving entity SHOULD ignore &lt;mark/&gt; and &lt;report/&gt; elements of a stanza if:
<p>To avoid obvious false positives and user confusions, a filtering entity SHOULD NOT add &lt;mark/&gt; or &lt;report/&gt; elements to a stanza and a receiving entity SHOULD ignore &lt;mark/&gt; and &lt;report/&gt; elements of a stanza if:</p>
<ul>
<li>The receiving entity has the sender's subscription information of the type "both", "from" or "to".</li>
<li>The receiving entity has pending subscription to the sender, i.e. subscription of type "none" and ask='subscribe'.</li>
<li>The receiving entity has sent direct presence to the sender.</li>
</ul>
</p>
</section1>
<section1 topic='Determining Support' anchor='support'>
<p>If an entity supports the spim markers, it MUST report that by including a service discovery feature of "urn:xmpp:spim-marker:0" in response to a &xep0030; information request. If an entity supports the spim reports, it MUST report that by including a service discovery feature of "urn:xmpp:spim-report:0" in response to a &xep0030; information request:</p>

View File

@ -12,6 +12,7 @@
<number>xxxx</number>
<status>ProtoXEP</status>
<type>Standards Track</type>
<sig>Standards</sig>
<approver>Council</approver>
<dependencies>
<spec>XMPP Core</spec>
@ -1041,4 +1042,3 @@ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
</section1>
</xep>

View File

@ -18,6 +18,7 @@
<number>xxxx</number>
<status>ProtoXEP</status>
<type>Standards Track</type>
<sig>Standards</sig>
<approver>Council</approver>
<dependencies>
<spec>XMPP Core</spec>
@ -263,6 +264,7 @@
<p>
During the game, players change in turn, each of them MUST send only one move at a time.
It MUST possess these attributes:
</p>
<table caption='&MOVE; attributes'>
<tr>
<td><strong>Name</strong></td>
@ -285,7 +287,6 @@
<td>The vertical position of the mark.</td>
</tr>
</table>
</p>
<example caption='Juliet Sends a Move'><![CDATA[
<message
to='tictactoe@games.shakespeare.lit'

View File

@ -18,6 +18,7 @@
<number>xxxx</number>
<status>ProtoXEP</status>
<type>Standards Track</type>
<sig>Standards</sig>
<approver>Council</approver>
<dependencies>
<spec>XMPP Core</spec>
@ -133,6 +134,7 @@
Furthermore, the &MESSAGE; stanza contains a &TURN; element which in turn contains exactly one &MOVE; element
qualified by 'http://jabber.org/protocol/games/tictactoe'.
It MUST possess these attributes:
</p>
<table caption='&MOVE; attributes'>
<tr>
<td><strong>Name</strong></td>
@ -155,7 +157,6 @@
<td>The vertical position of the mark.</td>
</tr>
</table>
</p>
<example caption='Part of the Match Between Romeo and Juliet'><![CDATA[
<message
from='romeo@montague.net/room'

View File

@ -121,7 +121,7 @@
device, they both MAY know the exact format and existence of supported
commands.
</p>
</section1>SkkdJi88C())oo
</section1>
<section1 topic='Glossary' anchor='glossary'>
<p>
@ -164,8 +164,8 @@
</p>
<p>
<em>Note: The text that follows assumes that implementors have
read and understood <cite>XEP-0050</cite>, password
generation algorithms described in &rfc4226; and <cite>RFC 6238</cite></em>,
read and understood &xep0050;, password
generation algorithms described in &rfc4226; and &rfc6238;</em>,
and randomness requirements described in &rfc4086;,
and know about one-time pads and perfect secrecy.
</p>
@ -173,8 +173,8 @@
<section2 topic='Authenticate with a Time-Based One-Time Password (TOTP)' anchor='set-totp'>
<p>
Time-Based One-Time Password (TOTP) algorithm described in
<cite>RFC 6238</cite> is an extension of the HMAC-based
One-Time Password (HOTP) algorithm defined in <cite>RFC 4226</cite>,
&rfc6238; is an extension of the HMAC-based
One-Time Password (HOTP) algorithm defined in &rfc4226;,
to support the time-based moving factor. In TOTP, time
reference and a time step replaces the counter in the HOTP
computation.
@ -431,14 +431,14 @@
</li>
</ul>
In each case, the Verifier MAY check Prover's JID right after
<p>In each case, the Verifier MAY check Prover's JID right after
receiving the first Ad-Hoc command or after a succesful verification
process.
process.</p>
If Prover's JID is not approved, the Verifier SHOULD
reply with &forbidden; error message.
<p>If Prover's JID is not approved, the Verifier SHOULD
reply with &forbidden; error message.</p>
After the a succesful verification the Verifier can, e.g.,
<p>After the a succesful verification the Verifier can, e.g.,</p>
<ul>
<li>start the wanted process,</li>
<li>ask access rights from additional provision servers,

View File

@ -55,7 +55,7 @@
</section1>
<section1 topic='Use Cases' anchor='usecases'>
<section2 topic='Retrieving rating' anchor='retrieverating'>
A user may obtain their own rating by sending an IQ-get with no to address and an element qualified by the rating namespace.
<p>A user may obtain their own rating by sending an IQ-get with no to address and an element qualified by the rating namespace.</p>
<example caption='Rating retrieval request'><![CDATA[
<iq from=romeo@montague.net
id=aa1a
@ -63,7 +63,7 @@
<query xmlns=rating />
</iq>
]]></example>
The server should return an IQ result stanza with <rating/> element:
<p>The server should return an IQ result stanza with &lt;rating/&gt; element:</p>
<example caption='Server Response'><![CDATA[
<iq type=result to=romeo@montague.net
id=aa1a
@ -74,8 +74,8 @@
</iq>
]]></example>
</section2>
<section3 topic='User-moderated server' anchor='usermodserver'>
In installations that run as chat servers, moderation of spam users can be delivered to online users and administrators. Users receiving spam from a bare JID can send an IQ stanza to the server that increases the user rating.
<section2 topic='User-moderated server' anchor='usermodserver'>
<p>In installations that run as chat servers, moderation of spam users can be delivered to online users and administrators. Users receiving spam from a bare JID can send an IQ stanza to the server that increases the user rating.</p>
<example caption='Reporting Spam/Abuse'><![CDATA[
<iq type=set
from=romeo@montague.net
@ -145,7 +145,7 @@
</p>
<p>
JIDs that are critical to server functionality or admins should have a
permanent <rating/> of -100 to indicate that they are protected. Should a
permanent &lt;rating/&gt; of -100 to indicate that they are protected. Should a
user attempt to report a protected user, the server should send the
following:
</p>
@ -178,7 +178,7 @@
XEP-0191 Blocking Command, or an internal implementation to prevent
communication from known spammer accounts.
</p>
</section3>
</section2>
</section1>
<section1 topic='Business Rules' anchor='rules'>
<p>OPTIONAL.</p>

1
inbox/xep.dtd Symbolic link
View File

@ -0,0 +1 @@
../xep.dtd

1
inbox/xep.ent Symbolic link
View File

@ -0,0 +1 @@
../xep.ent

View File

@ -1,6 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE xep SYSTEM 'xep.dtd' [
<!ENTITY % ents SYSTEM 'xep.ent'>
<!ENTITY rfc3920bis "<span class='ref'><link url='http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis'>rfc3920bis</link></span> <note>RFC 3920: Extensible Messaging and Presence Protocol (XMPP): Core &lt;<link url='http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis'>http://tools.ietf.org/html/draft-ietf-saintandre-rfc3920bis</link>&gt;.</note>" >
%ents;
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>

145
inxep.py
View File

@ -1,145 +0,0 @@
#!/usr/bin/env python
# File: inxep.py
# Version: 0.1
# Description: a script for announcing proto-XEPs
# Last Modified: 2004-09-14
# Author: Peter Saint-Andre (stpeter@jabber.org)
# License: public domain
# HowTo: ./inxep.py filename approver
# (note: do not include extension!)
## LICENSE ##
#
# Copyright (c) 1999 - 2010 XMPP Standards Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
## END LICENSE ##
# IMPORTS:
#
import glob
import os
from select import select
import smtplib
import socket
from string import split,strip,join,find
import sys
import time
from xml.dom.minidom import parse,parseString,Document
def getText(nodelist):
thisText = ""
for node in nodelist:
if node.nodeType == node.TEXT_NODE:
thisText = thisText + node.data
return thisText
# READ in XEP filename (sans extension)
xepname = sys.argv[1];
if len(sys.argv) >= 3:
approver = sys.argv[2]
else:
approver = "XMPP Council"
xepfile = 'inbox/' + xepname + '.xml'
# PARSE XEP HEADERS:
#
# - title
# - abstract
# - version
# - date
# - initials
# - remark
thexep = parse(xepfile)
xepNode = (thexep.getElementsByTagName("xep")[0])
headerNode = (xepNode.getElementsByTagName("header")[0])
titleNode = (headerNode.getElementsByTagName("title")[0])
title = getText(titleNode.childNodes)
abstractNode = (headerNode.getElementsByTagName("abstract")[0])
abstract = getText(abstractNode.childNodes)
statusNode = (headerNode.getElementsByTagName("status")[0])
xepstatus = getText(statusNode.childNodes)
typeNode = (headerNode.getElementsByTagName("type")[0])
xeptype = getText(typeNode.childNodes)
revNode = (headerNode.getElementsByTagName("revision")[0])
versionNode = (revNode.getElementsByTagName("version")[0])
version = getText(versionNode.childNodes)
dateNode = (revNode.getElementsByTagName("date")[0])
date = getText(dateNode.childNodes)
initialsNode = (revNode.getElementsByTagName("initials")[0])
initials = getText(initialsNode.childNodes)
remarkNode = (revNode.getElementsByTagName("remark")[0])
remark = getText(remarkNode.childNodes)
# SEND MAIL:
#
# From: editor@xmpp.org
# To: standards@xmpp.org
# Subject: Proposed XMPP Extension: XEP-$xepnum ($title)
# Body:
# The XMPP Extensions Editor has received a proposal for a new XEP.
#
# Title: $title
#
# Abstract: $abstract
#
# URL: https://xmpp.org/extensions/inbox/$xepname.html
#
# The $approver will now consider whether to accept
# this proposal as a full XEP.
#
fromaddr = "editor@xmpp.org"
# for testing...
# toaddrs = "editor@jabber.org"
# for real...
toaddrs = "standards@xmpp.org"
thesubject = 'Proposed XMPP Extension: ' + title
introline = 'The XMPP Extensions Editor has received a proposal for a new XEP.'
titleline = 'Title: ' + title
abstractline = 'Abstract: ' + abstract
urlline = 'URL: https://xmpp.org/extensions/inbox/' + xepname + '.html'
actionline = 'The ' + approver + ' will decide in the next two weeks whether to accept this proposal as an official XEP.'
msg = "From: XMPP Extensions Editor <%s>\r\n" % fromaddr
msg = msg + "To: %s\r\n" % toaddrs
msg = msg + "Subject: %s\r\n" % thesubject
msg = msg + introline
msg = msg + "\r\n\n"
msg = msg + titleline
msg = msg + "\r\n\n"
msg = msg + abstractline
msg = msg + "\r\n\n"
msg = msg + urlline
msg = msg + "\r\n\n"
msg = msg + actionline
msg = msg + "\r\n\n"
server = smtplib.SMTP('localhost')
server.set_debuglevel(1)
server.sendmail(fromaddr, toaddrs, msg)
server.quit()
# END

90
tools/archive.py Executable file
View File

@ -0,0 +1,90 @@
#!/usr/bin/env python3
import pathlib
import shutil
import sys
import xml.etree.ElementTree as etree
from datetime import datetime, timedelta
from xeplib import load_xepinfos, Status
def main():
import argparse
parser = argparse.ArgumentParser(
description="Show the XEPs which need to be changed to deferred."
)
parser.add_argument(
"old",
type=argparse.FileType("rb"),
help="Old XEP list"
)
parser.add_argument(
"new",
type=argparse.FileType("rb"),
help="New XEP list"
)
parser.add_argument(
"-d", "--xeps-dir",
type=pathlib.Path,
default=pathlib.Path.cwd() / "build",
help="Path to the built XEPs (defaults to ./build)"
)
parser.add_argument(
"-a", "--attic",
type=pathlib.Path,
default=pathlib.Path.cwd() / '../xep-attic/content/',
help="Path to the attic (defaults to ../xep-attic/content/)"
)
args = parser.parse_args()
with args.old as f:
old_tree = etree.parse(f)
old_accepted, _ = load_xepinfos(old_tree)
with args.new as f:
new_tree = etree.parse(f)
new_accepted, _ = load_xepinfos(new_tree)
changed = False
for xep, new_info in new_accepted.items():
old_version = old_accepted.get(xep, {}).get("last_revision", {}).get(
"version"
)
new_version = new_info["last_revision"]["version"]
if old_version == new_version:
continue
curr_file = args.xeps_dir / "xep-{:04d}.html".format(xep)
attic_file = args.attic / "xep-{:04d}-{}.html".format(xep, new_version)
print("XEP-{:04d}:".format(xep), old_version, "->", new_version)
shutil.copy(str(curr_file), str(attic_file))
changed = True
if changed:
print(
"{}: do not forget to commit & push the attic!".format(
sys.argv[0]
),
file=sys.stderr
)
else:
print("{}: nothing to do".format(sys.argv[0]),
file=sys.stderr)
if __name__ == "__main__":
main()

57
tools/deferrals.py Executable file
View File

@ -0,0 +1,57 @@
#!/usr/bin/env python3
import xml.etree.ElementTree as etree
from datetime import datetime, timedelta
from xeplib import load_xepinfos, Status
def get_deferred(accepted):
now = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0)
threshold = now.replace(year=now.year - 1)
for number, info in sorted(accepted.items()):
if info["status"] == Status.EXPERIMENTAL and "last_revision" in info:
last_update = info["last_revision"]["date"]
if last_update <= threshold:
yield info
def main():
import argparse
parser = argparse.ArgumentParser(
description="Show the XEPs which need to be changed to deferred."
)
parser.add_argument(
"-l", "--xeplist",
type=argparse.FileType("rb"),
default=None,
help="XEP list to use (defaults to ./build/xeplist.xml)"
)
parser.add_argument(
"-m", "--modify",
action="store_true",
default=False,
help="Modify the XEP files in-place."
)
args = parser.parse_args()
if args.xeplist is None:
args.xeplist = open("./build/xeplist.xml", "rb")
with args.xeplist as f:
tree = etree.parse(f)
accepted, _ = load_xepinfos(tree)
deferred = list(get_deferred(accepted))
for deferred_info in deferred:
print(deferred_info["number"])
if __name__ == "__main__":
main()

215
tools/extract-metadata.py Executable file
View File

@ -0,0 +1,215 @@
#!/usr/bin/env python3
import pathlib
import sys
import xml.dom.minidom
import xml.etree.ElementTree as etree
from xeplib import (
minidom_find_child,
minidom_find_header,
minidom_get_text,
minidom_children,
)
DESCRIPTION = """\
Extract a list of XEPs with metadata from the xeps repository."""
EPILOG = """"""
def open_xml(f):
return xml.dom.minidom.parse(f)
def extract_xep_metadata(document):
header = minidom_find_header(document)
latest_revision = minidom_find_child(header, "revision")
if latest_revision is not None:
last_revision_version = minidom_get_text(
minidom_find_child(latest_revision, "version")
)
last_revision_date = minidom_get_text(
minidom_find_child(latest_revision, "date")
)
remark_el = minidom_find_child(latest_revision, "remark")
last_revision_remark = None
if remark_el is not None:
remark_children = minidom_children(remark_el)
if len(remark_children) == 1 and remark_children[0].tagName == "p":
last_revision_remark = minidom_get_text(remark_children[0])
if last_revision_remark is not None:
initials_el = minidom_find_child(latest_revision, "initials")
last_revision_initials = initials_el and minidom_get_text(
initials_el
)
else:
last_revision_initials = None
else:
last_revision_version = None
last_revision_date = None
last_revision_remark = None
last_revision_initials = None
status = minidom_get_text(minidom_find_child(header, "status"))
type_ = minidom_get_text(minidom_find_child(header, "type"))
abstract = " ".join(minidom_get_text(
minidom_find_child(header, "abstract")
).split())
sig_el = minidom_find_child(header, "sig")
if sig_el is None:
sig = None
else:
sig = minidom_get_text(sig_el)
shortname = minidom_get_text(minidom_find_child(header, "shortname"))
if shortname.replace("-", " ").replace("_", " ").lower() in [
"not yet assigned", "n/a", "none", "to be assigned",
"to be issued"]:
shortname = None
title = minidom_get_text(minidom_find_child(header, "title"))
approver_el = minidom_find_child(header, "approver")
if approver_el is not None:
approver = minidom_get_text(approver_el)
else:
approver = "Board" if type_ == "Procedural" else "Council"
return {
"last_revision": {
"version": last_revision_version,
"date": last_revision_date,
"initials": last_revision_initials,
"remark": last_revision_remark,
},
"status": status,
"type": type_,
"sig": sig,
"abstract": abstract,
"shortname": shortname,
"title": title,
"approver": approver,
}
def text_element(tag, text):
el = etree.Element(tag)
el.text = text
return el
def make_metadata_element(number, metadata, accepted, *, protoname=None):
result = etree.Element("xep")
result.append(text_element("number", number))
result.append(text_element("title", metadata["title"]))
result.append(text_element("abstract", metadata["abstract"]))
result.append(text_element("type", metadata["type"]))
result.append(text_element("status", metadata["status"]))
result.append(text_element("approver", metadata["approver"]))
if metadata["shortname"] is not None:
result.append(text_element("shortname", metadata["shortname"]))
if metadata["last_revision"]["version"] is not None:
last_revision = metadata["last_revision"]
revision_el = etree.Element("last-revision")
revision_el.append(text_element("date", last_revision["date"]))
revision_el.append(text_element("version", last_revision["version"]))
if last_revision["initials"]:
revision_el.append(text_element("initials",
last_revision["initials"]))
if last_revision["remark"]:
revision_el.append(text_element("remark",
last_revision["remark"]))
result.append(revision_el)
if metadata["sig"] is not None:
result.append(
text_element("sig", metadata["sig"])
)
if accepted:
result.set("accepted", "true")
else:
result.set("accepted", "false")
if protoname is not None:
result.append(text_element("proto-name", protoname))
return result
def parse_checked_and_print_error(xepfile):
try:
with xepfile.open("rb") as f:
return open_xml(f)
except xml.parsers.expat.ExpatError as exc:
print("{}: {}".format(xepfile, exc), file=sys.stderr)
return None
def main():
import argparse
import sys
parser = argparse.ArgumentParser(
description=DESCRIPTION,
epilog=EPILOG,
)
parser.add_argument(
"xepdir",
nargs="?",
type=pathlib.Path,
default=pathlib.Path.cwd(),
help="Directory where the XEP XMLs are. Defaults to current directory."
)
args = parser.parse_args()
tree = etree.Element("xep-infos")
has_error = False
for xepfile in args.xepdir.glob("xep-*.xml"):
number = xepfile.name.split("-", 1)[1].split(".", 1)[0]
try:
number = str(int(number))
except ValueError:
continue
parsed = parse_checked_and_print_error(xepfile)
if parsed is None:
has_error = True
continue
tree.append(make_metadata_element(
number,
extract_xep_metadata(parsed),
True,
))
for xepfile in (args.xepdir / "inbox").glob("*.xml"):
protoname = xepfile.name.rsplit(".", 1)[0]
parsed = parse_checked_and_print_error(xepfile)
if parsed is None:
has_error = True
continue
tree.append(make_metadata_element(
"xxxx",
extract_xep_metadata(parsed),
False,
protoname=protoname
))
if has_error:
sys.exit(2)
sys.stdout.buffer.raw.write(etree.tostring(tree))
if __name__ == "__main__":
main()

435
tools/send-updates.py Executable file
View File

@ -0,0 +1,435 @@
#!/usr/bin/env python3
import configparser
import getpass
import itertools
import email.message
import os
import smtplib
import sys
import textwrap
from datetime import datetime
import xml.etree.ElementTree as etree
from xeplib import Status, Action, load_xepinfos
DESCRIPTION = """\
Send email updates for XEP changes based on the difference between two \
xeplist files."""
EPILOG = """\
Configuration file contents:
[smtp]
host=<smtp server to send through>
port=587
user=<optional: user name to authenticate with>
password=<optional: password to authn. with>
from=<address to send from>
If user is omitted, anonymous mail sending is attempted.
If options are missing from the configuration file and the standard input and \
standard output are a terminal, the script interactively asks for the option \
values. If no terminal is connected, the script exits with an error instead."""
XEP_URL_PREFIX = "https://xmpp.org/extensions/"
MAIL_PROTO_TEMPLATE = """\
The XMPP Extensions Editor has received a proposal for a new XEP.
Title: {info[title]}
Abstract:
{info[abstract]}
URL: {url}
The {approver} will decide in the next two weeks whether to accept this \
proposal as an official XEP."""
SUBJECT_PROTO_TEMPLATE = "Proposed XMPP Extension: {info[title]}"
MAIL_NONPROTO_TEMPLATE = """\
Version {info[last_revision][version]} of XEP-{info[number]:04d} \
({info[title]}) has been released.
Abstract:
{info[abstract]}
Changelog:
{changelog}
URL: {url}"""
SUBJECT_NONPROTO_TEMPLATE = \
"{action.value}: XEP-{info[number]:04d} ({info[title]})"
def dummy_info(number):
return {
"status": None,
"accepted": False,
"number": number,
}
def diff_infos(old, new):
if old["status"] != new["status"]:
if new["status"] == Status.PROTO:
return Action.PROTO
elif old["status"] is None:
return Action.NEW
else:
return Action.fromstatus(new["status"])
old_version = old.get("last_revision", {}).get("version")
new_version = new.get("last_revision", {}).get("version")
if old_version != new_version:
return Action.UPDATE
return None
def wraptext(text):
return "\n".join(
itertools.chain(
*[textwrap.wrap(line) if line else [line] for line in text.split("\n")]
)
)
def make_proto_mail(info):
kwargs = {
"info": info,
"approver": info["approver"],
"url": "{}inbox/{}.html".format(
XEP_URL_PREFIX,
info["protoname"],
),
}
mail = email.message.EmailMessage()
mail["Subject"] = SUBJECT_PROTO_TEMPLATE.format(**kwargs)
mail["XSF-XEP-Action"] = "PROTO"
mail["XSF-XEP-Title"] = info["title"]
mail["XSF-XEP-Type"] = info["type"]
mail["XSF-XEP-Status"] = info["status"].value
mail["XSF-XEP-Url"] = kwargs["url"]
mail["XSF-XEP-Approver"] = kwargs["approver"]
mail.set_content(
wraptext(MAIL_PROTO_TEMPLATE.format(**kwargs)),
"plain",
"utf-8",
)
return mail
def make_nonproto_mail(action, info):
last_revision = info.get("last_revision")
changelog = "(see in-document revision history)"
if last_revision is not None:
remark = last_revision.get("remark")
initials = last_revision.get("initials")
if remark and initials:
changelog = "{} ({})".format(remark, initials)
kwargs = {
"info": info,
"changelog": changelog,
"action": action,
"url": "{}xep-{:04d}.html".format(
XEP_URL_PREFIX,
info["number"],
),
}
mail = email.message.EmailMessage()
mail["Subject"] = SUBJECT_NONPROTO_TEMPLATE.format(**kwargs)
mail["XSF-XEP-Action"] = action.value
mail["XSF-XEP-Title"] = info["title"]
mail["XSF-XEP-Type"] = info["type"]
mail["XSF-XEP-Status"] = info["status"].value
mail["XSF-XEP-Number"] = "{:04d}".format(info["number"])
mail["XSF-XEP-Url"] = kwargs["url"]
mail.set_content(
wraptext(MAIL_NONPROTO_TEMPLATE.format(**kwargs)),
"plain",
"utf-8",
)
return mail
def get_or_ask(config, section, name, prompt):
try:
return config.get(section, name)
except (configparser.NoSectionError,
configparser.NoOptionError):
return input(prompt)
def interactively_extend_smtp_config(config):
try:
host = config.get("smtp", "host")
except (configparser.NoSectionError,
configparser.NoOptionError):
host = input("SMTP server: ").strip()
port = int(input("SMTP port (blank for 587): ").strip() or "587")
user = input(
"SMTP user (leave blank for anon): "
).strip() or None
if user:
password = getpass.getpass()
else:
password = None
else:
port = config.getint("smtp", "port", fallback=587)
user = config.get("smtp", "user", fallback=None)
password = config.get("smtp", "password", fallback=None)
try:
from_ = config.get("smtp", "from")
except (configparser.NoSectionError,
configparser.NoOptionError):
from_ = input("From address: ").strip()
if not config.has_section("smtp"):
config.add_section("smtp")
config.set("smtp", "host", host)
config.set("smtp", "port", str(port))
if user:
config.set("smtp", "user", user)
if password is None:
password = getpass.getpass()
config.set("smtp", "password", password)
config.set("smtp", "from", from_)
def choose(prompt, options, *,
eof=EOFError,
keyboard_interrupt=KeyboardInterrupt):
while True:
try:
choice = input(prompt).strip()
except EOFError:
if eof is EOFError:
raise
return eof
except KeyboardInterrupt:
if keyboard_interrupt is KeyboardInterrupt:
raise
return keyboard_interrupt
if choice not in options:
print("invalid choice. please enter one of: {}".format(
", ".join(map(str, options))
))
continue
return choice
def make_smtpconn(config):
host = config.get("smtp", "host")
port = config.getint("smtp", "port")
user = config.get("smtp", "user", fallback=None)
password = config.get("smtp", "password", fallback=None)
conn = smtplib.SMTP(host, port)
conn.starttls()
if user is not None:
conn.login(user, password)
return conn
def make_fake_smtpconn():
class Fake:
def send_message(self, mail):
print("---8<---")
print(mail.as_string())
print("--->8---")
def close(self):
pass
return Fake()
def main():
import argparse
parser = argparse.ArgumentParser(
description=wraptext(DESCRIPTION),
epilog=wraptext(EPILOG),
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument(
"-c", "--config",
metavar="FILE",
type=argparse.FileType("r"),
help="Configuration file",
)
parser.add_argument(
"-y",
dest="ask_confirmation",
default=True,
action="store_false",
help="'I trust this script to do the right thing and send emails"
"without asking for confirmation.'"
)
parser.add_argument(
"--no-proto",
dest="process_proto",
default=True,
action="store_false",
help="Disable processing of ProtoXEPs.",
)
parser.add_argument(
"-n", "--dry-run",
dest="dry_run",
action="store_true",
default=False,
help="Instead of sending emails, print them to stdout (implies -y)",
)
parser.add_argument(
"old",
type=argparse.FileType("rb"),
help="Old xep-infos XML file",
)
parser.add_argument(
"new",
type=argparse.FileType("rb"),
help="New xep-infos XML file",
)
parser.add_argument(
"to",
nargs="+",
help="The mail addresses to send the update mails to."
)
args = parser.parse_args()
can_be_interactive = (
os.isatty(sys.stdin.fileno()) and
os.isatty(sys.stdout.fileno())
)
if args.dry_run:
args.ask_confirmation = False
if args.ask_confirmation and not can_be_interactive:
print("Cannot ask for confirmation (stdio is not a TTY), but -y is",
"not given either. Aborting.", sep="\n", file=sys.stderr)
sys.exit(2)
config = configparser.ConfigParser()
if args.config is not None:
config.read_file(args.config)
with args.old as f:
tree = etree.parse(f)
old_accepted, old_proto = load_xepinfos(tree)
with args.new as f:
tree = etree.parse(f)
new_accepted, new_proto = load_xepinfos(tree)
old_xeps = set(old_accepted.keys())
new_xeps = set(new_accepted.keys())
common_xeps = old_xeps & new_xeps
added_xeps = new_xeps - old_xeps
added_protos = set(new_proto.keys()) - set(old_proto.keys())
updates = []
for common_xep in common_xeps:
old_info = old_accepted[common_xep]
new_info = new_accepted[common_xep]
action = diff_infos(old_info, new_info)
if action is not None:
updates.append((common_xep, action, new_info))
for added_xep in added_xeps:
old_info = dummy_info(added_xep)
new_info = new_accepted[common_xep]
action = diff_infos(old_info, new_info)
if action is not None:
updates.append((added_xep, action, new_info))
if args.process_proto:
for added_proto in added_protos:
old_info = dummy_info('xxxx')
new_info = new_proto[added_proto]
action = diff_infos(old_info, new_info)
if action is not None:
updates.append((added_proto, action, new_info))
if args.dry_run:
smtpconn = make_fake_smtpconn()
else:
if can_be_interactive:
interactively_extend_smtp_config(config)
try:
smtpconn = make_smtpconn(config)
except (configparser.NoSectionError,
configparser.NoOptionError) as exc:
print("Missing configuration: {}".format(exc),
file=sys.stderr)
print("(cannot ask for configuration on stdio because it is "
"not a TTY)", file=sys.stderr)
sys.exit(3)
try:
for id_, action, info in updates:
if action == Action.PROTO:
mail = make_proto_mail(info)
else:
mail = make_nonproto_mail(action, info)
mail["Date"] = datetime.utcnow()
mail["From"] = config.get("smtp", "from")
mail["To"] = args.to
if args.ask_confirmation:
print()
print("---8<---")
print(mail.as_string())
print("--->8---")
print()
choice = choose(
"Send this email? [y]es, [n]o, [a]bort: ",
"yna",
eof="a",
)
if choice == "n":
continue
elif choice == "a":
print("Exiting on user request.", file=sys.stderr)
sys.exit(4)
smtpconn.send_message(mail)
finally:
smtpconn.close()
if __name__ == "__main__":
main()

138
tools/xeplib.py Normal file
View File

@ -0,0 +1,138 @@
import enum
import xml.dom.minidom
from datetime import datetime
class Status(enum.Enum):
PROTO = 'ProtoXEP'
EXPERIMENTAL = 'Experimental'
PROPOSED = 'Proposed'
DRAFT = 'Draft'
ACTIVE = 'Active'
FINAL = 'Final'
RETRACTED = 'Retracted'
OBSOLETE = 'Obsolete'
DEFERRED = 'Deferred'
REJECTED = 'Rejected'
DEPRECATED = 'Deprecated'
@classmethod
def fromstr(cls, s):
if s == "Proto" or s.lower() == "protoxep":
s = "ProtoXEP"
return cls(s)
class Action(enum.Enum):
PROTO = "Proposed XMPP Extension"
NEW = "NEW"
DRAFT = "DRAFT"
ACTIVE = "ACTIVE"
FINAL = "FINAL"
RETRACT = "RETRACTED"
OBSOLETE = "OBSOLETED"
DEFER = "DEFERRED"
UPDATE = "UPDATED"
@classmethod
def fromstatus(cls, status):
return {
Status.EXPERIMENTAL: cls.NEW,
Status.DRAFT: cls.DRAFT,
Status.ACTIVE: cls.ACTIVE,
Status.FINAL: cls.FINAL,
Status.RETRACTED: cls.RETRACT,
Status.OBSOLETED: cls.OBSOLETE,
Status.DEPRECATED: cls.DEPRECATE,
Status.DEFERRED: cls.DEFERRED,
}[status]
def load_xepinfo(el):
accepted = el.get("accepted").lower() == "true"
info = {
"title": el.find("title").text,
"abstract": el.find("abstract").text,
"type": el.find("type").text,
"status": Status.fromstr(el.find("status").text),
"approver": el.find("approver").text,
"accepted": accepted,
}
last_revision_el = el.find("last-revision")
if last_revision_el is not None:
last_revision = {
"version": last_revision_el.find("version").text,
"date": datetime.strptime(
last_revision_el.find("date").text,
"%Y-%m-%d",
),
"initials": None,
"remark": None,
}
initials_el = last_revision_el.find("initials")
if initials_el is not None:
last_revision["initials"] = initials_el.text
remark_el = last_revision_el.find("remark")
if remark_el is not None:
last_revision["remark"] = remark_el.text
info["last_revision"] = last_revision
sig = el.find("sig")
if sig is not None:
info["sig"] = sig.text
if accepted:
info["number"] = int(el.find("number").text)
else:
info["protoname"] = el.find("proto-name").text
return info
def load_xepinfos(tree):
accepted, protos = {}, {}
for info_el in tree.getroot():
info = load_xepinfo(info_el)
if info["accepted"]:
accepted[info["number"]] = info
else:
protos[info["protoname"]] = info
return accepted, protos
def minidom_find_child(elem, child_tag):
for child in elem.childNodes:
if hasattr(child, "tagName") and child.tagName == child_tag:
return child
return None
def minidom_find_header(document):
header = minidom_find_child(document.documentElement, "header")
if header is None:
raise ValueError("cannot find <header/>")
return header
def minidom_get_text(elem):
return "".join(
child.nodeValue
for child in elem.childNodes
if isinstance(child, (xml.dom.minidom.Text,
xml.dom.minidom.CDATASection))
)
def minidom_children(elem):
return [
child for child in elem.childNodes
if isinstance(child, (xml.dom.minidom.Element))
]

View File

@ -45,6 +45,14 @@
</schemaloc>
<registry/>
&stpeter;
<revision>
<version>1.28</version>
<date>2017-05-31</date>
<initials>gl</initials>
<remark>
<p>Introduce &lt;x/&gt; tag in MUC-PMs to support better Carbon delivery.</p>
</remark>
</revision>
<revision>
<version>1.27.1</version>
<date>2016-12-03</date>
@ -1903,6 +1911,8 @@
<section2 topic='Sending a Private Message' anchor='privatemessage'>
<p>Since each occupant has its own occupant JID, an occupant can send a "private message" to a selected occupant via the service by sending a message to the intended recipient's occupant JID. The message type SHOULD be "chat" and MUST NOT be "groupchat", but MAY be left unspecified (i.e., a normal message). This privilege is controlled by the "muc#roomconfig_allowpm" room configuration option.</p>
<p>To allow for proper synchronization of these messages to the user's other clients by &xep0280;, the sending client SHOULD add an &lt;x/&gt; element qualified by the 'http://jabber.org/protocol/muc#user' namespace to the message.</p>
<p><strong>Note:</strong> because this requirement was only added in revision 1.28 of this XEP, receiving entities MUST NOT rely on the existence of the &lt;x/&gt; element on private messages for proper processing.</p>
<example caption='Occupant Sends Private Message'><![CDATA[
<message
from='wiccarocks@shakespeare.lit/laptop'
@ -1910,9 +1920,10 @@
to='coven@chat.shakespeare.lit/firstwitch'
type='chat'>
<body>I'll give thee a wind.</body>
<x xmlns='http://jabber.org/protocol/muc#user' />
</message>
]]></example>
<p>The service is responsible for changing the 'from' address to the sender's occupant JID and delivering the message to the intended recipient's full JID.</p>
<p>The service is responsible for changing the 'from' address to the sender's occupant JID and delivering the message to the intended recipient's full JID. The service SHOULD add the &lt;x/&gt; element if the message does not contain it already.</p>
<example caption='Recipient Receives the Private Message'><![CDATA[
<message
from='coven@chat.shakespeare.lit/firstwitch'
@ -1920,6 +1931,7 @@
to='crone1@shakespeare.lit/desktop'
type='chat'>
<body>I'll give thee a wind.</body>
<x xmlns='http://jabber.org/protocol/muc#user' />
</message>
]]></example>
<p>If the sender attempts to send a private message of type "groupchat" to a particular occupant, the service MUST refuse to deliver the message (since the recipient's client would expect in-room messages to be of type "groupchat") and return a &badrequest; error to the sender:</p>

View File

@ -49,6 +49,12 @@
&stpeter;
&ralphm;
<revision>
<version>1.13.6</version>
<date>2017-06-22</date>
<initials>dg</initials>
<remark><p>Clarify behaviour of publish-options. Fields must be registered</p></remark>
</revision>
<revision>
<version>1.13.5</version>
<date>2016-12-21</date>
@ -2940,11 +2946,11 @@ And by opposing end them?
</pubsub>
</iq>
]]></example>
<p>The &lt;publish-options/&gt; element SHOULD contain a data form (see <cite>XEP-0004</cite>), whose FORM_TYPE SHOULD be "http://jabber.org/protocol/pubsub#publish-options" (see <cite>XEP-0068</cite>).</p>
<p>How the fields are to be handled is up to the the pubsub service, which in the language of XEP-0004 functions as a form-processing entity.</p>
<p>For example, the service may treat the field as a precondition, in which case the service should proceed as follows:</p>
<p>The &lt;publish-options/&gt; element MUST contain a data form (see <cite>XEP-0004</cite>), whose FORM_TYPE MUST be "http://jabber.org/protocol/pubsub#publish-options" (see <cite>XEP-0068</cite>).</p>
<p>Fields and their behaviour MUST be registered with the XMPP Registrar. Each field MUST specify whether it defines METADATA to be attached to the item, a per-item OVERRIDE of the node configuration, or a PRECONDITION to be checked against the node configuration. A pubsub service advertising support for publishing options MUST reject publications with unknown fields.</p>
<p>A field defined as a precondition MUST be processed as follows:</p>
<ol>
<li>If the node exists and the precondition is not met, then the publish shall fail with a &conflict; error condition and a pubsub-specific condition of &lt;precondition-not-met/&gt;.</li>
<li>If the node exists and the precondition is not met, then the publish MUST fail with a &conflict; error condition and a pubsub-specific condition of &lt;precondition-not-met/&gt;.</li>
<li>If the node exists and the precondition is met, then the publish succeeds.</li>
<li>If the node does not exist and the service supports the "auto-create" feature, then the service shall auto-create the node with default configuration in all respects except those specified in the preconditions, and the publish succeeds.</li>
<li>If the node does not exist and the service does not support the "auto-create" feature, then the publish shall fail.</li>

View File

@ -24,6 +24,17 @@
<shortname>NOT_YET_ASSIGNED</shortname>
&stpeter;
&lance;
<revision>
<version>0.18.2</version>
<date>2017-08-23</date>
<initials>editor (jwi)</initials>
<remark><ul>
<li>Fix a date missing its timezone in examples. (egp)</li>
<li>Remove the mention of UTC, timestamps are already properly described in XEP-0082. (egp)</li>
<li>Add missing length attribute to XML schema. (ps)</li>
<li>Fix incorrect XML in examples. (ps)</li>
</ul></remark>
</revision>
<revision>
<version>0.18.1</version>
<date>2017-05-20</date>
@ -327,7 +338,7 @@
<file>
<media-type>text/plain</media-type>
<name>test.txt</name>
<date>2015-07-26T21:46:00</date>
<date>2015-07-26T21:46:00+01:00</date>
<size>6144</size>
<hash xmlns='urn:xmpp:hashes:2'
algo='sha-1'>w0mcJylzCn+AfvuGdqkty2+KP48=</hash>
@ -343,7 +354,7 @@
</tr>
<tr>
<td>date</td>
<td>UTC timestamp specifying the last modified time of the file (which MUST conform to the DateTime profile of &xep0082;).</td>
<td>Timestamp specifying the last modified time of the file (which MUST conform to the DateTime profile of &xep0082;).</td>
<td>OPTIONAL</td>
</tr>
<tr>
@ -750,7 +761,7 @@ a=file-range:<offset>-<(offset + length) | *>]]></code>
<file>
<media-type>text/plain</media-type>
<name>test.txt</name>
<date>2015-07-26T21:46:00</date>
<date>2015-07-26T21:46:00+01:00</date>
<size>6144</size>
<hash xmlns='urn:xmpp:hashes:2'
algo='sha-1'>w0mcJylzCn+AfvuGdqkty2+KP48=</hash>
@ -880,7 +891,7 @@ a=file-range:1024-*]]></code>
<jingle xmlns='urn:xmpp:jingle:1'
action='content-reject'
sid='uj3b2'>
<content creator='initiator' name='requesting-file' senders='initiator'>
<content creator='initiator' name='requesting-file' senders='initiator'/>
<reason>
<failed-application />
<file-not-available xmlns='urn:xmpp:jingle:apps:file-transfer:errors:0' />
@ -904,7 +915,7 @@ a=file-range:1024-*]]></code>
<jingle xmlns='urn:xmpp:jingle:1'
action='content-remove'
sid='uj3b2'>
<content creator='initiator' name='big-file' senders='initiator'>
<content creator='initiator' name='big-file' senders='initiator'/>
<reason>
<media-error />
<file-too-large xmlns='urn:xmpp:jingle:apps:file-transfer:errors:0' />
@ -1054,6 +1065,7 @@ a=file-range:1024-*]]></code>
<xs:complexType name='fileTransferRangeType'>
<xs:attribute name='offset' type='xs:nonNegativeInteger' use='optional' default='0' />
<xs:attribute name='length' type='xs:nonNegativeInteger' use='optional' />
<xs:all xmlns:h='urn:xmpp:hashes:2' minOccurs='0'>
<xs:element ref='h:hash' minOccurs='0' maxOccurs='unbounded' />
</xs:all>
@ -1080,7 +1092,7 @@ a=file-range:1024-*]]></code>
</section1>
<section1 topic='Acknowledgements' anchor='ack'>
<p>Thanks to Diana Cionoiu, Olivier Crête, Viktor Fast, Philipp Hancke, Waqas Hussain, Justin Karneges, Steffen Larsen, Yann Leboulanger, Marcus Lundblad, Robert McQueen, Joe Maissel, Glenn Maynard, Ali Sabil, Sjoerd Simons, Will Thompson, Matthew Wild, and Jiří Zárevúcky for their feedback.</p>
<p>Thanks to Diana Cionoiu, Olivier Crête, Viktor Fast, Philipp Hancke, Waqas Hussain, Justin Karneges, Steffen Larsen, Yann Leboulanger, Marcus Lundblad, Robert McQueen, Joe Maissel, Glenn Maynard, Ali Sabil, Sjoerd Simons, Will Thompson, Matthew Wild, Paul Schaub and Jiří Zárevúcky for their feedback.</p>
</section1>
</xep>

View File

@ -55,16 +55,16 @@
<p>This document addresses the following requirements:</p>
<ol>
<li>Make it possible for remote services or entities to manage user's roster by the same mechanisms that descibed in the &rfc6121;.</li>
<li>Provide a way for user to control which services have permission to manage his roster.</li>
<li>Provide a way for users to control which services have permission to manage their roster.</li>
</ol>
</section1>
<section1 topic='Glossary' anchor='glossary'>
<ul>
<li><strong>Remote entity</strong> — the entity that wants to modify user's roster.</li>
<li><strong>User</strong> — the entity which roster the remote entity wants to have access to.</li>
<li><strong>User's server</strong> — the XMPP server User connected to.</li>
<li><strong>Roster</strong> — the list of User's contacts as defined in the &rfc6121;.</li>
</ul>
<dl>
<di><dt>Remote entity</dt><dd>the entity that wants to modify user's roster.</dd></di>
<di><dt>User</dt><dd>the entity which roster the remote entity wants to have access to.</dd></di>
<di><dt>User's server</dt><dd>the XMPP server User connected to.</dd></di>
<di><dt>Roster</dt><dd>the list of User's contacts as defined in the &rfc6121;.</dd></di>
</dl>
</section1>
<section1 topic='Use Cases' anchor='usecases'>
<section2 topic='Remote entity asks for permission to manage user&apos;s roster' anchor='ask_permission'>
@ -82,7 +82,7 @@
<text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>You must have a presence subscription to be able to request remote roster management service.</text>
</error>
</iq>]]></example>
<p>The user's server SHOULD then generate a form request using &xep0004; to client in order to ask user if he's OK with granting the permission to the remote entity. The "challenge" form field is generated by the server and is used to identify the client's response. The server also MUST immediatly answer to the request IQ.</p>
<p>The user's server SHOULD then generate a form request using &xep0004; to client in order to ask user if they are OK with granting the permission to the remote entity. The "challenge" form field is generated by the server and is used to identify the client's response. The server also MUST immediatly answer to the request IQ.</p>
<p>NOTE: if the entity is already granted with the permission, the server SHOULD immediatly answer with a success response and skip querying the user.</p>
<example caption='Server asks user for the permission'><![CDATA[
<message from='example.com'
@ -220,7 +220,7 @@
<text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>You have tried to modify the item you don't allowed to.</text>
</iq>]]></example>
</section2>
<section2 topic='Client requests list of components with permissions to edit his roster'>
<section2 topic='Client requests list of components with permissions to edit their roster'>
<p>User can ask the server to provide a list of components or servers which have permissions to edit their roster.</p>
<example caption='User asks the server to get list of components which can edit their roster'><![CDATA[
<iq from='juliet@example.com/home' to='icq.example.com' type='get' id='roster_5'>

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,22 @@
<supersededby/>
<shortname>sasl2</shortname>
&dcridland;
<revision>
<version>0.2.0</version>
<date>2017-08-14</date>
<initials>dwd</initials>
<remark>
<p>Updated according to implementation experience:</p>
<ul>
<li>Updated namespace</li>
<li>Continue "mechanisms" are not; changed these to "tasks".</li>
<li>Added stream features after Success.</li>
<li>Don't need complexity of "=" encoding; removed.</li>
<li>Fixed internal links.</li>
<li>Updated examples.</li>
</ul>
</remark>
</revision>
<revision>
<version>0.1.0</version>
<date>2017-03-16</date>
@ -60,28 +76,28 @@
<section1 topic='Overview' anchor="overview">
<section2 topic="Discovering Support" anchor="feature">
<p>Servers capable of SASL2 offer a stream feature of &lt;mechanisms/>, qualified by the "urn:xmpp:sasl:0" namespace. This in turn contains one or more &lt;mechanism/> elements in the same namespace, and potentially other elements (for example, the &lt;hostname/> element defined within XEP-0233).</p>
<p>Servers capable of SASL2 offer a stream feature of &lt;mechanisms/>, qualified by the "urn:xmpp:sasl:1" namespace. This in turn contains one or more &lt;mechanism/> elements in the same namespace, and potentially other elements (for example, the &lt;hostname/> element defined within XEP-0233).</p>
<p>Note that SASL2 is impossible for clients to initiate without at least one mechanism being available, and therefore MUST NOT be offered.</p>
<p>The feature so advertised, and its child content, SHOULD be stable for the given stream to and from attributes and encryption state, and therefore MAY be cached by clients for later connections.</p>
<p>The Service Name used by XMPP is unchanged from RFC 6120.</p>
</section2>
<section2 topic="SASL Data Encoding">
<p>In all cases, both Clients and Servers encode SASL exchanges using Base 64 encoding. This SHOULD NOT include any line wrapping or other whitespace. As the form &lt;element/> is equivalent to &lt;element>&lt;/element>, these both indicate an empty string, which is used to indicate no data (ie, the absence of the data). In order to explicitly transmit a zero-length SASL challenge or response, the sending party sends a single equals sign character ("=").</p>
<p>In all cases, both Clients and Servers encode SASL exchanges using Base 64 encoding. This SHOULD NOT include any line wrapping or other whitespace. As the form &lt;element/> is equivalent to &lt;element>&lt;/element>, these both indicate an empty string. Challenges and responses with no data do not occur in SASL, and so require no special handling. To indicate the absence of an initial response, or the absence of success data, the element is simply not included.</p>
</section2>
<section2 topic="Initiation">
<p>Clients, upon observing this stream feature, initiate the authentication by the use of the &lt;authenticate/> top-level element, within the same namespace. The nature of this element is to inform the server about properties of the final stream state, as well as initiate authentication itself. To achieve the latter, it has a single mandatory attribute of "mechanism", with a string value of a mechanism name offered by the Server in the stream feature, and an optional child element of &lt;initial-response/>, containing a base64-encoded SASL Initial Response.</p>
<p>On subsequent connections, if a Client has previously cache the stream feature, the Client MAY choose to send it before seeing the stream features - sending it "pipelined" with the Stream Open tag for example.</p>
<example caption="An authentication request"><![CDATA[
<authenticate xmlns='urn:xmpp:sasl:0' mechanism="BLURDLYBLOOP">
<initial-response>SW1wcm92ZWQgZW5jYXNwdWxhdGlvbiBvZiBvcHRpb25hbCBTQVNMLUlSIGRhdGE=</initial-response>
<authenticate xmlns='urn:xmpp:sasl:1' mechanism="BLURDLYBLOOP">
<initial-response>Tm9ib2R5IGV2ZXIgZGVjb2RlcyB0aGUgZXhhbXBsZXMu</initial-response>
</authenticate>
]]>
</example>
<p>In order to provide support for other desired stream states beyond authentication, additional child elements are used. For example, a hypothetical XEP-0198 session resumption element might be included, and/or Resource Binding requests.</p>
<example caption="An authentication request with a (hypothetical) bind request"><![CDATA[
<authenticate xmlns='urn:xmpp:sasl:0' mechanism='BLURDYBLOOP'>
<authenticate xmlns='urn:xmpp:sasl:1' mechanism='BLURDYBLOOP'>
<initial-response>
U0FTTC1JUiBlbmNvZGVkIGFsb25nc2lkZSBiaW5kIHJlcXVlc3Q=
SSBzaG91bGQgbWFrZSB0aGlzIGEgY29tcGV0aXRpb24=
</initial-response>
<bind xmlns='urn:xmpp:bind:example'/>
</authenticate>
@ -92,13 +108,13 @@
<p>Server Challenges MAY then be sent. Each Challenge MUST be responded to by a Client in a Client Response. These are not extensible, and contain the corresponding base64 encoded SASL data:</p>
<example caption="A challenge and response exchange"><![CDATA[
<!-- A server might send: -->
<challenge xmlns='urn:xmpp:sasl:0'>
QmFzZSA2NCBlbmNvZGVkIFNBU0wgY2hhbGxlbmdlIGRhdGE=
<challenge xmlns='urn:xmpp:sasl:1'>
U28sIG5leHQgRk9TREVNIC0gMjAxOCwgdGhhdCBpcy4uLg==
</challenge>
<!-- A client might respond: -->
<response xmlns='urn:xmpp:sasl:0'>
QmFzZSA2NCBlbmNvZGVkIFNBU0wgcmVzcG9uc2UgZGF0YQ==
<response xmlns='urn:xmpp:sasl:1'>
Li4uSSdsbCBidXkgYSBiZWVyIGZvciB0aGUgZmlyc3QgcGVyc29uIHdoby4uLg==
</response>
]]>
</example>
@ -112,29 +128,30 @@
<section3 topic="Success">
<p>If the Client is now authenticated, the Server sends a &lt;success/> element, which contains an OPTIONAL &lt;additional-data/> element containing SASL additional data. It also contains a &lt;authorization-identity/> element containing the negotiated identity - this is a bare JID, unless resource binding has occurred, in which case it is a full JID.</p>
<example caption="Successful authentication"><![CDATA[
<success xmlns='urn:xmpp:sasl:0'>
<success xmlns='urn:xmpp:sasl:1'>
<success-data>
T3B0aW9uYWwgQmFzZSA2NCBlbmNvZGVkIFNBU0wgc3VjY2VzcyBkYXRh
ip/AeIOfZXKBV+fW2smE0GUB3I//nnrrLCYkt0Vj
</success-data>
<authorization-identifier>juliet@montague.example/Balcony/a987dsh9a87sdh</authorization-identifier>
</success>
]]></example>
<p>Other extension elements MAY also be contained by the &lt;success/> element.</p>
<example caption="Successful re-authentication and resumption"><![CDATA[
<success xmlns='urn:xmpp:sasl:0'>
<success xmlns='urn:xmpp:sasl:1'>
<additional-data>
T3B0aW9uYWwgQmFzZSA2NCBlbmNvZGVkIFNBU0wgc3VjY2VzcyBkYXRh
SGFkIHlvdSBnb2luZywgdGhlcmUsIGRpZG4ndCBJPw==
</additional-data>
<authorization-identifier>juliet@montague.example/Balcony/a987dsh9a87sdh</authorization-identifier>
<sm:resumed xmlns='urn:xmpp:sm:3:example' h='345' previd='124'/>
</success>
]]></example>
<p>Any security layer negotiated SHALL take effect after the ">" octet of the closing tag (ie, immediately after "&lt;/success>").</p>
<p>Any security layer negotiated SHALL take effect after the ">" octet of the closing tag (ie, immediately after "&lt;/success>"), if it has not already taken effect at a &lt;continue> - see <link url='#continue'>Continue</link> below.</p>
<p>The &lt;success> element is immediately followed by a &lt;features> element containing the applicable stream features of the newly authenticated stream. Note that no stream restart occurs.</p>
</section3>
<section3 topic="Failure">
<p>A &lt;failure/> element is used by the server to terminate the authentication attempt. It MAY contain application-specific error codes, and MAY contain a textual error. It MUST contain one of the SASL error codes from RFC 6120 Section 6.5.</p>
<example caption="Failure"><![CDATA[
<failure xmlns='urn:xmpp:sasl:0'>
<failure xmlns='urn:xmpp:sasl:1'>
<aborted xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>
<optional-application-specific xmlns='urn:something:else'/>
<text>This is a terrible example.</text>
@ -143,25 +160,28 @@
</section3>
<section3 topic="Continue" anchor="continue">
<p>A &lt;continue/> element is used to indicate that while the SASL exchange was successful, it is insufficient to allow authentication at this time.</p>
<p>This can be used to indicate that the Client needs to perform a Second Factor Authentication ("2FA"), or is required to change password. These are conducted as additional SASL mechanisms. Such SASL mechanisms MUST NOT change the authorization identifier, or introduce any security layer. The authorization identifer transmitted during the subsequent &lt;success/>, and any security layer which comes into effect after the eventual &lt;success/>, therefore MUST be that of the first mechanism.</p>
<p>The element contains a &lt;mechanisms/> element, as defined above as a stream feature, containing suitable mechanisms. It MAY contain an &lt;additional-data/> element, as the &lt;success/> element does.</p>
<p>This can be used to indicate that the Client needs to perform a Second Factor Authentication ("2FA"), or is required to change password.</p>
<p>Such tasks are presented within a &lt;tasks> element, which contains a sequence of &lt;task> elements, each containing a name. These tasks are analogous to a SASL mechanism, but have a number of differences - they may never attempt to negotiate a new authorization identifier, nor a new security layer.</p>
<p>A client MAY choose any one of the offered tasks; if multiple are required a sequence of &lt;continue> exchanges will occur until all mandatory tasks are complete.</p>
<p>The &lt;continue element therefore always contains a &lt;tasks/> element, as defined above. It MAY contain an &lt;additional-data/> element, as the &lt;success/> element does.</p>
<p>Finally, it MAY contain a &lt;text/> element, which can contain human-readable data explaining the nature of the step required.</p>
<example caption="Continue Required"><![CDATA[
<continue xmlns='urn:xmpp:sasl:0'>
<continue xmlns='urn:xmpp:sasl:1'>
<additional-data>
T3B0aW9uYWwgQmFzZSA2NCBlbmNvZGVkIFNBU0wgc3VjY2VzcyBkYXRh
SSdtIGJvcmVkIG5vdy4=
</additional-data>
<mechanisms>
<mechanism>HOTP-EXAMPLE</mechanism>
<mechanism>TOTP-EXAMPLE</mechanism>
<mechanisms>
<tasks>
<task>HOTP-EXAMPLE</task>
<task>TOTP-EXAMPLE</task>
<tasks>
<text>This account requires 2FA</text>
</continue>
]]></example>
<p>Clients respond with a &lt;next-authenticate/> element, which has a single mandatory attribute of "mechanism", containing the selected mechanism name, and contains an OPTIONAL base64 encoded initial response.</p>
<p>After the final octet of the first &lt;continue> element, any SASL security layer negotiated in the preceding exchange SHALL be immediately in effect.</p>
<p>Clients respond with a &lt;next/> element, which has a single mandatory attribute of "task", containing the selected task name, and contains an OPTIONAL base64 encoded initial response.</p>
<example caption="Client Continues"><![CDATA[
<next-authenticate xmlns='urn:xmpp:sasl' mechanism='TOTP-EXAMPLE'>
MkZBIG9yIHBhc3N3b3JkIGNoYW5nZSBvciBzb21ldGhpbmc=
<next xmlns='urn:xmpp:sasl:1' task='TOTP-EXAMPLE'>
SSd2ZSBydW4gb3V0IG9mIGlkZWFzIGhlcmUu
</next-authenticate>
]]></example>
</section3>
@ -169,46 +189,48 @@
</section1>
<section1 topic="SASL Profile Definition">
<p>This provides pointers and/or clarifications to the <link url="#overview"/> in the order and manner defined in RFC 4422, section 4.</p>
<p>This provides pointers and/or clarifications to the <link url="#overview">Overview</link> in the order and manner defined in RFC 4422, section 4.</p>
<section2 topic="Service Name">
<p>The service name SHALL be "xmpp", as defined by RFC 6120.</p>
</section2>
<section2 topic="Mechanism negotiation">
<p>Servers list mechanisms during stream features (See <link url="#features"/>) and within the &lt;continue/> element (See <link url="#continue"/>).</p>
<p>TODO: Neither this specification nor RFC 6120 allow clients access to the mechanism list after SASL negotiation...?</p>
<p>Servers list mechanisms during stream features (See <link url="#features">Discovering Support</link>).</p>
</section2>
<section2 topic="Message Definitions">
<section3 topic="Initiation">
<p>Clients initiate using the &lt;authenticate/> top level element (See <link url="#auth"/>, and after any &lt;continue/> with the &lt;next-authenticate/> message (See <link url="#continue"/>).</p>
<p>Clients initiate using the &lt;authenticate/> top level element (See <link url="#auth">Initiation</link>.</p>
</section3>
<section3 topic="Server Challenges and Client Responses">
<p>See <link url="#challenge"/>.</p>
<p>See <link url="#challenge">Challenges and Responses</link>.</p>
</section3>
<section3 topic="Outcome">
<p>See <link url="#outcome"/>.</p>
<p>See <link url="#outcome">Completing Authentication</link>.</p>
</section3>
</section2>
<section2 topic="Non-Empty Authorization Strings">
<p>If a Client specifies an authorization string which is non-empty, the identifier is normalized by treating it as a JID, and performing normalization as described in RFC 7622.</p>
<p>In general, implementors are advised that a non-empty authorization string MAY be considered an error if the stream's from attribute (if present) does not match.</p>
</section2>
<section2 topic="Aborting">
<p>Clients MAY abort unilaterally by sending &lt;abort/> as specified in <link url="#abort"/>.</p>
<p>Servers MAY abort unliterally by sending &lt;failure/> with the &lt;aborted/> error code as defined in <link url="#failure"/>.</p>
<p>Clients MAY abort unilaterally by sending &lt;abort/> as specified in <link url="#abort">Client Aborts</link>.</p>
<p>Servers MAY abort unliterally by sending &lt;failure/> with the &lt;aborted/> error code as defined in <link url="#failure">Failure</link>.</p>
</section2>
<section2 topic="Security Layer Effect">
<p>See <link url="#success"/>.</p>
<p>Security Layers take effect after the SASL mechanism itself (ie, the first negotiation) has completed successfully, after the final octet of the server's &lt;success> or &lt;continue>. See <link url="#success">Success</link> and <link url="#continue">Continue</link>.</p>
</section2>
<section2 topic="Security Layer Order">
<p>Option (a) is used - any SASL Security Layer is applied first to data being sent, and TLS applied last.</p>
</section2>
<section2 topic="Multiple Authentication">
<p>Although the &lt;continue/> concept does use multiple SASL sequences, only the first SASL mechanism used is considered an authentication, and only the first can negotiate a security layer.</p>
<p>Although the &lt;continue/> concept does use tasks analogous to multiple SASL sequences, only the first SASL mechanism used is considered an authentication, and only the first can negotiate a security layer.</p>
<p>In particular, once &lt;success/> has been sent by the server, any further &lt;authenticate/> element MUST result in a stream error.</p>
</section2>
</section1>
<section1 topic='Security Considerations' anchor='security'>
<p>Relative to the SASL profile documented in RFC 6120, this introduces more data unprotected by any security layer negotiated by SASL itself.</p>
<p>While no actual exchanges are introduced that are unprotected, the nature of this exchange might allow for (for example) a resource binding extension to be introduced.</p>
<p>SASL security layers are sparingly used in the field, however., so this is thought to be a theoretical, rather than practical, concern.</p>
</section1>
<section1 topic='IANA Considerations' anchor='iana'>

View File

@ -20,6 +20,8 @@
<!ENTITY procents "<em>Processing Entities</em>">
<!ENTITY genent "<em>Generating Entity</em>">
<!ENTITY genents "<em>Generating Entities</em>">
<!ENTITY queryintercept "<em>Query Interception</em>">
<!ENTITY gratcaps "<em>Gratuitous Capabilities</em>">
<!ENTITY mlwaqas1 "<note>org.jabber.security Mailing List Archive: '[Security] Trivial preimage attack against the entity capabilities protocol)' from 2009-07-22, &lt;<link url='https://mail.jabber.org/pipermail/security/2009-July/000812.html'>https://mail.jabber.org/pipermail/security/2009-July/000812.html</link>&gt;.</note>">
<!ENTITY capsdb "<span class='ref'><link url='https://github.com/xnyhps/capsdb/'>capsdb</link></span> <note><link url='https://github.com/xnyhps/capsdb/'>https://github.com/xnyhps/capsdb/</link></note>">
]>
@ -51,6 +53,18 @@
<email>jonas@wielicki.name</email>
<jid>jonas@wielicki.name</jid>
</author>
<revision>
<version>0.2</version>
<date>2017-06-14</date>
<initials>jwi</initials>
<remark>
<ul>
<li>Clearly specify handling of xml:lang attributes.</li>
<li>Add Query Interception.</li>
<li>Add Gratuitous Caps.</li>
</ul>
</remark>
</revision>
<revision>
<version>0.1</version>
<date>2017-03-23</date>
@ -85,11 +99,12 @@
<li>The bandwidth consumption should be as minimal as possible, while reusing existing specifications.</li>
<li>It must be possible to write &xep0045; and &xep0369; implementations which can forward this protocol with negligible extra work.</li>
<li>Entities must be able to update their published information arbitrarily often in a single presence session.</li>
<li>Server infrastructure beyond <cite>XMPP Core</cite> and <cite>XMPP IM</cite> must not be required for this to work.</li>
<li>Server infrastructure beyond <cite>XMPP Core</cite> and <cite>XMPP IM</cite> must not be required for this to work (but may be beneficial).</li>
<li>Entities must be able to be confident that the information obtained from the broadcast is equivalent to the information which would be obtained from querying the generating entity directly at the time the broadcast was generated.</li>
<li>The protocol must be able to coexist (but not necessarily exchange information) with &xep0115;.</li>
<li>No special XML features beyond what is needed to implement <cite>XMPP Core</cite> itself should be required.</li>
<li>Obsoletion of hash functions should not need a new version of the specification.</li>
<li>Support for pushing Entity Capabilities to the clients server without sending presence.</li>
</ol>
</section1>
@ -101,6 +116,8 @@
<di><dt>Capability Hash Set</dt><dd>A set of &hashes; which cover the same <cite>XEP-0030</cite> response, possibly in the form of a &lt;c/&gt; element with &xep0300; &lt;hash/&gt; children.</dd></di>
<di><dt>Generating Entity</dt><dd>An entity which emits a &hashset; to other entities.</dd></di>
<di><dt>Processing Entity</dt><dd>An entity which receives and processes a &hashset; from a &genent;.</dd></di>
<di><dt>Query Interception</dt><dd>Server-side processing of disco#info queries directed to a resource based on the &hashsets; published by that resource.</dd></di>
<di><dt>Gratuitous Capabilities</dt><dd>The sending of a &hashset; to a server before initial presence has been sent and without being asked by the server.</dd></di>
</dl>
</section1>
@ -109,7 +126,11 @@
<section2 topic='Hash Function Input' anchor='algorithm-input'>
<p>The input to this algorithm is a &xep0030; disco#info &lt;query/&gt; response. The output is an octet string which can be used as input to a hash function or an error.</p>
<p>General remarks: The algorithm strongly distinguishes between character data (sequences of Unicode code points) and octet strings (sequences of 8-bit bytes). Whenever character data is encoded to octet strings in the following algorithm, the UTF-8 encoding as specified in &rfc3629; is used. Whenever octet strings are sorted in the following algorithm, the i;octet collation as specified in &rfc4790; is used.</p>
<div class="box"><p>General remarks:</p>
<ul>
<li><p>The algorithm strongly distinguishes between character data (sequences of Unicode code points) and octet strings (sequences of 8-bit bytes). Whenever character data is encoded to octet strings in the following algorithm, the UTF-8 as specified in &rfc3629; encoding is used. Whenever octet strings are sorted in the following algorithm, the i;octet collation as specified in &rfc4790; is used.</p></li>
<li><p>The algorithm uses the <tt>xml:lang</tt> attribute. Implementations must take implicit values for the <tt>xml:lang</tt> attribute into account, for example those inherited from the disco#info or the IQ element.</p></li>
</ul></div>
<ol>
<li>If the &lt;query/&gt; element contains any elements except &lt;identity/&gt;, &lt;feature/&gt; (both from the &xep0030; disco#info namespace) or &xep0128; data forms, abort with an error.</li>
<li>If any &xep0128; &lt;x/&gt; element contains a data form which contains a &lt;reported/&gt; or &lt;item/&gt; element, abort with an error.</li>
@ -714,6 +735,44 @@ cDp0aW1lHxw=</code>
</iq>
]]></example>
</section2>
<section2 topic='Gratuitous Capabilities' anchor='usecases-gratuitous'>
<p>A server MAY support pushing of &hashes; from clients before sending initial presence. This allows servers to discover capabilities of clients before those have sent initial presence, which may be useful or important for some protocols (such as &xep0369;). This feature is called &gratcaps;.</p>
<p>To advertise support, the server publishes the <tt>urn:xmpp:caps:gratuitous</tt> feature:</p>
<example caption='Response to a disco#info request if the server supports Gratuitous Capabilities'><![CDATA[
<iq from='montague.lit'
id='disco3'
to='romeo@montague.lit/chamber'
type='result'>
<query xmlns='http://jabber.org/protocol/disco#info'>
...
<feature var='urn:xmpp:caps'/>
<feature var='urn:xmpp:caps:gratuitous'/>
...
</query>
</iq>
]]></example>
<p>After determining server support, a client can send &hashes; via &gratcaps; before sending initial presence:</p>
<example caption='Sending Gratuitous Capabilities'><![CDATA[
<iq from='romeo@montague.lit/chamber'
to='montague.lit'
id='grat1'
type='set'>
<c xmlns="urn:xmpp:caps">
<hash xmlns="urn:xmpp:hashes:2" algo="sha-256">u79ZroNJbdSWhdSp311mddz44oHHPsEBntQ5b1jqBSY=</hash>
<hash xmlns="urn:xmpp:hashes:2" algo="sha3-256">XpUJzLAc93258sMECZ3FJpebkzuyNXDzRNwQog8eycg=</hash>
</c>
</iq>
<iq from='montague.lit'
to='romeo@montague.lit/chamber'
id='grat1'
type='result'>
</iq>
]]></example>
<p>The server replies with an empty result on success.</p>
<p>The server MUST NOT broadcast the &hashes; submitted via &gratcaps; using presence.</p>
<p>Clients SHOULD NOT send &gratcaps; after they have sent initial presence; instead, they SHOULD re-send presence to update the &hashes;. Otherwise, entities subscribed to the presence will not receive the updated &hashes;.</p>
</section2>
</section1>
<section1 topic='Business Rules' anchor='rules'>
@ -721,7 +780,8 @@ cDp0aW1lHxw=</code>
<ul>
<li>Entities MUST respond to disco#info queries for all &hashnodes; of at least the most recent 3 &hashsets; emitted.</li>
<li>Entities MUST broadcast the &hashset; of the current disco#info it publishes in every non-directed "available" &lt;presence/&gt; they send and SHOULD do so for directed "available" &lt;presence/&gt;.</li>
<li>Entities MUST re-broadcast the &hashset; after their disco#info response changes, but MAY limit the rate at which presences are emitted solely for the purpose of sending new &hashsets;.</li>
<li>After initial presence has been sent, entities MUST re-broadcast the &hashset; after their disco#info response changes, but MAY limit the rate at which presences are emitted solely for the purpose of sending new &hashsets;.</li>
<li>Before initial presence has been sent and if the server supports &gratcaps;, entities SHOULD send &gratcaps; after their disco#info response changes, but MAY limit the rate at which &gratcaps; are sent. (For example, a client may load and enable additional functionality (thus changing its features) based on server support and only send &gratcaps; once all functionality has been set up, not after each individual feature.)</li>
<li>Entities MAY assume that another entity supports &caps; after receiving a &hashset; from that entity.</li>
<li>Entities MAY also send &xep0115; capabilities to support legacy entities.</li>
</ul>
@ -739,6 +799,7 @@ cDp0aW1lHxw=</code>
<p>Instead of issuing a &xep0030; disco#info &lt;query/&gt; with absent 'node' attribute to a target entity, an entity MAY use a &hashcache; to obtain the response. To look up the disco#info response in the &hashcache;, an entity MUST use a hash from the &hashset; which was most recently received from the entity to which the &lt;query/&gt; would have been sent otherwise. If none of the most recently received &hashes; are found in the &hashcache;, the entity MUST fall back to sending the request.</p>
<p>An entity MUST NOT use &hashes; which were not included in the most recent &hashset; received from the target entity.</p>
<p>An entity MAY use external data sources to fill the &hashcache;.</p>
<p>An entity MUST ensure that implicit values for <tt>xml:lang</tt> attributes is preserved when disco#info data is cached. This can for example happen by making the implicit values explicit in the storage.</p>
</section3>
</section2>
@ -751,6 +812,17 @@ cDp0aW1lHxw=</code>
<li>Servers MAY answer disco#info requests for &hashnodes; on behalf of their and others clients if the disco#info response belonging to that &hash; is known to them.</li>
</ul>
</section2>
<section2 topic='Query Interception' anchor='rules-servers'>
<p>Servers MAY implement &queryintercept; to further optimise bandwidth consumption. The idea is that servers intercept &xep0030; disco#info queries sent to clients if they already know the answer from &hashes; published by the client. The rules for &queryintercept; are the following (to be applied in this order):</p>
<ul>
<li>Servers MUST NOT intercept disco#info queries except those with empty <tt>node</tt> or a <tt>node</tt> which refers to a &hashnode; known to the server.</li>
<li>Servers MUST NOT intercept disco#info queries on behalf of the resource unless the query would be forwarded to the resource otherwise.</li>
<li>Servers MUST NOT intercept disco#info queries to resources which do not support &caps; (clients not implementing &caps; may legitimately use disco#info nodes matching the format of &hashnodes; for different purposes).</li>
<li>Servers SHOULD intercept disco#info queries with empty <tt>node</tt> and answer them with the disco#info of the most recent &hashset; published by the client.</li>
<li>Servers SHOULD intercept disco#info queries a valid &hashnode; <tt>node</tt>, if the server knows the disco#info for the &hashnode;. Otherwise, the query MUST be forwarded to the addressed resource. Note that it is valid for a sevrer to reply for &hashnodes; which have not been published by the resource.</li>
</ul>
</section2>
</section1>
<section1 topic='Implementation Notes' anchor='impl'>
@ -773,11 +845,26 @@ cDp0aW1lHxw=</code>
<p>This was an issue with &xep0115; and has been addressed with a new algorithm for generating the hash function input which keeps the structural information of the disco#info input.</p>
<p>An entity MUST NOT ever use disco#info which has not been verified to belong to a &hash; obtained from a cache using that &hash;. Using cache contents from a trusted source (at the discretion of the entity) counts as verifying.</p>
<p>A malicious entity could send a large amount of &hashsets; in short intervals, while making sure that it provides matching disco#info responses. If a &procent; uses caching, this can overflow or thrash the caches. &procents; should be aware of this risk and apply proper rate-limiting for processing &hashsets;. To reduce the attack surface, an entity MAY choose to not cache &hashes; obtained from entities not in its roster.</p>
<p>As mentioned earlier, when storing disco#info data in a cache for later retrieval, implementations MUST ensure that implicit values for <tt>xml:lang</tt> attributes are reconstructed correctly when the disco#info is restored.</p>
</section2>
<section2 topic='Directed Presence' anchor='security-directed-presence'>
<p>Entities MAY choose to not send &hashsets; with directed presence (for example to increase privacy). In that case, entities SHOULD also refuse direct &xep0030; queries.</p>
</section2>
<section2 topic='Query Interception' anchor='security-query-interception'>
<p>The server replies to certain disco#info queries on behalf of the client. This means that the client has no choice on to whom they reply. Otherwise, a client could choose to reply with <tt>&lt;service-unavailable/&gt;</tt> to mask its existence. We consider two effects of this:</p>
<ul>
<li>
<p>A remote entity could attempt to detect that an entity exists behind a resource. For this, they send a disco#info query to the resource since nearly everyone implements disco#info. As the client responds with <tt>&lt;service-unavailable/&gt;</tt>, it looks as if no client was present at this resource.</p>
<p>With &queryintercept;, the server would reply on behalf of the client. However, the consensus in the community is that by measuring the difference between the reply from the server of the resource and the reply from the actual resource, it would generally be possible to detect the existence of a resource.</p>
</li>
<li>
<p>A remote entity can obtain the disco#info information of any resource which supports &caps; and of which the entity knows the resource.</p>
<p>This cannot be mitigated with &queryintercept;. The risk is deemed acceptable considering that resources should generally be chosen randomly.</p>
</li>
</ul>
</section2>
</section1>
<section1 topic='Design Considerations' anchor='design'>
@ -871,7 +958,7 @@ cDp0aW1lHxw=</code>
<p>Thanks to the authors of &xep0115; for coming up with the original idea of using presence broadcast to convey service discovery information, as well as the optimization strategies.</p>
<p>The note below the example in <link url='#usecases-stream-feature'>Advertisement of Support and Capabilities by Servers</link> has been copied verbatimly from <cite>XEP-0115</cite>.</p>
<p>Thanks to Waqas Hussain for originally (to my knowledge) pointing out the security flaws in <cite>XEP-0115</cite> (see &mlwaqas1;).</p>
<p>Thanks to Georg Lukas, Link Mauve, Sebastian Riese, Florian Schmaus and Sam Whithed for their input, editorial and otherwise.</p>
<p>Thanks to Dave Cridland, Georg Lukas, Link Mauve, Sebastian Riese, Florian Schmaus and Sam Whited for their input, editorial and otherwise.</p>
</section1>
</xep>

View File

@ -40,6 +40,7 @@ OR OTHER DEALINGS IN THE SOFTWARE.
<html>
<head>
<title>XEP-<xsl:value-of select='/xep/header/number'/>:<xsl:text> </xsl:text><xsl:value-of select='/xep/header/title' /></title>
<base><xsl:attribute name='href'><xsl:value-of select='$htmlbase'/></xsl:attribute></base>
<link rel='stylesheet' type='text/css' href='xmpp.css' />
<link href="prettify.css" type="text/css" rel="stylesheet" />
<link rel='shortcut icon' type='image/x-icon' href='/favicon.ico' />