sapling/eden/fs/config/FieldConverter.cpp
Katie Mancini fa180ad585 check multiple locations for x509 certs
Summary:
This stack updates eden to be able to check all of the locations that able
users certificate may reside.

There can be multiple places where a cert may reside (we cant always
definitively choose one place to look based on the platform). Thus we
need to be able to configure multiple locations for certs in our eden
config.

This makes the switch over in eden from using one place for the client
cert to use and using the first available client cert from a list.

NOTE: most of this diff is fixing unit tests take a look at `EdenConfig.h` and `EdenConfig.cpp` first

Reviewed By: wez

Differential Revision: D23359939

fbshipit-source-id: 44beecce3ef098a734dbd7c5eb3fa5f0aad6b50b
2020-09-23 19:58:52 -07:00

122 lines
3.5 KiB
C++

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This software may be used and distributed according to the terms of the
* GNU General Public License version 2.
*/
#include "eden/fs/config/FieldConverter.h"
#include <folly/Conv.h>
#include "eden/fs/utils/ChronoParse.h"
using folly::Expected;
using std::string;
namespace {
constexpr std::array<folly::StringPiece, 4> kEnvVars = {
folly::StringPiece{"HOME"},
folly::StringPiece{"USER"},
folly::StringPiece{"USER_ID"},
folly::StringPiece{"THRIFT_TLS_CL_CERT_PATH"},
};
/**
* Check if string represents a well-formed file path.
*/
bool isValidAbsolutePath(folly::StringPiece path) {
// All we really care about here is making sure that
// normalizeBestEffort() isn't going to treat the path as relatively. We
// probably should just add an option to normalizeBestEffort() to make it
// reject relative paths.
try {
facebook::eden::detail::AbsolutePathSanityCheck()(path);
return true;
} catch (std::domain_error&) {
return false;
}
}
} // namespace
namespace facebook {
namespace eden {
Expected<AbsolutePath, string> FieldConverter<AbsolutePath>::fromString(
folly::StringPiece value,
const std::map<string, string>& convData) const {
auto sString = value.str();
for (auto varName : kEnvVars) {
auto it = convData.find(varName.str());
if (it != convData.end()) {
auto envVar = folly::to<string>("${", varName, "}");
// There may be multiple ${USER} tokens to replace, so loop
// until we've processed all of them
while (true) {
auto idx = sString.find(envVar);
if (idx == string::npos) {
break;
}
sString.replace(idx, envVar.size(), it->second);
}
}
}
if (!::isValidAbsolutePath(sString)) {
return folly::makeUnexpected<string>(folly::to<string>(
"Cannot convert value '", value, "' to an absolute path"));
}
// normalizeBestEffort typically will not throw, but, we want to handle
// cases where it does, eg. getcwd fails.
try {
return facebook::eden::normalizeBestEffort(sString);
} catch (const std::exception& ex) {
return folly::makeUnexpected<string>(folly::to<string>(
"Failed to convert value '",
value,
"' to an absolute path, error : ",
ex.what()));
}
}
Expected<string, string> FieldConverter<string>::fromString(
folly::StringPiece value,
const std::map<string, string>& /* unused */) const {
return folly::makeExpected<string, string>(value.toString());
}
Expected<std::chrono::nanoseconds, string>
FieldConverter<std::chrono::nanoseconds>::fromString(
folly::StringPiece value,
const std::map<string, string>& /* unused */) const {
auto result = stringToDuration(value);
if (result.hasValue()) {
return result.value();
}
return folly::makeUnexpected(chronoParseErrorToString(result.error()).str());
}
std::string FieldConverter<std::chrono::nanoseconds>::toDebugString(
std::chrono::nanoseconds value) const {
return durationToString(value);
}
Expected<std::shared_ptr<re2::RE2>, string>
FieldConverter<std::shared_ptr<re2::RE2>>::fromString(
folly::StringPiece value,
const std::map<string, string>& /* unused */) const {
// value is a regex
return std::make_shared<re2::RE2>(value.str());
}
std::string FieldConverter<std::shared_ptr<re2::RE2>>::toDebugString(
std::shared_ptr<re2::RE2> value) const {
if (value) {
return value->pattern();
}
return "";
}
} // namespace eden
} // namespace facebook