Beispiel #1
0
        public static ResultReport <Root> ReadUpdateJson(string metaJsonFile)
        {
            // Prepare JsonSerializer
            JsonSerializer serializer = CreateJsonSerializer();

            // Read json file
            Root jsonRoot;

            try
            {
                // Use UTF-8 without a BOM signature, as the file was served by a web server
                using (StreamReader sr = new StreamReader(metaJsonFile, new UTF8Encoding(false), false))
                    using (JsonTextReader jr = new JsonTextReader(sr))
                    {
                        jsonRoot = serializer.Deserialize <Root>(jr);
                    }
            }
            catch (JsonException e)
            {
                return(new ResultReport <Root>(false, null, $"Update json file is corrupted: {Logger.LogExceptionMessage(e)}"));
            }

            // Validate json instance
            ResultReport report = jsonRoot.Validate();

            if (!report.Success)
            {
                return(new ResultReport <Root>(false, null, report.Message));
            }

            return(new ResultReport <Root>(true, jsonRoot));
        }
Beispiel #2
0
            /// <summary>
            /// Return true if a schema is valid
            /// </summary>
            /// <returns>True if valid</returns>
            public ResultReport Validate()
            {
                if (!Enum.IsDefined(typeof(ScriptFormat), Format))
                {
                    return(new ResultReport(false, $"Not supported script format {Format}"));
                }

                switch (Format)
                {
                case ScriptFormat.IniBased:
                    if (IniBased == null)
                    {
                        return(new ResultReport(false, $"Unable to find script information"));
                    }
                    ResultReport report = IniBased.Validate();
                    if (!report.Success)
                    {
                        return(report);
                    }
                    break;

                default:
                    return(new ResultReport(false, $"Internal error at {nameof(UpdateJson)}.{nameof(ScriptInfo)}.{nameof(Validate)}"));
                }

                return(new ResultReport(true));
            }
Beispiel #3
0
        public (Script[], LogInfo[]) UpdateScripts(IEnumerable <Script> scripts, bool preserveScriptState)
        {
            // Get updateable scripts urls
            Script[] updateableScripts = scripts.Where(s => s.IsUpdateable).ToArray();

            List <Script>  newScripts = new List <Script>(updateableScripts.Length);
            List <LogInfo> logs       = new List <LogInfo>(updateableScripts.Length);

            if (_m != null)
            {
                _m.BuildScriptProgressVisibility = Visibility.Collapsed;
            }
            _m?.SetBuildCommandProgress("Download Progress", updateableScripts.Length);
            try
            {
                int i = 0;
                foreach (Script sc in updateableScripts)
                {
                    i++;

                    ScriptStateBackup stateBackup = null;
                    if (preserveScriptState)
                    {
                        stateBackup = BackupScriptState(sc);
                        Debug.Assert(stateBackup != null, "ScriptStateBackup is null");
                    }

                    if (_m != null)
                    {
                        _m.BuildEchoMessage = $"Updating script [{sc.Title}]... ({i}/{updateableScripts.Length})";
                    }
                    ResultReport <Script> report = InternalUpdateOneScript(sc, stateBackup);
                    if (report.Success && report.Result != null)
                    {
                        newScripts.Add(report.Result);
                    }
                    logs.Add(report.ToLogInfo());

                    if (_m != null)
                    {
                        _m.BuildCommandProgressValue += 1;
                    }
                }
            }
            finally
            {
                _m?.ResetBuildCommandProgress();
                if (_m != null)
                {
                    _m.BuildEchoMessage = string.Empty;
                    _m.BuildScriptProgressVisibility = Visibility.Visible;
                }
            }

            return(newScripts.ToArray(), logs.ToArray());
        }
Beispiel #4
0
            /// <summary>
            /// Return true if schema is valid
            /// </summary>
            /// <returns>True if valid</returns>
            public ResultReport Validate()
            {
                // Check if properties are not null
                if (SchemaVer == null || PEBakeryMinVer == null)
                {
                    return(new ResultReport(false, "Update json is corrupted"));
                }

                // Check schema_ver and pebakery_min_ver
                if (Global.Const.UpdateSchemaMaxVerInst < SchemaVer)
                {
                    return(new ResultReport(false, "Requires newer version of PEBakery"));
                }
                if (SchemaVer < Global.Const.UpdateSchemaMinVerInst)
                {
                    return(new ResultReport(false, "Update json is too old to be read by PEbakery"));
                }
                if (Global.Const.ProgramVersionInst < PEBakeryMinVer)
                {
                    return(new ResultReport(false, $"Requires PEBakery {Global.Const.ProgramVersionStr} or higher"));
                }

                // Check created_at
                if (CreatedAt.Equals(DateTime.MinValue))
                {
                    return(new ResultReport(false, "Update json is corrupted"));
                }

                // Check file index
                if (Index == null)
                {
                    return(new ResultReport(false, "Update json is corrupted"));
                }
                ResultReport report = Index.Validate();

                if (!report.Success)
                {
                    return(report);
                }

                return(new ResultReport(true));
            }
        public static LogInfo ToLogInfo <T1, T2>(this ResultReport <T1, T2> report)
        {
            LogState state = report.Success ? LogState.Success : LogState.Error;

            return(new LogInfo(state, report.Message));
        }
