diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d4ca345 --- /dev/null +++ b/Makefile @@ -0,0 +1,45 @@ +KEY_DIR=..\include + +###################################################################### +# Main targets +###################################################################### + +All :: \ + GenRSAKeypair + +Clean :: +# Ommited intentionally not to delete keys accidentaly. + + +###################################################################### +# Folder creation +###################################################################### + +"$(KEY_DIR)" : + if not exist $@ md $@ + + +###################################################################### +# Building +###################################################################### + +GenRSAKeypair :: \ + "$(KEY_DIR)" \ + "$(KEY_DIR)\UpdaterKeyPrivate.bin" \ + "$(KEY_DIR)\UpdaterKeyPublic.bin" + +"$(KEY_DIR)\UpdaterKeypair.txt" : + openssl.exe genrsa -out $@ 4096 + +"$(KEY_DIR)\UpdaterKeyPrivate.bin" : "$(KEY_DIR)\UpdaterKeypair.txt" + if exist $@ del /f /q $@ + if exist "$(@:"=).tmp" del /f /q "$(@:"=).tmp" + openssl.exe rsa -in $** -inform PEM -outform DER -out "$(@:"=).tmp" + move /y "$(@:"=).tmp" $@ > NUL + +"$(KEY_DIR)\UpdaterKeyPublic.bin" : "$(KEY_DIR)\UpdaterKeypair.txt" + if exist $@ del /f /q $@ + if exist "$(@:"=).tmp" del /f /q "$(@:"=).tmp" + openssl.exe rsa -in $** -inform PEM -outform DER -out "$(@:"=).tmp" -pubout + move /y "$(@:"=).tmp" $@ > NUL + diff --git a/include/version.h b/UpdCheck/UpdCheck.h similarity index 52% rename from include/version.h rename to UpdCheck/UpdCheck.h index 1439fa9..26e727b 100644 --- a/include/version.h +++ b/UpdCheck/UpdCheck.h @@ -19,25 +19,7 @@ #pragma once -// -// Product version as a single DWORD -// Note: Used for version comparison within C/C++ code. -// -#define UPDATER_VERSION 0x01000000 +#define IDR_KEY_PUBLIC 1 -// -// Product version by components -// Note: Resource Compiler has limited preprocessing capability, -// thus we need to specify major, minor and other version components -// separately. -// -#define UPDATER_VERSION_MAJ 1 -#define UPDATER_VERSION_MIN 0 -#define UPDATER_VERSION_REV 0 -#define UPDATER_VERSION_BUILD 0 - -// -// Human readable product version and build year for UI -// -#define UPDATER_VERSION_STR "2.0-alpha" -#define UPDATER_BUILD_YEAR_STR "2016" +#if !defined(RC_INVOKED) && !defined(MIDL_PASS) +#endif // !defined(RC_INVOKED) && !defined(MIDL_PASS) diff --git a/UpdCheck/UpdCheck.props b/UpdCheck/UpdCheck.props index 6e51ada..cc02624 100644 --- a/UpdCheck/UpdCheck.props +++ b/UpdCheck/UpdCheck.props @@ -9,6 +9,9 @@ ..\..\lib\wxExtend\include;..\..\lib\stdex\include;%(AdditionalIncludeDirectories) + + RequireAdministrator + \ No newline at end of file diff --git a/UpdCheck/UpdCheck.rc b/UpdCheck/UpdCheck.rc index 4a02bba..e654d0c 100644 Binary files a/UpdCheck/UpdCheck.rc and b/UpdCheck/UpdCheck.rc differ diff --git a/UpdCheck/UpdCheck.vcxproj b/UpdCheck/UpdCheck.vcxproj index f5e5ac8..55252be 100644 --- a/UpdCheck/UpdCheck.vcxproj +++ b/UpdCheck/UpdCheck.vcxproj @@ -85,6 +85,7 @@ + diff --git a/UpdCheck/UpdCheck.vcxproj.filters b/UpdCheck/UpdCheck.vcxproj.filters index 759f9d9..6bbb893 100644 --- a/UpdCheck/UpdCheck.vcxproj.filters +++ b/UpdCheck/UpdCheck.vcxproj.filters @@ -30,6 +30,9 @@ Header Files + + Header Files + diff --git a/UpdCheck/main.cpp b/UpdCheck/main.cpp index 7b52a4b..e6ae4d1 100644 --- a/UpdCheck/main.cpp +++ b/UpdCheck/main.cpp @@ -18,6 +18,73 @@ */ #include "stdafx.h" +#pragma comment(lib, "Crypt32.lib") + + +/// +/// Reads package information from a stream +/// +/// \param[in] stream Input stream +/// \param[out] pkg Package information +/// +/// \returns The stream \p stream +/// +inline std::istream& operator >>(_In_ std::istream& stream, _Out_ Updater::package_info &pkg) +{ + // Read binary version. + stream.read((char*)&pkg.ver, sizeof(pkg.ver)); + if (!stream.good()) return stream; + + // Read human readable description (length prefixed). + unsigned __int32 count; + stream.read((char*)&count, sizeof(count)); + if (!stream.good()) return stream; + pkg.desc.resize(count); + stream.read((char*)pkg.desc.data(), sizeof(wchar_t)*count); + + // Read package language (length prefixed). + stream.read((char*)&count, sizeof(count)); + if (!stream.good()) return stream; + pkg.lang.resize(count); + stream.read((char*)pkg.lang.data(), sizeof(char)*count); + + // Read package download URL (length prefixed). + stream.read((char*)&count, sizeof(count)); + if (!stream.good()) return stream; + pkg.url.resize(count); + stream.read((char*)pkg.url.data(), sizeof(char)*count); + + return stream; +} + + +/// +/// Reads signature from a stream +/// +/// \param[in] stream Input stream +/// \param[out] sig Signature +/// +/// \returns The stream \p stream +/// +inline std::istream& operator >>(_In_ std::istream& stream, _Out_ Updater::signature &sig) +{ + // Read signature (length prefixed). + unsigned __int32 count; + stream.read((char*)&count, sizeof(count)); + if (!stream.good()) return stream; + + // Read, and reverse signature byte order (to be OpenSSL compatible). + std::vector sig_swap(count); + stream.read((char*)sig_swap.data(), sizeof(unsigned char)*count); + if (!stream.good()) return stream; + sig.resize(count); + for (unsigned __int32 i = 0, j = count - 1; i < count; i++, j--) + sig[i] = sig_swap[j]; + + return stream; +} + + /// @@ -29,12 +96,104 @@ int CALLBACK WinMain(_In_ HINSTANCE hInstance, _In_ HINSTANCE hPrevInstance, _In // Inizialize wxWidgets. wxInitializer initializer; - if (!initializer) { - _ftprintf(stderr, wxT("Failed to initialize the wxWidgets library, aborting.\n")); + if (!initializer) return -1; + + // Open data file. + std::ifstream dat(_T("..\\..\\output\\test.bin"), std::ios_base::in | std::ios_base::binary); + if (!dat.good()) { + wxFAIL_MSG(wxT("Error reading data file.")); + return 1; } + // Find the signature first. + if (stdex::idrec::find(dat, Updater::signature_rec::id)) { + // Signature found. Remember file position. + Updater::recordsize_t + sig_pos = (Updater::recordsize_t)dat.tellg(), // Position to return to to read the signature. + sig_start = sig_pos - sizeof(Updater::recordid_t); // Beginning of the signature block + // Create cryptographic context. + HCRYPTPROV cp = NULL; + wxVERIFY(::CryptAcquireContext(&cp, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)); + + // Hash the file up to signature block start. + HCRYPTHASH ch = NULL; + wxVERIFY(::CryptCreateHash(cp, CALG_SHA1, 0, 0, &ch)); + { + dat.seekg(0); + std::vector buf(8192); + for (Updater::recordsize_t data_left = sig_start; dat.good() && data_left;) { + dat.read((char*)buf.data(), std::min(buf.size(), data_left)); + Updater::recordsize_t count = dat.gcount(); + wxVERIFY(::CryptHashData(ch, buf.data(), count, 0)); + data_left -= count; + } + } + + // Read the signature. + dat.seekg(sig_pos); + Updater::signature sig; + dat >> Updater::signature_rec(sig); + if (dat.good()) { + // Import public key. + HCRYPTKEY ck = NULL; + { + HRSRC res = ::FindResource(NULL, MAKEINTRESOURCE(IDR_KEY_PUBLIC), RT_RCDATA); + wxASSERT_MSG(res, wxT("public key not found")); + HGLOBAL res_handle = ::LoadResource(NULL, res); + wxASSERT_MSG(res_handle, wxT("loading resource failed")); + + CERT_PUBLIC_KEY_INFO *keyinfo_data = NULL; + DWORD keyinfo_size = 0; + wxVERIFY(::CryptDecodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, (const BYTE*)::LockResource(res_handle), ::SizeofResource(NULL, res), CRYPT_DECODE_ALLOC_FLAG, NULL, &keyinfo_data, &keyinfo_size)); + + BYTE *key_data = NULL; + DWORD key_size = 0; + wxVERIFY(::CryptDecodeObjectEx(X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, (const BYTE*)keyinfo_data->PublicKey.pbData, keyinfo_data->PublicKey.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &key_data, &key_size)); + + wxVERIFY(::CryptImportKey(cp, key_data, key_size, NULL, 0, &ck)); + ::LocalFree(key_data); + ::LocalFree(keyinfo_data); + } + + // We have the hash, we have the signature, we have the public key. Now verify. + if (::CryptVerifySignature(ch, (BYTE*)sig.data(), sig.size(), ck, NULL, 0)) { + // The signature is correct. Now parse the file. + dat.seekg(0); + if (stdex::idrec::find(dat, UPDATER_DB_ID, sizeof(Updater::recordid_t))) { + Updater::recordsize_t size; + dat.read((char*)&size, sizeof(Updater::recordsize_t)); + if (dat.good()) { + if (size > sig_start) { + // Limit the size up to the file signature. Should have not get here. + wxFAIL_MSG(wxT("Updater file wrong record size.")); + size = sig_start; + } + if (stdex::idrec::find(dat, Updater::package_info_rec::id, size)) { + // Read package information. + Updater::package_info pi; + dat >> Updater::package_info_rec(pi); + if (dat.good()) { + + } else + wxFAIL_MSG(wxT("Error reading package information from Updater file.")); + } else + wxFAIL_MSG(wxT("Updater file has no package information.")); + } else + wxFAIL_MSG(wxT("Updater file read error.")); + } + } else + wxFAIL_MSG(wxT("Updater file signature does not match file content.")); + + wxVERIFY(::CryptDestroyKey(ck)); + } else + wxFAIL_MSG(wxT("Error reading signature from the Updater file.")); + + wxVERIFY(::CryptDestroyHash(ch)); + wxVERIFY(::CryptReleaseContext(cp, 0)); + } else + wxFAIL_MSG(wxT("Signature not found in the Updater file.")); return 0; } diff --git a/UpdCheck/stdafx.h b/UpdCheck/stdafx.h index 4fe41c1..ad9ffcb 100644 --- a/UpdCheck/stdafx.h +++ b/UpdCheck/stdafx.h @@ -19,8 +19,13 @@ #pragma once +#include "UpdCheck.h" +#include "../include/Updater.h" + #include #include #include + +#include diff --git a/UpdMkDesc/UpdMkDesc.h b/UpdMkDesc/UpdMkDesc.h new file mode 100644 index 0000000..8606b89 --- /dev/null +++ b/UpdMkDesc/UpdMkDesc.h @@ -0,0 +1,25 @@ +/* + 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 + +#define IDR_KEY_PRIVATE 1 + +#if !defined(RC_INVOKED) && !defined(MIDL_PASS) +#endif // !defined(RC_INVOKED) && !defined(MIDL_PASS) diff --git a/UpdMkDesc/UpdMkDesc.rc b/UpdMkDesc/UpdMkDesc.rc index 5f4db7a..fe544cd 100644 Binary files a/UpdMkDesc/UpdMkDesc.rc and b/UpdMkDesc/UpdMkDesc.rc differ diff --git a/UpdMkDesc/UpdMkDesc.vcxproj b/UpdMkDesc/UpdMkDesc.vcxproj index 09ec111..132dbed 100644 --- a/UpdMkDesc/UpdMkDesc.vcxproj +++ b/UpdMkDesc/UpdMkDesc.vcxproj @@ -88,6 +88,7 @@ + diff --git a/UpdMkDesc/UpdMkDesc.vcxproj.filters b/UpdMkDesc/UpdMkDesc.vcxproj.filters index 0514c72..de7c64b 100644 --- a/UpdMkDesc/UpdMkDesc.vcxproj.filters +++ b/UpdMkDesc/UpdMkDesc.vcxproj.filters @@ -30,6 +30,9 @@ Header Files + + Header Files + diff --git a/UpdMkDesc/locale/sl_SI.po b/UpdMkDesc/locale/sl_SI.po index 5e35145..b18e162 100644 --- a/UpdMkDesc/locale/sl_SI.po +++ b/UpdMkDesc/locale/sl_SI.po @@ -1,8 +1,8 @@ msgid "" msgstr "" "Project-Id-Version: UpdMkDesc\n" -"POT-Creation-Date: 2016-03-15 10:56+0100\n" -"PO-Revision-Date: 2016-03-15 10:57+0100\n" +"POT-Creation-Date: 2016-03-15 20:09+0100\n" +"PO-Revision-Date: 2016-03-15 20:10+0100\n" "Last-Translator: Simon Rozman \n" "Language-Team: Amebis, d. o. o., Kamnik \n" "Language: sl_SI\n" @@ -17,14 +17,29 @@ msgstr "" "X-Poedit-KeywordsList: _\n" "X-Poedit-SearchPath-0: .\n" -#: main.cpp:40 +#: main.cpp:138 msgid "Show this help message" msgstr "Pokaži to sporočilo pomoči" -#: main.cpp:41 -msgid "input file" -msgstr "vhodna datoteka" +#: main.cpp:139 +msgid "Hexadecimal version of the product" +msgstr "Verzija izdelka šesnajstiško" -#: main.cpp:42 +#: main.cpp:140 +msgid "String version of the product" +msgstr "Verzija izdelka opisno" + +#: main.cpp:141 +msgid "Package language" +msgstr "Jezik paketa" + +#: main.cpp:142 +msgid "Package download URL" +msgstr "URL za prenos paketa" + +#: main.cpp:143 msgid "output file" msgstr "izhodna datoteka" + +#~ msgid "Package URL in the form of platform;language;URL" +#~ msgstr "Naslov URL paketa oblike platforma;jezik;URL" diff --git a/UpdMkDesc/main.cpp b/UpdMkDesc/main.cpp index a63bca9..5066062 100644 --- a/UpdMkDesc/main.cpp +++ b/UpdMkDesc/main.cpp @@ -18,6 +18,104 @@ */ #include "stdafx.h" +#pragma comment(lib, "Crypt32.lib") + + +/// +/// Writes package information to a stream +/// +/// \param[in] stream Output stream +/// \param[in] pkg Package information +/// +/// \returns The stream \p stream +/// +inline std::ostream& operator <<(_In_ std::ostream& stream, _In_ const Updater::package_info &pkg) +{ + // Write binary version. + if (stream.fail()) return stream; + stream.write((const char*)&pkg.ver, sizeof(pkg.ver)); + + // Write human readable description (length prefixed). + std::wstring::size_type char_count = pkg.desc.length(); +#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) + // 4G check + if (char_count > 0xffffffff) { + stream.setstate(std::ios_base::failbit); + return stream; + } +#endif + if (stream.fail()) return stream; + unsigned __int32 count = (unsigned __int32)char_count; + stream.write((const char*)&count, sizeof(count)); + if (stream.fail()) return stream; + stream.write((const char*)pkg.desc.c_str(), sizeof(wchar_t)*count); + + // Write package language (length prefixed) + char_count = pkg.lang.length(); +#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) + // 4G check + if (char_count > 0xffffffff) { + stream.setstate(std::ios_base::failbit); + return stream; + } +#endif + if (stream.fail()) return stream; + count = (unsigned __int32)char_count; + stream.write((const char*)&count, sizeof(count)); + if (stream.fail()) return stream; + stream.write(pkg.lang.c_str(), sizeof(char)*count); + + // Write package download URL (length prefixed) + char_count = pkg.url.length(); +#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) + // 4G check + if (char_count > 0xffffffff) { + stream.setstate(std::ios_base::failbit); + return stream; + } +#endif + if (stream.fail()) return stream; + count = (unsigned __int32)char_count; + stream.write((const char*)&count, sizeof(count)); + if (stream.fail()) return stream; + stream.write(pkg.url.c_str(), sizeof(char)*count); + + return stream; +} + + +/// +/// Writes signature to a stream +/// +/// \param[in] stream Output stream +/// \param[in] sig Signature +/// +/// \returns The stream \p stream +/// +inline std::ostream& operator <<(_In_ std::ostream& stream, _In_ const Updater::signature &sig) +{ + // Write signature (length prefixed). + Updater::signature::size_type sig_count = sig.size(); +#if defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) + // 4G check + if (sig_count > 0xffffffff) { + stream.setstate(std::ios_base::failbit); + return stream; + } +#endif + if (stream.fail()) return stream; + unsigned __int32 count = (unsigned __int32)sig_count; + stream.write((const char*)&count, sizeof(count)); + + // Reverse signature byte order (to make OpenSSL compatible), and write. + if (stream.fail()) return stream; + std::vector sig_swap(count); + for (unsigned __int32 i = 0, j = count - 1; i < count; i++, j--) + sig_swap[j] = sig[i]; + stream.write((const char*)sig_swap.data(), sizeof(unsigned char)*count); + + return stream; +} /// @@ -38,7 +136,10 @@ int _tmain(int argc, _TCHAR *argv[]) static const wxCmdLineEntryDesc cmdLineDesc[] = { { wxCMD_LINE_SWITCH, "h" , "help" , _("Show this help message" ), wxCMD_LINE_VAL_NONE , wxCMD_LINE_OPTION_HELP }, - { wxCMD_LINE_SWITCH, "vh" , "ver-hex", _("Hexadecimal version of the product"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY }, + { wxCMD_LINE_OPTION, "x" , "ver-hex", _("Hexadecimal version of the product"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY }, + { wxCMD_LINE_OPTION, "s" , "ver-str", _("String version of the product" ), wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY }, + { wxCMD_LINE_OPTION, "l" , "lang" , _("Package language" ), wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY }, + { wxCMD_LINE_OPTION, "u" , "url" , _("Package download URL" ), wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY }, { wxCMD_LINE_PARAM , NULL, NULL , _("output file" ), wxCMD_LINE_VAL_STRING, wxCMD_LINE_OPTION_MANDATORY }, { wxCMD_LINE_NONE } @@ -58,5 +159,96 @@ int _tmain(int argc, _TCHAR *argv[]) return -1; } - return 0; + const wxString& filenameOut = parser.GetParam(0); + std::fstream dst((LPCTSTR)filenameOut, std::ios_base::out | std::ios_base::in | std::ios_base::trunc | std::ios_base::binary); + if (dst.fail()) { + _ftprintf(stderr, wxT("%s: error UMD0001: Error opening output file.\n"), filenameOut.fn_str()); + return 1; + } + + bool has_errors = false; + + // Open file ID. + std::streamoff dst_start = stdex::idrec::open(dst, UPDATER_DB_ID); + + Updater::package_info pi; + wxString val; + + pi.ver = parser.Found(wxT("x"), &val) ? _tcstoul(val, NULL, 16) : 0; + + if (parser.Found(wxT("s"), &val)) + pi.desc = val; + + if (parser.Found(wxT("l"), &val)) + pi.lang = val.ToAscii(); + + if (parser.Found(wxT("u"), &val)) + pi.url = val.ToUTF8(); + + dst << Updater::package_info_rec(pi); + if (dst.fail()) { + _ftprintf(stderr, wxT("%s: error UMD0002: Writing to output file failed.\n"), filenameOut.fn_str()); + has_errors = true; + } + + stdex::idrec::close(dst, dst_start); + + // Create cryptographic context. + HCRYPTPROV cp = NULL; + wxVERIFY(::CryptAcquireContext(&cp, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)); + + // Import private key. + { + HRSRC res = ::FindResource(NULL, MAKEINTRESOURCE(IDR_KEY_PRIVATE), RT_RCDATA); + wxASSERT_MSG(res, wxT("private key not found")); + HGLOBAL res_handle = ::LoadResource(NULL, res); + wxASSERT_MSG(res_handle, wxT("loading resource failed")); + + PUBLICKEYSTRUC *key_data = NULL; + DWORD key_size = 0; + wxVERIFY(::CryptDecodeObjectEx(X509_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, (const BYTE*)::LockResource(res_handle), ::SizeofResource(NULL, res), CRYPT_DECODE_ALLOC_FLAG, NULL, &key_data, &key_size)); + // See: http://pumka.net/2009/12/16/rsa-encryption-cplusplus-delphi-cryptoapi-php-openssl-2/comment-page-1/#comment-429 + key_data->aiKeyAlg = CALG_RSA_SIGN; + + HCRYPTKEY ck = NULL; + wxVERIFY(::CryptImportKey(cp, (const BYTE*)key_data, key_size, NULL, 0, &ck)); + wxVERIFY(::CryptDestroyKey(ck)); + ::LocalFree(key_data); + } + + // Hash the file. + HCRYPTHASH ch = NULL; + wxVERIFY(::CryptCreateHash(cp, CALG_SHA1, 0, 0, &ch)); + { + std::vector buf(8192); + for (dst.seekg(0); !dst.eof();) { + dst.read((char*)buf.data(), buf.size()); + wxVERIFY(::CryptHashData(ch, buf.data(), dst.gcount(), 0)); + } + dst.clear(); + } + + // Sign the hash. + DWORD sig_size = 0; + if (!::CryptSignHash(ch, AT_SIGNATURE, NULL, 0, NULL, &sig_size)) { + _ftprintf(stderr, wxT("%s: error UMD0003: Signing output file failed (%i).\n"), filenameOut.fn_str(), ::GetLastError()); + has_errors = true; + } + Updater::signature sig(sig_size); + if (!::CryptSignHash(ch, AT_SIGNATURE, NULL, 0, sig.data(), &sig_size)) { + _ftprintf(stderr, wxT("%s: error UMD0003: Signing output file failed (%i).\n"), filenameOut.fn_str(), ::GetLastError()); + has_errors = true; + } + wxVERIFY(::CryptDestroyHash(ch)); + wxVERIFY(::CryptReleaseContext(cp, 0)); + + // Append to the end of the file. + dst << Updater::signature_rec(sig); + + if (has_errors) { + dst.close(); + wxRemoveFile(filenameOut); + return 1; + } else + return 0; } diff --git a/UpdMkDesc/stdafx.h b/UpdMkDesc/stdafx.h index 65d22a1..4aba235 100644 --- a/UpdMkDesc/stdafx.h +++ b/UpdMkDesc/stdafx.h @@ -19,9 +19,18 @@ #pragma once +#include "UpdMkDesc.h" +#include "../include/Updater.h" + #include #include #include #include + +#include +#include +#include + +#include diff --git a/Updater.sln b/Updater.sln index 216fcef..a401120 100644 --- a/Updater.sln +++ b/Updater.sln @@ -5,7 +5,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libraries", "Libraries", "{ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{ECE3F336-FFD2-41EE-AD8F-17BD7472BDCB}" ProjectSection(SolutionItems) = preProject - include\version.h = include\version.h + include\Updater.h = include\Updater.h EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UpdMkDesc", "UpdMkDesc\UpdMkDesc.vcxproj", "{516AFFF6-F1E7-4806-B2E2-5CD9911ED2FB}" diff --git a/include/Updater.h b/include/Updater.h new file mode 100644 index 0000000..a6aabc6 --- /dev/null +++ b/include/Updater.h @@ -0,0 +1,96 @@ +/* + 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 + +// +// Product version as a single DWORD +// Note: Used for version comparison within C/C++ code. +// +#define UPDATER_VERSION 0x01000000 + +// +// Product version by components +// Note: Resource Compiler has limited preprocessing capability, +// thus we need to specify major, minor and other version components +// separately. +// +#define UPDATER_VERSION_MAJ 1 +#define UPDATER_VERSION_MIN 0 +#define UPDATER_VERSION_REV 0 +#define UPDATER_VERSION_BUILD 0 + +// +// Human readable product version and build year for UI +// +#define UPDATER_VERSION_STR "2.0-alpha" +#define UPDATER_BUILD_YEAR_STR "2016" + + +#if !defined(RC_INVOKED) && !defined(MIDL_PASS) + +#include + +#include +#include + + +/// +/// Data records alignment +/// +#define UPDATER_RECORD_ALIGN 1 + + +/// +/// Database IDs +/// +#define UPDATER_DB_ID (*(Updater::recordid_t*)"UPD") + + +namespace Updater { + typedef unsigned __int32 recordid_t; + typedef unsigned __int32 recordsize_t; + + + /// + /// Package information + /// + struct package_info { + unsigned __int32 ver; ///< Binary Version + std::wstring desc; ///< Human Readable Description (i. e. "1.2") + std::string lang; ///< Package Language (ISO 639-1 language code followed by underscore and ISO 3166 country code) + std::string url; ///< Package download URL (UTF-8 encoded) + }; + + typedef stdex::idrec::record package_info_rec; + + + /// + /// Signature + /// + typedef std::vector signature; + + typedef stdex::idrec::record signature_rec; +}; + + +const Updater::recordid_t stdex::idrec::record::id = *(Updater::recordid_t*)"PKG"; +const Updater::recordid_t stdex::idrec::record::id = *(Updater::recordid_t*)"SGN"; + +#endif // !defined(RC_INVOKED) && !defined(MIDL_PASS)