Skip to content

Commit

Permalink
Addressing FileUtils::ExtractExpandedPath Failure (#288)
Browse files Browse the repository at this point in the history
fixed linter issues

added logic for checking ExtractExpandedPath failures

Added/Fixed some tests and a typo

fixed test

fixed bugs and added style changes

fixed linter issues

fixed repeated code, capitalization, and removed TODO comment

Removed redundant code, added formatting for error messages, updated shadow file size/readme

fixed error message

fixed test

fixed repeated code, capitalization, and removed TODO comment

Removed redundant code, added formatting for error messages, updated shadow file size/readme

fixed error message

Added more specific error messages
  • Loading branch information
adanforth authored Jul 13, 2022
1 parent b64b6c0 commit b78192f
Show file tree
Hide file tree
Showing 10 changed files with 321 additions and 190 deletions.
150 changes: 112 additions & 38 deletions source/config/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1296,6 +1296,51 @@ constexpr char PlainConfig::SampleShadow::JSON_SAMPLE_SHADOW_NAME[];
constexpr char PlainConfig::SampleShadow::JSON_SAMPLE_SHADOW_INPUT_FILE[];
constexpr char PlainConfig::SampleShadow::JSON_SAMPLE_SHADOW_OUTPUT_FILE[];

bool PlainConfig::SampleShadow::createShadowOutputFile()
{
if (!FileUtils::CreateDirectoryWithPermissions(Config::DEFAULT_SAMPLE_SHADOW_OUTPUT_DIR, S_IRWXU))
{
LOGM_ERROR(
Config::TAG,
"Failed to access/create default directories: %s required for storage of shadow document",
Config::DEFAULT_SAMPLE_SHADOW_OUTPUT_DIR);

return false;
}
else
{
ostringstream outputPathStream;
outputPathStream << Config::DEFAULT_SAMPLE_SHADOW_OUTPUT_DIR << Config::DEFAULT_SAMPLE_SHADOW_DOCUMENT_FILE;
LOG_INFO(Config::TAG, outputPathStream.str().c_str());

string outputPath = FileUtils::ExtractExpandedPath(outputPathStream.str().c_str());

if (FileUtils::StoreValueInFile("", outputPath))
{
chmod(outputPath.c_str(), S_IRUSR | S_IWUSR);
if (FileUtils::ValidateFilePermissions(outputPath.c_str(), Permissions::SAMPLE_SHADOW_FILES))
{
shadowOutputFile = outputPath;
LOGM_INFO(
Config::TAG,
"Succesfully create default file: %s required for storage of shadow document",
outputPath.c_str());
}
}
else
{
LOGM_ERROR(
Config::TAG,
"Failed to access/create default file: %s required for storage of shadow document",
outputPath.c_str());

return false;
}
}

return true;
}

bool PlainConfig::SampleShadow::LoadFromJson(const Crt::JsonView &json)
{
const char *jsonKey = JSON_ENABLE_SAMPLE_SHADOW;
Expand Down Expand Up @@ -1340,10 +1385,10 @@ bool PlainConfig::SampleShadow::LoadFromJson(const Crt::JsonView &json)
}
else
{
LOGM_WARN(
Config::TAG,
"Output file {%s} was provided in the JSON configuration file with an empty value",
jsonKey);
if (!createShadowOutputFile())
{
return false;
}
}
}

Expand Down Expand Up @@ -1371,6 +1416,13 @@ bool PlainConfig::SampleShadow::LoadFromCliArgs(const CliArgs &cliArgs)
FileUtils::ExtractExpandedPath(cliArgs.at(PlainConfig::SampleShadow::CLI_SAMPLE_SHADOW_OUTPUT_FILE))
.c_str();
}
else
{
if (!createShadowOutputFile())
{
return false;
}
}

return true;
}
Expand Down Expand Up @@ -1404,6 +1456,18 @@ bool PlainConfig::SampleShadow::Validate() const
{
return false;
}