Beispiel #6
0
        private ResultReport <Script> InternalUpdateOneScript(Script sc, ScriptStateBackup stateBackup)
        {
            // Never should be triggered, because Script class constructor check it
            Debug.Assert(sc.ParsedVersion != null, $"Local script [{sc.Title}] does not provide proper version information");

            string updateUrl      = sc.UpdateUrl;
            string metaJsonUrl    = Path.ChangeExtension(updateUrl, ".meta.json");
            string metaJsonFile   = FileHelper.GetTempFile(".meta.json");
            string tempScriptFile = FileHelper.GetTempFile(".script");

            try
            {
                // Download .meta.json
                HttpFileDownloader.Report httpReport = DownloadFile(metaJsonUrl, metaJsonFile);
                if (!httpReport.Result)
                {
                    // Failed to send a request, such as network not available
                    if (httpReport.StatusCode == 0)
                    {
                        return(new ResultReport <Script>(false, null, $"Unable to connect to the server"));
                    }

                    // Try downloading .deleted to check if a script is deleted
                    string errorMsg;
                    string deletedUrl  = Path.ChangeExtension(updateUrl, ".deleted");
                    string deletedFile = Path.ChangeExtension(metaJsonFile, ".deleted");
                    try
                    {
                        httpReport = DownloadFile(deletedUrl, deletedFile);
                        if (httpReport.Result)
                        {                                     // Successfully received response
                            if (httpReport.StatusCode == 200) // .deleted file exists in the server
                            {
                                errorMsg = $"[{sc.Title}] was deleted from the server";
                            }
                            else // There is no .deleted file in the server
                            {
                                errorMsg = $"Update is not available for [{sc.Title}]";
                            }
                        }
                        else
                        {
                            if (httpReport.StatusCode == 0) // Failed to send a request, such as network not available
                            {
                                errorMsg = $"Unable to connect to the server";
                            }
                            else
                            {
                                errorMsg = $"Update is not available for [{sc.Title}]";
                            }
                        }
                    }
                    finally
                    {
                        if (File.Exists(deletedFile))
                        {
                            File.Delete(deletedFile);
                        }
                    }

                    return(new ResultReport <Script>(false, null, errorMsg));
                }

                // Check and read .meta.json
                ResultReport <UpdateJson.Root> jsonReport = UpdateJson.ReadUpdateJson(metaJsonFile);
                if (!jsonReport.Success)
                {
                    return(new ResultReport <Script>(false, null, jsonReport.Message));
                }

                UpdateJson.Root      metaJson = jsonReport.Result;
                UpdateJson.FileIndex index    = metaJson.Index;
                if (index.Kind != UpdateJson.IndexEntryKind.Script)
                {
                    return(new ResultReport <Script>(false, null, "Update json is not of a script file"));
                }
                UpdateJson.ScriptInfo scInfo = index.ScriptInfo;
                if (scInfo.Format != UpdateJson.ScriptFormat.IniBased)
                {
                    return(new ResultReport <Script>(false, null, $"Format [{scInfo.Format}] of remote script [{sc.Title}] is not supported"));
                }
                UpdateJson.IniBasedScript iniScInfo = scInfo.IniBased;
                if (iniScInfo.Version <= sc.ParsedVersion)
                {
                    return(new ResultReport <Script>(false, null, $"You are using the lastest version of script [{sc.Title}]"));
                }

                // Download .script file
                httpReport = DownloadFile(updateUrl, tempScriptFile);
                if (!httpReport.Result)
                {
                    return(new ResultReport <Script>(false, null, httpReport.ErrorMsg));
                }

                // Verify downloaded .script file with FileMetadata
                ResultReport verifyReport = index.FileMetadata.VerifyFile(tempScriptFile);
                if (!verifyReport.Success)
                {
                    return(new ResultReport <Script>(false, null, $"Remote script [{sc.Title}] is corrupted"));
                }

                // Check downloaded script's version and check
                // Must have been checked with the UpdateJson
                string    remoteVerStr = IniReadWriter.ReadKey(tempScriptFile, "Main", "Version");
                VersionEx remoteVer    = VersionEx.Parse(remoteVerStr);
                if (remoteVer == null)
                {
                    return(new ResultReport <Script>(false, null, $"Version of remote script [{sc.Title}] is corrupted"));
                }
                if (!remoteVer.Equals(iniScInfo.Version))
                {
                    return(new ResultReport <Script>(false, null, $"Version of remote script [{sc.Title}] is corrupted"));
                }
                if (remoteVer <= sc.ParsedVersion)
                {
                    return(new ResultReport <Script>(false, null, $"Version of remote script [{sc.Title}] is corrupted"));
                }

                // Check if remote script is valid
                Script remoteScript = _p.LoadScriptRuntime(tempScriptFile, new LoadScriptRuntimeOptions
                {
                    IgnoreMain             = false,
                    AddToProjectTree       = false,
                    OverwriteToProjectTree = false,
                });
                if (remoteScript == null)
                {
                    return(new ResultReport <Script>(false, null, $"Remote script [{sc.Title}] is corrupted"));
                }

                // Overwrite backup state to new script
                if (stateBackup != null)
                {
                    RestoreScriptState(remoteScript, stateBackup);

                    // Let's be extra careful
                    remoteScript = _p.RefreshScript(remoteScript);
                    if (remoteScript == null)
                    {
                        return(new ResultReport <Script>(false, null, $"Internal error at {nameof(FileUpdater)}.{nameof(RestoreScriptState)}"));
                    }
                }

                // Copy downloaded remote script into new script
                File.Copy(tempScriptFile, sc.DirectRealPath, true);
                Script newScript = _p.RefreshScript(sc);

                // Return updated script instance
                return(new ResultReport <Script>(true, newScript, $"Updated script [{sc.Title}] to [v{sc.RawVersion}] from [v{newScript.RawVersion}]"));
            }
            finally
            {
                if (File.Exists(metaJsonFile))
                {
                    File.Delete(metaJsonFile);
                }
                if (File.Exists(tempScriptFile))
                {
                    File.Delete(tempScriptFile);
                }
            }
        }
Beispiel #7
0
            /// <summary>
            /// Recursively check sanity of the FileIndex and its children. Return true if a schema is valid.
            /// </summary>
            /// <returns>Return true if a schema is valid.</returns>
            public ResultReport Validate()
            {
                Queue <FileIndex> q = new Queue <FileIndex>();

                q.Enqueue(this);
                do
                {
                    FileIndex fi = q.Dequeue();

                    // Check if properties are not null
                    if (fi.Name == null)
                    {
                        return(new ResultReport(false, "File index is corrupted"));
                    }

                    // Check filename / foldername
                    if (!FileHelper.CheckWin32Path(Name, false, false))
                    {
                        return(new ResultReport(false, "File index is corrupted"));
                    }

                    // Check per kind
                    switch (fi.Kind)
                    {
                    case IndexEntryKind.Folder:
                    {
                        if (Children == null)
                        {
                            return(new ResultReport(false, $"Children of folder [{Name}] is corrupted"));
                        }

                        foreach (FileIndex sub in Children)
                        {
                            q.Enqueue(sub);
                        }
                    }
                    break;

                    case IndexEntryKind.Script:
                    {
                        // Check null
                        if (FileMetadata == null)
                        {
                            return(new ResultReport(false, $"Metadata of script [{Name}] is corrupted"));
                        }
                        if (ScriptInfo == null)
                        {
                            return(new ResultReport(false, $"Information of script [{Name}] is corrupted"));
                        }

                        // Check file metadata
                        ResultReport report = FileMetadata.Validate();
                        if (!report.Success)
                        {
                            return(report);
                        }
                        // Check script information
                        report = ScriptInfo.Validate();
                        if (!report.Success)
                        {
                            return(report);
                        }
                    }
                    break;

                    case IndexEntryKind.NonScriptFile:
                    {
                        if (FileMetadata == null)
                        {
                            return(new ResultReport(false, $"Metadata of script {Name} is corrupted"));
                        }

                        // Check file metadata
                        ResultReport report = FileMetadata.Validate();
                        if (!report.Success)
                        {
                            return(report);
                        }
                    }
                    break;
                    }
                }while (0 < q.Count);

                return(new ResultReport(true));
            }