From e3c8b1c5273e20a6c20b5ba923cdcea919340950 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Mon, 21 May 2018 17:25:00 +0300 Subject: Add validate_package_name() function, validate manifest package names --- libbpkg/manifest.cxx | 86 +++++++++++++++++++++++++++++++++++++++++------ libbpkg/manifest.hxx | 7 ++++ tests/manifest/testscript | 79 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 11 deletions(-) diff --git a/libbpkg/manifest.cxx b/libbpkg/manifest.cxx index a7d8b95..3e9a4fa 100644 --- a/libbpkg/manifest.cxx +++ b/libbpkg/manifest.cxx @@ -17,7 +17,7 @@ #include #include #include // casecmp(), lcase(), alpha(), - // digit(), xdigit() + // alnum(), digit(), xdigit() #include #include #include @@ -870,6 +870,44 @@ namespace bpkg return o; } + // Package name. + // + static const strings illegal_pkg_names ({ + "build", + "con", "prn", "aux", "nul", + "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9", + "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9"}); + + static const string legal_pkg_chars ("_+-."); + + void + validate_package_name (const string& name) + { + if (name.size () < 2) + throw invalid_argument ("length is less than two characters"); + + if (find (illegal_pkg_names.begin (), illegal_pkg_names.end (), name) != + illegal_pkg_names.end ()) + throw invalid_argument ("illegal name"); + + if (!alpha (name.front ())) + throw invalid_argument ("illegal first character (must be alphabetic)"); + + // Here we rely on the fact that the name length >= 2. + // + for (auto i (name.cbegin () + 1), e (name.cend () - 1); i != e; ++i) + { + char c (*i); + + if (!(alnum(c) || legal_pkg_chars.find (c) != string::npos)) + throw invalid_argument ("illegal character"); + } + + if (!alnum (name.back ())) + throw invalid_argument ( + "illegal last character (must be alphabetic or digit)"); + } + // pkg_package_manifest // static void @@ -946,8 +984,14 @@ namespace bpkg if (!m.name.empty ()) bad_name ("package name redefinition"); - if (v.empty ()) - bad_value ("empty package name"); + try + { + validate_package_name (v); + } + catch (const invalid_argument& e) + { + bad_value (string ("invalid package name: ") + e.what ()); + } m.name = move (v); } @@ -1222,15 +1266,22 @@ namespace bpkg ne = i + 1; } + string nm (i == e ? move (lv) : string (b, ne)); + + try + { + validate_package_name (nm); + } + catch (const invalid_argument& e) + { + bad_value ( + string ("invalid prerequisite package name: ") + e.what ()); + } + if (i == e) - da.push_back (dependency {lv, nullopt}); + da.push_back (dependency {move (nm), nullopt}); else { - string nm (b, ne); - - if (nm.empty ()) - bad_value ("prerequisite package name not specified"); - try { da.push_back ( @@ -1356,14 +1407,27 @@ namespace bpkg serialize (serializer& s) const { // @@ Should we check that all non-optional values are specified ? - // @@ Should we check that values are valid: name is not empty, version - // release is not empty, sha256sum is a proper string, ...? + // @@ Should we check that values are valid: version release is not empty, + // sha256sum is a proper string, ...? // @@ Currently we don't know if we are serializing the individual package // manifest or the package list manifest, so can't ensure all values // allowed in the current context (*-file values). // s.next ("", "1"); // Start of manifest. + + auto bad_value ([&s](const string& d) { + throw serialization (s.name (), d);}); + + try + { + validate_package_name (name); + } + catch (const invalid_argument& e) + { + bad_value (string ("invalid package name: ") + e.what ()); + } + s.next ("name", name); s.next ("version", version.string ()); diff --git a/libbpkg/manifest.hxx b/libbpkg/manifest.hxx index f1e031e..97239db 100644 --- a/libbpkg/manifest.hxx +++ b/libbpkg/manifest.hxx @@ -376,6 +376,13 @@ namespace bpkg comment (std::move (c)) {} }; + // Check if the package name complies with the specification (see the bpkg + // manual for details) and throw std::invalid_argument if that's not the + // case. + // + LIBBPKG_EXPORT void + validate_package_name (const std::string&); + class LIBBPKG_EXPORT package_manifest { public: diff --git a/tests/manifest/testscript b/tests/manifest/testscript index 15a20ab..c8fdfaa 100644 --- a/tests/manifest/testscript +++ b/tests/manifest/testscript @@ -5,6 +5,85 @@ : packages : { + : name + : + { + : valid + : + $* -pp <>EOF + : 1 + sha256sum: a2b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + : + name: libfoo.c++-2 + version: 2.0.0 + summary: Modern C++ parser + license: LGPLv2 + url: http://www.example.org/projects/libfoo/ + email: libfoo-users@example.org + location: libfoo.c++-2-2.0.0.tar.bz2 + sha256sum: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + EOF + + : invalid + : + { + : short + : + $* -pp <'stdin:4:7: error: invalid package name: length is less than two characters' != 0 + : 1 + sha256sum: a2b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + : + name: b + EOI + + : illegal + : + $* -pp <'stdin:4:7: error: invalid package name: illegal name' != 0 + : 1 + sha256sum: a2b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + : + name: com3 + EOI + + : first-char + : + $* -pp <'stdin:4:7: error: invalid package name: illegal first character (must be alphabetic)' != 0 + : 1 + sha256sum: a2b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + : + name: 2b + EOI + + : last-char + : + $* -pp <'stdin:4:7: error: invalid package name: illegal last character (must be alphabetic or digit)' != 0 + : 1 + sha256sum: a2b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + : + name: foo_ + EOI + + : char + : + $* -pp <'stdin:4:7: error: invalid package name: illegal character' != 0 + : 1 + sha256sum: a2b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + : + name: foo'bar + EOI + + : dependency + : + $* -pp <'stdin:5:10: error: invalid prerequisite package name: length is less than two characters' != 0 + : 1 + sha256sum: a2b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + : + name: foo + depends: b + EOI + } + } + : pkg : { -- cgit v1.1