size_t incomingFileSize = FileUtils::GetFileSize(shadowInputFile->c_str());
if (MAXIMUM_SHADOW_INPUT_FILE_SIZE < incomingFileSize)
{
LOGM_ERROR(
Config::TAG,
"Refusing to open input file %s, file size %zu bytes is greater than allowable limit of %zu bytes",
Sanitize(shadowInputFile->c_str()).c_str(),
incomingFileSize,
MAXIMUM_SHADOW_INPUT_FILE_SIZE);
return false;
}
}

if (shadowOutputFile.has_value() && !shadowOutputFile->empty())
Expand Down Expand Up @@ -1984,6 +2048,7 @@ constexpr char Config::CLI_EXPORT_DEFAULT_SETTINGS[];
constexpr char Config::CLI_CONFIG_FILE[];
constexpr char Config::DEFAULT_FLEET_PROVISIONING_RUNTIME_CONFIG_FILE[];
constexpr char Config::DEFAULT_SAMPLE_SHADOW_OUTPUT_DIR[];
constexpr char Config::DEFAULT_SAMPLE_SHADOW_DOCUMENT_FILE[];

bool Config::CheckTerminalArgs(int argc, char **argv)
{
Expand Down Expand Up @@ -2124,55 +2189,64 @@ bool Config::ParseCliArgs(int argc, char **argv, CliArgs &cliArgs)

bool Config::init(const CliArgs &cliArgs)
{
string filename = Config::DEFAULT_CONFIG_FILE;
bool bReadConfigFile = FileUtils::FileExists(filename);

if (cliArgs.count(Config::CLI_CONFIG_FILE))
try
{
filename = cliArgs.at(Config::CLI_CONFIG_FILE);
if (!FileUtils::FileExists(filename))
string filename = Config::DEFAULT_CONFIG_FILE;
bool bReadConfigFile = FileUtils::FileExists(filename);

if (cliArgs.count(Config::CLI_CONFIG_FILE))
{
filename = cliArgs.at(Config::CLI_CONFIG_FILE);
if (!FileUtils::FileExists(filename))
{
LOGM_ERROR(
TAG,
"*** %s: Config file specified in the CLI doesn't exist: '%s' ***",
DeviceClient::DC_FATAL_ERROR,
Sanitize(filename).c_str());
return false;
}

bReadConfigFile = true;
}

if (bReadConfigFile && !ParseConfigFile(filename, false))
{
LOGM_ERROR(
TAG,
"*** %s: Config file specified in the CLI doesn't exist: '%s' ***",
"*** %s: Unable to Parse Config file: '%s' ***",
DeviceClient::DC_FATAL_ERROR,
Sanitize(filename).c_str());
return false;
}

bReadConfigFile = true;
}
if (!config.LoadFromCliArgs(cliArgs))
{
return false;
}

if (bReadConfigFile && !ParseConfigFile(filename, false))
{
LOGM_ERROR(
TAG,
"*** %s: Unable to Parse Config file: '%s' ***",
DeviceClient::DC_FATAL_ERROR,
Sanitize(filename).c_str());
return false;
}
if (!config.LoadFromEnvironment())
{
return false;
}

if (!config.LoadFromCliArgs(cliArgs))
{
return false;
}
if (ParseConfigFile(Config::DEFAULT_FLEET_PROVISIONING_RUNTIME_CONFIG_FILE, true) &&
ValidateAndStoreRuntimeConfig())
{
LOGM_INFO(
TAG,
"Successfully fetched Runtime config file '%s' and validated its content.",
Config::DEFAULT_FLEET_PROVISIONING_RUNTIME_CONFIG_FILE);
}

if (!config.LoadFromEnvironment())
{
return false;
return config.Validate();
}

if (ParseConfigFile(Config::DEFAULT_FLEET_PROVISIONING_RUNTIME_CONFIG_FILE, true) &&
ValidateAndStoreRuntimeConfig())
catch (const std::exception &e)
{
LOGM_INFO(
TAG,
"Successfully fetched Runtime config file '%s' and validated its content.",
Config::DEFAULT_FLEET_PROVISIONING_RUNTIME_CONFIG_FILE);
}
LOGM_ERROR(TAG, "Error while initializing configuration: %s", e.what());

return config.Validate();
return false;
}
}

