diff --git a/UpdPublish/UpdPublish.h b/UpdPublish/UpdPublish.h new file mode 100644 index 0000000..29bd503 --- /dev/null +++ b/UpdPublish/UpdPublish.h @@ -0,0 +1,23 @@ +/* + Copyright 2016 Amebis + + This file is part of Updater. + + Updater is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Updater is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Updater. If not, see . +*/ + +#pragma once + +#if !defined(RC_INVOKED) && !defined(MIDL_PASS) +#endif // !defined(RC_INVOKED) && !defined(MIDL_PASS) diff --git a/UpdPublish/UpdPublish.props b/UpdPublish/UpdPublish.props new file mode 100644 index 0000000..01fa15e --- /dev/null +++ b/UpdPublish/UpdPublish.props @@ -0,0 +1,18 @@ + + + + + + ..\..\output\$(Platform).$(Configuration)\ + + + + ..\..\lib\wxExtend\include;%(AdditionalIncludeDirectories) + _CONSOLE;%(PreprocessorDefinitions) + + + Console + + + + \ No newline at end of file diff --git a/UpdPublish/UpdPublish.rc b/UpdPublish/UpdPublish.rc new file mode 100644 index 0000000..c37804f Binary files /dev/null and b/UpdPublish/UpdPublish.rc differ diff --git a/UpdPublish/UpdPublish.vcxproj b/UpdPublish/UpdPublish.vcxproj new file mode 100644 index 0000000..9c5385b --- /dev/null +++ b/UpdPublish/UpdPublish.vcxproj @@ -0,0 +1,107 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {C5829278-D55E-41EB-B866-1E7D814694D1} + UpdPublish + + + + Application + true + Unicode + Dynamic + + + Application + true + Unicode + Dynamic + + + Application + false + true + Unicode + Dynamic + + + Application + false + true + Unicode + Dynamic + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + {a3a36689-ac35-4026-93da-a3ba0c0e767c} + + + + + + + + + + + + \ No newline at end of file diff --git a/UpdPublish/UpdPublish.vcxproj.filters b/UpdPublish/UpdPublish.vcxproj.filters new file mode 100644 index 0000000..6971853 --- /dev/null +++ b/UpdPublish/UpdPublish.vcxproj.filters @@ -0,0 +1,47 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {e43059ae-37ac-4b28-84fb-18d1b3972b30} + po;pot + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + + + Resource Files + + + + + Resource Files\Localization + + + \ No newline at end of file diff --git a/UpdPublish/locale/.gitignore b/UpdPublish/locale/.gitignore new file mode 100644 index 0000000..85ebba8 --- /dev/null +++ b/UpdPublish/locale/.gitignore @@ -0,0 +1 @@ +/*.mo diff --git a/UpdPublish/locale/sl_SI.po b/UpdPublish/locale/sl_SI.po new file mode 100644 index 0000000..b0340a2 --- /dev/null +++ b/UpdPublish/locale/sl_SI.po @@ -0,0 +1,46 @@ +msgid "" +msgstr "" +"Project-Id-Version: UpdPublish\n" +"POT-Creation-Date: 2016-04-01 14:36+0200\n" +"PO-Revision-Date: 2016-04-01 14:36+0200\n" +"Last-Translator: Simon Rozman \n" +"Language-Team: Amebis, d. o. o., Kamnik \n" +"Language: sl_SI\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 1.8.7\n" +"X-Poedit-Basepath: ..\n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n" +"%100==4 ? 2 : 3);\n" +"X-Poedit-SourceCharset: UTF-8\n" +"X-Poedit-KeywordsList: _\n" +"X-Poedit-SearchPath-0: .\n" + +#: main.cpp:38 +msgid "Show this help message" +msgstr "Pokaži to sporočilo pomoči" + +#: main.cpp:39 +msgid "Package file to calculate SHA-1 hash from" +msgstr "Datoteka paketa, od katere izračunamo odtis SHA-1" + +#: main.cpp:40 +msgid "" +msgstr "" + +#: main.cpp:41 +msgid "" +msgstr "" + +#: main.cpp:42 +msgid "" +msgstr "" + +#: main.cpp:43 +msgid "" +msgstr "" + +#: main.cpp:44 +msgid "" +msgstr "" diff --git a/UpdPublish/main.cpp b/UpdPublish/main.cpp new file mode 100644 index 0000000..6888ba4 --- /dev/null +++ b/UpdPublish/main.cpp @@ -0,0 +1,305 @@ +/* + Copyright 2016 Amebis + + This file is part of Updater. + + Updater is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Updater is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Updater. If not, see . +*/ + +#include "stdafx.h" + + +void UpdaterAddURL(wxXmlNode *elLocale, const wxString &url) +{ + wxXmlNode *elUrl = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("url")); + elUrl->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, url)); + + elLocale->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxT("\t"))); + elLocale->AddChild(elUrl); + elLocale->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxT("\n\t\t\t\t"))); +} + + +void UpdaterAddHash(wxXmlNode *elLocale, const wxMemoryBuffer &hash) +{ + wxXmlNode *elHash = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("hash")); + elHash->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxHexEncode(hash))); + + elLocale->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxT("\t"))); + elLocale->AddChild(elHash); + elLocale->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxT("\n\t\t\t\t"))); +} + + +void UpdaterAddLocalization(wxXmlNode *elPlatform, const wxString &languageId, const wxString &url, const wxMemoryBuffer &hash) +{ + wxXmlNode *elLocale = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Localization")); + elLocale->AddAttribute(new wxXmlAttribute(wxT("lang"), languageId)); + elLocale->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxT("\n\t\t\t\t"))); + UpdaterAddURL(elLocale, url); + if (!hash.IsEmpty()) + UpdaterAddHash(elLocale, hash); + + elPlatform->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxT("\t"))); + elPlatform->AddChild(elLocale); + elPlatform->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxT("\n\t\t\t"))); +} + + +void UpdaterAddPlatform(wxXmlNode *elDownloads, const wxString &platformId, const wxString &languageId, const wxString &url, const wxMemoryBuffer &hash) +{ + wxXmlNode *elPlatform = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Platform")); + elPlatform->AddAttribute(new wxXmlAttribute(wxT("id"), platformId)); + elPlatform->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxT("\n\t\t\t"))); + UpdaterAddLocalization(elPlatform, languageId, url, hash); + + elDownloads->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxT("\t"))); + elDownloads->AddChild(elPlatform); + elDownloads->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxT("\n\t\t"))); +} + + +void UpdaterAddDownloads(wxXmlNode *elPackage, const wxString &platformId, const wxString &languageId, const wxString &url, const wxMemoryBuffer &hash) +{ + wxXmlNode *elDownloads = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Downloads")); + elDownloads->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxT("\n\t\t"))); + UpdaterAddPlatform(elDownloads, platformId, languageId, url, hash); + + elPackage->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxT("\t"))); + elPackage->AddChild(elDownloads); + elPackage->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxT("\n\t"))); +} + + +void UpdaterAddPackage(wxXmlNode *elPackages, const wxString &platformId, const wxString &languageId, const wxString &url, const wxMemoryBuffer &hash) +{ + wxXmlNode *elHex = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("hex")); + elHex->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxString::Format(wxT("%08x"), UPDATER_PRODUCT_VERSION))); + + wxXmlNode *elDesc = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("desc")); + elDesc->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxT(UPDATER_PRODUCT_VERSION_STR))); + + wxXmlNode *elVersion = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Version")); + elVersion->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxT("\n\t\t\t"))); + elVersion->AddChild(elHex); + elVersion->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxT("\n\t\t\t"))); + elVersion->AddChild(elDesc); + elVersion->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxT("\n\t\t"))); + + wxXmlNode *elPackage = new wxXmlNode(wxXML_ELEMENT_NODE, wxT("Package")); + elPackage->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxT("\n\t\t"))); + elPackage->AddChild(elVersion); + elPackage->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxT("\n\t"))); + UpdaterAddDownloads(elPackage, platformId, languageId, url, hash); + + elPackages->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxT("\t"))); + elPackages->AddChild(elPackage); + elPackages->AddChild(new wxXmlNode(wxXML_TEXT_NODE, wxEmptyString, wxT("\n"))); +} + + +/// +/// Main function +/// +int _tmain(int argc, _TCHAR *argv[]) +{ + wxApp::CheckBuildOptions(WX_BUILD_OPTIONS_SIGNATURE, "program"); + + // Initialize wxWidgets. + wxInitializer initializer; + if (!initializer.IsOk()) + return -1; + + // Parse command line. + static const wxCmdLineEntryDesc cmdLineDesc[] = + { + { wxCMD_LINE_SWITCH, "h" , "help", _("Show this help message" ), wxCMD_LINE_VAL_NONE , wxCMD_LINE_OPTION_HELP }, + { wxCMD_LINE_OPTION, "f" , "file", _("Package file to calculate SHA-1 hash from"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, + { wxCMD_LINE_PARAM , NULL, NULL , _("" ), wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY }, + { wxCMD_LINE_PARAM , NULL, NULL , _("" ), wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY }, + { wxCMD_LINE_PARAM , NULL, NULL , _("" ), wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY }, + { wxCMD_LINE_PARAM , NULL, NULL , _("" ), wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY }, + { wxCMD_LINE_PARAM , NULL, NULL , _("" ), wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY }, + + { wxCMD_LINE_NONE } + }; + wxCmdLineParser parser(cmdLineDesc, argc, argv); + switch (parser.Parse()) { + case -1: + // Help was given, terminating. + return 0; + + case 0: + // everything is ok; proceed + break; + + default: + wxLogWarning(wxT("Syntax error detected, aborting.")); + return -1; + } + + // Load input XML document. + const wxString& filenameIn = parser.GetParam(0); + wxXmlDocument doc; + if (!doc.Load(filenameIn, "UTF-8", wxXMLDOC_KEEP_WHITESPACE_NODES)) + return 1; + + // Verify document type (root element). + wxXmlNode *elPackages = doc.GetRoot(); + const wxString &nameRoot = elPackages->GetName(); + if (nameRoot != wxT("Packages")) { + wxLogWarning(wxT("Invalid root element in repository catalogue (actual: %s, expected %s)."), nameRoot.c_str(), wxT("Packages")); + return 2; + } + + // Get package file hash. + wxString filenamePckg; + wxMemoryBuffer hash; + if (parser.Found(wxT("f"), &filenamePckg)) { + // Create RSA AES cryptographic session. + wxCryptoSessionRSAAES cs; + wxCHECK(cs.IsOk(), -1); + + // Calculate file SHA-1 hash. + wxCryptoHashSHA1 ch(cs); + wxCHECK(ch.HashFile(filenamePckg), 3); + ch.GetValue(hash); + } + + // Iterate over packages. + bool url_present = false; + const wxString& platformId = parser.GetParam(2); + const wxString& language = parser.GetParam(3); + const wxString& url = parser.GetParam(4); + wxString languageId(language); + for (wxXmlNode *elPackage = elPackages->GetChildren(); elPackage; elPackage = elPackage->GetNext()) { + if (elPackage->GetType() == wxXML_ELEMENT_NODE && elPackage->GetName() == wxT("Package")) { + // Get package version. + wxUint32 version = 0; + wxString versionStr; + for (wxXmlNode *elVersion = elPackage->GetChildren(); elVersion; elVersion = elVersion->GetNext()) { + if (elVersion->GetType() == wxXML_ELEMENT_NODE && elVersion->GetName() == wxT("Version")) { + for (wxXmlNode *elVersionNote = elVersion->GetChildren(); elVersionNote; elVersionNote = elVersionNote->GetNext()) { + if (elVersionNote->GetType() == wxXML_ELEMENT_NODE) { + const wxString &name = elVersionNote->GetName(); + if (name == wxT("hex")) + version = _tcstoul(elVersionNote->GetNodeContent(), NULL, 16); + else if (name == wxT("desc")) + versionStr = elVersionNote->GetNodeContent(); + } + } + } + } + if (version != UPDATER_PRODUCT_VERSION) { + // This package is not our version. Skip. + continue; + } + + // Set package download URL for given platform and language. + for (wxXmlNode *elDownloads = elPackage->GetChildren(); elDownloads; elDownloads = elDownloads->GetNext()) { + if (elDownloads->GetType() == wxXML_ELEMENT_NODE && elDownloads->GetName() == wxT("Downloads")) { + for (wxXmlNode *elPlatform = elDownloads->GetChildren(); elPlatform; elPlatform = elPlatform->GetNext()) { + if (elPlatform->GetType() == wxXML_ELEMENT_NODE) { + if (elPlatform->GetName() == wxT("Platform") && elPlatform->GetAttribute(wxT("id")) == platformId) { + // Get language. + for (wxXmlNode *elLocale = elPlatform->GetChildren(); elLocale; elLocale = elLocale->GetNext()) { + if (elLocale->GetType() == wxXML_ELEMENT_NODE && elLocale->GetName() == wxT("Localization") && elLocale->GetAttribute(wxT("lang")) == languageId) { + bool hash_present = false; + for (wxXmlNode *elLocaleNote = elLocale->GetChildren(); elLocaleNote; elLocaleNote = elLocaleNote->GetNext()) { + if (elLocaleNote->GetType() == wxXML_ELEMENT_NODE) { + const wxString &name = elLocaleNote->GetName(); + if (name == wxT("url")) { + if (elLocaleNote->GetNodeContent() == url) + url_present = true; + } else if (!hash.IsEmpty() && name == wxT("hash")) { + // Read the hash. + wxMemoryBuffer hashOrig; + wxString content(elLocaleNote->GetNodeContent()); + size_t len = wxHexDecodedSize(content.length()); + size_t res = wxHexDecode(hashOrig.GetWriteBuf(len), len, content, wxHexDecodeMode_SkipWS); + if (res != wxCONV_FAILED) { + hashOrig.SetDataLen(res); + if (hash.GetDataLen() == hashOrig.GetDataLen() && + memcmp(hash.GetData(), hashOrig.GetData(), hash.GetDataLen()) == 0) + { + hash_present = true; + } else { + wxLogError(wxT("This update package is already in the database. However, its hash is different.")); + return 3; + } + } else { + wxLogError(wxT("This update package is already in the database. However, its hash is corrupt.")); + return 4; + } + } + } + } + + if (!url_present) { + // Add URL. + UpdaterAddURL(elLocale, url); + url_present = true; + } + if (!hash_present && !hash.IsEmpty()) { + // Add hash. + UpdaterAddHash(elLocale, hash); + } + } + } + + if (!url_present) { + // Add localization. + UpdaterAddLocalization(elPlatform, languageId, url, hash); + url_present = true; + } + } + } + } + + if (!url_present) { + // Add platform. + UpdaterAddPlatform(elDownloads, platformId, languageId, url, hash); + url_present = true; + } + } + } + + if (!url_present) { + // Add downloads. + UpdaterAddDownloads(elPackage, platformId, languageId, url, hash); + url_present = true; + } + } + } + + if (!url_present) { + // Add package. + UpdaterAddPackage(elPackages, platformId, languageId, url, hash); + url_present = true; + } + + + // Write output XML document. + const wxString& filenameOut = parser.GetParam(1); + if (!doc.Save(filenameOut, wxXML_NO_INDENTATION)) { + wxLogError(wxT("%s: error USX0004: Error writing output file.\n"), filenameOut.fn_str()); + + // Remove the output file (if exists). + wxRemoveFile(filenameOut); + + return 4; + } + + return 0; +} diff --git a/UpdPublish/stdafx.cpp b/UpdPublish/stdafx.cpp new file mode 100644 index 0000000..6ade609 --- /dev/null +++ b/UpdPublish/stdafx.cpp @@ -0,0 +1,20 @@ +/* + Copyright 2016 Amebis + + This file is part of Updater. + + Updater is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Updater is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Updater. If not, see . +*/ + +#include "stdafx.h" diff --git a/UpdPublish/stdafx.h b/UpdPublish/stdafx.h new file mode 100644 index 0000000..e4bc9fd --- /dev/null +++ b/UpdPublish/stdafx.h @@ -0,0 +1,34 @@ +/* + Copyright 2016 Amebis + + This file is part of Updater. + + Updater is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Updater is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Updater. If not, see . +*/ + +#pragma once + +#include "../../include/UpdaterCfg.h" + +#include "UpdPublish.h" +#include "../include/Updater.h" + +#include +#include +#include +#include + +#include +#include +#include diff --git a/Updater.sln b/Updater.sln index 8adae70..5719922 100644 --- a/Updater.sln +++ b/Updater.sln @@ -14,6 +14,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wxExtend", "..\lib\wxExtend EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UpdSignXML", "UpdSignXML\UpdSignXML.vcxproj", "{2A403460-7834-41B8-9823-199E8FE36FA8}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UpdPublish", "UpdPublish\UpdPublish.vcxproj", "{C5829278-D55E-41EB-B866-1E7D814694D1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -46,6 +48,14 @@ Global {2A403460-7834-41B8-9823-199E8FE36FA8}.Release|Win32.Build.0 = Release|Win32 {2A403460-7834-41B8-9823-199E8FE36FA8}.Release|x64.ActiveCfg = Release|x64 {2A403460-7834-41B8-9823-199E8FE36FA8}.Release|x64.Build.0 = Release|x64 + {C5829278-D55E-41EB-B866-1E7D814694D1}.Debug|Win32.ActiveCfg = Debug|Win32 + {C5829278-D55E-41EB-B866-1E7D814694D1}.Debug|Win32.Build.0 = Debug|Win32 + {C5829278-D55E-41EB-B866-1E7D814694D1}.Debug|x64.ActiveCfg = Debug|x64 + {C5829278-D55E-41EB-B866-1E7D814694D1}.Debug|x64.Build.0 = Debug|x64 + {C5829278-D55E-41EB-B866-1E7D814694D1}.Release|Win32.ActiveCfg = Release|Win32 + {C5829278-D55E-41EB-B866-1E7D814694D1}.Release|Win32.Build.0 = Release|Win32 + {C5829278-D55E-41EB-B866-1E7D814694D1}.Release|x64.ActiveCfg = Release|x64 + {C5829278-D55E-41EB-B866-1E7D814694D1}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE