Compare commits
10
Commits
32485f0593
...
25dfcba60d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
25dfcba60d | ||
|
|
2217cbeab3 | ||
|
|
69b8797d3b | ||
|
|
3dbbf5910e | ||
|
|
600068440f | ||
|
|
9eb19d53e7 | ||
|
|
c438554f9a | ||
|
|
d8bc3d17bb | ||
|
|
99d7f8a41a | ||
|
|
ff173a8ea3 |
No files matched your search
@@ -1,4 +1,4 @@
|
||||
image: debian/buster
|
||||
image: debian/stable
|
||||
sources:
|
||||
- https://git.sr.ht/~singpolyma/biboumi
|
||||
packages:
|
||||
@@ -12,8 +12,9 @@ packages:
|
||||
- libidn11-dev
|
||||
- libidn2-dev
|
||||
- libudns-dev
|
||||
- libbotan-2-dev
|
||||
- libbotan-3-dev
|
||||
- libsystemd-dev
|
||||
- libcurl4-openssl-dev
|
||||
artifacts:
|
||||
- biboumi/biboumi
|
||||
environment:
|
||||
|
||||
@@ -3,17 +3,144 @@
|
||||
(guix packages)
|
||||
(guix download)
|
||||
(guix git-download)
|
||||
(guix gexp)
|
||||
(guix build-system cmake)
|
||||
(guix build-system gnu)
|
||||
(guix utils)
|
||||
(gnu packages)
|
||||
(gnu packages compression)
|
||||
(gnu packages crypto)
|
||||
(gnu packages curl)
|
||||
(gnu packages databases)
|
||||
(gnu packages gcc)
|
||||
(gnu packages libidn)
|
||||
(gnu packages linux)
|
||||
(gnu packages python)
|
||||
(gnu packages sqlite)
|
||||
(gnu packages python-xyz)
|
||||
(gnu packages readline)
|
||||
(gnu packages version-control)
|
||||
(gnu packages xml)
|
||||
(ice-9 match)
|
||||
(ice-9 rdelim)
|
||||
(ice-9 popen))
|
||||
(ice-9 popen)
|
||||
(srfi srfi-26))
|
||||
|
||||
(define (sqlite-uri version year)
|
||||
(let ((numeric-version
|
||||
(match (string-split version #\.)
|
||||
((first-digit other-digits ...)
|
||||
(string-append first-digit
|
||||
(string-pad-right
|
||||
(string-concatenate
|
||||
(map (cut string-pad <> 2 #\0)
|
||||
other-digits))
|
||||
6 #\0))))))
|
||||
(string-append "https://sqlite.org/" (number->string year)
|
||||
"/sqlite-autoconf-" numeric-version ".tar.gz")))
|
||||
|
||||
(define-public sqlite
|
||||
(package
|
||||
(name "sqlite")
|
||||
(version "3.39.3")
|
||||
(source (origin
|
||||
(method url-fetch)
|
||||
(uri (sqlite-uri version 2022))
|
||||
(patches (search-patches "sqlite-hurd.patch"))
|
||||
(sha256
|
||||
(base32
|
||||
"1f922kq16g7f4h3gpzim78lvrp5xw9nvlvqw97s2qgxyh8qgns3q"))))
|
||||
(build-system gnu-build-system)
|
||||
(inputs (list readline))
|
||||
(outputs '("out" "static"))
|
||||
(arguments
|
||||
`(#:configure-flags
|
||||
;; Add -DSQLITE_SECURE_DELETE, -DSQLITE_ENABLE_FTS3,
|
||||
;; -DSQLITE_ENABLE_UNLOCK_NOTIFY and -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
;; to CFLAGS. GNU Icecat will refuse to use the system SQLite
|
||||
;; unless these options are enabled.
|
||||
(list (string-append "CFLAGS=-O2 -g -DSQLITE_SECURE_DELETE "
|
||||
"-DSQLITE_ENABLE_FTS3 "
|
||||
"-DSQLITE_ENABLE_UNLOCK_NOTIFY "
|
||||
"-DSQLITE_ENABLE_DBSTAT_VTAB "
|
||||
;; Column metadata is required by GNU Jami and Qt, et.al.
|
||||
"-DSQLITE_ENABLE_COLUMN_METADATA"))
|
||||
#:phases (modify-phases %standard-phases
|
||||
(add-after 'install 'move-static-library
|
||||
(lambda* (#:key outputs #:allow-other-keys)
|
||||
(let* ((out (assoc-ref outputs "out"))
|
||||
(static (assoc-ref outputs "static"))
|
||||
(source (string-append out "/lib/libsqlite3.a")))
|
||||
(mkdir-p (string-append static "/lib"))
|
||||
(link source (string-append static "/lib/libsqlite3.a"))
|
||||
(delete-file source)
|
||||
|
||||
;; Remove reference to the static library from the .la file
|
||||
;; so that Libtool looks for it in the usual places.
|
||||
(substitute* (string-append out "/lib/libsqlite3.la")
|
||||
(("^old_library=.*")
|
||||
"old_library=''\n"))
|
||||
#t))))))
|
||||
(home-page "https://www.sqlite.org/")
|
||||
(synopsis "The SQLite database management system")
|
||||
(description
|
||||
"SQLite is a software library that implements a self-contained, serverless,
|
||||
zero-configuration, transactional SQL database engine. SQLite is the most
|
||||
widely deployed SQL database engine in the world. The source code for SQLite
|
||||
is in the public domain.")
|
||||
(license license:public-domain)))
|
||||
|
||||
(define-public botan
|
||||
(package
|
||||
(name "botan")
|
||||
(version "3.9.0")
|
||||
(source (origin
|
||||
(method git-fetch)
|
||||
(uri (git-reference
|
||||
(url "https://github.com/randombit/botan/")
|
||||
(commit version)))
|
||||
(file-name (git-file-name name version))
|
||||
(sha256
|
||||
(base32
|
||||
"1k5dyn39b77bfawly2yms0crbkn6g7msh16q7bxnh7dra4cnkmsn"))))
|
||||
(build-system gnu-build-system)
|
||||
(arguments
|
||||
(list
|
||||
#:phases
|
||||
#~(modify-phases %standard-phases
|
||||
(replace 'configure
|
||||
(lambda* (#:key inputs outputs #:allow-other-keys)
|
||||
;; Upstream tests and benchmarks with -O3.
|
||||
(setenv "CXXFLAGS" "-O3")
|
||||
(invoke "python" "./configure.py"
|
||||
(string-append "--prefix=" #$output)
|
||||
"--disable-static"
|
||||
|
||||
;; Otherwise, the `botan` executable cannot find
|
||||
;; libbotan.
|
||||
(string-append "--ldflags=-Wl,-rpath=" #$output "/lib")
|
||||
|
||||
"--with-os-feature=getentropy"
|
||||
"--with-rst2man"
|
||||
|
||||
;; Recommended by upstream
|
||||
"--with-zlib" "--with-bzip2" "--with-sqlite3")))
|
||||
(add-before 'check 'library-path-for-tests
|
||||
(lambda _ (setenv "LD_LIBRARY_PATH" (getcwd))))
|
||||
(replace 'check
|
||||
(lambda* (#:key tests? #:allow-other-keys)
|
||||
(when tests?
|
||||
(invoke "./botan-test")))))))
|
||||
(native-inputs (list python-wrapper python-docutils gcc-12))
|
||||
(inputs (list sqlite bzip2 zlib))
|
||||
(synopsis "Cryptographic library in C++11")
|
||||
(description "Botan is a cryptography library, written in C++11, offering
|
||||
the tools necessary to implement a range of practical systems, such as TLS/DTLS,
|
||||
PKIX certificate handling, PKCS#11 and TPM hardware support, password hashing,
|
||||
and post-quantum crypto schemes. In addition to the C++, botan has a C89 API
|
||||
specifically designed to be easy to call from other languages. A Python binding
|
||||
using ctypes is included, and several other language bindings are available.")
|
||||
(home-page "https://botan.randombit.net")
|
||||
(license license:bsd-2)))
|
||||
|
||||
;;;;
|
||||
|
||||
@@ -47,9 +174,13 @@
|
||||
(lambda* (#:key outputs #:allow-other-keys)
|
||||
(substitute* "CMakeLists.txt"
|
||||
((".etc.biboumi") (string-append (assoc-ref outputs "out") "/etc/biboumi"))))))))
|
||||
(native-inputs
|
||||
'(list
|
||||
gcc-12))
|
||||
(inputs
|
||||
'(list
|
||||
botan
|
||||
curl
|
||||
expat
|
||||
git
|
||||
libidn2
|
||||
|
||||
@@ -596,6 +596,32 @@ void Bridge::send_irc_nick_change(const Iid& iid, const std::string& new_nick, c
|
||||
if (!res_in_chan)
|
||||
return;
|
||||
IrcClient* irc = this->get_irc_client(iid.get_server());
|
||||
if (new_nick == irc->get_own_nick())
|
||||
return;
|
||||
|
||||
#ifdef USE_DATABASE
|
||||
auto soptions = Database::get_irc_server_options(this->get_bare_jid(), iid.get_server());
|
||||
const auto& db_nick = soptions.col<Database::Nick>();
|
||||
if (!db_nick.empty())
|
||||
{
|
||||
IrcChannel* channel = irc->get_channel(iid.get_local());
|
||||
const IrcUser* self = channel ? channel->get_self() : nullptr;
|
||||
// Send presence 110+210 to let them know the nick we're actually using
|
||||
if (self)
|
||||
{
|
||||
this->send_user_join(iid.get_server(), iid.get_local(), self,
|
||||
self->get_most_significant_mode(irc->get_sorted_user_modes()),
|
||||
true, requesting_resource);
|
||||
}
|
||||
else
|
||||
{
|
||||
IrcUser user(irc->get_own_nick());
|
||||
this->send_user_join(iid.get_server(), iid.get_local(), &user, '\0', true, requesting_resource);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
irc->send_nick_command(new_nick);
|
||||
}
|
||||
|
||||
|
||||
@@ -526,6 +526,11 @@ void IrcClient::send_user_command(const std::string& username, const std::string
|
||||
|
||||
void IrcClient::send_nick_command(const std::string& nick)
|
||||
{
|
||||
if (nick.find(' ') != std::string::npos)
|
||||
{
|
||||
this->on_erroneous_nickname(IrcMessage(std::string(this->hostname), "432", {this->get_own_nick(), nick, "Erroneous nickname"}));
|
||||
return;
|
||||
}
|
||||
this->send_message(IrcMessage("NICK", {nick}));
|
||||
}
|
||||
|
||||
|
||||
+9
-1
@@ -20,6 +20,10 @@ IrcUri::~IrcUri(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CURL_FOUND
|
||||
#include <curl/curl.h>
|
||||
#endif
|
||||
|
||||
const std::optional<std::string> IrcUri::get_server(void) const {
|
||||
#ifdef CURL_FOUND
|
||||
char *server;
|
||||
@@ -27,7 +31,9 @@ const std::optional<std::string> IrcUri::get_server(void) const {
|
||||
if (rc) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return server;
|
||||
std::string result(server);
|
||||
curl_free(server);
|
||||
return result;
|
||||
#else
|
||||
return std::nullopt;
|
||||
#endif // CURL_FOUND
|
||||
@@ -42,6 +48,7 @@ const std::optional<std::string> IrcUri::get_entity(void) const {
|
||||
if (rc)
|
||||
return std::nullopt;
|
||||
output = entity;
|
||||
curl_free(entity);
|
||||
if (!output.empty())
|
||||
output.erase(0, 1);
|
||||
if (output.empty()) {
|
||||
@@ -49,6 +56,7 @@ const std::optional<std::string> IrcUri::get_entity(void) const {
|
||||
if (rc)
|
||||
return std::nullopt;
|
||||
output = entity;
|
||||
curl_free(entity);
|
||||
output.insert(0, 1, '#');
|
||||
}
|
||||
return IrcUri::parse_entity(output);
|
||||
|
||||
@@ -33,3 +33,22 @@ std::string sha1(const std::string& input)
|
||||
return digest.str();
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string sha1_raw(const std::string& input)
|
||||
{
|
||||
#ifdef BOTAN_FOUND
|
||||
auto sha1 = Botan::HashFunction::create_or_throw("SHA-1");
|
||||
sha1->update(input);
|
||||
const auto digest = sha1->final();
|
||||
return std::string(
|
||||
reinterpret_cast<const char*>(digest.data()),
|
||||
digest.size()
|
||||
);
|
||||
#endif
|
||||
#ifdef GCRYPT_FOUND
|
||||
const auto hash_length = gcry_md_get_algo_dlen(GCRY_MD_SHA1);
|
||||
std::string output(hash_length, '\0');
|
||||
gcry_md_hash_buffer(GCRY_MD_SHA1, output.data(), input.data(), input.size());
|
||||
return output;
|
||||
#endif
|
||||
}
|
||||
@@ -3,3 +3,4 @@
|
||||
#include <string>
|
||||
|
||||
std::string sha1(const std::string& input);
|
||||
std::string sha1_raw(const std::string& input);
|
||||
@@ -576,9 +576,10 @@ void BiboumiComponent::handle_iq(const Stanza& stanza)
|
||||
}
|
||||
else if (iid.type == Iid::Type::Server)
|
||||
{
|
||||
if (node.empty())
|
||||
const std::string expected_node_name = std::string(NODE_NAME) + "#" + get_irc_server_ver(to_str);
|
||||
if (node.empty() || node == expected_node_name)
|
||||
{
|
||||
this->send_irc_server_disco_info(id, from, to_str);
|
||||
this->send_irc_server_disco_info(id, from, to_str, node);
|
||||
stanza_error.disable();
|
||||
}
|
||||
}
|
||||
@@ -1074,28 +1075,35 @@ void BiboumiComponent::send_self_disco_info(const std::string& id, const std::st
|
||||
this->send_stanza(iq);
|
||||
}
|
||||
|
||||
void BiboumiComponent::send_irc_server_disco_info(const std::string& id, const std::string& jid_to, const std::string& jid_from)
|
||||
void BiboumiComponent::send_irc_server_disco_info(const std::string& id, const std::string& jid_to,
|
||||
const std::string& jid_from, const std::string& node)
|
||||
{
|
||||
Stanza iq = get_irc_server_disco_info(jid_from, node);
|
||||
iq["id"] = id;
|
||||
iq["to"] = jid_to;
|
||||
iq["from"] = jid_from;
|
||||
this->send_stanza(iq);
|
||||
}
|
||||
|
||||
Stanza BiboumiComponent::get_irc_server_disco_info(const std::string& jid_from, const std::string& node)
|
||||
{
|
||||
Jid from(jid_from);
|
||||
Stanza iq("iq");
|
||||
{
|
||||
iq["type"] = "result";
|
||||
iq["id"] = id;
|
||||
iq["to"] = jid_to;
|
||||
iq["from"] = jid_from;
|
||||
XmlSubNode query(iq, "query");
|
||||
query["xmlns"] = DISCO_INFO_NS;
|
||||
XmlSubNode identity(query, "identity");
|
||||
identity["category"] = "gateway";
|
||||
identity["type"] = "irc";
|
||||
identity["name"] = "IRC server " + from.local + " over Biboumi";
|
||||
for (const char *ns: {DISCO_INFO_NS, ADHOC_NS, PING_NS, VERSION_NS})
|
||||
{
|
||||
XmlSubNode feature(query, "feature");
|
||||
feature["var"] = ns;
|
||||
}
|
||||
}
|
||||
this->send_stanza(iq);
|
||||
iq["type"] = "result";
|
||||
XmlSubNode query(iq, "query");
|
||||
query["xmlns"] = DISCO_INFO_NS;
|
||||
if (!node.empty())
|
||||
query["node"] = node;
|
||||
XmlSubNode identity(query, "identity");
|
||||
identity["category"] = "gateway";
|
||||
identity["type"] = "irc";
|
||||
identity["name"] = "IRC server " + from.local + " over Biboumi";
|
||||
for (const char *ns: {DISCO_INFO_NS, CAPS_NS, ADHOC_NS, PING_NS, VERSION_NS})
|
||||
{
|
||||
XmlSubNode feature(query, "feature");
|
||||
feature["var"] = ns;
|
||||
}
|
||||
return iq;
|
||||
}
|
||||
|
||||
void BiboumiComponent::send_irc_channel_muc_traffic_info(const std::string& id, const std::string& jid_to, const std::string& jid_from)
|
||||
@@ -1303,13 +1311,24 @@ void BiboumiComponent::send_presence_to_contact(const std::string& from, const s
|
||||
if (!id.empty())
|
||||
presence["id"] = id;
|
||||
|
||||
if (type.empty() && from == this->served_hostname) {
|
||||
XmlSubNode c(presence, "c");
|
||||
c["xmlns"] = CAPS_NS;
|
||||
c["hash"] = "sha-1";
|
||||
c["node"] = NODE_NAME;
|
||||
c["ver"] = this->get_self_ver();
|
||||
}
|
||||
if (type.empty())
|
||||
{
|
||||
Jid from_jid(from);
|
||||
const Iid from_iid(from_jid.local, {'&', '#', '+', '!'});
|
||||
const std::string fixed_irc_server = Config::get("fixed_irc_server", "");
|
||||
const bool is_server_jid = !from_jid.local.empty() && from_jid.resource.empty() &&
|
||||
((fixed_irc_server.empty() && from_iid.type == Iid::Type::Server) ||
|
||||
(!fixed_irc_server.empty() && from_jid.local == fixed_irc_server));
|
||||
if (from == this->served_hostname ||
|
||||
(from_jid.domain == this->served_hostname && is_server_jid))
|
||||
{
|
||||
XmlSubNode c(presence, "c");
|
||||
c["xmlns"] = CAPS_NS;
|
||||
c["hash"] = "sha-1";
|
||||
c["node"] = NODE_NAME;
|
||||
c["ver"] = from == this->served_hostname ? this->get_self_ver() : get_irc_server_ver(from);
|
||||
}
|
||||
}
|
||||
this->send_stanza(presence);
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,8 @@ public:
|
||||
/**
|
||||
* Send a result IQ with the disco informations regarding IRC server JIDs.
|
||||
*/
|
||||
void send_irc_server_disco_info(const std::string& id, const std::string& jid_to, const std::string& jid_from);
|
||||
void send_irc_server_disco_info(const std::string& id, const std::string& jid_to,
|
||||
const std::string& jid_from, const std::string& node);
|
||||
/**
|
||||
* Sends the allowed namespaces in MUC message, according to
|
||||
* http://xmpp.org/extensions/xep-0045.html#impl-service-traffic
|
||||
@@ -93,6 +94,9 @@ private:
|
||||
void send_invitation_from_fulljid(const std::string& room_target, const std::string& jid_to, const std::string& from);
|
||||
static Stanza get_self_disco_info(const std::string &node);
|
||||
static std::string get_self_ver() { return Xmpp::hash_disco_sha1(get_self_disco_info("")); };
|
||||
static Stanza get_irc_server_disco_info(const std::string& jid_from, const std::string& node);
|
||||
static std::string get_irc_server_ver(const std::string& jid_from)
|
||||
{ return Xmpp::hash_disco_sha1(get_irc_server_disco_info(jid_from, "")); }
|
||||
#ifdef CURL_FOUND
|
||||
std::optional<Stanza> handle_iq_gateway(const Stanza *stanza, const Jid *from, const std::string to, const std::string id);
|
||||
#endif
|
||||
|
||||
@@ -17,7 +17,7 @@ const std::string hash_disco_sha1(const Stanza &stanza) {
|
||||
return category_compare;
|
||||
const std::string type_a = a->get_tag("type");
|
||||
const std::string type_b = b->get_tag("type");
|
||||
const int type_compare = type_a > type_b;
|
||||
const int type_compare = type_a < type_b;
|
||||
return type_compare;
|
||||
});
|
||||
|
||||
@@ -33,7 +33,7 @@ const std::string hash_disco_sha1(const Stanza &stanza) {
|
||||
[](const XmlNode *a, const XmlNode *b) {
|
||||
const std::string var_a = a->get_tag("var");
|
||||
const std::string var_b = b->get_tag("var");
|
||||
const int var_compare = var_a > var_b;
|
||||
const int var_compare = var_a < var_b;
|
||||
return var_compare;
|
||||
});
|
||||
|
||||
@@ -42,7 +42,7 @@ const std::string hash_disco_sha1(const Stanza &stanza) {
|
||||
s += var + "<";
|
||||
}
|
||||
|
||||
const std::string hashed = sha1(s);
|
||||
const std::string hashed = sha1_raw(s);
|
||||
const std::string encoded = base64::encode(hashed);
|
||||
|
||||
return encoded;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
from scenarios import *
|
||||
|
||||
scenario = (
|
||||
# IRC server JIDs advertise caps for their own disco info
|
||||
send_stanza("<iq type='get' id='get6' from='{jid_one}/{resource_one}' to='{irc_server_one}'><query xmlns='http://jabber.org/protocol/disco#info'/></iq>"),
|
||||
expect_stanza("/iq[@from='{irc_server_one}'][@to='{jid_one}/{resource_one}'][@type='result']/disco_info:query/disco_info:identity[@category='gateway'][@type='irc']",
|
||||
"/iq/disco_info:query/disco_info:feature[@var='http://jabber.org/protocol/disco#info']",
|
||||
"/iq/disco_info:query/disco_info:feature[@var='http://jabber.org/protocol/caps']"
|
||||
),
|
||||
send_stanza("<presence from='{jid_one}/{resource_one}' to='#foo%{irc_server_one}/{nick_one}'><x xmlns='http://jabber.org/protocol/muc'/></presence>"),
|
||||
sequences.connection(),
|
||||
scenarios.simple_channel_join.expect_self_join_presence(),
|
||||
send_stanza("<presence from='{jid_one}/{resource_one}' to='{irc_server_one}' type='subscribe'/>"),
|
||||
expect_stanza("/presence[@from='{irc_server_one}'][@to='{jid_one}'][@type='subscribed']"),
|
||||
expect_stanza("/presence[@from='{irc_server_one}'][@to='{jid_one}']/caps:c[@hash='sha-1'][@node][@ver]",
|
||||
after = (
|
||||
save_value("server_ver", extract_attribute("/presence/caps:c[@hash='sha-1'][@node][@ver]", "ver")),
|
||||
save_value("server_node", extract_attribute("/presence/caps:c[@hash='sha-1'][@node][@ver]", "node")),
|
||||
)
|
||||
),
|
||||
send_stanza("<iq type='get' id='get8' from='{jid_one}/{resource_one}' to='{irc_server_one}'><query xmlns='http://jabber.org/protocol/disco#info' node='{server_node}#{server_ver}'/></iq>"),
|
||||
expect_stanza("/iq[@from='{irc_server_one}'][@type='result']/disco_info:query[@node='{server_node}#{server_ver}']"),
|
||||
)
|
||||
@@ -0,0 +1,13 @@
|
||||
from scenarios import *
|
||||
|
||||
scenario = (
|
||||
send_stanza("<presence from='{jid_one}/{resource_one}' to='#foo%{irc_server_one}/{nick_one}' ><x xmlns='http://jabber.org/protocol/muc'/></presence>"),
|
||||
sequences.connection(),
|
||||
expect_stanza("/presence[@to='{jid_one}/{resource_one}'][@from='#foo%{irc_server_one}/{nick_one}']/muc_user:x/muc_user:item[@affiliation='admin'][@role='moderator']",
|
||||
"/presence/muc_user:x/muc_user:status[@code='110']"),
|
||||
expect_stanza("/message[@from='#foo%{irc_server_one}'][@type='groupchat']/subject[not(text())]"),
|
||||
|
||||
# Attempt to change nick to a nickname containing a space
|
||||
send_stanza("<presence from='{jid_one}/{resource_one}' to='#foo%{irc_server_one}/Nick With Space' />"),
|
||||
expect_stanza("/message[@from='{irc_server_one}'][@to='{jid_one}/{resource_one}']/body[text()='irc.localhost: Erroneous nickname: Nick With Space']"),
|
||||
)
|
||||
@@ -0,0 +1,26 @@
|
||||
from scenarios import *
|
||||
|
||||
scenario = (
|
||||
send_stanza("<presence from='{jid_one}/{resource_one}' to='#foo%{irc_server_one}/{nick_one}' ><x xmlns='http://jabber.org/protocol/muc'/></presence>"),
|
||||
sequences.connection(),
|
||||
expect_stanza("/presence[@to='{jid_one}/{resource_one}'][@from='#foo%{irc_server_one}/{nick_one}']/muc_user:x/muc_user:item[@affiliation='admin'][@role='moderator']",
|
||||
"/presence/muc_user:x/muc_user:status[@code='110']"),
|
||||
expect_stanza("/message[@from='#foo%{irc_server_one}'][@type='groupchat']/subject[not(text())]"),
|
||||
|
||||
# Configure a nickname in the database for this server
|
||||
send_stanza("<iq type='set' id='conf1' from='{jid_one}/{resource_one}' to='{irc_server_one}'><command xmlns='http://jabber.org/protocol/commands' node='configure' action='execute' /></iq>"),
|
||||
expect_stanza("/iq[@type='result']",
|
||||
after = save_value("sessionid", extract_attribute("/iq[@type='result']/commands:command[@node='configure']", "sessionid"))),
|
||||
send_stanza("<iq type='set' id='conf2' from='{jid_one}/{resource_one}' to='{irc_server_one}'>"
|
||||
"<command xmlns='http://jabber.org/protocol/commands' node='configure' sessionid='{sessionid}' action='complete'>"
|
||||
"<x xmlns='jabber:x:data' type='submit'>"
|
||||
"<field var='nick'><value>{nick_one}</value></field>"
|
||||
"</x></command></iq>"),
|
||||
expect_stanza("/iq[@type='result']/commands:command[@node='configure'][@status='completed']/commands:note[@type='info'][text()='Configuration successfully applied.']"),
|
||||
|
||||
# Now with a DB nick configured, attempt to change nick: should reply with 110 + 210 presence rewriting to DB nick
|
||||
send_stanza("<presence from='{jid_one}/{resource_one}' to='#foo%{irc_server_one}/SomeOtherNick' />"),
|
||||
expect_stanza("/presence[@to='{jid_one}/{resource_one}'][@from='#foo%{irc_server_one}/{nick_one}']/muc_user:x/muc_user:item[@affiliation='admin'][@role='moderator']",
|
||||
"/presence/muc_user:x/muc_user:status[@code='110']",
|
||||
"/presence/muc_user:x/muc_user:status[@code='210']"),
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
from scenarios import *
|
||||
|
||||
scenario = (
|
||||
send_stanza("<presence from='{jid_one}/{resource_one}' to='#foo%{irc_server_one}/{nick_one}' ><x xmlns='http://jabber.org/protocol/muc'/></presence>"),
|
||||
sequences.connection(),
|
||||
expect_stanza("/presence[@to='{jid_one}/{resource_one}'][@from='#foo%{irc_server_one}/{nick_one}']/muc_user:x/muc_user:item[@affiliation='admin'][@role='moderator']",
|
||||
"/presence/muc_user:x/muc_user:status[@code='110']"),
|
||||
expect_stanza("/message[@from='#foo%{irc_server_one}'][@type='groupchat']/subject[not(text())]"),
|
||||
|
||||
# Presence with the current nick (status update) should be ignored (no error, no change)
|
||||
send_stanza("<presence from='{jid_one}/{resource_one}' to='#foo%{irc_server_one}/{nick_one}'><show>away</show></presence>"),
|
||||
)
|
||||
@@ -32,7 +32,7 @@ TEST_CASE("Hash disco 1") {
|
||||
|
||||
auto check_stanza = [](const Stanza &stanza) {
|
||||
const std::string hash = Xmpp::hash_disco_sha1(stanza);
|
||||
CHECK(hash == "YjVkN2NhODU2ZWQyZjhhNjJjOTE1MWMxYjQ0YmUwM2Q0ODhhZDI2MA==");
|
||||
CHECK(hash == "GRREviyyjLzK2wK4QLX5NNF9FmQ=");
|
||||
};
|
||||
xml.add_stanza_callback([check_stanza](const Stanza &stanza) {
|
||||
check_stanza(stanza);
|
||||
@@ -62,7 +62,7 @@ TEST_CASE("Hash disco 2") {
|
||||
|
||||
auto check_stanza = [](const Stanza &stanza) {
|
||||
const std::string hash = Xmpp::hash_disco_sha1(stanza);
|
||||
CHECK(hash == "ZmY1ZTJjZjUyZjkwMjA2OTliZGFhYzYxMmVmMTI5YjdmYzNhZTIwYw==");
|
||||
CHECK(hash == "ga7DGXbUk3tyt5T/WMlqa5qM0zM=");
|
||||
};
|
||||
xml.add_stanza_callback([check_stanza](const Stanza &stanza) {
|
||||
check_stanza(stanza);
|
||||
@@ -91,7 +91,7 @@ TEST_CASE("Hash disco 2 different order") {
|
||||
|
||||
auto check_stanza = [](const Stanza &stanza) {
|
||||
const std::string hash = Xmpp::hash_disco_sha1(stanza);
|
||||
CHECK(hash == "ZmY1ZTJjZjUyZjkwMjA2OTliZGFhYzYxMmVmMTI5YjdmYzNhZTIwYw==");
|
||||
CHECK(hash == "ga7DGXbUk3tyt5T/WMlqa5qM0zM=");
|
||||
};
|
||||
xml.add_stanza_callback([check_stanza](const Stanza &stanza) {
|
||||
check_stanza(stanza);
|
||||
|
||||
Reference in new issue
Block a user