bool Config::ValidateAndStoreRuntimeConfig()
Expand Down
4 changes: 4 additions & 0 deletions source/config/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ namespace Aws
bool Validate() const override;
/** Serialize SampleShadow feature To Json Object **/
void SerializeToObject(Crt::JsonObject &object) const;
bool createShadowOutputFile();

static constexpr char CLI_ENABLE_SAMPLE_SHADOW[] = "--enable-sample-shadow";
static constexpr char CLI_SAMPLE_SHADOW_NAME[] = "--shadow-name";
Expand All @@ -309,6 +310,8 @@ namespace Aws
static constexpr char JSON_SAMPLE_SHADOW_INPUT_FILE[] = "shadow-input-file";
static constexpr char JSON_SAMPLE_SHADOW_OUTPUT_FILE[] = "shadow-output-file";

static constexpr int MAXIMUM_SHADOW_INPUT_FILE_SIZE = 8 * 1024;

bool enabled{false};
Aws::Crt::Optional<std::string> shadowName;
Aws::Crt::Optional<std::string> shadowInputFile;
Expand Down Expand Up @@ -440,6 +443,7 @@ namespace Aws
static constexpr char DEFAULT_FLEET_PROVISIONING_RUNTIME_CONFIG_FILE[] =
"~/.aws-iot-device-client/aws-iot-device-client-runtime.conf";
static constexpr char DEFAULT_SAMPLE_SHADOW_OUTPUT_DIR[] = "~/.aws-iot-device-client/sample-shadow/";
static constexpr char DEFAULT_SAMPLE_SHADOW_DOCUMENT_FILE[] = "default-sample-shadow-document";

