ADUC_Result _workflow_parse()

in src/utils/workflow_utils/src/workflow_utils.c [1242:1364]


ADUC_Result _workflow_parse(const JSON_Value* updateActionJson, bool validateManifest, ADUC_WorkflowHandle* handle)
{
    ADUC_Result result = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 };

    ADUC_Workflow* wf = NULL;
    JSON_Value* updateActionJsonClone = NULL;
    ADUCITF_UpdateAction updateAction = ADUCITF_UpdateAction_Undefined;

    if (handle == NULL)
    {
        result.ExtendedResultCode = ADUC_ERC_UTILITIES_WORKFLOW_UTIL_ERROR_BAD_PARAM;
        return result;
    }

    *handle = NULL;

    wf = malloc(sizeof(*wf));
    if (wf == NULL)
    {
        result.ExtendedResultCode = ADUC_ERC_NOMEM;
        goto done;
    }

    memset(wf, 0, sizeof(*wf));

    updateActionJsonClone = json_value_deep_copy(updateActionJson);
    updateActionJson = NULL;

    // commit ownership of cloned JSON_Value to the workflow's UpdateActionObject.
    wf->UpdateActionObject = json_value_get_object(updateActionJsonClone);
    updateActionJsonClone = NULL;

    // At this point, we have had a side-effect of committing to the
    // wf->UpdateActionObject.
    //
    // Now, if not a cancel update action, then update the
    // wf->UpdateManifestObj only after validating update manifest signature.
    //
    // After that, if a detached manifest exists in the manifest, then
    // overwrite wf->UpdateManifestObj after downloading and verifying the
    // detached manifest.

    // 'cancel' action doesn't contains UpdateManifest and UpdateSignature.
    // Skip this part.
    workflow_parse_peek_unprotected_workflow_properties(
        wf->UpdateActionObject,
        &updateAction,
        NULL /* outRootKeyPkgUrl_optional */,
        NULL /* outWorkflowId_optional */);
    if (updateAction != ADUCITF_UpdateAction_Cancel)
    {
        ADUC_Result tmpResult = { .ResultCode = ADUC_GeneralResult_Failure, .ExtendedResultCode = 0 };

        // Skip signature validation if specified.
        // Also, some (partial) action data may not contain an UpdateAction,
        // e.g., Components-Update manifest that delivered as part of Bundle Updates,
        // We will skip the validation for these cases.
        if (updateAction != ADUCITF_UpdateAction_Undefined && validateManifest)
        {
            tmpResult = workflow_validate_update_manifest_signature(wf->UpdateActionObject);
            if (IsAducResultCodeFailure(tmpResult.ResultCode))
            {
                result = tmpResult;
                goto done;
            }
        }

        tmpResult = UpdateWorkflowUpdateManifestObjFromUpdateActionObj(wf);
        if (IsAducResultCodeFailure(tmpResult.ResultCode))
        {
            result = tmpResult;
            goto done;
        }

        // Starting from version 4, the update manifest can contain both embedded manifest,
        // or a downloadable update manifest file (files["manifest"] contains the update manifest file info)
        if (!IsNullOrEmpty(json_object_get_string(
                wf->UpdateManifestObject, UPDATE_MANIFEST_PROPERTY_FIELD_DETACHED_MANIFEST_FILE_ID)))
        {
            tmpResult = DownloadAndUseDetachedManifest(wf);
            if (IsAducResultCodeFailure(tmpResult.ResultCode))
            {
                result = tmpResult;
                goto done;
            }
        }

        if (validateManifest)
        {
            int manifestVersion = workflow_get_update_manifest_version(handle_from_workflow(wf));
            if (manifestVersion < SUPPORTED_UPDATE_MANIFEST_VERSION_MIN
                || manifestVersion > SUPPORTED_UPDATE_MANIFEST_VERSION_MAX)
            {
                Log_Error(
                    "Bad update manifest version: %d. (min: %d, max: %d)",
                    manifestVersion,
                    SUPPORTED_UPDATE_MANIFEST_VERSION_MIN,
                    SUPPORTED_UPDATE_MANIFEST_VERSION_MAX);
                result.ExtendedResultCode = ADUC_ERC_UTILITIES_UPDATE_DATA_PARSER_UNSUPPORTED_UPDATE_MANIFEST_VERSION;
                goto done;
            }
        }
    }

    *handle = wf;
    result.ResultCode = ADUC_GeneralResult_Success;
    result.ExtendedResultCode = 0;

done:

    if (updateActionJsonClone != NULL)
    {
        json_value_free(updateActionJsonClone);
    }

    if (IsAducResultCodeFailure(result.ResultCode))
    {
        free(wf);
        wf = NULL;
    }

    return result;
}