<commit_before>/**
 *  For conditions of distribution and use, see copyright notice in license.txt
 *
 *  @file   JavascriptInstance.cpp
 *  @brief  Javascript script instance used wit EC_Script.
 */

#include "StableHeaders.h"
#include "DebugOperatorNew.h"
#include "MemoryLeakCheck.h"
#include "JavascriptInstance.h"
#include "JavascriptModule.h"
#include "ScriptMetaTypeDefines.h"
#include "ScriptCoreTypeDefines.h"
#include "EC_Script.h"
#include "ScriptAsset.h"
#include "IModule.h"
#include "AssetAPI.h"
#include "IAssetStorage.h"

#include "LoggingFunctions.h"

#include <QFile>
#include <sstream>

#include <QScriptClass>
Q_DECLARE_METATYPE(QScriptClass*)

//#ifndef QT_NO_SCRIPTTOOLS
//#include <QScriptEngineDebugger>
//#endif

#include "MemoryLeakCheck.h"

JavascriptInstance::JavascriptInstance(const QString &fileName, JavascriptModule *module) :
    engine_(0),
    sourceFile(fileName),
    module_(module),
    evaluated(false)
{
    CreateEngine();
    Load();
}

JavascriptInstance::JavascriptInstance(ScriptAssetPtr scriptRef, JavascriptModule *module) :
    engine_(0),
    module_(module),
    evaluated(false)
{
    // Make sure we do not push null or empty script assets as sources
    if (scriptRef && !scriptRef->scriptContent.isEmpty())
        scriptRefs_.push_back(scriptRef);
    
    CreateEngine();
    Load();
}

JavascriptInstance::JavascriptInstance(const std::vector<ScriptAssetPtr>& scriptRefs, JavascriptModule *module) :
    engine_(0),
    module_(module),
    evaluated(false)
{
    // Make sure we do not push null or empty script assets as sources
    for (unsigned i = 0; i < scriptRefs.size(); ++i)
        if (scriptRefs[i] && !scriptRefs[i]->scriptContent.isEmpty()) scriptRefs_.push_back(scriptRefs[i]);
    
    CreateEngine();
    Load();
}


JavascriptInstance::~JavascriptInstance()
{
    DeleteEngine();
}

