Commit 326facdb authored by Ivan Vilata-i-Balaguer's avatar Ivan Vilata-i-Balaguer
Browse files

Merge branch 'swarm-name-fixes'.

This includes several fixes related with automatic swarm name computation:

  - Use lower-case, unpadded Base32-encoding for injector keys in swarm names.
  - Disable obsolete `announce-in-bep5-swarm` injector option in Docker
    wrapper script.
  - Show injector public key in the client front-end (to ease showing it to
    other users).
  - Also allow setting the injector public in Base32-encoded format for the
    `--cache-http-public-key` client option (to ease receiving it from other
    users in written form).
parents aa4649cd 60272e9f
......@@ -18,9 +18,6 @@ open-file-limit = 32768
#listen-on-utp-tls = 0.0.0.0:7085 # all IPv4
#listen-on-utp-tls = :::7085 # all IPv4 and IPv6
#listen-on-utp-tls = 127.0.0.1:7085 # loopback IPv4
# This announces the uTP/TLS endpoint in a BEP5 swarm based on this name.
# **PLEASE USE YOUR OWN SWARM NAME!**
announce-in-bep5-swarm = test_swarm_name_change_me
# This sets an anonymous, encrypted HTTP proxy over I2P (for production).
listen-on-i2p = true
......
......@@ -84,12 +84,6 @@ if [ ! -d "$REPO" ] && ! has_help_arg "$@"; then
sed -i -E "s/^#?(listen-on-utp-tls\s*=\s*0\.0\.0\.0:)[0-9]+(.*)/\1${INJECTOR_UTP_TLS_PORT}\2/" "$CONF"
fi
# Generate a random injector BEP5 swarm name.
if [ "$PROG" = injector ]; then
swarm=$(dd if=/dev/urandom bs=1024 count=1 status=none | sha256sum | cut -f1 -d' ')
sed -i -E "s/^(announce-in-bep5-swarm\s*=\s*).*/\1$swarm/" "$CONF"
fi
# Generate a random password for injector credentials.
if [ "$PROG" = injector ]; then
password=$(dd if=/dev/urandom bs=1024 count=1 status=none | md5sum | cut -f1 -d' ')
......@@ -136,8 +130,8 @@ if grep -qE '^\s*disable-cache\s*=\b' "$CONF" && ! has_help_arg "$@"; then
fi
# Comment out some obsolete configuration parameters.
if grep -qE '^\s*(cache-index|index-ipns-id)\s*=' "$CONF" && ! has_help_arg "$@"; then
sed -i -E 's/^(\s*)(cache-index|index-ipns-id)(\s*=.*)/##\1\2\3 # obsolete/' "$CONF"
if grep -qE '^\s*(cache-index|index-ipns-id|announce-in-bep5-swarm)\s*=' "$CONF" && ! has_help_arg "$@"; then
sed -i -E 's/^(\s*)(cache-index|index-ipns-id|announce-in-bep5-swarm)(\s*=.*)/##\1\2\3 # obsolete/' "$CONF"
fi
# Update TCP/TLS endpoint file name.
......
#include "bep5_swarms.h"
#include "util/str.h"
#include "util/bytes.h"
#include "util.h"
namespace ouinet { namespace bep5 {
std::string compute_injector_swarm_name(const ouinet::util::Ed25519PublicKey& pubkey, unsigned protocol_version)
{
return util::str
( "ed25519:", util::bytes::to_hex(pubkey.serialize())
( "ed25519:", util::base32up_encode(pubkey.serialize())
, "/v", protocol_version
, "/injectors");
}
......@@ -15,7 +14,7 @@ std::string compute_injector_swarm_name(const ouinet::util::Ed25519PublicKey& pu
std::string compute_bridge_swarm_name(const ouinet::util::Ed25519PublicKey& pubkey, unsigned protocol_version)
{
return util::str
( "ed25519:", util::bytes::to_hex(pubkey.serialize())
( "ed25519:", util::base32up_encode(pubkey.serialize())
, "/v", protocol_version
, "/bridges");
}
......@@ -23,7 +22,7 @@ std::string compute_bridge_swarm_name(const ouinet::util::Ed25519PublicKey& pubk
std::string compute_uri_swarm_name(const ouinet::util::Ed25519PublicKey& pubkey, unsigned protocol_version, boost::string_view key)
{
return util::str
( "ed25519:", util::bytes::to_hex(pubkey.serialize())
( "ed25519:", util::base32up_encode(pubkey.serialize())
, "/v", protocol_version
, "/uri/", key);
}
......
......@@ -6,6 +6,7 @@
#include "namespaces.h"
#include "util.h"
#include "util/bytes.h"
#include "parse/endpoint.h"
#include "util/crypto.h"
#include "increase_open_file_limit.h"
......@@ -119,9 +120,9 @@ public:
("injector-ep"
, po::value<string>()
, "Injector's endpoint as <TYPE>:<EP>, "
"where <TYPE> can be \"tcp\", \"utp\", \"bep5\", \"obfs2\", \"obfs3\", \"obfs4\", \"lampshade\" or \"i2p\", "
"where <TYPE> can be \"tcp\", \"utp\", \"obfs2\", \"obfs3\", \"obfs4\", \"lampshade\" or \"i2p\", "
"and <EP> depends on the type of endpoint: "
"<IP>:<PORT> for TCP and uTP, <STRING> for BEP5, <IP>:<PORT>[,<OPTION>=<VALUE>...] for OBFS and Lampshade, "
"<IP>:<PORT> for TCP and uTP, <IP>:<PORT>[,<OPTION>=<VALUE>...] for OBFS and Lampshade, "
"<B32_PUBKEY>.b32.i2p or <B64_PUBKEY> for I2P")
("client-credentials", po::value<string>()
, "<username>:<password> authentication pair for the client")
......@@ -135,7 +136,8 @@ public:
, "Type of d-cache {none, bep5-http}")
("cache-http-public-key"
, po::value<string>()
, "Public key for HTTP signatures in the BEP5/HTTP cache (hex-encoded)")
, "Public key for HTTP signatures in the BEP5/HTTP cache "
"(hex-encoded or Base32-encoded)")
("max-cached-age"
, po::value<int>()->default_value(_max_cached_age.total_seconds())
, "Discard cached content older than this many seconds "
......@@ -331,7 +333,16 @@ ClientConfig::ClientConfig(int argc, char* argv[])
if (vm.count(opt)) {
string value = vm[opt].as<string>();
pk = util::Ed25519PublicKey::from_hex(value);
using PubKey = util::Ed25519PublicKey;
pk = PubKey::from_hex(value);
if (!pk) { // attempt decoding from Base32
auto pk_s = util::base32_decode(value);
if (pk_s.size() == PubKey::key_size) {
auto pk_a = util::bytes::to_array<uint8_t, PubKey::key_size>(pk_s);
pk = PubKey(std::move(pk_a));
}
}
if (!pk) {
throw std::runtime_error(
......@@ -351,19 +362,23 @@ ClientConfig::ClientConfig(int argc, char* argv[])
LOG_DEBUG("Using bep5-http cache");
if (_injector_ep) {
throw std::runtime_error(
util::str("Using --cache-type=bep5-http for which injector endpoint is"
" derived implicitly. But it is already set to ", *_injector_ep));
}
if (!_cache_http_pubkey) {
throw std::runtime_error(
"--cache-type=bep5-http must be used with --cache-http-public-key");
}
_injector_ep = Endpoint{
Endpoint::Bep5Endpoint,
bep5::compute_injector_swarm_name(*_cache_http_pubkey, http_::protocol_version_current)
};
if (_injector_ep && _injector_ep->type == Endpoint::Bep5Endpoint) {
throw std::runtime_error(
util::str("A BEP5 injector endpoint is derived implicitly"
" when using --cache-type=bep5-http,"
" but it is already set to ", *_injector_ep));
}
if (!_injector_ep) {
_injector_ep = Endpoint{
Endpoint::Bep5Endpoint,
bep5::compute_injector_swarm_name(*_cache_http_pubkey, http_::protocol_version_current)
};
}
}
else if (type_str == "none" || type_str == "") {
_cache_type = CacheType::None;
......
......@@ -268,6 +268,12 @@ void ClientFrontEnd::handle_portal( ClientConfig& config
ss << "<br>\n";
ss << "Now: " << now_as_string() << "<br>\n";
ss << "Injector endpoint: " << config.injector_endpoint() << "<br>\n";
auto inj_pubkey = config.cache_http_pub_key();
if (inj_pubkey) {
auto inj_pubkey_s = inj_pubkey->serialize();
ss << "Injector pubkey (hex): " << util::bytes::to_hex(inj_pubkey_s) << "<br>\n";
ss << "Injector pubkey (Base32): " << util::base32up_encode(inj_pubkey_s) << "<br>\n";
}
if (_show_pending_tasks) {
ss << " <h2>Pending tasks " << _pending_tasks.size() << "</h2>\n";
......
......@@ -9,6 +9,8 @@
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include "util/iterators/base32_from_binary.hpp"
#include "util/iterators/binary_from_base32.hpp"
using namespace std;
......@@ -41,6 +43,30 @@ string ouinet::util::zlib_decompress(const boost::string_view& in, sys::error_co
return zlib_filter<boost::iostreams::zlib_decompressor>(in);
}
// Based on <https://stackoverflow.com/a/28471421> by user "ltc"
// and <https://stackoverflow.com/a/10973348> by user "PiQuer".
string ouinet::util::detail::base32up_encode(const char* data, size_t size) {
using namespace boost::archive::iterators;
using It = base32_from_binary<transform_width<const char*, 5, 8>>;
It begin = data;
It end = data + size;
string out(begin, end); // encode to base32
return out; // do not add padding
}
string ouinet::util::base32_decode(const boost::string_view in) {
using namespace boost::archive::iterators;
using It = transform_width<binary_from_base32<const char*>, 8, 5>;
It begin = in.data();
It end = in.data() + in.size();
string out(begin, end); // decode from base32
size_t npad = count(in.begin(), in.end(), '=');
if (npad > 6) npad = 6;
static const size_t padding_bytes[7] = {0, 1, 1, 2, 3, 3, 4};
npad = padding_bytes[npad];
return out.erase((npad > out.size()) ? 0 : out.size() - npad); // remove padding
}
// Based on <https://stackoverflow.com/a/28471421> by user "ltc"
// and <https://stackoverflow.com/a/10973348> by user "PiQuer".
string ouinet::util::detail::base64_encode(const char* data, size_t size) {
......
......@@ -163,11 +163,19 @@ std::string format_ep(const asio::ip::tcp::endpoint& ep) {
///////////////////////////////////////////////////////////////////////////////
namespace detail {
std::string base32up_encode(const char*, size_t);
std::string base64_encode(const char*, size_t);
}
std::string zlib_compress(const boost::string_view&);
std::string zlib_decompress(const boost::string_view&, sys::error_code&);
template<class In>
std::string base32up_encode(const In& in) { // unpadded!
return detail::base32up_encode(reinterpret_cast<const char*>(in.data()), in.size());
}
std::string base32_decode(const boost::string_view);
template<class In>
std::string base64_encode(const In& in) {
return detail::base64_encode(reinterpret_cast<const char*>(in.data()), in.size());
......
#ifndef BOOST_ARCHIVE_ITERATORS_BASE32_FROM_BINARY_HPP
#define BOOST_ARCHIVE_ITERATORS_BASE32_FROM_BINARY_HPP
// MS compatible compilers support #pragma once
#if defined(_MSC_VER)
# pragma once
#endif
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// base32_from_binary.hpp
// Adapted from Robert Ramsey's "base64_from_binary.hpp".
// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// See http://www.boost.org for updates, documentation, and revision history.
#include <boost/assert.hpp>
#include <cstddef> // size_t
#if defined(BOOST_NO_STDC_NAMESPACE)
namespace std{
using ::size_t;
} // namespace std
#endif
#include <boost/iterator/transform_iterator.hpp>
#include <boost/archive/iterators/dataflow_exception.hpp>
namespace boost {
namespace archive {
namespace iterators {
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// convert binary integers to base32 characters
namespace detail {
template<class CharType>
struct from_5_bit {
typedef CharType result_type;
CharType operator()(CharType t) const{
static const char * lookup_table =
"abcdefghijklmnopqrstuvwxyz"
"234567";
BOOST_ASSERT(t < 32);
return lookup_table[static_cast<size_t>(t)];
}
};
} // namespace detail
// note: what we would like to do is
// template<class Base, class CharType = typename Base::value_type>
// typedef transform_iterator<
// from_5_bit<CharType>,
// transform_width<Base, 5, sizeof(Base::value_type) * 8, CharType>
// > base32_from_binary;
// but C++ won't accept this. Rather than using a "type generator" and
// using a different syntax, make a derivation which should be equivalent.
//
// Another issue addressed here is that the transform_iterator doesn't have
// a templated constructor. This makes it incompatible with the dataflow
// ideal. This is also addressed here.
//template<class Base, class CharType = typename Base::value_type>
template<
class Base,
class CharType = typename boost::iterator_value<Base>::type
>
class base32_from_binary :
public transform_iterator<
detail::from_5_bit<CharType>,
Base
>
{
friend class boost::iterator_core_access;
typedef transform_iterator<
typename detail::from_5_bit<CharType>,
Base
> super_t;
public:
// make composible buy using templated constructor
template<class T>
base32_from_binary(T start) :
super_t(
Base(static_cast< T >(start)),
detail::from_5_bit<CharType>()
)
{}
// intel 7.1 doesn't like default copy constructor
base32_from_binary(const base32_from_binary & rhs) :
super_t(
Base(rhs.base_reference()),
detail::from_5_bit<CharType>()
)
{}
// base32_from_binary(){};
};
} // namespace iterators
} // namespace archive
} // namespace boost
#endif // BOOST_ARCHIVE_ITERATORS_BASE32_FROM_BINARY_HPP
#ifndef BOOST_ARCHIVE_ITERATORS_BINARY_FROM_BASE32_HPP
#define BOOST_ARCHIVE_ITERATORS_BINARY_FROM_BASE32_HPP
// MS compatible compilers support #pragma once
#if defined(_MSC_VER)
# pragma once
#endif
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// binary_from_base32.hpp
// Adapted from Robert Ramsey's "binary_from_base64.hpp".
// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// See http://www.boost.org for updates, documentation, and revision history.
#include <boost/assert.hpp>
#include <boost/serialization/throw_exception.hpp>
#include <boost/static_assert.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/archive/iterators/dataflow_exception.hpp>
namespace boost {
namespace archive {
namespace iterators {
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// convert base32 characters to binary data
namespace detail {
template<class CharType>
struct to_5_bit {
typedef CharType result_type;
CharType operator()(CharType t) const{
static const signed char lookup_table[] = {
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,26,27,28,29,30,31,-1,-1,-1,-1,-1, 0,-1,-1, // render '=' as 0
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1
};
// metrowerks trips this assertion - how come?
#if ! defined(__MWERKS__)
BOOST_STATIC_ASSERT(128 == sizeof(lookup_table));
#endif
signed char value = -1;
if((unsigned)t <= 127)
value = lookup_table[(unsigned)t];
if(-1 == value)
boost::serialization::throw_exception(
// TODO: A specific exception should be added here for Base32.
//dataflow_exception(dataflow_exception::invalid_base32_character)
dataflow_exception(dataflow_exception::invalid_conversion)
);
return value;
}
};
} // namespace detail
// note: what we would like to do is
// template<class Base, class CharType = typename Base::value_type>
// typedef transform_iterator<
// from_5_bit<CharType>,
// transform_width<Base, 5, sizeof(Base::value_type) * 8, CharType>
// > base32_from_binary;
// but C++ won't accept this. Rather than using a "type generator" and
// using a different syntax, make a derivation which should be equivalent.
//
// Another issue addressed here is that the transform_iterator doesn't have
// a templated constructor. This makes it incompatible with the dataflow
// ideal. This is also addressed here.
template<
class Base,
class CharType = typename boost::iterator_value<Base>::type
>
class binary_from_base32 : public
transform_iterator<
detail::to_5_bit<CharType>,
Base
>
{
friend class boost::iterator_core_access;
typedef transform_iterator<
detail::to_5_bit<CharType>,
Base
> super_t;
public:
// make composible buy using templated constructor
template<class T>
binary_from_base32(T start) :
super_t(
Base(static_cast< T >(start)),
detail::to_5_bit<CharType>()
)
{}
// intel 7.1 doesn't like default copy constructor
binary_from_base32(const binary_from_base32 & rhs) :
super_t(
Base(rhs.base_reference()),
detail::to_5_bit<CharType>()
)
{}
// binary_from_base32(){};
};
} // namespace iterators
} // namespace archive
} // namespace boost
#endif // BOOST_ARCHIVE_ITERATORS_BINARY_FROM_BASE32_HPP
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment