Browse Source

Added support for XEP-0215: External Service Discovery

pull/978/head
Timothée Jaussoin 5 years ago
parent
commit
01ccbbcb7f
  1. 1
      CHANGELOG.md
  2. 7
      doap.xml
  3. 224
      linker.php

1
CHANGELOG.md

@ -42,6 +42,7 @@ v0.18 (trunk)
* Create a new Toast widget
* Remove favico.js and rewrite it to a custom pure Javascript
* Fix some notifications issues
* Added support for XEP-0368: SRV records for XMPP over TLS
v0.17.1
---------------------------

7
doap.xml

@ -391,6 +391,13 @@
<xmpp:note>for reactions</xmpp:note>
</xmpp:SupportedXep>
</implements>
<implements>
<xmpp:SupportedXep>
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0368.html"/>
<xmpp:status>complete</xmpp:status>
<xmpp:version>1.1.0</xmpp:version>
</xmpp:SupportedXep>
</implements>
<implements>
<xmpp:SupportedXep>
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0372.html"/>

224
linker.php

@ -7,6 +7,8 @@ use Movim\Bootstrap;
use Movim\RPC;
use Movim\Session;
use React\Promise\Timer;
$bootstrap = new Bootstrap;
$bootstrap->boot();
@ -18,7 +20,6 @@ $connector = new React\Socket\TimeoutConnector(
// DNS
$config = React\Dns\Config\Config::loadSystemConfigBlocking();
\Utils::debug(serialize($config));
$server = $config->nameservers ? reset($config->nameservers) : '8.8.8.8';
$factory = new React\Dns\Resolver\Factory();
@ -29,6 +30,7 @@ $wrapper = \Movim\Widget\Wrapper::getInstance();
$wrapper->registerAll($bootstrap->getWidgets());
$xmppSocket = null;
$directTLSSocket = false;
$parser = new \Moxl\Parser(function ($node) {
\Moxl\Xec\Handler::handle($node);
@ -67,6 +69,11 @@ function writeOut($msg = null)
}
}
function logOut($log)
{
fwrite(STDERR, colorize(getenv('sid'), 'yellow')." : ".$log."\n");
}
function writeXMPP($xml)
{
global $xmppSocket;
@ -77,8 +84,102 @@ function writeXMPP($xml)
$xmppSocket->write(trim($xml));
if (getenv('debug')) {
fwrite(STDERR, colorize(trim($xml), 'yellow')." : ".colorize('sent to XMPP', 'green')."\n");
logOut(colorize(trim($xml).' ', 'yellow') . colorize('sent to XMPP', 'green'));
}
}
}
function enableEncryption($stream): bool
{
logOut(colorize('Enable TLS on the socket', 'blue')."\n");
$session = Session::start();
stream_set_blocking($stream, 1);
stream_context_set_option($stream, 'ssl', 'SNI_enabled', false);
stream_context_set_option($stream, 'ssl', 'peer_name', $session->get('host'));
stream_context_set_option($stream, 'ssl', 'allow_self_signed', false);
// See http://php.net/manual/en/function.stream-socket-enable-crypto.php#119122
$crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
if (defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT')) {
$crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT;
}
if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
$crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
$crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
}
set_error_handler('handleSSLErrors');
$out = stream_socket_enable_crypto($stream, 1, $crypto_method);
restore_error_handler();
if ($out !== true) {
$evt = new Movim\Widget\Event;
$evt->run('ssl_error');
shutdown();
return false;
}
return true;
}
function handleClientDNS(array $results, $dns, $connector, $xmppBehaviour)
{
if (count($results) > 1) {
$port = 5222;
global $directTLSSocket;
if ($results['directtls'] !== false && $results['directtls'][0]['target'] !== '.'
&& $results['starttls'] !== false) {
if ($results['starttls'][0]['priority'] > $results['directtls'][0]['priority']) {
$host = $results['starttls'][0]['target'];
$port = $results['starttls'][0]['port'];
logOut(colorize('Picked STARTTLS', 'blue'));
} else {
$host = $results['directtls'][0]['target'];
$port = $results['directtls'][0]['port'];
$directTLSSocket = true;
logOut(colorize('Picked DirectTLS', 'blue'));
}
} elseif ($results['directtls'] !== false && $results['directtls'][0]['target'] !== '.') {
$host = $results['directtls'][0]['target'];
$port = $results['directtls'][0]['port'];
$directTLSSocket = true;
logOut(colorize('Picked DirectTLS', 'blue'));
} elseif ($results['starttls'] !== false) {
$host = $results['starttls'][0]['target'];
$port = $results['starttls'][0]['port'];
logOut(colorize('Picked STARTTLS', 'blue'));
} else {
// No SRV, we fallback to the default host
$session = Session::start();
$host = $session->get('host');
}
logOut(colorize('Resolving '.$host.':'.$port, 'blue'));
React\Promise\any([
$dns->resolve($host, React\Dns\Model\Message::TYPE_AAAA),
//$dns->resolve($host, React\Dns\Model\Message::TYPE_A)
])->then(function ($ip) use ($port, $connector, $xmppBehaviour) {
logOut(colorize('Connect to '.$ip.':'.$port, 'blue'));
$connector->connect('['.$ip.']:'. $port)
->then(
$xmppBehaviour,
function () {
$evt = new Movim\Widget\Event;
$evt->run('timeout_error');
$this->cancel();
}
);
}, function() {
$evt = new Movim\Widget\Event;
$evt->run('dns_error');
});
}
}
@ -127,58 +228,36 @@ $wsSocketBehaviour = function ($msg) use (&$xmppSocket, &$connector, &$xmppBehav
break;
case 'register':
$port = 5222;
$host = $msg->host;
// Set the host, useful for the CN certificate check
$session = Session::start();
$session->set('host', $msg->host);
$dns->resolveAll('_xmpp-client._tcp.' . $msg->host, React\Dns\Model\Message::TYPE_SRV)
global $loop;
$results = [];
Timer\timeout($dns->resolveAll('_xmpps-client._tcp.' . $msg->host, React\Dns\Model\Message::TYPE_SRV), 3.0, $loop)
->then(
function ($resolved) use (&$host, &$port, &$msg) {
$host = $resolved[0]['target'];
$port = $resolved[0]['port'];
if (getenv('verbose')) {
fwrite(
STDERR,
colorize(
getenv('sid'),
'yellow'
)." : ".
colorize('Resolved target '.$host.' from '.$msg->host, 'blue').
"\n"
);
}
function ($resolved) use (&$results, &$dns, $connector, $xmppBehaviour) {
$results['directtls'] = $resolved;
handleClientDNS($results, $dns, $connector, $xmppBehaviour);
},
function ($rejected) use (&$results, &$dns, $connector, $xmppBehaviour) {
$results['directtls'] = false;
handleClientDNS($results, $dns, $connector, $xmppBehaviour);
}
)
->always(function () use (&$connector, &$xmppBehaviour, &$dns, &$host, &$port) {
$dns->resolve($host, React\Dns\Model\Message::TYPE_AAAA)
->then(
function ($ip) use (&$connector, &$xmppBehaviour, $host, $port) {
if (getenv('verbose')) {
fwrite(
STDERR,
colorize(
getenv('sid'),
'yellow'
)." : ".
colorize('Connection to '.$host.' ('.$ip.')', 'blue').
"\n"
);
}
$connector->connect('['.$ip.']:'. $port)
->then($xmppBehaviour)
->otherwise(function () {
$evt = new Movim\Widget\Event;
$evt->run('timeout_error');
$this->cancel();
});
}
)
->otherwise(function () {
$evt = new Movim\Widget\Event;
$evt->run('dns_error');
});
});
);
Timer\timeout($dns->resolveAll('_xmpp-client._tcp.' . $msg->host, React\Dns\Model\Message::TYPE_SRV), 3.0, $loop)
->then(
function ($resolved) use (&$results, &$dns, $connector, $xmppBehaviour) {
$results['starttls'] = $resolved;
handleClientDNS($results, $dns, $connector, $xmppBehaviour);
},
function ($rejected) use (&$results, &$dns, $connector, $xmppBehaviour) {
$results['starttls'] = false;
handleClientDNS($results, $dns, $connector, $xmppBehaviour);
}
);
break;
}
@ -189,12 +268,18 @@ $wsSocketBehaviour = function ($msg) use (&$xmppSocket, &$connector, &$xmppBehav
$xmppBehaviour = function (React\Socket\Connection $stream) use (&$xmppSocket, $parser, &$timestampReceive) {
global $wsSocket;
global $directTLSSocket;
$xmppSocket = $stream;
if ($directTLSSocket) {
enableEncryption($xmppSocket->stream);
stream_set_blocking($xmppSocket->stream, 0);
}
if (getenv('verbose')) {
fwrite(STDERR, colorize(getenv('sid'), 'yellow')." : ".colorize('XMPP socket launched', 'blue')."\n");
fwrite(STDERR, colorize(getenv('sid'), 'yellow')." launched : ".\sizeToCleanSize(memory_get_usage())."\n");
logOut(colorize('XMPP socket launched', 'blue'));
logOut(" launched : ".\sizeToCleanSize(memory_get_usage()));
}
$xmppSocket->on('data', function ($message) use (&$xmppSocket, $parser, &$timestampReceive) {
@ -202,7 +287,7 @@ $xmppBehaviour = function (React\Socket\Connection $stream) use (&$xmppSocket, $
$restart = false;
if (getenv('debug')) {
fwrite(STDERR, colorize($message, 'yellow')." : ".colorize('received', 'green')."\n");
logOut(colorize($message.' ', 'yellow') . colorize('received', 'green'));
}
if ($message == '</stream:stream>') {
@ -210,34 +295,11 @@ $xmppBehaviour = function (React\Socket\Connection $stream) use (&$xmppSocket, $
shutdown();
} elseif ($message == "<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"
|| $message == '<proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>') {
$session = Session::start();
stream_set_blocking($xmppSocket->stream, 1);
stream_context_set_option($xmppSocket->stream, 'ssl', 'SNI_enabled', false);
stream_context_set_option($xmppSocket->stream, 'ssl', 'peer_name', $session->get('host'));
stream_context_set_option($xmppSocket->stream, 'ssl', 'allow_self_signed', true);
// See http://php.net/manual/en/function.stream-socket-enable-crypto.php#119122
$crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
$crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
$crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
}
set_error_handler('handleSSLErrors');
$out = stream_socket_enable_crypto($xmppSocket->stream, 1, $crypto_method);
restore_error_handler();
if ($out !== true) {
$evt = new Movim\Widget\Event;
$evt->run('ssl_error');
shutdown();
return;
}
$success = enableEncryption($xmppSocket->stream);
if (!$success) return;
if (getenv('verbose')) {
fwrite(STDERR, colorize(getenv('sid'), 'yellow')." : ".colorize('TLS enabled', 'blue')."\n");
logOut(colorize('TLS enabled', 'blue')."\n");
}
$restart = true;
@ -253,7 +315,7 @@ $xmppBehaviour = function (React\Socket\Connection $stream) use (&$xmppSocket, $
}
if (!$parser->parse($message)) {
fwrite(STDERR, colorize(getenv('sid'), 'yellow')." ".$parser->getError()."\n");
logOut($parser->getError());
}
}
});

Loading…
Cancel
Save