blob: 5662e679f6464f1335437ff13a21c1b1a3d34285 [file] [log] [blame]
#ifdef WITH_RIVE_SCRIPTING
#include "rive/importers/script_asset_importer.hpp"
#include "rive/importers/file_asset_importer.hpp"
#include "rive/assets/file_asset_contents.hpp"
#include "rive/assets/script_asset.hpp"
#include "rive/file_asset_loader.hpp"
#include "rive/span.hpp"
#include <cstdint>
#include "libhydrogen.h"
using namespace rive;
namespace rive
{
// Public key for script signature verification (32 bytes)
// TODO: Replace with permanent production public key.
const uint8_t g_scriptVerificationPublicKey[32] = {
180, 113, 86, 235, 225, 24, 110, 236, 105, 86, 201, 6, 73, 5, 203, 102,
81, 179, 12, 240, 226, 55, 103, 134, 227, 94, 82, 187, 51, 178, 96, 46};
} // namespace rive
ScriptAssetImporter::ScriptAssetImporter(
ScriptAsset* fileAsset,
rcp<FileAssetLoader> assetLoader,
Factory* factory,
std::vector<InBandByteCode>* inbandBytecode) :
FileAssetImporter(fileAsset, assetLoader, factory),
m_scriptVerificationSet(inbandBytecode)
{}
ScriptAsset* ScriptAssetImporter::scriptAsset()
{
return m_fileAsset->as<ScriptAsset>();
}
void ScriptAssetImporter::onFileAssetContents(
std::unique_ptr<FileAssetContents> contents)
{
// When contents are found in band, this script is part of the verification
// set.
m_scriptVerificationSet->emplace_back(
InBandByteCode(scriptAsset(), contents->bytes()));
FileAssetImporter::onFileAssetContents(std::move(contents));
}
InBandByteCode::InBandByteCode(ScriptAsset* asset,
SimpleArray<uint8_t>& content) :
m_scriptAsset(asset), m_bytes(SimpleArray<uint8_t>(content))
{}
StatusCode ScriptAssetImporter::resolve()
{
auto status = FileAssetImporter::resolve();
if (status != StatusCode::Ok)
{
return status;
}
if (m_content && !m_content->signature().empty())
{
std::vector<uint8_t> combinedBytecode;
// Verify the scripts loaded so far which have content in-band.
for (auto& inband : *m_scriptVerificationSet)
{
SimpleArray<uint8_t>& bytecode = inband.m_bytes;
combinedBytecode.insert(combinedBytecode.end(),
bytecode.begin(),
bytecode.end());
}
Span<uint8_t> signature = m_content->signature();
if (signature.size() != hydro_sign_BYTES)
{
return StatusCode::Ok;
}
int isVerified = hydro_sign_verify(signature.data(),
combinedBytecode.data(),
combinedBytecode.size(),
"RiveCode",
g_scriptVerificationPublicKey);
// Mark all the in-band scripts from verifyFrom onwards.
for (auto& inband : *m_scriptVerificationSet)
{
inband.m_scriptAsset->m_verified = isVerified == 0;
}
m_scriptVerificationSet->clear();
}
// Note that it's ok for an asset to not resolve (or to resolve async).
return StatusCode::Ok;
}
#endif