diff options
Diffstat (limited to 'spec/scansion')
30 files changed, 2304 insertions, 45 deletions
diff --git a/spec/scansion/basic_message.scs b/spec/scansion/basic_message.scs index fb21c465..1258dbf5 100644 --- a/spec/scansion/basic_message.scs +++ b/spec/scansion/basic_message.scs @@ -79,7 +79,7 @@ Juliet's phone receives: <message from="${Romeo's full JID}" type="chat"> <body>Hello Juliet, are you there?</body> <delay xmlns='urn:xmpp:delay' from='localhost' stamp='{scansion:any}' /> - </message> + </message> # Romeo sends another bare-JID message, it should be delivered # instantly to Juliet's phone @@ -92,7 +92,7 @@ Romeo sends: Juliet's phone receives: <message from="${Romeo's full JID}" type="chat"> <body>Oh, hi!</body> - </message> + </message> # Juliet's laptop goes online, but with a negative priority @@ -122,7 +122,7 @@ Romeo sends: Juliet's phone receives: <message from="${Romeo's full JID}" type="chat"> <body>How are you?</body> - </message> + </message> # Romeo sends direct to Juliet's full JID, and she should receive it diff --git a/spec/scansion/blocking.scs b/spec/scansion/blocking.scs index 6a9f199e..5bb5a41b 100644 --- a/spec/scansion/blocking.scs +++ b/spec/scansion/blocking.scs @@ -145,16 +145,16 @@ Juliet receives: </message> # Bye -Juliet disconnects - Juliet sends: <presence type="unavailable"/> +Juliet disconnects + Romeo receives: <presence from="${Juliet's full JID}" to="${Romeo's JID}" type="unavailable"/> -Romeo disconnects - Romeo sends: <presence type="unavailable"/> +Romeo disconnects + diff --git a/spec/scansion/extdisco.scs b/spec/scansion/extdisco.scs new file mode 100644 index 00000000..fd73c9da --- /dev/null +++ b/spec/scansion/extdisco.scs @@ -0,0 +1,57 @@ +# XEP-0215: External Service Discovery + +[Client] Romeo + password: password + jid: user@localhost/mFquWxSr + +----- + +Romeo connects + +Romeo sends: + <iq type='get' xml:lang='sv' id='lx2' to='localhost'> + <services xmlns='urn:xmpp:extdisco:2'/> + </iq> + +Romeo receives: + <iq type='result' id='lx2' from='localhost'> + <services xmlns='urn:xmpp:extdisco:2'> + <service host='default.example' transport='udp' port='9876' type='stun'/> + <service port='9876' type='turn' restricted='1' password='yHYYBDN7M3mdlug0LTdJbW0GvvQ=' transport='udp' host='default.example' username='1219525744'/> + <service port='9876' type='turn' restricted='1' password='1Uc6QfrDhIlbK97rGCUQ/cUICxs=' transport='udp' host='default.example' username='1219525744'/> + <service port='2121' type='ftp' restricted='1' password='password' transport='tcp' host='default.example' username='john'/> + <service port='21' type='ftp' restricted='1' password='password' transport='tcp' host='ftp.example.com' username='john'/> + </services> + </iq> + +Romeo sends: + <iq type='get' xml:lang='sv' id='lx3' to='localhost'> + <services xmlns='urn:xmpp:extdisco:2' type='ftp'/> + </iq> + +Romeo receives: + <iq type='result' id='lx3' from='localhost'> + <services xmlns='urn:xmpp:extdisco:2'> + <service port='2121' type='ftp' restricted='1' password='password' transport='tcp' host='default.example' username='john'/> + <service port='21' type='ftp' restricted='1' password='password' transport='tcp' host='ftp.example.com' username='john'/> + </services> + </iq> + +Romeo sends: + <iq type='get' xml:lang='sv' id='lx4' to='localhost'> + <credentials xmlns='urn:xmpp:extdisco:2'> + <service host='default.example' type='turn'/> + </credentials> + </iq> + +Romeo receives: + <iq type='result' id='lx4' from='localhost'> + <credentials xmlns='urn:xmpp:extdisco:2'> + <service port='9876' type='turn' restricted='1' password='yHYYBDN7M3mdlug0LTdJbW0GvvQ=' transport='udp' host='default.example' username='1219525744'/> + <service port='9876' type='turn' restricted='1' password='1Uc6QfrDhIlbK97rGCUQ/cUICxs=' transport='udp' host='default.example' username='1219525744'/> + </credentials> + </iq> + +Romeo disconnects + +# recording ended on 2020-07-18T16:47:57Z diff --git a/spec/scansion/http_upload.scs b/spec/scansion/http_upload.scs new file mode 100644 index 00000000..b3031bac --- /dev/null +++ b/spec/scansion/http_upload.scs @@ -0,0 +1,83 @@ +# XEP-0363 HTTP Upload with mod_http_file_share + +[Client] Romeo + password: password + jid: filesharingenthusiast@localhost/krxLaE3s + +----- + +Romeo connects + +Romeo sends: + <iq to='upload.localhost' type='get' id='932c02fe-4461-4ad4-9c85-54863294b4dc' xml:lang='en'> + <request content-type='text/plain' filename='verysmall.dat' xmlns='urn:xmpp:http:upload:0' size='5'/> + </iq> + +Romeo receives: + <iq id='932c02fe-4461-4ad4-9c85-54863294b4dc' from='upload.localhost' type='result'> + <slot xmlns='urn:xmpp:http:upload:0'> + <get url='{scansion:any}'/> + <put url='{scansion:any}'> + <header name='Authorization'></header> + </put> + </slot> + </iq> + +Romeo sends: + <iq to='upload.localhost' type='get' id='46ca64f3-518e-42bd-8e2f-4ab2f6d2224f' xml:lang='en'> + <request content-type='text/plain' filename='toolarge.dat' xmlns='urn:xmpp:http:upload:0' size='10000000000'/> + </iq> + +Romeo receives: + <iq id='46ca64f3-518e-42bd-8e2f-4ab2f6d2224f' from='upload.localhost' type='error'> + <error type='modify'> + <not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> + <text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>File too large</text> + <file-too-large xmlns='urn:xmpp:http:upload:0'> + <max-file-size>10000000</max-file-size> + </file-too-large> + </error> + </iq> + +Romeo sends: + <iq to='upload.localhost' type='get' id='497c20dd-dda2-4feb-8199-7086e203de46' xml:lang='en'> + <request content-type='text/plain' filename='negative.dat' xmlns='urn:xmpp:http:upload:0' size='-1000'/> + </iq> + +Romeo receives: + <iq id='497c20dd-dda2-4feb-8199-7086e203de46' from='upload.localhost' type='error'> + <error type='modify'> + <bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> + <text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>File size must be positive integer</text> + </error> + </iq> + +Romeo sends: + <iq to='upload.localhost' type='get' id='ac56d83f-a627-4732-8399-60492d1210b6' xml:lang='en'> + <request content-type='text/plain' filename='invalid/filename.dat' xmlns='urn:xmpp:http:upload:0' size='1000'/> + </iq> + +Romeo receives: + <iq id='ac56d83f-a627-4732-8399-60492d1210b6' from='upload.localhost' type='error'> + <error type='modify'> + <bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> + <text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>Invalid filename</text> + </error> + </iq> + +Romeo sends: + <iq to='upload.localhost' type='get' id='1401d3b5-7973-486f-85b3-3e63d13c7f0e' xml:lang='en'> + <request content-type='application/x-executable' filename='evil.exe' xmlns='urn:xmpp:http:upload:0' size='1000'/> + </iq> + +Romeo receives: + <iq id='1401d3b5-7973-486f-85b3-3e63d13c7f0e' from='upload.localhost' type='error'> + <error type='modify'> + <not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> + <text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>File type not allowed</text> + </error> + </iq> + +Romeo disconnects + +# recording ended on 2021-01-27T22:10:46Z diff --git a/spec/scansion/keep_full_sub_req.scs b/spec/scansion/keep_full_sub_req.scs new file mode 100644 index 00000000..41ffec0d --- /dev/null +++ b/spec/scansion/keep_full_sub_req.scs @@ -0,0 +1,58 @@ +# server MUST keep a record of the complete presence stanza comprising the subscription request (#689) + +[Client] Alice + jid: pars-a@localhost + password: password + +[Client] Bob + jid: pars-b@localhost + password: password + +[Client] Bob's phone + jid: pars-b@localhost/phone + password: password + +--------- + +Alice connects + +Alice sends: + <presence to="${Bob's JID}" type="subscribe"> + <preauth xmlns="urn:xmpp:pars:0" token="1tMFqYDdKhfe2pwp" /> + </presence> + +Alice disconnects + +Bob connects + +Bob sends: + <presence/> + +Bob receives: + <presence from="${Bob's full JID}"/> + +Bob receives: + <presence from="${Alice's JID}" type="subscribe"> + <preauth xmlns="urn:xmpp:pars:0" token="1tMFqYDdKhfe2pwp" /> + </presence> + +Bob disconnects + +# Works if they reconnect too + +Bob's phone connects + +Bob's phone sends: + <presence/> + +Bob's phone receives: + <presence from="${Bob's phone's full JID}"/> + + +Bob's phone receives: + <presence from="${Alice's JID}" type="subscribe"> + <preauth xmlns="urn:xmpp:pars:0" token="1tMFqYDdKhfe2pwp" /> + </presence> + +Bob's phone disconnects + diff --git a/spec/scansion/lastactivity.scs b/spec/scansion/lastactivity.scs new file mode 100644 index 00000000..44f4e516 --- /dev/null +++ b/spec/scansion/lastactivity.scs @@ -0,0 +1,45 @@ +# XEP-0012: Last Activity / mod_lastactivity + +[Client] Romeo + jid: romeo@localhost + password: password + +----- + +Romeo connects + +Romeo sends: + <presence> + <status>Hello</status> + </presence> + +Romeo receives: + <presence from="${Romeo's full JID}"> + <status>Hello</status> + </presence> + +Romeo sends: + <presence type="unavailable"> + <status>Goodbye</status> + </presence> + +Romeo receives: + <presence from="${Romeo's full JID}" type="unavailable"> + <status>Goodbye</status> + </presence> + +# mod_lastlog saves time + status message from the last unavailable presence + +Romeo sends: + <iq id='a' type='get'> + <query xmlns='jabber:iq:last'/> + </iq> + +Romeo receives: + <iq type='result' id='a'> + <query xmlns='jabber:iq:last' seconds='0'>Goodbye</query> + </iq> + +Romeo disconnects + +# recording ended on 2020-04-20T14:39:47Z diff --git a/spec/scansion/mam_extended.scs b/spec/scansion/mam_extended.scs new file mode 100644 index 00000000..2c6840df --- /dev/null +++ b/spec/scansion/mam_extended.scs @@ -0,0 +1,126 @@ +# MAM 0.7.x Extended features + +[Client] Romeo + jid: extmamtester@localhost + password: password + +--------- + +Romeo connects + +# Enable MAM so we can save some messages +Romeo sends: + <iq type="set" id="enablemam"> + <prefs xmlns="urn:xmpp:mam:2" default="always"> + <always/> + <never/> + </prefs> + </iq> + +Romeo receives: + <iq type="result" id="enablemam"> + <prefs xmlns="urn:xmpp:mam:2" default="always"> + <always/> + <never/> + </prefs> + </iq> + +# Some messages to look for later +Romeo sends: + <message to="someone@localhost" type="chat" id="chat01"> + <body>Hello</body> + </message> + +Romeo sends: + <message to="someone@localhost" type="chat" id="chat02"> + <body>U there?</body> + </message> + +# Metadata +Romeo sends: + <iq type="get" id="mamextmeta"> + <metadata xmlns="urn:xmpp:mam:2"/> + </iq> + +Romeo receives: + <iq type="result" id="mamextmeta"> + <metadata xmlns="urn:xmpp:mam:2"> + <start timestamp="2008-08-22T21:09:04Z" xmlns="urn:xmpp:mam:2" id="{scansion:any}"/> + <end timestamp="2008-08-22T21:09:04Z" xmlns="urn:xmpp:mam:2" id="{scansion:any}"/> + </metadata> + </iq> + +Romeo sends: + <iq type="set" id="mamquery1"> + <query xmlns="urn:xmpp:mam:2" queryid="q1"/> + </iq> + +Romeo receives: + <message to="${Romeo's full JID}"> + <result xmlns="urn:xmpp:mam:2" queryid="q1" id="{scansion:any}"> + <forwarded xmlns="urn:xmpp:forward:0"> + <delay stamp="2008-08-22T21:09:04Z" xmlns="urn:xmpp:delay"/> + <message to="someone@localhost" xmlns="jabber:client" type="chat" xml:lang="en" id="chat01" from="${Romeo's full JID}"> + <body>Hello</body> + </message> + </forwarded> + </result> + </message> + +Romeo receives: + <message to="${Romeo's full JID}"> + <result xmlns="urn:xmpp:mam:2" queryid="q1" id="{scansion:any}"> + <forwarded xmlns="urn:xmpp:forward:0"> + <delay stamp="2008-08-22T21:09:04Z" xmlns="urn:xmpp:delay"/> + <message to="someone@localhost" xmlns="jabber:client" type="chat" xml:lang="en" id="chat02" from="${Romeo's full JID}"> + <body>U there?</body> + </message> + </forwarded> + </result> + </message> + +# FIXME unstable tag order from util.rsm +Romeo receives: + <iq type="result" id="mamquery1" to="${Romeo's full JID}"> + <fin xmlns="urn:xmpp:mam:2" complete="true" scansion:strict="false"> + </fin> + </iq> + +# Get results in reverse order +Romeo sends: + <iq type="set" id="mamquery2"> + <query xmlns="urn:xmpp:mam:2" queryid="q1"> + <flip-page/> + </query> + </iq> + +Romeo receives: + <message to="${Romeo's full JID}"> + <result xmlns="urn:xmpp:mam:2" queryid="q1" id="{scansion:any}"> + <forwarded xmlns="urn:xmpp:forward:0"> + <delay stamp="2008-08-22T21:09:04Z" xmlns="urn:xmpp:delay"/> + <message to="someone@localhost" xmlns="jabber:client" type="chat" xml:lang="en" id="chat02" from="${Romeo's full JID}"> + <body>U there?</body> + </message> + </forwarded> + </result> + </message> + +Romeo receives: + <message to="${Romeo's full JID}"> + <result xmlns="urn:xmpp:mam:2" queryid="q1" id="{scansion:any}"> + <forwarded xmlns="urn:xmpp:forward:0"> + <delay stamp="2008-08-22T21:09:04Z" xmlns="urn:xmpp:delay"/> + <message to="someone@localhost" xmlns="jabber:client" type="chat" xml:lang="en" id="chat01" from="${Romeo's full JID}"> + <body>Hello</body> + </message> + </forwarded> + </result> + </message> + +# FIXME unstable tag order from util.rsm +Romeo receives: + <iq type="result" id="mamquery2" to="${Romeo's full JID}"> + <fin xmlns="urn:xmpp:mam:2" complete="true" scansion:strict="false"> + </fin> + </iq> diff --git a/spec/scansion/mam_prefs_prep.scs b/spec/scansion/mam_prefs_prep.scs index 9589ec65..1175a6de 100644 --- a/spec/scansion/mam_prefs_prep.scs +++ b/spec/scansion/mam_prefs_prep.scs @@ -1,4 +1,4 @@ -# mod_mam shold apply JIDprep in prefs +# mod_mam should apply JIDprep in prefs [Client] Romeo jid: romeo@localhost diff --git a/spec/scansion/muc_create_destroy.scs b/spec/scansion/muc_create_destroy.scs new file mode 100644 index 00000000..789d4c41 --- /dev/null +++ b/spec/scansion/muc_create_destroy.scs @@ -0,0 +1,316 @@ +# MUC creation, basic messages and destruction + +[Client] Romeo + jid: romeo@localhost/mK0dD6Ha + password: password + +[Client] Juliet + jid: juliet@localhost/lVwkim_k + password: password + +[Client] Admin + jid: admin@localhost/DfNgg9VE + password: password + +----- + +Romeo connects + +Romeo sends: + <presence to="garden@conference.localhost/romeo"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +Romeo receives: + <presence from="garden@conference.localhost/romeo"> + <x xmlns="vcard-temp:x:update"> + <photo/> + </x> + <x xmlns="http://jabber.org/protocol/muc#user"> + <status code="201"/> + <item affiliation="owner" jid="${Romeo's full JID}" role="moderator"/> + <status code="110"/> + </x> + </presence> + +Romeo receives: + <message from="garden@conference.localhost" type="groupchat"> + <subject/> + </message> + +Romeo sends: + <iq to="garden@conference.localhost" id="lx3" type="set"> + <query xmlns="http://jabber.org/protocol/muc#owner"> + <x type="submit" xmlns="jabber:x:data"/> + </query> + </iq> + +Romeo receives: + <iq id="lx3" type="result" from="garden@conference.localhost"/> + +Juliet connects + +Romeo sends: + <message to="garden@conference.localhost" type="groupchat" id="rm1"> + <body>Where are thou my Juliet?</body> + </message> + +Romeo receives: + <message type="groupchat" from="garden@conference.localhost/romeo" id="rm1"> + <body>Where are thou my Juliet?</body> + </message> + +Juliet sends: + <presence to="garden@conference.localhost/juliet"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +Juliet receives: + <presence from="garden@conference.localhost/romeo"> + <x xmlns="vcard-temp:x:update"> + <photo/> + </x> + <x xmlns="http://jabber.org/protocol/muc#user"> + <item affiliation="owner" role="moderator"/> + </x> + </presence> + +Juliet receives: + <presence from="garden@conference.localhost/juliet"> + <x xmlns="vcard-temp:x:update"> + <photo/> + </x> + <x xmlns="http://jabber.org/protocol/muc#user"> + <item affiliation="none" jid="${Juliet's full JID}" role="participant"/> + <status code="110"/> + </x> + </presence> + +Juliet receives: + <message from="garden@conference.localhost/romeo" id="rm1" type="groupchat"> + <body>Where are thou my Juliet?</body> + <delay stamp="{scansion:any}" xmlns="urn:xmpp:delay" from="garden@conference.localhost"/> + </message> + +Juliet receives: + <message from="garden@conference.localhost" type="groupchat"> + <subject/> + </message> + +Romeo receives: + <presence from="garden@conference.localhost/juliet"> + <x xmlns="vcard-temp:x:update"> + <photo/> + </x> + <x xmlns="http://jabber.org/protocol/muc#user"> + <item affiliation="none" jid="${Juliet's full JID}" role="participant"/> + </x> + </presence> + +Juliet sends: + <message to="garden@conference.localhost" type="groupchat" id="jm1"> + <body>/me jumps out from behind a tree</body> + </message> + +Romeo receives: + <message type="groupchat" id="jm1" from="garden@conference.localhost/juliet"> + <body>/me jumps out from behind a tree</body> + </message> + +Juliet receives: + <message type="groupchat" id="jm1" from="garden@conference.localhost/juliet"> + <body>/me jumps out from behind a tree</body> + </message> + +Juliet sends: + <message to="garden@conference.localhost" type="groupchat" id="jm2"> + <body>Here I am!</body> + </message> + +Romeo receives: + <message type="groupchat" id="jm2" from="garden@conference.localhost/juliet"> + <body>Here I am!</body> + </message> + +Juliet receives: + <message type="groupchat" id="jm2" from="garden@conference.localhost/juliet"> + <body>Here I am!</body> + </message> + +Romeo sends: + <message to="garden@conference.localhost" type="groupchat" id="rm2"> + <body>What is this place?</body> + </message> + +Romeo receives: + <message type="groupchat" id="rm2" from="garden@conference.localhost/romeo"> + <body>What is this place?</body> + </message> + +Juliet receives: + <message type="groupchat" id="rm2" from="garden@conference.localhost/romeo"> + <body>What is this place?</body> + </message> + +Juliet sends: + <message to="garden@conference.localhost" type="groupchat" id="jm3"> + <body>I think we're in a script!</body> + </message> + +Romeo receives: + <message type="groupchat" id="jm3" from="garden@conference.localhost/juliet"> + <body>I think we're in a script!</body> + </message> + +Juliet receives: + <message type="groupchat" id="jm3" from="garden@conference.localhost/juliet"> + <body>I think we're in a script!</body> + </message> + +Romeo sends: + <message to="garden@conference.localhost" type="groupchat" id="rm3"> + <body>Oh no! Does that mean our love is not real?!</body> + </message> + +Romeo receives: + <message type="groupchat" id="rm3" from="garden@conference.localhost/romeo"> + <body>Oh no! Does that mean our love is not real?!</body> + </message> + +Juliet receives: + <message type="groupchat" id="rm3" from="garden@conference.localhost/romeo"> + <body>Oh no! Does that mean our love is not real?!</body> + </message> + +Juliet sends: + <message to="garden@conference.localhost" type="groupchat" id="jm4"> + <body>I refuse to accept this! Let's burn this place to the ground!</body> + </message> + +Romeo receives: + <message type="groupchat" id="jm4" from="garden@conference.localhost/juliet"> + <body>I refuse to accept this! Let's burn this place to the ground!</body> + </message> + +Juliet receives: + <message type="groupchat" id="jm4" from="garden@conference.localhost/juliet"> + <body>I refuse to accept this! Let's burn this place to the ground!</body> + </message> + +Romeo sends: + <message to="garden@conference.localhost" type="groupchat" id="rm4"> + <body>Yes!</body> + </message> + +Romeo receives: + <message type="groupchat" id="rm4" from="garden@conference.localhost/romeo"> + <body>Yes!</body> + </message> + +Juliet receives: + <message type="groupchat" id="rm4" from="garden@conference.localhost/romeo"> + <body>Yes!</body> + </message> + +Romeo sends: + <iq to="garden@conference.localhost" id="lx4" type="set"> + <query xmlns="http://jabber.org/protocol/muc#owner"> + <destroy> + <reason>We refuse to live in this fantasy!</reason> + </destroy> + </query> + </iq> + +Juliet receives: + <presence from="garden@conference.localhost/juliet" type="unavailable"> + <x xmlns="http://jabber.org/protocol/muc#user"> + <destroy> + <reason>We refuse to live in this fantasy!</reason> + </destroy> + <item affiliation="none" jid="${Juliet's full JID}" role="none"/> + <status code="110"/> + </x> + </presence> + +Romeo receives: + <presence from="garden@conference.localhost/romeo" type="unavailable"> + <x xmlns="http://jabber.org/protocol/muc#user"> + <destroy> + <reason>We refuse to live in this fantasy!</reason> + </destroy> + <item affiliation="owner" jid="${Romeo's full JID}" role="none"/> + <status code="110"/> + </x> + </presence> + +Romeo receives: + <iq id="lx4" type="result" from="garden@conference.localhost"/> + +Juliet disconnects + +Romeo sends: + <presence to="elsewhere@conference.localhost/romeo"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +Romeo receives: + <presence from="elsewhere@conference.localhost/romeo"> + <x xmlns="vcard-temp:x:update"> + <photo/> + </x> + <x xmlns="http://jabber.org/protocol/muc#user"> + <status code="201"/> + <item affiliation="owner" jid="${Romeo's full JID}" role="moderator"/> + <status code="110"/> + </x> + </presence> + +Romeo receives: + <message from="elsewhere@conference.localhost" type="groupchat"> + <subject/> + </message> + +Romeo sends: + <iq to="elsewhere@conference.localhost" id="lx5" type="set"> + <query xmlns="http://jabber.org/protocol/muc#owner"> + <x type="submit" xmlns="jabber:x:data"/> + </query> + </iq> + +Romeo receives: + <iq id="lx5" type="result" from="elsewhere@conference.localhost"/> + +Admin connects + +Admin sends: + <iq id="destroy" type="set" to="conference.localhost"> + <command xmlns="http://jabber.org/protocol/commands" node="http://prosody.im/protocol/muc#destroy"> + <x xmlns="jabber:x:data"> + <field var="rooms"> + <value>elsewhere@conference.localhost</value> + </field> + </x> + </command> + </iq> + +Romeo receives: + <presence from="elsewhere@conference.localhost/romeo" type="unavailable"> + <x xmlns="http://jabber.org/protocol/muc#user"> + <destroy/> + <item affiliation="owner" jid="${Romeo's full JID}" role="none"/> + <status code="110"/> + </x> + </presence> + +Romeo disconnects + +Admin receives: + <iq id="destroy" type="result" from="conference.localhost"> + <command xmlns="http://jabber.org/protocol/commands" node="http://prosody.im/protocol/muc#destroy" status="completed" sessionid="{scansion:any}"> + <note type="info">The following rooms were destroyed: elsewhere@conference.localhost</note> + </command> + </iq> + +Admin disconnects + +# recording ended on 2019-08-31T13:45:32Z diff --git a/spec/scansion/muc_members_only_change.scs b/spec/scansion/muc_members_only_change.scs index dc40b5a0..a708dbfb 100644 --- a/spec/scansion/muc_members_only_change.scs +++ b/spec/scansion/muc_members_only_change.scs @@ -94,7 +94,7 @@ Romeo sends: <item affiliation='none' jid="${Juliet's JID}" /> </query> </iq> - + # As a non-member, Juliet must now be removed from the room Romeo receives: <presence type='unavailable' from='room@conference.localhost/Juliet'> diff --git a/spec/scansion/muc_nickname_change.scs b/spec/scansion/muc_nickname_change.scs new file mode 100644 index 00000000..73f81203 --- /dev/null +++ b/spec/scansion/muc_nickname_change.scs @@ -0,0 +1,127 @@ +# MUC: Change nickname +# Make sure a role is not reset, see #1466 + +[Client] Romeo + jid: user@localhost + password: password + +[Client] Juliet + jid: user2@localhost + password: password + +----- + +Romeo connects + +Romeo sends: + <presence to="room@conference.localhost/Romeo"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +Romeo receives: + <presence from='room@conference.localhost/Romeo'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <status code='201'/> + <item jid="${Romeo's full JID}" affiliation='owner' role='moderator'/> + <status code='110'/> + </x> + </presence> + +Romeo receives: + <message type='groupchat' from='room@conference.localhost'><subject/></message> + +Romeo sends: + <iq id='config1' to='room@conference.localhost' type='set'> + <query xmlns='http://jabber.org/protocol/muc#owner'> + <x xmlns='jabber:x:data' type='submit'> + <field var='FORM_TYPE'> + <value>http://jabber.org/protocol/muc#roomconfig</value> + </field> + <field var='muc#roomconfig_moderatedroom'> + <value>1</value> + </field> + </x> + </query> + </iq> + +Romeo receives: + <iq id="config1" from="room@conference.localhost" type="result"/> + +Juliet connects + +Juliet sends: + <presence to="room@conference.localhost/Juliet"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +Juliet receives: + <presence from='room@conference.localhost/Romeo'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <item role='moderator' xmlns='http://jabber.org/protocol/muc#user' affiliation='owner'/> + </x> + </presence> + +Juliet receives: + <presence from='room@conference.localhost/Juliet'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <item jid="${Juliet's full JID}" affiliation='none' role='visitor'/> + <status code='110'/> + </x> + </presence> + + +Juliet receives: + <message type='groupchat' from='room@conference.localhost'><subject/></message> + +Romeo receives: + <presence from='room@conference.localhost/Juliet'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <item affiliation="none" role="visitor" jid="${Juliet's full JID}"/> + </x> + </presence> + +Romeo sends: + <iq id='config1' to='room@conference.localhost' type='set'> + <query xmlns='http://jabber.org/protocol/muc#owner'> + <x xmlns='jabber:x:data' type='submit'> + <field var='FORM_TYPE'> + <value>http://jabber.org/protocol/muc#roomconfig</value> + </field> + <field var='muc#roomconfig_moderatedroom'> + <value>0</value> + </field> + </x> + </query> + </iq> + +Romeo receives: + <iq id="config1" from="room@conference.localhost" type="result"/> + +Juliet receives: + <message type='groupchat' from='room@conference.localhost'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <status xmlns='http://jabber.org/protocol/muc#user' code='104'/> + </x> + </message> + +Juliet sends: + <presence to="room@conference.localhost/Juliet2"> + </presence> + +Juliet receives: + <presence from='room@conference.localhost/Juliet' type='unavailable'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <status code='303'/> + <item nick='Juliet2' jid="${Juliet's full JID}" affiliation='none' role='visitor'/> + <status code='110'/> + </x> + </presence> + +Juliet receives: + <presence from='room@conference.localhost/Juliet2'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <item jid="${Juliet's full JID}" affiliation='none' role='visitor'/> + <status code='110'/> + </x> + </presence> + diff --git a/spec/scansion/muc_nickname_robotface.scs b/spec/scansion/muc_nickname_robotface.scs new file mode 100644 index 00000000..160c13d6 --- /dev/null +++ b/spec/scansion/muc_nickname_robotface.scs @@ -0,0 +1,46 @@ +# MUC: Prevent nicknames failing strict resourceprep + +[Client] Romeo + jid: user@localhost + password: password + +[Client] Roboteo + jid: bot@localhost + password: password + +----- + +Romeo connects + +Romeo sends: + <presence to="nobots@conference.localhost/Romeo"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +Romeo receives: + <presence from='nobots@conference.localhost/Romeo'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <status code='201'/> + <item jid="${Romeo's full JID}" affiliation='owner' role='moderator'/> + <status code='110'/> + </x> + </presence> + +Romeo receives: + <message type='groupchat' from='nobots@conference.localhost'><subject/></message> + +Roboteo connects + +Roboteo sends: + <presence to="nobots@conference.localhost/🤖️"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +Roboteo receives: + <presence type='error' from='nobots@conference.localhost/🤖'> + <error by='nobots@conference.localhost' type='modify'> + <jid-malformed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> + <text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>Nickname must pass strict validation</text> + </error> + </presence> + diff --git a/spec/scansion/muc_password.scs b/spec/scansion/muc_password.scs index 82611183..63c821e0 100644 --- a/spec/scansion/muc_password.scs +++ b/spec/scansion/muc_password.scs @@ -58,7 +58,7 @@ Juliet sends: Juliet receives: <presence from="room@conference.localhost/Juliet" type="error"> - <error type="auth" code="401"> + <error type="auth" code="401" by="room@conference.localhost"> <not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </presence> diff --git a/spec/scansion/muc_presence_probe.scs b/spec/scansion/muc_presence_probe.scs new file mode 100644 index 00000000..1fb5d9f5 --- /dev/null +++ b/spec/scansion/muc_presence_probe.scs @@ -0,0 +1,178 @@ +# #1535 Let MUCs respond to presence probes + +[Client] Romeo + jid: user@localhost + password: password + +[Client] Juliet + jid: user2@localhost + password: password + +[Client] Mercutio + jid: user3@localhost + password: password + +----- + +Romeo connects + +# Romeo joins the MUC + +Romeo sends: + <presence to="room@conference.localhost/Romeo"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +Romeo receives: + <presence from='room@conference.localhost/Romeo'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <status code='201'/> + <item jid="${Romeo's full JID}" affiliation='owner' role='moderator'/> + <status code='110'/> + </x> + </presence> + +Romeo receives: + <message type='groupchat' from='room@conference.localhost'><subject/></message> + +# Disable presences for non-mods +Romeo sends: + <iq id='config1' to='room@conference.localhost' type='set'> + <query xmlns='http://jabber.org/protocol/muc#owner'> + <x xmlns='jabber:x:data' type='submit'> + <field var='FORM_TYPE'> + <value>http://jabber.org/protocol/muc#roomconfig</value> + </field> + <field var='muc#roomconfig_presencebroadcast'> + <value>moderator</value> + </field> + </x> + </query> + </iq> + +Romeo receives: + <iq id="config1" from="room@conference.localhost" type="result"> + </iq> + +# Romeo probes himself + +Romeo sends: + <presence to="room@conference.localhost/Romeo" type="probe"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +Romeo receives: + <presence from='room@conference.localhost/Romeo'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <item jid="${Romeo's full JID}" affiliation='owner' role='moderator'/> + </x> + </presence> + +# Juliet tries to probe Romeo before joining the room + +Juliet connects + +Juliet sends: + <presence to="room@conference.localhost/Romeo" type="probe"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +Juliet receives: + <presence from="room@conference.localhost/Romeo" type="error"> + <error type="cancel"> + <not-acceptable xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/> + </error> + </presence> + +# Juliet tries to probe Mercutio (who's not in the MUC) before joining the room + +Juliet sends: + <presence to="room@conference.localhost/Mercutio" type="probe"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +Juliet receives: + <presence from="room@conference.localhost/Mercutio" type="error"> + <error type="cancel"> + <not-acceptable xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/> + </error> + </presence> + +# Juliet joins the room + +Juliet sends: + <presence to="room@conference.localhost/Juliet"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +Juliet receives: + <presence from="room@conference.localhost/Romeo" /> + +Juliet receives: + <presence from="room@conference.localhost/Juliet" /> + +# Romeo probes Juliet + +Romeo sends: + <presence to="room@conference.localhost/Juliet" type="probe"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +Romeo receives: + <presence from='room@conference.localhost/Juliet'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <item jid="${Juliet's full JID}" affiliation='none' role='participant'/> + </x> + </presence> + + +# Mercutio tries to probe himself in a MUC before joining + +Mercutio connects + +Mercutio sends: + <presence to="room@conference.localhost/Mercutio" type="probe"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +Mercutio receives: + <presence from="room@conference.localhost/Mercutio" type="error"> + <error type="cancel"> + <not-acceptable xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/> + </error> + </presence> + + +# Romeo makes Mercutio a member and registers his nickname + +Romeo sends: + <iq id='member1' to='room@conference.localhost' type='set'> + <query xmlns='http://jabber.org/protocol/muc#admin'> + <item affiliation='member' jid="${Mercutio's JID}" nick="Mercutio"/> + </query> + </iq> + +Romeo receives: + <message from='room@conference.localhost'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <item jid="${Mercutio's JID}" affiliation='member' /> + </x> + </message> + +Romeo receives: + <iq from='room@conference.localhost' id='member1' type='result'/> + + +# Romeo probes Mercutio, even though he's unavailable + +Romeo sends: + <presence to="room@conference.localhost/Mercutio" type="probe"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +Romeo receives: + <presence from='room@conference.localhost/Mercutio' type="unavailable"> + <x xmlns='http://jabber.org/protocol/muc#user'> + <item nick="Mercutio" affiliation='member' role='none' jid="${Mercutio's JID}" /> + </x> + </presence> diff --git a/spec/scansion/muc_register.scs b/spec/scansion/muc_register.scs index a7e57177..9fcce688 100644 --- a/spec/scansion/muc_register.scs +++ b/spec/scansion/muc_register.scs @@ -100,7 +100,9 @@ Juliet receives: <field type='hidden' var='FORM_TYPE'> <value>http://jabber.org/protocol/muc#register</value> </field> - <field type='text-single' label='Nickname' var='muc#register_roomnick'/> + <field type='text-single' label='Nickname' var='muc#register_roomnick'> + <required/> + </field> </x> </query> </iq> @@ -175,7 +177,7 @@ Rosaline sends: Rosaline receives: <presence type='error' from='room@conference.localhost/Juliet'> - <error type='cancel'> + <error type='cancel' by='room@conference.localhost'> <conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> <x xmlns='http://jabber.org/protocol/muc'/> @@ -286,7 +288,7 @@ Rosaline sends: Rosaline receives: <presence type='error' from='room@conference.localhost/Juliet'> - <error type='cancel'> + <error type='cancel' by='room@conference.localhost'> <conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> <x xmlns='http://jabber.org/protocol/muc'/> @@ -326,7 +328,7 @@ Romeo receives: </iq> # Romeo updates his own registration - + Romeo sends: <iq id='jw81b36f' to='room@conference.localhost' type='get'> <query xmlns='jabber:iq:register'/> @@ -339,7 +341,9 @@ Romeo receives: <field type='hidden' var='FORM_TYPE'> <value>http://jabber.org/protocol/muc#register</value> </field> - <field type='text-single' label='Nickname' var='muc#register_roomnick'/> + <field type='text-single' label='Nickname' var='muc#register_roomnick'> + <required/> + </field> </x> </query> </iq> diff --git a/spec/scansion/muc_show_offline.scs b/spec/scansion/muc_show_offline.scs new file mode 100644 index 00000000..57b75ec7 --- /dev/null +++ b/spec/scansion/muc_show_offline.scs @@ -0,0 +1,544 @@ +# MUC: Room registration and presence broadcast of unavailable members + +[Client] Romeo + jid: user@localhost + password: password + +[Client] Juliet + jid: user2@localhost + password: password + +[Client] Rosaline + jid: user3@localhost + password: password + +----- + +Romeo connects + +Romeo sends: + <presence to="room@conference.localhost/Romeo"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +Romeo receives: + <presence from='room@conference.localhost/Romeo'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <status code='201'/> + <item jid="${Romeo's full JID}" affiliation='owner' role='moderator'/> + <status code='110'/> + </x> + </presence> + +Romeo receives: + <message type='groupchat' from='room@conference.localhost'><subject/></message> + +# Submit config form +Romeo sends: + <iq id='config1' to='room@conference.localhost' type='set'> + <query xmlns='http://jabber.org/protocol/muc#owner'> + <x xmlns='jabber:x:data' type='submit'> + <field var='FORM_TYPE'> + <value>http://jabber.org/protocol/muc#roomconfig</value> + </field> + <field var='muc#roomconfig_presencebroadcast'> + <value>none</value> + <value>participant</value> + <value>moderator</value> + </field> + </x> + </query> + </iq> + +Romeo receives: + <iq id="config1" from="room@conference.localhost" type="result"> + </iq> + +Romeo sends: + <iq id='member1' to='room@conference.localhost' type='set'> + <query xmlns='http://jabber.org/protocol/muc#admin'> + <item affiliation='member' jid="${Juliet's JID}" /> + </query> + </iq> + +Romeo receives: + <message from='room@conference.localhost'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <item jid="${Juliet's JID}" affiliation='member' /> + </x> + </message> + +Romeo receives: + <iq from='room@conference.localhost' id='member1' type='result'/> + +# Juliet connects, and joins the room +Juliet connects + +Juliet sends: + <presence to="room@conference.localhost/Juliet"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +Juliet receives: + <presence from="room@conference.localhost/Romeo" /> + +Juliet receives: + <presence from="room@conference.localhost/Juliet" /> + +Juliet receives: + <message type='groupchat' from='room@conference.localhost'><subject/></message> + +Romeo receives: + <presence from="room@conference.localhost/Juliet" /> + +# Juliet retrieves the registration form + +Juliet sends: + <iq id='jw81b36f' to='room@conference.localhost' type='get'> + <query xmlns='jabber:iq:register'/> + </iq> + +Juliet receives: + <iq type='result' from='room@conference.localhost' id='jw81b36f'> + <query xmlns='jabber:iq:register'> + <x type='form' xmlns='jabber:x:data'> + <field type='hidden' var='FORM_TYPE'> + <value>http://jabber.org/protocol/muc#register</value> + </field> + <field type='text-single' label='Nickname' var='muc#register_roomnick'> + <required/> + </field> + </x> + </query> + </iq> + +Juliet sends: + <iq id='nv71va54' to='room@conference.localhost' type='set'> + <query xmlns='jabber:iq:register'> + <x xmlns='jabber:x:data' type='submit'> + <field var='FORM_TYPE'> + <value>http://jabber.org/protocol/muc#register</value> + </field> + <field var='muc#register_roomnick'> + <value>Juliet</value> + </field> + </x> + </query> + </iq> + +Juliet receives: + <presence from='room@conference.localhost/Juliet'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <item affiliation='member' jid="${Juliet's full JID}" role='participant'/> + <status code='110'/> + </x> + </presence> + +Juliet receives: + <iq type='result' from='room@conference.localhost' id='nv71va54'/> + +# Juliet discovers her reserved nick + +Juliet sends: + <iq id='getnick1' to='room@conference.localhost' type='get'> + <query xmlns='http://jabber.org/protocol/disco#info' node='x-roomuser-item'/> + </iq> + +Juliet receives: + <iq type='result' from='room@conference.localhost' id='getnick1'> + <query xmlns='http://jabber.org/protocol/disco#info' node='x-roomuser-item'> + <identity category='conference' name='Juliet' type='text'/> + </query> + </iq> + +# Juliet leaves the room: + +Juliet sends: + <presence type="unavailable" to="room@conference.localhost/Juliet" /> + +Juliet receives: + <presence type='unavailable' from='room@conference.localhost/Juliet'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <item jid="${Juliet's full JID}" affiliation='member' role='none'/> + <status code='110'/> + </x> + </presence> + +Romeo receives: + <presence from='room@conference.localhost/Juliet'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <item jid="${Juliet's full JID}" affiliation='member' role='participant'/> + </x> + </presence> + +# Rosaline connect and tries to join the room as Juliet + +Rosaline connects + +Rosaline sends: + <presence to="room@conference.localhost/Juliet"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +Rosaline receives: + <presence type='error' from='room@conference.localhost/Juliet'> + <error type='cancel' by='room@conference.localhost'> + <conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> + </error> + <x xmlns='http://jabber.org/protocol/muc'/> + </presence> + +# In a heated moment, Juliet unregisters from the room + +Juliet sends: + <iq type='set' to='room@conference.localhost' id='unreg1'> + <query xmlns='jabber:iq:register'> + <remove/> + </query> + </iq> + +Juliet receives: + <iq type='result' from='room@conference.localhost' id='unreg1'/> + +# Romeo is notified of Juliet's sad decision + +Romeo receives: + <message from='room@conference.localhost'> + <x xmlns='http://jabber.org/protocol/muc#user' scansion:strict='true'> + <item jid="${Juliet's JID}" affiliation='none' /> + </x> + </message> + +# Rosaline attempts once more to sneak into the room, disguised as Juliet + +Rosaline sends: + <presence to="room@conference.localhost/Juliet"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +Rosaline receives: + <presence from='room@conference.localhost/Romeo'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <item affiliation='owner' role='moderator'/> + </x> + </presence> + +Rosaline receives: + <presence from='room@conference.localhost/Juliet'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <item affiliation='none' jid="${Rosaline's full JID}" role='participant'/> + <status code='110'/> + </x> + </presence> + +Romeo receives: + <presence from='room@conference.localhost/Juliet'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <item affiliation='none' jid="${Rosaline's full JID}" role='participant'/> + </x> + </presence> + +# On discovering the ruse, Romeo restores Juliet's nick and status within the room + +Romeo sends: + <iq id='member1' to='room@conference.localhost' type='set'> + <query xmlns='http://jabber.org/protocol/muc#admin'> + <item affiliation='member' jid="${Juliet's JID}" nick='Juliet' /> + </query> + </iq> + +# Rosaline is evicted from the room + +Romeo receives: + <presence from='room@conference.localhost/Juliet' type='unavailable'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <status code='307'/> + <item affiliation='none' role='none' jid="${Rosaline's full JID}"> + <reason>This nickname is reserved</reason> + </item> + </x> + </presence> + +# An out-of-room affiliation change is received for Juliet + +Romeo receives: + <message from='room@conference.localhost'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <item jid="${Juliet's JID}" affiliation='member' /> + </x> + </message> + +Romeo receives: + <iq type='result' id='member1' from='room@conference.localhost' /> + +Rosaline receives: + <presence type='unavailable' from='room@conference.localhost/Juliet'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <status code='307'/> + <item affiliation='none' jid="${Rosaline's full JID}" role='none'> + <reason>This nickname is reserved</reason> + </item> + <status code='110'/> + </x> + </presence> + +# Rosaline, frustrated, attempts to get back into the room... + +Rosaline sends: + <presence to="room@conference.localhost/Juliet"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +# ...but once again, is denied + +Rosaline receives: + <presence type='error' from='room@conference.localhost/Juliet'> + <error type='cancel' by='room@conference.localhost'> + <conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> + </error> + <x xmlns='http://jabber.org/protocol/muc'/> + </presence> + +# Juliet, however, quietly joins the room with success + +Juliet sends: + <presence to="room@conference.localhost/Juliet"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +Juliet receives: + <presence from="room@conference.localhost/Romeo" /> + +Juliet receives: + <presence from="room@conference.localhost/Juliet" /> + +Juliet receives: + <message type='groupchat' from='room@conference.localhost'><subject/></message> + +Romeo receives: + <presence from="room@conference.localhost/Juliet" /> + +# Romeo checks whether he has reserved his own nick yet + +Romeo sends: + <iq id='getnick1' to='room@conference.localhost' type='get'> + <query xmlns='http://jabber.org/protocol/disco#info' node='x-roomuser-item'/> + </iq> + +# But no nick is returned, as he hasn't registered yet! + +Romeo receives: + <iq type='result' from='room@conference.localhost' id='getnick1'> + <query xmlns='http://jabber.org/protocol/disco#info' node='x-roomuser-item' scansion:strict='true' /> + </iq> + +# Romeo updates his own registration + +Romeo sends: + <iq id='jw81b36f' to='room@conference.localhost' type='get'> + <query xmlns='jabber:iq:register'/> + </iq> + +Romeo receives: + <iq type='result' from='room@conference.localhost' id='jw81b36f'> + <query xmlns='jabber:iq:register'> + <x type='form' xmlns='jabber:x:data'> + <field type='hidden' var='FORM_TYPE'> + <value>http://jabber.org/protocol/muc#register</value> + </field> + <field type='text-single' label='Nickname' var='muc#register_roomnick'> + <required/> + </field> + </x> + </query> + </iq> + +Romeo sends: + <iq id='nv71va54' to='room@conference.localhost' type='set'> + <query xmlns='jabber:iq:register'> + <x xmlns='jabber:x:data' type='submit'> + <field var='FORM_TYPE'> + <value>http://jabber.org/protocol/muc#register</value> + </field> + <field var='muc#register_roomnick'> + <value>Romeo</value> + </field> + </x> + </query> + </iq> + +Romeo receives: + <presence from='room@conference.localhost/Romeo'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <item affiliation='owner' jid="${Romeo's full JID}" role='moderator'/> + <status code='110'/> + </x> + </presence> + +Romeo receives: + <iq type='result' from='room@conference.localhost' id='nv71va54'/> + +Juliet receives: + <presence from='room@conference.localhost/Romeo'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <item role='moderator' xmlns='http://jabber.org/protocol/muc#user' affiliation='owner'/> + </x> + </presence> + +# Romeo discovers his reserved nick + +Romeo sends: + <iq id='getnick1' to='room@conference.localhost' type='get'> + <query xmlns='http://jabber.org/protocol/disco#info' node='x-roomuser-item'/> + </iq> + +Romeo receives: + <iq type='result' from='room@conference.localhost' id='getnick1'> + <query xmlns='http://jabber.org/protocol/disco#info' node='x-roomuser-item'> + <identity category='conference' name='Romeo' type='text'/> + </query> + </iq> + +# To check the status of the room is as expected, Romeo requests the member list + +Romeo sends: + <iq id='member3' to='room@conference.localhost' type='get'> + <query xmlns='http://jabber.org/protocol/muc#admin'> + <item affiliation='member'/> + </query> + </iq> + +Romeo receives: + <iq from='room@conference.localhost' type='result' id='member3'> + <query xmlns='http://jabber.org/protocol/muc#admin'> + <item jid="${Juliet's JID}" affiliation='member' nick='Juliet'/> + </query> + </iq> + +Juliet sends: + <presence type="unavailable" to="room@conference.localhost/Juliet" /> + +Juliet receives: + <presence from='room@conference.localhost/Juliet' type='unavailable' /> + +Romeo receives: + <presence type='unavailable' from='room@conference.localhost/Juliet' /> + +# Rosaline joins as herself + +Rosaline sends: + <presence to="room@conference.localhost/Rosaline"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +Rosaline receives: + <presence from="room@conference.localhost/Romeo" /> + +Rosaline receives: + <presence from='room@conference.localhost/Juliet' type='unavailable'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <item affiliation='member' role='none' nick='Juliet' xmlns='http://jabber.org/protocol/muc#user'/> + </x> + </presence> + +Rosaline receives: + <presence from="room@conference.localhost/Rosaline" /> + +Rosaline receives: + <message type='groupchat' from='room@conference.localhost'><subject/></message> + +Romeo receives: + <presence from='room@conference.localhost/Rosaline'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <item jid="${Rosaline's full JID}" affiliation='none' role='participant'/> + </x> + </presence> + +# Rosaline tries to register her own nickname, but unaffiliated +# registration is disabled by default + +Rosaline sends: + <iq id='reg990' to='room@conference.localhost' type='get'> + <query xmlns='jabber:iq:register'/> + </iq> + +Rosaline receives: + <iq type='error' from='room@conference.localhost' id='reg990'> + <error type='auth'> + <registration-required xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> + </error> + </iq> + +Rosaline sends: + <iq id='reg991' to='room@conference.localhost' type='set'> + <query xmlns='jabber:iq:register'> + <x xmlns='jabber:x:data' type='submit'> + <field var='FORM_TYPE'> + <value>http://jabber.org/protocol/muc#register</value> + </field> + <field var='muc#register_roomnick'> + <value>Romeo</value> + </field> + </x> + </query> + </iq> + +Rosaline receives: + <iq id='reg991' type='error'> + <error type='auth'> + <registration-required xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> + </error> + </iq> + +# Romeo reserves her nickname for her + +Romeo sends: + <iq id='member2' to='room@conference.localhost' type='set'> + <query xmlns='http://jabber.org/protocol/muc#admin'> + <item affiliation='member' jid="${Rosaline's JID}" nick='Rosaline' /> + </query> + </iq> + +Romeo receives: + <presence from='room@conference.localhost/Rosaline'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <item affiliation='member' role='participant' jid="${Rosaline's full JID}"> + <actor jid="${Romeo's full JID}" nick='Romeo'/> + </item> + </x> + </presence> + +Romeo receives: + <iq type='result' id='member2' from='room@conference.localhost' /> + +Rosaline receives: + <presence from='room@conference.localhost/Rosaline'> + <x xmlns='http://jabber.org/protocol/muc#user'> + <item affiliation='member' role='participant' jid="${Rosaline's full JID}"> + <actor nick='Romeo' /> + </item> + <status xmlns='http://jabber.org/protocol/muc#user' code='110'/> + </x> + </presence> + +# Romeo sets their their own nickname via admin query (see #1273) +Romeo sends: + <iq to="room@conference.localhost" id="reserve" type="set"> + <query xmlns="http://jabber.org/protocol/muc#admin"> + <item nick="Romeo" affiliation="owner" jid="${Romeo's JID}"/> + </query> + </iq> + +Romeo receives: + <presence from="room@conference.localhost/Romeo"> + <x xmlns="http://jabber.org/protocol/muc#user"> + <item xmlns="http://jabber.org/protocol/muc#user" role="moderator" jid="${Romeo's full JID}" affiliation="owner"> + <actor xmlns="http://jabber.org/protocol/muc#user" nick="Romeo"/> + </item> + <status xmlns="http://jabber.org/protocol/muc#user" code="110"/> + </x> + </presence> + +Romeo receives: + <iq from="room@conference.localhost" id="reserve" type="result"/> + diff --git a/spec/scansion/muc_subject_issue_667.scs b/spec/scansion/muc_subject_issue_667.scs new file mode 100644 index 00000000..74980073 --- /dev/null +++ b/spec/scansion/muc_subject_issue_667.scs @@ -0,0 +1,129 @@ +# #667 MUC message with subject and body SHALL NOT be interpreted as a subject change + +[Client] Romeo + password: password + jid: romeo@localhost + +----- + +Romeo connects + +# and creates a room +Romeo sends: + <presence to="issue667@conference.localhost/Romeo"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +Romeo receives: + <presence from="issue667@conference.localhost/Romeo"> + <x xmlns="http://jabber.org/protocol/muc#user"> + <status code="201"/> + <item affiliation="owner" role="moderator" jid="${Romeo's full JID}"/> + <status code="110"/> + </x> + </presence> + +# the default (empty) subject +Romeo receives: + <message type="groupchat" from="issue667@conference.localhost"> + <subject/> + </message> + +# this should be treated as a normal message +Romeo sends: + <message to="issue667@conference.localhost" type="groupchat"> + <subject>Greetings</subject> + <body>Hello everyone</body> + </message> + +Romeo receives: + <message type="groupchat" from="issue667@conference.localhost/Romeo"> + <subject>Greetings</subject> + <body>Hello everyone</body> + </message> + +# Resync +Romeo sends: + <presence to="issue667@conference.localhost/Romeo"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +# Presences +Romeo receives: + <presence from="issue667@conference.localhost/Romeo"> + <x xmlns="http://jabber.org/protocol/muc#user"> + <item affiliation="owner" role="moderator" jid="${Romeo's full JID}"/> + <status code="110"/> + </x> + </presence> + +Romeo receives: + <message type="groupchat" from="issue667@conference.localhost/Romeo"> + <subject>Greetings</subject> + <body>Hello everyone</body> + </message> + +# the still empty subject +Romeo receives: + <message type="groupchat" from="issue667@conference.localhost"> + <subject/> + </message> + +# this is a subject change +Romeo sends: + <message to="issue667@conference.localhost" type="groupchat"> + <subject>Something to talk about</subject> + </message> + +Romeo receives: + <message type="groupchat" from="issue667@conference.localhost/Romeo"> + <subject>Something to talk about</subject> + </message> + +# a message without <subject> +Romeo sends: + <message to="issue667@conference.localhost" type="groupchat"> + <body>Lorem ipsum dolor sit amet</body> + </message> + +Romeo receives: + <message type="groupchat" from="issue667@conference.localhost/Romeo"> + <body>Lorem ipsum dolor sit amet</body> + </message> + +# Resync +Romeo sends: + <presence to="issue667@conference.localhost/Romeo"> + <x xmlns="http://jabber.org/protocol/muc"/> + </presence> + +# Presences +Romeo receives: + <presence from="issue667@conference.localhost/Romeo"> + <x xmlns="http://jabber.org/protocol/muc#user"> + <item affiliation="owner" role="moderator" jid="${Romeo's full JID}"/> + <status code="110"/> + </x> + </presence> + +# History +# These have delay tags but we ignore those for now +Romeo receives: + <message type="groupchat" from="issue667@conference.localhost/Romeo"> + <subject>Greetings</subject> + <body>Hello everyone</body> + </message> + +Romeo receives: + <message type="groupchat" from="issue667@conference.localhost/Romeo"> + <body>Lorem ipsum dolor sit amet</body> + </message> + +# Finally, the topic +Romeo receives: + <message type="groupchat" from="issue667@conference.localhost/Romeo"> + <subject>Something to talk about</subject> + </message> + +Romeo disconnects + diff --git a/spec/scansion/pep_nickname.scs b/spec/scansion/pep_nickname.scs index f958ec75..aaf53c87 100644 --- a/spec/scansion/pep_nickname.scs +++ b/spec/scansion/pep_nickname.scs @@ -1,7 +1,7 @@ # Publishing a nickname in PEP and receiving a notification [Client] Romeo - jid: romeo@localhost/nJi7BeTR + jid: romeo@localhost password: password ----- @@ -20,7 +20,7 @@ Romeo sends: </iq> Romeo receives: - <iq id="4" to="romeo@localhost/nJi7BeTR" type="result"> + <iq id="4" type="result"> <pubsub xmlns="http://jabber.org/protocol/pubsub"> <publish node="http://jabber.org/protocol/nick"> <item id="current"/> @@ -34,12 +34,12 @@ Romeo sends: </presence> Romeo receives: - <iq id="disco" to="romeo@localhost/nJi7BeTR" from="romeo@localhost" type="get"> + <iq id="disco" from="romeo@localhost" type="get"> <query xmlns="http://jabber.org/protocol/disco#info" node="http://code.matthewwild.co.uk/clix/#jC32N+FhQoLrZ7nNQtZK3aqR0Fk="/> </iq> Romeo receives: - <presence from="romeo@localhost/nJi7BeTR"> + <presence> <c xmlns="http://jabber.org/protocol/caps" hash="sha-1" node="http://code.matthewwild.co.uk/clix/" ver="jC32N+FhQoLrZ7nNQtZK3aqR0Fk="/> </presence> @@ -55,10 +55,10 @@ Romeo sends: </iq> Romeo receives: - <message type="headline" from="romeo@localhost" to="romeo@localhost/nJi7BeTR"> + <message type="headline" from="romeo@localhost"> <event xmlns="http://jabber.org/protocol/pubsub#event"> <items node="http://jabber.org/protocol/nick"> - <item id="current"> + <item id="current" publisher="${Romeo's JID}"> <nickname xmlns="http://jabber.org/protocol/nick"/> </item> </items> diff --git a/spec/scansion/pep_publish_subscribe.scs b/spec/scansion/pep_publish_subscribe.scs index e8080134..6d33ffeb 100644 --- a/spec/scansion/pep_publish_subscribe.scs +++ b/spec/scansion/pep_publish_subscribe.scs @@ -182,7 +182,7 @@ Juliet sends: <iq type='result' id='fixme'/> Juliet sends: - <iq type='set' id='7'><pubsub xmlns='http://jabber.org/protocol/pubsub'><publish node='http://jabber.org/protocol/tune'><item id='current'><tune xmlns='http://jabber.org/protocol/tune'><title>Beautiful Cedars</title><artist>The Spinners</artist><source>Not Quite Folk</source><track>4</track></tune></item></publish></pubsub></iq> + <iq type='set' id='7'><pubsub xmlns='http://jabber.org/protocol/pubsub'><publish node='http://jabber.org/protocol/tune'><item id='current' publisher="${Juliet's JID}"><tune xmlns='http://jabber.org/protocol/tune'><title>Beautiful Cedars</title><artist>The Spinners</artist><source>Not Quite Folk</source><track>4</track></tune></item></publish></pubsub></iq> Juliet receives: <iq type='result' id='7' ><pubsub xmlns='http://jabber.org/protocol/pubsub'><publish node='http://jabber.org/protocol/tune'><item id='current'/></publish></pubsub></iq> @@ -197,13 +197,13 @@ Juliet sends: <iq type='result' id='{scansion:any}'/> Romeo receives: - <message type='headline' from='pep-test-tqvqu_pv@localhost'><event xmlns='http://jabber.org/protocol/pubsub#event'><items node='http://jabber.org/protocol/tune'><item id='current'><tune xmlns='http://jabber.org/protocol/tune'><title>Beautiful Cedars</title><artist>The Spinners</artist><source>Not Quite Folk</source><track>4</track></tune></item></items></event></message> + <message type='headline' from='pep-test-tqvqu_pv@localhost'><event xmlns='http://jabber.org/protocol/pubsub#event'><items node='http://jabber.org/protocol/tune'><item id='current' publisher="${Juliet's JID}"><tune xmlns='http://jabber.org/protocol/tune'><title>Beautiful Cedars</title><artist>The Spinners</artist><source>Not Quite Folk</source><track>4</track></tune></item></items></event></message> Romeo sends: <iq type='result' id='disco' to='pep-test-tqvqu_pv@localhost'><query xmlns='http://jabber.org/protocol/disco#info' node='http://code.matthewwild.co.uk/verse/#IfQwbaaDB4LEP5tkGArEaB/3Y+s='><identity type='pc' name='Verse' category='client'/><feature var='http://jabber.org/protocol/tune+notify'/><feature var='http://jabber.org/protocol/disco#info'/><feature var='http://jabber.org/protocol/disco#items'/><feature var='http://jabber.org/protocol/caps'/><feature var='http://jabber.org/protocol/mood+notify'/></query></iq> Romeo receives: - <message type='headline' from='pep-test-tqvqu_pv@localhost'><event xmlns='http://jabber.org/protocol/pubsub#event'><items node='http://jabber.org/protocol/tune'><item id='current'><tune xmlns='http://jabber.org/protocol/tune'><title>Beautiful Cedars</title><artist>The Spinners</artist><source>Not Quite Folk</source><track>4</track></tune></item></items></event></message> + <message type='headline' from='pep-test-tqvqu_pv@localhost'><event xmlns='http://jabber.org/protocol/pubsub#event'><items node='http://jabber.org/protocol/tune'><item id='current' publisher="${Juliet's JID}"><tune xmlns='http://jabber.org/protocol/tune'><title>Beautiful Cedars</title><artist>The Spinners</artist><source>Not Quite Folk</source><track>4</track></tune></item></items></event></message> Juliet disconnects diff --git a/spec/scansion/pep_pubsub_max.scs b/spec/scansion/pep_pubsub_max.scs new file mode 100644 index 00000000..6961304c --- /dev/null +++ b/spec/scansion/pep_pubsub_max.scs @@ -0,0 +1,47 @@ +# PEP max_items=max + +[Client] Romeo + jid: pep-test-maxitems@localhost + password: password + +----- + +Romeo connects + +Romeo sends: + <iq type="set" id="pub"> + <pubsub xmlns="http://jabber.org/protocol/pubsub"> + <publish node="urn:xmpp:microblog:0"> + <item> + <entry xmlns='http://www.w3.org/2005/Atom'> + <title>Hello</title> + </entry> + </item> + </publish> + <publish-options> + <x xmlns="jabber:x:data" type="submit"> + <field type="hidden" var="FORM_TYPE"> + <value>http://jabber.org/protocol/pubsub#publish-options</value> + </field> + <field var="pubsub#persist_items"> + <value>true</value> + </field> + <field var="pubsub#access_model"> + <value>open</value> + </field> + <field var="pubsub#max_items"> + <value>max</value> + </field> + </x> + </publish-options> + </pubsub> + </iq> + +Romeo receives: + <iq type="result" id="pub"> + <pubsub xmlns="http://jabber.org/protocol/pubsub"> + <publish node="urn:xmpp:microblog:0"> + <item id="{scansion:any}"/> + </publish> + </pubsub> + </iq> diff --git a/spec/scansion/presence_preapproval.scs b/spec/scansion/presence_preapproval.scs new file mode 100644 index 00000000..e34ac7cf --- /dev/null +++ b/spec/scansion/presence_preapproval.scs @@ -0,0 +1,74 @@ +# server supports contact subscription pre-approval (RFC 6121 3.4) + +[Client] Alice + jid: preappove-a@localhost + password: password + +[Client] Bob + jid: preapprove-b@localhost + password: password + +--------- + +Alice connects + +Alice sends: + <presence/> + +Alice receives: + <presence/> + +Alice sends: + <presence to="${Bob's JID}" type="subscribed"/> + +Bob connects + +Bob sends: + <iq type="get" id="roster1"> + <query xmlns="jabber:iq:roster"/> + </iq> + +Bob receives: + <iq type="result" id="roster1"> + <query xmlns="jabber:iq:roster" ver="{scansion:any}"> + </query> + </iq> + +Bob sends: + <presence/> + +Bob receives: + <presence from="${Bob's full JID}"/> + +Bob sends: + <presence to="${Alice's JID}" type="subscribe" /> + +Bob receives: + <iq type='set' id='{scansion:any}'> + <query ver='1' xmlns='jabber:iq:roster'> + <item jid="${Alice's JID}" subscription='none' ask='subscribe' /> + </query> + </iq> + + + +Bob receives: + <presence from="${Alice's JID}" type="subscribed" /> + +Bob disconnects + +Alice sends: + <iq type="get" id="roster1"> + <query xmlns="jabber:iq:roster"/> + </iq> + +Alice receives: + <iq type="result" id="roster1"> + <query xmlns="jabber:iq:roster" ver="{scansion:any}"> + <item jid="${Bob's JID}" subscription="from" /> + </query> + </iq> + +Alice disconnects + +Bob disconnects diff --git a/spec/scansion/prosody.cfg.lua b/spec/scansion/prosody.cfg.lua index f95ea31b..d4389cbe 100644 --- a/spec/scansion/prosody.cfg.lua +++ b/spec/scansion/prosody.cfg.lua @@ -1,23 +1,36 @@ --luacheck: ignore +-- Mock time functions to simplify tests +function _G.os.time() + return 1219439344; +end +package.preload["util.time"] = function () + return { + now = function () return 1219439344.1; end; + monotonic = function () return 0.1; end; + } +end + admins = { "admin@localhost" } -use_libevent = true +network_backend = ENV_PROSODY_NETWORK_BACKEND or "epoll" +network_settings = require"util.json".decode(ENV_PROSODY_NETWORK_SETTINGS or "{}") modules_enabled = { -- Generally required "roster"; -- Allow users to have a roster. Recommended ;) "saslauth"; -- Authentication for clients and servers. Recommended if you want to log in. - "tls"; -- Add support for secure TLS on c2s/s2s connections - "dialback"; -- s2s dialback support + --"tls"; -- Add support for secure TLS on c2s/s2s connections + --"dialback"; -- s2s dialback support "disco"; -- Service discovery -- Not essential, but recommended "carbons"; -- Keep multiple clients in sync - "pep"; -- Enables users to publish their mood, activity, playing music and more + "pep"; -- Enables users to publish their avatar, mood, activity, playing music and more "private"; -- Private XML storage (for room bookmarks, etc.) "blocklist"; -- Allow users to block communications with other users - "vcard"; -- Allow users to set vCards + "vcard4"; -- User profiles (stored in PEP) + "vcard_legacy"; -- Conversion between legacy vCard and PEP Avatar, vcard -- Nice to have "version"; -- Replies to server version requests @@ -26,6 +39,11 @@ modules_enabled = { "ping"; -- Replies to XMPP pings with pongs "register"; -- Allow users to register on this server using a client and change passwords "mam"; -- Store messages in an archive and allow users to access it + --"csi_simple"; -- Simple Mobile optimizations + + -- Admin interfaces + --"admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands + --"admin_telnet"; -- Opens telnet console interface on localhost port 5582 -- HTTP modules --"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP" @@ -35,19 +53,48 @@ modules_enabled = { -- Other specific functionality --"limits"; -- Enable bandwidth limiting for XMPP connections --"groups"; -- Shared roster support - --"server_contact_info"; -- Publish contact information for this service + "server_contact_info"; -- Publish contact information for this service --"announce"; -- Send announcement to all online users --"welcome"; -- Welcome users who register accounts --"watchregistrations"; -- Alert admins of registrations --"motd"; -- Send a message to users when they log in --"legacyauth"; -- Legacy authentication. Only used by some old clients and bots. --"proxy65"; -- Enables a file transfer proxy service which clients behind NAT can use + "lastactivity"; + "external_services"; -- Useful for testing --"scansion_record"; -- Records things that happen in scansion test case format } -certificate = "certs" +contact_info = { + abuse = { "mailto:abuse@localhost", "xmpp:abuse@localhost" }; + admin = { "mailto:admin@localhost", "xmpp:admin@localhost" }; + feedback = { "http://localhost/feedback.html", "mailto:feedback@localhost", "xmpp:feedback@localhost" }; + sales = { "xmpp:sales@localhost" }; + security = { "xmpp:security@localhost" }; + status = { "gopher://status.localhost" }; + support = { "https://localhost/support.html", "xmpp:support@localhost" }; +} + +external_service_host = "default.example" +external_service_port = 9876 +external_service_secret = "<secret>" +external_services = { + {type = "stun"; transport = "udp"}; + {type = "turn"; transport = "udp"; secret = true}; + {type = "turn"; transport = "udp"; secret = "foo"}; + {type = "ftp"; transport = "tcp"; port = 2121; username = "john"; password = "password"}; + {type = "ftp"; transport = "tcp"; host = "ftp.example.com"; port = 21; username = "john"; password = "password"}; +} + +modules_disabled = { + "s2s"; +} + +-- TLS is not used during the test, set certificate dir to the config directory +-- (spec/scansion) to silence an error from the certificate indexer +certificates = "." allow_registration = false @@ -69,15 +116,26 @@ mam_smart_enable = true -- Logging configuration -- For advanced logging see https://prosody.im/doc/logging -log = "*console" +log = {"*console",debug = ENV_PROSODY_LOGFILE} -daemonize = true pidfile = "prosody.pid" VirtualHost "localhost" +hide_os_type = true -- absence tested for in version.scs + Component "conference.localhost" "muc" storage = "memory" + admins = { "Admin@localhost" } + modules_enabled = { + "muc_mam"; + } + Component "pubsub.localhost" "pubsub" storage = "memory" + expose_publisher = true + +Component "upload.localhost" "http_file_share" +http_file_share_size_limit = 10000000 +http_file_share_allowed_file_types = { "text/plain", "image/*" } diff --git a/spec/scansion/pubsub_advanced.scs b/spec/scansion/pubsub_advanced.scs index c873486e..74ca5309 100644 --- a/spec/scansion/pubsub_advanced.scs +++ b/spec/scansion/pubsub_advanced.scs @@ -129,7 +129,7 @@ Juliet receives: <message type="headline" from="pubsub.localhost"> <event xmlns="http://jabber.org/protocol/pubsub#event"> <items node="princely_musings"> - <item id="current"> + <item id="current" publisher="${Romeo's JID}"> <entry xmlns="http://www.w3.org/2005/Atom"> <title>Soliloquy</title> <summary>Lorem ipsum dolor sit amet</summary> @@ -150,7 +150,11 @@ Juliet sends: </iq> Juliet receives: - <iq type="result" id='unsub1'/> + <iq type="result" id='unsub1'> + <pubsub xmlns='http://jabber.org/protocol/pubsub'> + <subscription jid="${Juliet's full JID}" node='princely_musings' subscription='none'/> + </pubsub> + </iq> Balthasar sends: <iq type="set" to="pubsub.localhost" id='del1'> diff --git a/spec/scansion/pubsub_basic.scs b/spec/scansion/pubsub_basic.scs index d983ff66..610a6612 100644 --- a/spec/scansion/pubsub_basic.scs +++ b/spec/scansion/pubsub_basic.scs @@ -32,7 +32,7 @@ Juliet connects -- <subscribe node="princely_musings" jid="${Romeo's full JID}"/> -- </pubsub> -- </iq> --- +-- -- Juliet receives: -- <iq type="error"/> @@ -67,7 +67,7 @@ Juliet receives: <message type="headline" from="pubsub.localhost"> <event xmlns="http://jabber.org/protocol/pubsub#event"> <items node="princely_musings"> - <item id="current"> + <item id="current" publisher="${Romeo's JID}"> <entry xmlns="http://www.w3.org/2005/Atom"> <title>Soliloquy</title> <summary>Lorem ipsum dolor sit amet</summary> diff --git a/spec/scansion/pubsub_config.scs b/spec/scansion/pubsub_config.scs index d979aca5..2cad9115 100644 --- a/spec/scansion/pubsub_config.scs +++ b/spec/scansion/pubsub_config.scs @@ -48,7 +48,7 @@ Romeo receives: <field var="pubsub#description" label="Description" type="text-single"/> <field var="pubsub#type" label="The type of node data, usually specified by the namespace of the payload (if any)" type="text-single"/> <field var="pubsub#max_items" label="Max # of items to persist" type="text-single"> - <validate xmlns="http://jabber.org/protocol/xdata-validate" datatype="xs:integer"/> + <validate xmlns="http://jabber.org/protocol/xdata-validate" datatype="pubsub:integer-or-max"/> <value>1</value> </field> <field var="pubsub#persist_items" label="Persist items to storage" type="boolean"> @@ -124,7 +124,7 @@ Romeo sends: <field var="pubsub#description" type="text-single" label="Description"/> <field var="pubsub#type" type="text-single" label="The type of node data, usually specified by the namespace of the payload (if any)"/> <field var="pubsub#max_items" type="text-single" label="Max # of items to persist"> - <validate xmlns="http://jabber.org/protocol/xdata-validate" datatype="xs:integer"/> + <validate xmlns="http://jabber.org/protocol/xdata-validate" datatype="pubsub:integer-or-max"/> <value>1</value> </field> <field var="pubsub#persist_items" type="boolean" label="Persist items to storage"> diff --git a/spec/scansion/pubsub_multi_items.scs b/spec/scansion/pubsub_multi_items.scs index 147aaa8d..331093ca 100644 --- a/spec/scansion/pubsub_multi_items.scs +++ b/spec/scansion/pubsub_multi_items.scs @@ -43,11 +43,11 @@ Alice receives: <field var="pubsub#description" label="Description" type="text-single"/> <field var="pubsub#type" label="The type of node data, usually specified by the namespace of the payload (if any)" type="text-single"/> <field var="pubsub#max_items" label="Max # of items to persist" type="text-single"> - <validate xmlns="http://jabber.org/protocol/xdata-validate" datatype="xs:integer"/> + <validate xmlns="http://jabber.org/protocol/xdata-validate" datatype="pubsub:integer-or-max"/> <value>20</value> </field> <field var="pubsub#persist_items" label="Persist items to storage" type="boolean"> - <value>0</value> + <value>1</value> </field> <field var="pubsub#access_model" label="Specify the subscriber model" type="list-single"> <option label="authorize"> @@ -159,10 +159,10 @@ Alice receives: <iq xmlns:stream="http://etherx.jabber.org/streams" to="${Alice's full JID}" from="pubsub.localhost" type="result" id=":3nvB2E20p1iuM6lOPaP6"> <pubsub xmlns="http://jabber.org/protocol/pubsub"> <items node="e96caf12-264f-4e5a-988e-00ae191771b6"> - <item xmlns="http://jabber.org/protocol/pubsub" id="20e9eb9e-8acb-436e-a486-40e80400faf1"> + <item publisher="${Alice's JID}" xmlns="http://jabber.org/protocol/pubsub" id="20e9eb9e-8acb-436e-a486-40e80400faf1"> <foo xmlns="https://zombofant.net/xmlns/aioxmpp#test">foo</foo> </item> - <item xmlns="http://jabber.org/protocol/pubsub" id="4b94623d-1127-41c0-ac47-e283fd890557"> + <item publisher="${Alice's JID}" xmlns="http://jabber.org/protocol/pubsub" id="4b94623d-1127-41c0-ac47-e283fd890557"> <foo xmlns="https://zombofant.net/xmlns/aioxmpp#test">bar</foo> </item> </items> @@ -180,10 +180,10 @@ Alice receives: <iq xmlns:stream="http://etherx.jabber.org/streams" to="${Alice's full JID}" from="pubsub.localhost" type="result" id=":XQdyK54iyOKiJvUoX9t_"> <pubsub xmlns="http://jabber.org/protocol/pubsub"> <items node="e96caf12-264f-4e5a-988e-00ae191771b6"> - <item xmlns="http://jabber.org/protocol/pubsub" id="20e9eb9e-8acb-436e-a486-40e80400faf1"> + <item xmlns="http://jabber.org/protocol/pubsub" publisher="${Alice's JID}" id="20e9eb9e-8acb-436e-a486-40e80400faf1"> <foo xmlns="https://zombofant.net/xmlns/aioxmpp#test">foo</foo> </item> - <item xmlns="http://jabber.org/protocol/pubsub" id="4b94623d-1127-41c0-ac47-e283fd890557"> + <item xmlns="http://jabber.org/protocol/pubsub" publisher="${Alice's JID}" id="4b94623d-1127-41c0-ac47-e283fd890557"> <foo xmlns="https://zombofant.net/xmlns/aioxmpp#test">bar</foo> </item> </items> diff --git a/spec/scansion/pubsub_preconditions.scs b/spec/scansion/pubsub_preconditions.scs new file mode 100644 index 00000000..7e4e593b --- /dev/null +++ b/spec/scansion/pubsub_preconditions.scs @@ -0,0 +1,234 @@ +# Pubsub preconditions are enforced + +[Client] Romeo + password: password + jid: jqpcrbq2@localhost + +----- + +Romeo connects + +Romeo sends: + <iq id="67eb1f47-1e69-4cb3-91e2-4d5943e72d4c" type="set"> + <pubsub xmlns="http://jabber.org/protocol/pubsub"> + <publish node="http://jabber.org/protocol/tune"> + <item id="current"> + <tune xmlns="http://jabber.org/protocol/tune"/> + </item> + </publish> + </pubsub> + </iq> + +Romeo receives: + <iq id="67eb1f47-1e69-4cb3-91e2-4d5943e72d4c" type="result"> + <pubsub xmlns="http://jabber.org/protocol/pubsub"> + <publish node="http://jabber.org/protocol/tune"> + <item id="current"/> + </publish> + </pubsub> + </iq> + +Romeo sends: + <iq id="52d74a36-afb0-4028-87ed-b25b988b049e" type="get"> + <pubsub xmlns="http://jabber.org/protocol/pubsub#owner"> + <configure node="http://jabber.org/protocol/tune"/> + </pubsub> + </iq> + +Romeo receives: + <iq id="52d74a36-afb0-4028-87ed-b25b988b049e" type="result"> + <pubsub xmlns="http://jabber.org/protocol/pubsub#owner"> + <configure node="http://jabber.org/protocol/tune"> + <x xmlns="jabber:x:data" type="form"> + <field var="FORM_TYPE" type="hidden"> + <value>http://jabber.org/protocol/pubsub#node_config</value> + </field> + <field var="pubsub#title" label="Title" type="text-single"/> + <field var="pubsub#description" label="Description" type="text-single"/> + <field var="pubsub#type" label="The type of node data, usually specified by the namespace of the payload (if any)" type="text-single"/> + <field var="pubsub#max_items" label="Max # of items to persist" type="text-single"> + <validate xmlns="http://jabber.org/protocol/xdata-validate" datatype="pubsub:integer-or-max"/> + <value>1</value> + </field> + <field var="pubsub#persist_items" label="Persist items to storage" type="boolean"> + <value>1</value> + </field> + <field var="pubsub#access_model" label="Specify the subscriber model" type="list-single"> + <option label="authorize"> + <value>authorize</value> + </option> + <option label="open"> + <value>open</value> + </option> + <option label="presence"> + <value>presence</value> + </option> + <option label="roster"> + <value>roster</value> + </option> + <option label="whitelist"> + <value>whitelist</value> + </option> + <value>presence</value> + </field> + <field var="pubsub#publish_model" label="Specify the publisher model" type="list-single"> + <option label="publishers"> + <value>publishers</value> + </option> + <option label="subscribers"> + <value>subscribers</value> + </option> + <option label="open"> + <value>open</value> + </option> + <value>publishers</value> + </field> + <field var="pubsub#deliver_notifications" label="Whether to deliver event notifications" type="boolean"> + <value>1</value> + </field> + <field var="pubsub#deliver_payloads" label="Whether to deliver payloads with event notifications" type="boolean"> + <value>1</value> + </field> + <field var="pubsub#notification_type" label="Specify the delivery style for notifications" type="list-single"> + <option label="Messages of type normal"> + <value>normal</value> + </option> + <option label="Messages of type headline"> + <value>headline</value> + </option> + <value>headline</value> + </field> + <field var="pubsub#notify_delete" label="Whether to notify subscribers when the node is deleted" type="boolean"> + <value>1</value> + </field> + <field var="pubsub#notify_retract" label="Whether to notify subscribers when items are removed from the node" type="boolean"> + <value>1</value> + </field> + </x> + </configure> + </pubsub> + </iq> + +Romeo sends: + <iq id="a73aac09-74be-4ee2-97e5-571bbdbcd956" type="set"> + <pubsub xmlns="http://jabber.org/protocol/pubsub#owner"> + <configure node="http://jabber.org/protocol/tune"> + <x xmlns="jabber:x:data" type="submit"> + <field var="FORM_TYPE" type="hidden"> + <value>http://jabber.org/protocol/pubsub#node_config</value> + </field> + <field var="pubsub#title" type="text-single" label="Title"> + <value>Nice tunes</value> + </field> + <field var="pubsub#description" type="text-single" label="Description"/> + <field var="pubsub#type" type="text-single" label="The type of node data, usually specified by the namespace of the payload (if any)"/> + <field var="pubsub#max_items" type="text-single" label="Max # of items to persist"> + <validate xmlns="http://jabber.org/protocol/xdata-validate" datatype="pubsub:integer-or-max"/> + <value>1</value> + </field> + <field var="pubsub#persist_items" type="boolean" label="Persist items to storage"> + <value>1</value> + </field> + <field var="pubsub#access_model" type="list-single" label="Specify the subscriber model"> + <option label="authorize"> + <value>authorize</value> + </option> + <option label="open"> + <value>open</value> + </option> + <option label="presence"> + <value>presence</value> + </option> + <option label="roster"> + <value>roster</value> + </option> + <option label="whitelist"> + <value>whitelist</value> + </option> + <value>presence</value> + </field> + <field var="pubsub#publish_model" type="list-single" label="Specify the publisher model"> + <option label="publishers"> + <value>publishers</value> + </option> + <option label="subscribers"> + <value>subscribers</value> + </option> + <option label="open"> + <value>open</value> + </option> + <value>publishers</value> + </field> + <field var="pubsub#deliver_notifications" type="boolean" label="Whether to deliver event notifications"> + <value>1</value> + </field> + <field var="pubsub#deliver_payloads" type="boolean" label="Whether to deliver payloads with event notifications"> + <value>1</value> + </field> + <field var="pubsub#notification_type" type="list-single" label="Specify the delivery style for notifications"> + <option label="Messages of type normal"> + <value>normal</value> + </option> + <option label="Messages of type headline"> + <value>headline</value> + </option> + <value>headline</value> + </field> + <field var="pubsub#notify_delete" type="boolean" label="Whether to notify subscribers when the node is deleted"> + <value>1</value> + </field> + <field var="pubsub#notify_retract" type="boolean" label="Whether to notify subscribers when items are removed from the node"> + <value>1</value> + </field> + </x> + </configure> + </pubsub> + </iq> + +Romeo receives: + <iq id="a73aac09-74be-4ee2-97e5-571bbdbcd956" type="result"/> + +Romeo sends: + <iq id="ab0e92d2-c06b-4987-9d45-f9f9e7721709" type="get"> + <query xmlns="http://jabber.org/protocol/disco#items"/> + </iq> + +Romeo receives: + <iq id="ab0e92d2-c06b-4987-9d45-f9f9e7721709" type="result"> + <query xmlns="http://jabber.org/protocol/disco#items"> + <item name="Nice tunes" node="http://jabber.org/protocol/tune" jid="${Romeo's JID}"/> + </query> + </iq> + +Romeo sends: + <iq id="67eb1f47-1e69-4cb3-91e2-4d5943e72d4c" type="set"> + <pubsub xmlns="http://jabber.org/protocol/pubsub"> + <publish node="http://jabber.org/protocol/tune"> + <item id="current"> + <tune xmlns="http://jabber.org/protocol/tune"/> + </item> + </publish> + <publish-options> + <x xmlns="jabber:x:data"> + <field var="FORM_TYPE" type="hidden"> + <value>http://jabber.org/protocol/pubsub#publish-options</value> + </field> + <field var="pubsub#access_model"> + <value>whitelist</value> + </field> + </x> + </publish-options> + </pubsub> + </iq> + +Romeo receives: + <iq type='error' id='67eb1f47-1e69-4cb3-91e2-4d5943e72d4c'> + <error type='cancel'> + <conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> + <text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>Field does not match: access_model</text> + <precondition-not-met xmlns='http://jabber.org/protocol/pubsub#errors'/> + </error> + </iq> + +Romeo disconnects + diff --git a/spec/scansion/server_contact_info.scs b/spec/scansion/server_contact_info.scs new file mode 100644 index 00000000..f33d0957 --- /dev/null +++ b/spec/scansion/server_contact_info.scs @@ -0,0 +1,81 @@ +# XEP-0157: Contact Addresses for XMPP Services +# mod_server_contact_info + +[Client] Romeo + jid: romeo@localhost + password: password + +----- + +Romeo connects + +Romeo sends: + <iq type='get' id='lx2' to='localhost'> + <query xmlns='http://jabber.org/protocol/disco#info'/> + </iq> + +# Ignore other disco#info features, identities etc + +Romeo receives: + <iq from='localhost' id='lx2' type='result'> + <query xmlns='http://jabber.org/protocol/disco#info' scansion:strict='false'> + <x xmlns='jabber:x:data' type='result'> + <field type='hidden' var='FORM_TYPE'> + <value>http://jabber.org/network/serverinfo</value> + </field> + <field type='list-multi' var='abuse-addresses'> + <value>mailto:abuse@localhost</value> + <value>xmpp:abuse@localhost</value> + </field> + <field type='list-multi' var='admin-addresses'> + <value>mailto:admin@localhost</value> + <value>xmpp:admin@localhost</value> + </field> + <field type='list-multi' var='feedback-addresses'> + <value>http://localhost/feedback.html</value> + <value>mailto:feedback@localhost</value> + <value>xmpp:feedback@localhost</value> + </field> + <field type='list-multi' var='sales-addresses'> + <value>xmpp:sales@localhost</value> + </field> + <field type='list-multi' var='security-addresses'> + <value>xmpp:security@localhost</value> + </field> + <field type='list-multi' var='status-addresses'> + <value>gopher://status.localhost</value> + </field> + <field type='list-multi' var='support-addresses'> + <value>https://localhost/support.html</value> + <value>xmpp:support@localhost</value> + </field> + </x> + </query> + </iq> + + +Romeo sends: + <iq type='get' id='lx2' to='conference.localhost'> + <query xmlns='http://jabber.org/protocol/disco#info'/> + </iq> + + <iq from='localhost' id='lx2' type='result'> + <query xmlns='http://jabber.org/protocol/disco#info' scansion:strict='false'> + <x xmlns='jabber:x:data' type='result'> + <field type='hidden' var='FORM_TYPE'> + <value>http://jabber.org/network/serverinfo</value> + </field> + <field type='list-multi' var='abuse-addresses'/> + <field type='list-multi' var='admin-addresses'> + <value>xmpp:admin@localhost</value> + </field> + <field type='list-multi' var='feedback-addresses'/> + <field type='list-multi' var='sales-addresses'/> + <field type='list-multi' var='security-addresses'/> + <field type='list-multi' var='status-addresses'/> + <field type='list-multi' var='support-addresses'/> + </x> + </query> + </iq> + +Romeo disconnects diff --git a/spec/scansion/uptime.scs b/spec/scansion/uptime.scs new file mode 100644 index 00000000..188b9eb5 --- /dev/null +++ b/spec/scansion/uptime.scs @@ -0,0 +1,21 @@ +# XEP-0012: Last Activity / mod_uptime + +[Client] Romeo + jid: romeo@localhost + password: password + +----- + +Romeo connects + +Romeo sends: + <iq id='a' type='get' to='localhost'> + <query xmlns='jabber:iq:last'/> + </iq> + +Romeo receives: + <iq type='result' id='a' from='localhost'> + <query xmlns='jabber:iq:last' seconds='0'/> + </iq> + +Romeo disconnects diff --git a/spec/scansion/version.scs b/spec/scansion/version.scs new file mode 100644 index 00000000..6c841dd9 --- /dev/null +++ b/spec/scansion/version.scs @@ -0,0 +1,27 @@ +# XEP-0092: Software Version / mod_version + +[Client] Romeo + password: password + jid: romeo@localhost/dfaZpuxV + +----- + +Romeo connects + +Romeo sends: + <iq id='lx2' to='localhost' type='get'> + <query xmlns='jabber:iq:version'/> + </iq> + +# Version string would vary so we can't do an exact match atm +# Inclusion of <os/> is disabled in the config, it should be absent +Romeo receives: + <iq id='lx2' from='localhost' type='result'> + <query xmlns='jabber:iq:version' scansion:strict='true'> + <name>Prosody</name> + <version scansion:strict='false'/> + </query> + </iq> + + +Romeo disconnects |