commit 309f9221a58a612bc54150badb01a7a662b7dd0b
parent 6780823b360ae657902e13ba40a92dedc2063132
Author: cfillion <cfillion@users.noreply.github.com>
Date: Fri, 28 Oct 2016 19:54:37 -0400
remote: improve name validaton
turns out Windows disallows weird stuff
Diffstat:
2 files changed, 72 insertions(+), 58 deletions(-)
diff --git a/src/remote.cpp b/src/remote.cpp
@@ -30,12 +30,18 @@ static char DATA_DELIMITER = '|';
static bool validateName(const string &name)
{
- static const regex validPattern("[^~#%&*{}\\\\:<>?/+|\"]{4,24}");
+ using namespace std::regex_constants;
+
+ // see https://en.wikipedia.org/wiki/Filename#Reserved%5Fcharacters%5Fand%5Fwords
+ static const regex validPattern("[^*\\\\:<>?/|\"[:cntrl:]]{4,24}");
+ static const regex invalidPattern(
+ "[\\.\x20].+|.+[\\.\x20]|CLOCK\\$|COM\\d|LPT\\d", icase);
smatch match, invalid;
regex_match(name, match, validPattern);
+ regex_match(name, invalid, invalidPattern);
- return !match.empty();
+ return !match.empty() && invalid.empty();
}
static bool validateUrl(const string &url)
@@ -44,7 +50,7 @@ static bool validateUrl(const string &url)
// see http://tools.ietf.org/html/rfc3986#section-2
static const regex pattern(
- "^(?:[a-z0-9._~:/?#[\\]@!$&'()*+,;=-]|%[a-f0-9]{2})+$", icase);
+ "(?:[a-z0-9._~:/?#[\\]@!$&'()*+,;=-]|%[a-f0-9]{2})+", icase);
smatch match;
regex_match(url, match, pattern);
diff --git a/test/remote.cpp b/test/remote.cpp
@@ -18,71 +18,79 @@ TEST_CASE("construct remote", M) {
REQUIRE_FALSE(remote.isProtected());
}
-TEST_CASE("construct invalid remote", M) {
- SECTION("empty name") {
- try {
- Remote remote({}, "url");
- FAIL();
- }
- catch(const reapack_error &e) {
- REQUIRE(string(e.what()) == "invalid name");
+TEST_CASE("remote name validation", M) {
+ SECTION("invalid") {
+ const string invalidNames[] = {
+ "",
+ "ab/cd",
+ "ab\\cd",
+ "..",
+ ".",
+ "....",
+ ".hidden",
+ "trailing.",
+ " leading",
+ "trailing ",
+ "ctrl\4chars",
+
+ // Windows device names...
+ "CLOCK$",
+ "COM1",
+ "LPT2",
+ "lpt1",
+ };
+
+ for(const string &name : invalidNames) {
+ try {
+ Remote remote(name, "url");
+ FAIL("'" + name + "' was allowed");
+ }
+ catch(const reapack_error &e) {
+ REQUIRE(string(e.what()) == "invalid name");
+ }
}
}
- SECTION("invalid name") {
- try {
- Remote remote("a/", "url");
- FAIL();
- }
- catch(const reapack_error &e) {
- REQUIRE(string(e.what()) == "invalid name");
- }
- }
-
- SECTION("directory traversal in name") {
- try {
- Remote remote("..", "url");
- FAIL("dotdot was allowed");
- }
- catch(const reapack_error &e) {
- REQUIRE(string(e.what()) == "invalid name");
- }
-
- try {
- Remote remote(".", "url");
- FAIL("single dot was allowed");
- }
- catch(const reapack_error &e) {
- REQUIRE(string(e.what()) == "invalid name");
- }
- }
-
- SECTION("empty url") {
- try {
- Remote remote("name", {});
- FAIL();
- }
- catch(const reapack_error &e) {
- REQUIRE(string(e.what()) == "invalid url");
+ SECTION("valid") {
+ const string validNames[] = {
+ "1234",
+ "hello world",
+ "hello_world",
+ "Новая папка",
+ "Hello ~World~",
+ "Repository #1"
+ };
+
+ for(const string &name : validNames) {
+ try {
+ Remote remote(name, "url");
+ }
+ catch(const reapack_error &e) {
+ FAIL("'" + name + "' was denied (" + e.what() + ')');
+ }
}
}
+}
- SECTION("invalid url") {
- try {
- Remote remote("name", "hello world");
- FAIL();
- }
- catch(const reapack_error &e) {
- REQUIRE(string(e.what()) == "invalid url");
+TEST_CASE("remote url validation", M) {
+ SECTION("invalid") {
+ const string invalidUrls[] = {
+ "",
+ "hello world", // space should be %20
+ };
+
+ for(const string &url : invalidUrls) {
+ try {
+ Remote remote("hello", url);
+ FAIL("'" + url + "' was allowed");
+ }
+ catch(const reapack_error &e) {
+ REQUIRE(string(e.what()) == "invalid url");
+ }
}
}
}
-TEST_CASE("unicode name") {
- SECTION("cyrillic")
- Remote remote("Новая папка", "url");
-}
-
TEST_CASE("set invalid values", M) {
Remote remote;