You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libcutefish/network/tests/tst_vpnutils.cpp

207 lines
12 KiB
C++

#include "../vpnutils.h"
#include <QTemporaryDir>
#include <QTest>
static QStringList keys(const QList<VpnUtils::SecretField> &fields)
{
QStringList keys;
for (const auto &field : fields)
keys << field.key;
return keys;
}
static const QString openvpn = QStringLiteral("org.freedesktop.NetworkManager.openvpn");
class VpnUtilsTest : public QObject
{
Q_OBJECT
private slots:
void initTestCase()
{
QVERIFY(plugins.isValid());
QFile name(plugins.filePath(QStringLiteral("nm-openvpn-service.name")));
QVERIFY(name.open(QIODevice::WriteOnly));
name.write("[VPN Connection]\nname=openvpn\nservice=org.freedesktop.NetworkManager.openvpn\n"
"program=/usr/libexec/nm-openvpn-service\n\n[libnm]\nplugin=libnm-vpn-plugin-openvpn.so\n");
name.close();
VpnUtils::setPluginDirectories({plugins.path()});
}
void readsInstalledPlugins()
{
QCOMPARE(VpnUtils::installedPlugins(), QStringList {QStringLiteral("openvpn")});
QVERIFY(VpnUtils::pluginInstalled(openvpn));
QVERIFY(!VpnUtils::pluginInstalled(QStringLiteral("org.freedesktop.NetworkManager.l2tp")));
QCOMPARE(VpnUtils::package(QStringLiteral("l2tp")), QStringLiteral("network-manager-l2tp"));
}
void openVpnAsksForWhatItsTypeNeeds()
{
QCOMPARE(keys(VpnUtils::secretFields(openvpn, {{QStringLiteral("connection-type"), QStringLiteral("password")}}, {})),
QStringList {QStringLiteral("password")});
QCOMPARE(keys(VpnUtils::secretFields(openvpn, {{QStringLiteral("connection-type"), QStringLiteral("password-tls")},
{QStringLiteral("key"), QStringLiteral("/k.pem")}},
{})),
(QStringList {QStringLiteral("password"), QStringLiteral("cert-pass")}));
// A key file whose password is not required, and no key at all, ask nothing.
QVERIFY(VpnUtils::secretFields(openvpn, {{QStringLiteral("connection-type"), QStringLiteral("tls")},
{QStringLiteral("key"), QStringLiteral("/k.pem")},
{QStringLiteral("cert-pass-flags"), QStringLiteral("4")}},
{})
.isEmpty());
QVERIFY(VpnUtils::secretFields(openvpn, {{QStringLiteral("connection-type"), QStringLiteral("static-key")}}, {})
.isEmpty());
}
void hintsNameTheSecret()
{
const auto fields = VpnUtils::secretFields(openvpn, {{QStringLiteral("connection-type"), QStringLiteral("password")}},
{QStringLiteral("x-vpn-message:Enter your token"),
QStringLiteral("x-dynamic-challenge-echo:Token")});
QCOMPARE(fields.size(), 1);
QCOMPARE(fields.first().key, QStringLiteral("x-dynamic-challenge-echo:Token"));
QCOMPARE(fields.first().label, QStringLiteral("Token"));
QVERIFY(!fields.first().secret);
QCOMPARE(VpnUtils::hintMessage({QStringLiteral("x-vpn-message:Enter your token")}),
QStringLiteral("Enter your token"));
}
void otherPlugins()
{
QCOMPARE(keys(VpnUtils::secretFields(QStringLiteral("org.freedesktop.NetworkManager.l2tp"),
{{QStringLiteral("machine-auth-type"), QStringLiteral("psk")}}, {})),
(QStringList {QStringLiteral("password"), QStringLiteral("ipsec-psk")}));
QCOMPARE(keys(VpnUtils::secretFields(QStringLiteral("org.freedesktop.NetworkManager.vpnc"), {}, {})),
(QStringList {QStringLiteral("Xauth password"), QStringLiteral("IPSec secret")}));
QVERIFY(VpnUtils::secretFields(QStringLiteral("org.freedesktop.NetworkManager.strongswan"),
{{QStringLiteral("method"), QStringLiteral("agent")}}, {})
.isEmpty());
QCOMPARE(keys(VpnUtils::secretFields(QStringLiteral("org.freedesktop.NetworkManager.pptp"), {}, {})),
QStringList {QStringLiteral("password")});
}
void userNames()
{
QCOMPARE(VpnUtils::userNameKey(openvpn, {{QStringLiteral("connection-type"), QStringLiteral("password")}}),
QStringLiteral("username"));
QVERIFY(VpnUtils::userNameKey(openvpn, {{QStringLiteral("connection-type"), QStringLiteral("tls")}}).isEmpty());
QCOMPARE(VpnUtils::userNameKey(QStringLiteral("org.freedesktop.NetworkManager.l2tp"), {}), QStringLiteral("user"));
QCOMPARE(VpnUtils::userNameKey(QStringLiteral("org.freedesktop.NetworkManager.vpnc"), {}),
QStringLiteral("Xauth username"));
}
void profilesByHand()
{
QString error;
NMVariantMapMap openvpnProfile = VpnUtils::manualProfile({{QStringLiteral("kind"), QStringLiteral("openvpn")},
{QStringLiteral("server"), QStringLiteral("vpn.example.com")},
{QStringLiteral("authentication"), QStringLiteral("certificates")},
{QStringLiteral("caFile"), QStringLiteral("/ca.pem")},
{QStringLiteral("certFile"), QStringLiteral("/me.pem")},
{QStringLiteral("keyFile"), QStringLiteral("/me.key")}},
&error);
QVERIFY2(!openvpnProfile.isEmpty(), qPrintable(error));
QCOMPARE(openvpnProfile.value(QStringLiteral("connection")).value(QStringLiteral("id")).toString(),
QStringLiteral("vpn.example.com"));
const auto data = openvpnProfile.value(QStringLiteral("vpn")).value(QStringLiteral("data")).value<QMap<QString, QString>>();
QCOMPARE(data.value(QStringLiteral("connection-type")), QStringLiteral("tls"));
QCOMPARE(data.value(QStringLiteral("key")), QStringLiteral("/me.key"));
QCOMPARE(data.value(QStringLiteral("cert-pass-flags")), QStringLiteral("1"));
const NMVariantMapMap wireguard = VpnUtils::manualProfile({{QStringLiteral("kind"), QStringLiteral("wireguard")},
{QStringLiteral("name"), QStringLiteral("Home")},
{QStringLiteral("server"), QStringLiteral("vpn.example.com")},
{QStringLiteral("privateKey"), QStringLiteral("yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk=")},
{QStringLiteral("publicKey"), QStringLiteral("xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg=")},
{QStringLiteral("address"), QStringLiteral("10.0.0.2/24")}},
&error);
QVERIFY2(!wireguard.isEmpty(), qPrintable(error));
const auto peers = wireguard.value(QStringLiteral("wireguard")).value(QStringLiteral("peers")).value<QList<QVariantMap>>();
QCOMPARE(peers.first().value(QStringLiteral("endpoint")).toString(), QStringLiteral("vpn.example.com:51820"));
QCOMPARE(peers.first().value(QStringLiteral("allowed-ips")).toStringList(),
(QStringList {QStringLiteral("0.0.0.0/0"), QStringLiteral("::/0")}));
const NMVariantMapMap ipv6Server = VpnUtils::manualProfile({{QStringLiteral("kind"), QStringLiteral("wireguard")},
{QStringLiteral("server"), QStringLiteral("2001:db8::1")},
{QStringLiteral("privateKey"), QStringLiteral("yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk=")},
{QStringLiteral("publicKey"), QStringLiteral("xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg=")},
{QStringLiteral("address"), QStringLiteral("10.0.0.2/24")}},
&error);
QVERIFY2(!ipv6Server.isEmpty(), qPrintable(error));
QCOMPARE(ipv6Server.value(QStringLiteral("wireguard")).value(QStringLiteral("peers")).value<QList<QVariantMap>>()
.first().value(QStringLiteral("endpoint")).toString(),
QStringLiteral("[2001:db8::1]:51820"));
QVERIFY(VpnUtils::manualProfile({{QStringLiteral("kind"), QStringLiteral("pptp")},
{QStringLiteral("server"), QStringLiteral("x")}},
&error)
.isEmpty());
QVERIFY(!error.isEmpty());
}
void failures()
{
// NM_ACTIVE_CONNECTION_STATE_REASON_USER_DISCONNECTED and _NO_SECRETS say nothing.
QVERIFY(VpnUtils::failureMessage(2).isEmpty());
QVERIFY(VpnUtils::failureMessage(9).isEmpty());
QVERIFY(!VpnUtils::failureMessage(10).isEmpty());
}
void readsWireGuard()
{
const QByteArray config = "[Interface]\n"
"PrivateKey = yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk= # mine\n"
"Address = 10.99.0.2/24, fd00::2\n"
"DNS = 10.99.0.1, corp.example\n"
"\n"
"[Peer]\n"
"PublicKey = xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg=\n"
"AllowedIPs = 10.99.0.0/24, 10.98.0.0/24\n"
"Endpoint = vpn.example.com:51820\n"
"PersistentKeepalive = 25\n";
QVERIFY(VpnUtils::isWireGuardConfig(config));
QString error;
const NMVariantMapMap profile = VpnUtils::wireGuardProfile(config, QStringLiteral("Cafe (Tokyo)"), &error);
QVERIFY2(!profile.isEmpty(), qPrintable(error));
QCOMPARE(profile.value(QStringLiteral("connection")).value(QStringLiteral("id")).toString(), QStringLiteral("Cafe (Tokyo)"));
QCOMPARE(profile.value(QStringLiteral("connection")).value(QStringLiteral("interface-name")).toString(),
QStringLiteral("CafeTokyo"));
const auto peers = profile.value(QStringLiteral("wireguard")).value(QStringLiteral("peers")).value<QList<QVariantMap>>();
QCOMPARE(peers.size(), 1);
QCOMPARE(peers.first().value(QStringLiteral("allowed-ips")).toStringList(),
(QStringList {QStringLiteral("10.99.0.0/24"), QStringLiteral("10.98.0.0/24")}));
QCOMPARE(peers.first().value(QStringLiteral("persistent-keepalive")).metaType(), QMetaType::fromType<uint>());
const QVariantMap ipv4 = profile.value(QStringLiteral("ipv4"));
QCOMPARE(ipv4.value(QStringLiteral("method")).toString(), QStringLiteral("manual"));
const auto addresses = ipv4.value(QStringLiteral("address-data")).value<QList<QVariantMap>>();
QCOMPARE(addresses.first().value(QStringLiteral("prefix")).toUInt(), 24u);
QCOMPARE(ipv4.value(QStringLiteral("dns-search")).toStringList(), QStringList {QStringLiteral("corp.example")});
QCOMPARE(profile.value(QStringLiteral("ipv6")).value(QStringLiteral("address-data")).value<QList<QVariantMap>>()
.first().value(QStringLiteral("prefix")).toUInt(),
128u);
}
void rejectsWhatIsNotWireGuard()
{
QString error;
QVERIFY(VpnUtils::wireGuardProfile("[Interface]\nPrivateKey = short\n", QStringLiteral("x"), &error).isEmpty());
QVERIFY(!error.isEmpty());
QVERIFY(VpnUtils::wireGuardProfile("[Interface]\nPrivateKey = yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk=\nFoo = 1\n",
QStringLiteral("x"), &error)
.isEmpty());
QVERIFY(!VpnUtils::isWireGuardConfig("client\nremote vpn.example.com 1194\n"));
}
private:
QTemporaryDir plugins;
};
QTEST_GUILESS_MAIN(VpnUtilsTest)
#include "tst_vpnutils.moc"