static constexpr char CLI_HELP[] = "--help";
static constexpr char CLI_VERSION[] = "--version";
Expand Down
133 changes: 72 additions & 61 deletions source/fleetprovisioning/FleetProvisioning.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -489,92 +489,103 @@ bool FleetProvisioning::RegisterThing(Iotidentity::IotIdentityClient identityCli

bool FleetProvisioning::ProvisionDevice(shared_ptr<SharedCrtResourceManager> fpConnection, PlainConfig &config)
{
LOG_INFO(TAG, "Fleet Provisioning Feature has been started.");

bool didSetup = FileUtils::CreateDirectoryWithPermissions(keyDir.c_str(), S_IRWXU) &&
FileUtils::CreateDirectoryWithPermissions(Config::DEFAULT_CONFIG_DIR, S_IRWXU);
if (!didSetup)
{
LOGM_ERROR(
TAG,
"*** %s: Failed to access/create directories required for storage of provisioned certificates, cannot "
"continue ***",
DeviceClient::DC_FATAL_ERROR);
return false;
}

IotIdentityClient identityClient(fpConnection.get()->getConnection());
templateName = config.fleetProvisioning.templateName.value().c_str();
if (!MapParameters(config.fleetProvisioning.templateParameters))
try
{
return false;
}
LOG_INFO(TAG, "Fleet Provisioning Feature has been started.");

if (config.fleetProvisioning.csrFile.has_value() && !config.fleetProvisioning.csrFile->empty())
{
if (!GetCsrFileContent(config.fleetProvisioning.csrFile->c_str()) ||
!LocateDeviceKey(config.fleetProvisioning.deviceKey->c_str()) || !CreateCertificateUsingCSR(identityClient))
bool didSetup = FileUtils::CreateDirectoryWithPermissions(keyDir.c_str(), S_IRWXU) &&
FileUtils::CreateDirectoryWithPermissions(Config::DEFAULT_CONFIG_DIR, S_IRWXU);
if (!didSetup)
{
LOGM_ERROR(
TAG,
"*** %s: Fleet Provisioning Feature failed to generate a certificate from a certificate signing "
"request (CSR) ***",
"*** %s: Failed to access/create directories required for storage of provisioned certificates, cannot "
"continue ***",
DeviceClient::DC_FATAL_ERROR);
return false;
}
if (!config.secureElement.enabled && config.fleetProvisioning.deviceKey.has_value() &&
!config.fleetProvisioning.deviceKey->empty())
{
keyPath = config.fleetProvisioning.deviceKey->c_str();
}
else

IotIdentityClient identityClient(fpConnection.get()->getConnection());
templateName = config.fleetProvisioning.templateName.value().c_str();
if (!MapParameters(config.fleetProvisioning.templateParameters))
{
keyPath = "";
return false;
}
}
else
{
if (config.secureElement.enabled)

if (config.fleetProvisioning.csrFile.has_value() && !config.fleetProvisioning.csrFile->empty())
{
LOGM_ERROR(
TAG,
"*** %s: When Secure Tunneling feature is enabled, Device Client only provide support for Fleet "
"Provisioning using certificate signing request. Please provide valid CSR file path ***",
DeviceClient::DC_FATAL_ERROR);
return false;
if (!GetCsrFileContent(config.fleetProvisioning.csrFile->c_str()) ||
!LocateDeviceKey(config.fleetProvisioning.deviceKey->c_str()) ||
!CreateCertificateUsingCSR(identityClient))
{
LOGM_ERROR(
TAG,
"*** %s: Fleet Provisioning Feature failed to generate a certificate from a certificate signing "
"request (CSR) ***",
DeviceClient::DC_FATAL_ERROR);
return false;
}
if (!config.secureElement.enabled && config.fleetProvisioning.deviceKey.has_value() &&
!config.fleetProvisioning.deviceKey->empty())
{
keyPath = config.fleetProvisioning.deviceKey->c_str();
}
else
{
keyPath = "";
}
}
else
{
if (!CreateCertificateAndKey(identityClient))
if (config.secureElement.enabled)
{
LOGM_ERROR(
TAG,
"*** %s: Fleet Provisioning Feature failed to create a new certificate and private key ***",
"*** %s: When Secure Tunneling feature is enabled, Device Client only provide support for Fleet "
"Provisioning using certificate signing request. Please provide valid CSR file path ***",
DeviceClient::DC_FATAL_ERROR);
return false;
}
else
{
if (!CreateCertificateAndKey(identityClient))
{
LOGM_ERROR(
TAG,
"*** %s: Fleet Provisioning Feature failed to create a new certificate and private key ***",
DeviceClient::DC_FATAL_ERROR);
return false;
}
}
}
if (RegisterThing(identityClient))
{
/*
* Store data in runtime conf file and update @config object.
*/
if (!ExportRuntimeConfig(
Config::DEFAULT_FLEET_PROVISIONING_RUNTIME_CONFIG_FILE,
certPath.c_str(),
keyPath.c_str(),
thingName.c_str(),
deviceConfig.c_str()))
{
return false;
}

LOGM_INFO(TAG, "Successfully provisioned thing: %s", thingName.c_str());
return true;
}
LOGM_ERROR(
TAG, "*** %s: Fleet Provisioning Feature failed to provision device. ***", DeviceClient::DC_FATAL_ERROR);
return false;
}
if (RegisterThing(identityClient))
catch (const std::exception &e)
{
/*
* Store data in runtime conf file and update @config object.
*/
if (!ExportRuntimeConfig(
Config::DEFAULT_FLEET_PROVISIONING_RUNTIME_CONFIG_FILE,
certPath.c_str(),
keyPath.c_str(),
thingName.c_str(),
deviceConfig.c_str()))
{
return false;
}
LOGM_ERROR(TAG, "Error while provisioning device using fleet indexing: %s", e.what());

LOGM_INFO(TAG, "Successfully provisioned thing: %s", thingName.c_str());
return true;
return false;
}
LOGM_ERROR(TAG, "*** %s: Fleet Provisioning Feature failed to provision device. ***", DeviceClient::DC_FATAL_ERROR);
return false;
}

/*
Expand Down
Loading

0 comments on commit b78192f

Please sign in to comment.