void JavascriptInstance::Load()
{
    if (!engine_)
        CreateEngine();

    if (sourceFile.isEmpty() && scriptRefs_.empty())
    {
        LogError("JavascriptInstance::Load: No script content to load!");
        return;
    }
    // Can't specify both a file source and an Asset API source.
    if (!sourceFile.isEmpty() && !scriptRefs_.empty())
    {
        LogError("JavascriptInstance::Load: Cannot specify both an local input source file and a list of script refs to load!");
        return;
    }

    bool useAssetAPI = !scriptRefs_.empty();
    unsigned numScripts = useAssetAPI ? scriptRefs_.size() : 1;

    // Determine based on code origin whether it can be trusted with system access or not
    if (useAssetAPI)
    {
        trusted_ = true;
        for(unsigned i = 0; i < scriptRefs_.size(); ++i)
        {
            AssetStoragePtr storage = scriptRefs_[i]->GetAssetStorage();
            trusted_ = trusted_ && storage->Trusted();
        }
    }
    else // Local file: always trusted.
    {
        program_ = LoadScript(sourceFile);
        trusted_ = true; // This is a file on the local filesystem. We are making an assumption nobody can inject untrusted code here.
        // Actually, we are assuming the attacker does not know the absolute location of the asset cache locally here, since if he makes
        // the client to load a script into local cache, he could use this code path to automatically load that unsafe script from cache, and make it trusted. -jj.
    }

    // Check the validity of the syntax in the input.
    for (unsigned i = 0; i < numScripts; ++i)
    {
        QString scriptSourceFilename = (useAssetAPI ? scriptRefs_[i]->Name() : sourceFile);
        QString &scriptContent = (useAssetAPI ? scriptRefs_[i]->scriptContent : program_);

        QScriptSyntaxCheckResult syntaxResult = engine_->checkSyntax(scriptContent);
        if (syntaxResult.state() != QScriptSyntaxCheckResult::Valid)
        {
            LogError("Syntax error in script " + scriptSourceFilename + "," + QString::number(syntaxResult.errorLineNumber()) +
                ": " + syntaxResult.errorMessage());
<commit_msg>Fixed a crash bug on null AssetStorage dereference when checking for trusted js assets.<commit_after>/**
 *  For conditions of distribution and use, see copyright notice in license.txt
 *
 *  @file   JavascriptInstance.cpp
 *  @brief  Javascript script instance used wit EC_Script.
 */

#include "StableHeaders.h"
#include "DebugOperatorNew.h"
#include "MemoryLeakCheck.h"
#include "JavascriptInstance.h"
#include "JavascriptModule.h"
#include "ScriptMetaTypeDefines.h"
#include "ScriptCoreTypeDefines.h"
#include "EC_Script.h"
#include "ScriptAsset.h"
#include "IModule.h"
#include "AssetAPI.h"
#include "IAssetStorage.h"

#include "LoggingFunctions.h"

#include <QFile>
#include <sstream>

#include <QScriptClass>
Q_DECLARE_METATYPE(QScriptClass*)

//#ifndef QT_NO_SCRIPTTOOLS
//#include <QScriptEngineDebugger>
//#endif

#include "MemoryLeakCheck.h"

JavascriptInstance::JavascriptInstance(const QString &fileName, JavascriptModule *module) :
    engine_(0),
    sourceFile(fileName),
    module_(module),
    evaluated(false)
{
    CreateEngine();
    Load();
}

JavascriptInstance::JavascriptInstance(ScriptAssetPtr scriptRef, JavascriptModule *module) :
    engine_(0),
    module_(module),
    evaluated(false)
{
    // Make sure we do not push null or empty script assets as sources
    if (scriptRef && !scriptRef->scriptContent.isEmpty())
        scriptRefs_.push_back(scriptRef);
    
    CreateEngine();
    Load();
}

JavascriptInstance::JavascriptInstance(const std::vector<ScriptAssetPtr>& scriptRefs, JavascriptModule *module) :
    engine_(0),
    module_(module),
    evaluated(false)
{
    // Make sure we do not push null or empty script assets as sources
    for (unsigned i = 0; i < scriptRefs.size(); ++i)
        if (scriptRefs[i] && !scriptRefs[i]->scriptContent.isEmpty()) scriptRefs_.push_back(scriptRefs[i]);
    
    CreateEngine();
    Load();
}


JavascriptInstance::~JavascriptInstance()
{
    DeleteEngine();
}

void JavascriptInstance::Load()
{
    if (!engine_)
        CreateEngine();

    if (sourceFile.isEmpty() && scriptRefs_.empty())
    {
        LogError("JavascriptInstance::Load: No script content to load!");
        return;
    }
    // Can't specify both a file source and an Asset API source.
    if (!sourceFile.isEmpty() && !scriptRefs_.empty())
    {
        LogError("JavascriptInstance::Load: Cannot specify both an local input source file and a list of script refs to load!");
        return;
    }

    bool useAssetAPI = !scriptRefs_.empty();
    unsigned numScripts = useAssetAPI ? scriptRefs_.size() : 1;

    // Determine based on code origin whether it can be trusted with system access or not
    if (useAssetAPI)
    {
        trusted_ = true;
        for(unsigned i = 0; i < scriptRefs_.size(); ++i)
        {
            AssetStoragePtr storage = scriptRefs_[i]->GetAssetStorage();
            trusted_ = trusted_ && storage && storage->Trusted();
        }
    }
    else // Local file: always trusted.
    {
        program_ = LoadScript(sourceFile);
        trusted_ = true; // This is a file on the local filesystem. We are making an assumption nobody can inject untrusted code here.
        // Actually, we are assuming the attacker does not know the absolute location of the asset cache locally here, since if he makes
        // the client to load a script into local cache, he could use this code path to automatically load that unsafe script from cache, and make it trusted. -jj.
    }

    // Check the validity of the syntax in the input.
    for (unsigned i = 0; i < numScripts; ++i)
    {
        QString scriptSourceFilename = (useAssetAPI ? scriptRefs_[i]->Name() : sourceFile);
        QString &scriptContent = (useAssetAPI ? scriptRefs_[i]->scriptContent : program_);

        QScriptSyntaxCheckResult syntaxResult = engine_->checkSyntax(scriptContent);
        if (syntaxResult.state() != QScriptSyntaxCheckResult::Valid)
        {
            LogError("Syntax error in script " + scriptSourceFilename + "," + QString::number(syntaxResult.errorLineNumber()) +
                ": " + syntaxResult.errorMessage());

{'fraction_non_alphanumeric': 0.11113852226470951, 'fraction_numerical': 0.001726902676699149, 'mean_word_length': 3.4672176308539946, 'pattern_counts': {'":': 2, '<': 19, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6076379', 'n_tokens_mistral': 2371, 'n_tokens_neox': 2301, 'n_words': 690}