|
2 | 2 | #include <vector> // std::vector |
3 | 3 | #include <string> // std::string |
4 | 4 | #include <string_view> // std::string_view |
| 5 | +#include <algorithm> // std::all_of |
| 6 | +#include <cctype> // std::isalnum |
5 | 7 | #include "CxxNodeApiHostModule.hpp" |
6 | 8 | #include "Logger.hpp" |
7 | 9 |
|
8 | 10 | using namespace facebook; |
9 | 11 |
|
10 | 12 | namespace { |
11 | 13 |
|
| 14 | +bool isModulePathLike(const std::string_view &path) { |
| 15 | + return std::all_of(path.begin(), path.end(), [](unsigned char c) { |
| 16 | + return std::isalnum(c) || '_' == c || '-' == c |
| 17 | + || '.' == c || '/' == c || ':' == c; |
| 18 | + }); |
| 19 | +} |
| 20 | + |
12 | 21 | // NOTE: behaves like `explode()` in PHP |
13 | 22 | std::vector<std::string_view> explodePath(const std::string_view &path) { |
14 | 23 | std::vector<std::string_view> parts; |
@@ -138,6 +147,13 @@ CxxNodeApiHostModule::requireNodeAddon(jsi::Runtime &rt, |
138 | 147 | const std::string &requiredPath, |
139 | 148 | const std::string &requiredPackageName, |
140 | 149 | const std::string &requiredFrom) { |
| 150 | + // Ensure that user-supplied inputs contain only allowed characters |
| 151 | + if (!isModulePathLike(requiredPath)) { |
| 152 | + throw jsi::JSError(rt, "Invalid characters in `requiredPath`. Only ASCII alphanumerics are allowed."); |
| 153 | + } |
| 154 | + if (!isModulePathLike(requiredFrom)) { |
| 155 | + throw jsi::JSError(rt, "Invalid characters in `requiredFrom`. Only ASCII alphanumerics are allowed."); |
| 156 | + } |
141 | 157 |
|
142 | 158 | const std::string &libraryNameStr = requiredPath; |
143 | 159 | auto [it, inserted] = nodeAddons_.emplace(libraryNameStr, NodeAddon()); |
|
0 commit comments