示例#1
0
TEST(UpdateCrypto, Binary)
{
	CAutoTempDir tempdir;
	CString testFile = tempdir.GetTempDir() + L"\\test.bin";

	unsigned char binaryFile[99] = // based on link.png
	{
		0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
		0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x01, 0x03, 0x00, 0x00, 0x00, 0xFE, 0xC1, 0x2C,
		0xC8, 0x00, 0x00, 0x00, 0x06, 0x50, 0x4C, 0x54, 0x45, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xA5,
		0xD9, 0x9F, 0xDD, 0x00, 0x00, 0x00, 0x18, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5E, 0x63, 0xF8, 0xC0,
		0xF0, 0x87, 0xE1, 0x17, 0x83, 0x18, 0x43, 0x3E, 0x43, 0x38, 0x43, 0x39, 0x03, 0x3B, 0x00, 0x2C,
		0x98, 0x04, 0x41, 0xFA, 0xEC, 0xE7, 0x75, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE,
		0x42, 0x60, 0x82,
	};

	CAutoFile file = ::CreateFile(testFile, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
	ASSERT_TRUE(file.IsValid());
	DWORD written = 0;
	EXPECT_TRUE(::WriteFile(file, binaryFile, sizeof(binaryFile), &written, nullptr));
	EXPECT_EQ(sizeof(binaryFile), written);
	EXPECT_TRUE(file.CloseHandle());

	CString testFileSignature = testFile + _T(".rsa.asc");
	EXPECT_TRUE(CStringUtils::WriteStringToTextFile((LPCTSTR)testFileSignature, L"-----BEGIN PGP SIGNATURE-----\nVersion: GnuPG v2\n\niQIcBAABCgAGBQJVxPvgAAoJEPfxez+d2VOerKsP/iQlt4S20LdUknT5udD8fFpT\nEFhZDPTXMRWkd8OhCLxa+t5b/ijyxFKWNz808Q7BDQcQoOQtC19NDvVmAcfqXflt\nR4Z+ugCG/lqP+3y0xBrL9m4UT9fNzQCiUY8Xpaih+6riLGnXVVpUe29BgVZppEWn\nMG9RVXpXwC+M3VQ0yQWu1F2Yy5OjdH4Ww5kpluoseZMOPhT6VaSfXeyQmg2DrBbw\nUfVV+w718noZ5znDH9MiD5y+sd4o7vqN2YFdg6FNvTjHyha39aFV8UCpPX1lH9ME\nN9v1vt5IWGCWL0zsZ6umHqibGG3Q2S3mlqktFhKJGWci+Swy4cNMpXDHIKY6e5v7\nxPIP92djyFtbjdixcSqBaYFC/Dd0KuCa1eYmyi2KxzUP29rZ+EHWoazfbeL1Y2Pu\nkSBrVFv64j0URzSMxUpJMqYXZRC5QW7vdbVwHGAPzoS+0rBBddwfSKteBQjagcHA\nkLk3sAIZNj1JaP5dcGL2K4Wxlaae0WgwI48lZSBMoL8SaInQvcKq9iL64xfpU+FU\nG0mzbidvTfZpyEU3eeSNiFi+6z4XLQ3NUFxsOr5jEPVKvgRoPljhJ4nCx034KQRQ\nHbVF9KYgMJSroKN9bNi/UFkC45Pc4wVov/XyH82XCVS30Du4hsVXsTdAiiXb3i6w\nkrWIJWYRxx76XGtQoHrR\n=PlFQ\n-----END PGP SIGNATURE-----"));
	EXPECT_EQ(0, VerifyIntegrity(testFile, testFileSignature, nullptr));

	// signature is shorter than pubkey; did not work w/o commit 941c103c00e48b0ffe592ab4d87d40ff48f899f6
	EXPECT_TRUE(CStringUtils::WriteStringToTextFile((LPCTSTR)testFileSignature, L"-----BEGIN PGP SIGNATURE-----\nVersion: GnuPG v2\n\niQIbBAABCgAGBQJVxQQOAAoJEPfxez+d2VOe7GoP+KflvYJVpNXSwnteXyDc1zTo\nJAyAJFtW6mgqCLrN6KoMrncEvd0cHrD07hT5mxULkbP6zy9fGaFYF0gHO0mOqErF\nIIbDcpPTWooJWUHMbnuQjf2I0x70Cr8ikycZQ7uDg7scZx7E8EIwHOJX60dcfdVX\nK1SQ+c+VIvo1uxL1PndloACaeINz6rL0Pj504lVDJaaGBvzdAV6KEIcjjm+Jb4r0\n6CYEntmt1i3Mc8FM6Xp1QfGtJqp4ogjv6o89hvtaBBLihB54EVQn66/2qIjdhX8W\nkdqJE6+pmFTfuD02XNECwl6stDIZcxXCw6EE87/1hdHip8oW9enIVTxKWB3fUWHl\n236eE2qb8zAN/WWGx/2Cvi6ctyosy9Cc/1hopnmV0KgZFfmDJWw0lISlC/3ZYWEe\nQFiXs5FPzLwfKnkq4REpoOKKfbZNk329J2iLFnwrF0mlL4vUZ1m26BBBk6lhm41J\nnjOSFWhJG/AqBbR5DqdJfXMqnxpfVZfaE5cry2rhjI4mfzw0xzrgvL4M9FZ7R9F8\njVHAV11CMqtp/7gMHXu6ljkTEBBQ7cgbU5DEAwfWddaJF+R30jmNSVliN2JW2FAk\nIbE8yV+uPiyXebn49CmRzkOWOAZqx+DShqriXGam37qjhdys147wPMMiwk8lZKjP\n4V66gTFw45UvBpophyg=\n=0bmW\n-----END PGP SIGNATURE-----"));
	EXPECT_EQ(0, VerifyIntegrity(testFile, testFileSignature, nullptr));
}
示例#2
0
TEST(UpdateCrypto, BinarySignature)
{
	CAutoTempDir tempdir;
	CString testFile = tempdir.GetTempDir() + L"\\test.txt";

	EXPECT_TRUE(CStringUtils::WriteStringToTextFile((LPCTSTR)testFile, L"Text with\r\nNewline"));

	unsigned char binarySignature[543] =
	{
		0x89, 0x02, 0x1C, 0x04, 0x00, 0x01, 0x0A, 0x00, 0x06, 0x05, 0x02, 0x55, 0xC5, 0x03, 0x29, 0x00,
		0x0A, 0x09, 0x10, 0xF7, 0xF1, 0x7B, 0x3F, 0x9D, 0xD9, 0x53, 0x9E, 0x1E, 0xDF, 0x0F, 0xFF, 0x6C,
		0xE9, 0x7B, 0xE0, 0xD6, 0x97, 0x1A, 0xC0, 0x07, 0x77, 0x1C, 0xAB, 0x63, 0x67, 0x9A, 0x75, 0x34,
		0xF7, 0x17, 0x84, 0xE2, 0x52, 0xD8, 0x79, 0x4E, 0x35, 0x60, 0xF6, 0x2D, 0x30, 0x1D, 0xF1, 0x09,
		0x55, 0x56, 0x4D, 0x00, 0x2E, 0xBF, 0x2C, 0x1A, 0xCA, 0xDE, 0xEF, 0xA2, 0x86, 0xF5, 0xE1, 0x07,
		0x7B, 0x48, 0xB5, 0x42, 0x73, 0x59, 0x7D, 0xE0, 0xC9, 0x57, 0x86, 0x06, 0x12, 0xAE, 0xF0, 0xC4,
		0xF1, 0x73, 0x9B, 0x23, 0xB8, 0xF8, 0x67, 0x99, 0xB0, 0xB3, 0xCA, 0x0F, 0xF9, 0x1F, 0xD1, 0x5D,
		0xD3, 0xFD, 0x44, 0x5C, 0x30, 0x17, 0x4D, 0x84, 0x3A, 0x4E, 0x7B, 0x01, 0xB4, 0x07, 0x37, 0x70,
		0x0F, 0x5D, 0xE1, 0x8C, 0x1A, 0x6B, 0xAE, 0x7D, 0x5E, 0x58, 0x6F, 0x16, 0xE8, 0xBD, 0x3D, 0xC1,
		0x83, 0x89, 0x52, 0x56, 0x57, 0x5E, 0x3A, 0xA6, 0xD1, 0x5E, 0xC6, 0xB0, 0x3F, 0x8D, 0xDC, 0xA8,
		0xAF, 0x32, 0xC4, 0x30, 0x33, 0x9A, 0x5F, 0x5F, 0xF9, 0xAA, 0xFE, 0xCE, 0xBA, 0x4C, 0x86, 0xFD,
		0xC1, 0x46, 0x85, 0x0B, 0x0B, 0x5F, 0xF3, 0x78, 0x55, 0x74, 0x85, 0x13, 0x0D, 0xA0, 0x4B, 0xEF,
		0x36, 0x37, 0xB0, 0xC8, 0x8B, 0x16, 0x10, 0x2D, 0x97, 0xBD, 0x9E, 0x83, 0x14, 0x70, 0x76, 0xD5,
		0x3C, 0xC1, 0x70, 0x35, 0xEF, 0xD1, 0x0D, 0xDA, 0x0B, 0xEA, 0x2B, 0x3F, 0x31, 0x24, 0x26, 0xF8,
		0x6E, 0x2F, 0x43, 0x4B, 0xDD, 0xC2, 0x2F, 0x7B, 0x98, 0x3B, 0x1B, 0x6B, 0x3B, 0x12, 0x6D, 0x94,
		0xC2, 0x04, 0x41, 0x16, 0xF0, 0xB7, 0xE1, 0xBD, 0x2B, 0x35, 0x3F, 0x0D, 0x3A, 0x8B, 0x2D, 0xE0,
		0x1A, 0x07, 0x3E, 0x51, 0xB6, 0xD7, 0x06, 0x27, 0x2E, 0x71, 0x8F, 0x88, 0x0A, 0xC0, 0xF9, 0xE4,
		0x0D, 0x71, 0x86, 0x9F, 0x80, 0xCB, 0x72, 0xC4, 0x8F, 0x2E, 0x4E, 0x7B, 0x83, 0x35, 0xBA, 0xAD,
		0x73, 0xAB, 0x8A, 0x69, 0xEE, 0xCE, 0xA7, 0x34, 0x69, 0x88, 0xF7, 0x39, 0x13, 0xE9, 0x67, 0xE5,
		0x4E, 0x74, 0x16, 0xAB, 0xA4, 0x84, 0xD4, 0x7A, 0x19, 0x5A, 0x71, 0x72, 0xC9, 0xCD, 0x52, 0xFA,
		0xE8, 0x16, 0x33, 0xAF, 0x0B, 0x78, 0xC8, 0xA9, 0x05, 0x57, 0xD1, 0x6A, 0x0D, 0x46, 0x36, 0x46,
		0x45, 0x4A, 0xC4, 0x64, 0x81, 0xC8, 0x0E, 0x8A, 0xDC, 0xF3, 0x75, 0xD2, 0x5D, 0x60, 0x86, 0xE9,
		0x23, 0x02, 0xFA, 0x9C, 0xF5, 0x95, 0xEE, 0x80, 0x47, 0x7F, 0xD1, 0xEE, 0xCC, 0xCF, 0x2D, 0x62,
		0x3E, 0x8A, 0x29, 0xEE, 0x8E, 0x43, 0x5F, 0x74, 0xED, 0xB1, 0x8D, 0xC7, 0x41, 0x5A, 0x51, 0xC8,
		0xE6, 0xCE, 0xCE, 0x03, 0x77, 0x86, 0x60, 0xEA, 0x73, 0xFC, 0x6D, 0x62, 0x62, 0xAF, 0x6C, 0x2A,
		0x1F, 0x84, 0xC4, 0x10, 0x61, 0x78, 0x51, 0x38, 0x8B, 0x4F, 0xE3, 0xDA, 0x39, 0xB6, 0x32, 0x58,
		0x84, 0x0C, 0xE7, 0xCD, 0xDF, 0xB1, 0x6D, 0x72, 0xFD, 0xF6, 0x22, 0x50, 0xB0, 0x7F, 0x35, 0x56,
		0xF0, 0x9B, 0x47, 0xF1, 0x45, 0x13, 0x06, 0xE5, 0x71, 0x15, 0xE9, 0xB2, 0x5E, 0x78, 0xE0, 0x70,
		0xAB, 0x98, 0xBF, 0xF3, 0x15, 0x6A, 0x3D, 0x3E, 0xDF, 0x2D, 0x23, 0xBF, 0x16, 0x96, 0x0D, 0xF3,
		0x4F, 0xD4, 0x48, 0x66, 0x2E, 0x52, 0xB0, 0x48, 0x2E, 0x37, 0x7A, 0xCA, 0xFA, 0x89, 0x3B, 0x21,
		0xAA, 0xD1, 0x96, 0x1C, 0x2E, 0x28, 0x7A, 0xEF, 0xCB, 0x09, 0x62, 0xF4, 0xC5, 0x3E, 0x81, 0x87,
		0xBB, 0x9B, 0x48, 0xAB, 0x1E, 0xD5, 0xAE, 0x3B, 0x20, 0x1A, 0xD1, 0x51, 0x9D, 0xE0, 0x6E, 0x6E,
		0xCC, 0x29, 0x24, 0x34, 0xCF, 0x07, 0xF4, 0x33, 0x42, 0x3A, 0xF2, 0x86, 0x4F, 0xFA, 0xEE, 0x5D,
		0x0A, 0x6A, 0x33, 0xE0, 0xFC, 0xBB, 0x1C, 0xA0, 0xA4, 0x76, 0xE8, 0xB1, 0x17, 0xF5, 0xE4,
	};

	CString testFileSignature = testFile + _T(".rsa.asc");
	CAutoFile file = ::CreateFile(testFileSignature, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
	ASSERT_TRUE(file.IsValid());
	DWORD written = 0;
	EXPECT_TRUE(::WriteFile(file, binarySignature, sizeof(binarySignature), &written, nullptr));
	EXPECT_EQ(sizeof(binarySignature), written);
	EXPECT_TRUE(file.CloseHandle());

	EXPECT_EQ(0, VerifyIntegrity(testFile, testFileSignature, nullptr));

	EXPECT_TRUE(CStringUtils::WriteStringToTextFile((LPCTSTR)testFile, L"Text with\nNewline"));
	EXPECT_EQ(-1, VerifyIntegrity(testFile, testFileSignature, nullptr));
}
示例#3
0
bool SyncCommand::Execute()
{
    bool bRet = false;
    CRegString rSyncPath(L"Software\\TortoiseSVN\\SyncPath");
    CTSVNPath syncPath = CTSVNPath(CString(rSyncPath));
    CTSVNPath syncFolder = syncPath;
    CRegDWORD regCount(L"Software\\TortoiseSVN\\SyncCounter");
    CRegDWORD regSyncAuth(L"Software\\TortoiseSVN\\SyncAuth");
    bool bSyncAuth = DWORD(regSyncAuth) != 0;
    if (!cmdLinePath.IsEmpty())
        syncPath = cmdLinePath;
    if (syncPath.IsEmpty() && !parser.HasKey(L"askforpath"))
    {
        return false;
    }
    syncPath.AppendPathString(L"tsvnsync.tsex");

    BOOL bWithLocals = FALSE;
    if (parser.HasKey(L"askforpath"))
    {
        // ask for the path first, then for the password
        // this is used for a manual import/export
        CString path;
        bool bGotPath = FileOpenSave(path, bWithLocals, !!parser.HasKey(L"load"), GetExplorerHWND());
        if (bGotPath)
        {
            syncPath = CTSVNPath(path);
            if (!parser.HasKey(L"load") && syncPath.GetFileExtension().IsEmpty())
                syncPath.AppendRawString(L".tsex");
        }
        else
            return false;
    }


    CSimpleIni iniFile;
    iniFile.SetMultiLine(true);
    SVNAuthData authData;

    CAutoRegKey hMainKey;
    RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\TortoiseSVN", 0, KEY_READ, hMainKey.GetPointer());
    FILETIME filetime = { 0 };
    RegQueryInfoKey(hMainKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &filetime);

    bool bCloudIsNewer = false;
    if (!parser.HasKey(L"save"))
    {
        // open the file in read mode
        CAutoFile hFile = CreateFile(syncPath.GetWinPathString(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hFile.IsValid())
        {
            // load the file
            LARGE_INTEGER fsize = { 0 };
            if (GetFileSizeEx(hFile, &fsize))
            {
                auto filebuf = std::make_unique<char[]>(DWORD(fsize.QuadPart));
                DWORD bytesread = 0;
                if (ReadFile(hFile, filebuf.get(), DWORD(fsize.QuadPart), &bytesread, NULL))
                {
                    // decrypt the file contents
                    std::string encrypted;
                    if (bytesread > 0)
                        encrypted = std::string(filebuf.get(), bytesread);
                    CRegString regPW(L"Software\\TortoiseSVN\\SyncPW");
                    CString password;
                    if (parser.HasKey(L"askforpath") && parser.HasKey(L"load"))
                    {
                        INT_PTR dlgret = 0;
                        bool bPasswordMatches = true;
                        do
                        {
                            bPasswordMatches = true;
                            CPasswordDlg passDlg(CWnd::FromHandle(GetExplorerHWND()));
                            passDlg.m_bForSave = !!parser.HasKey(L"save");
                            dlgret = passDlg.DoModal();
                            password = passDlg.m_sPW1;
                            if ((dlgret == IDOK) && (parser.HasKey(L"load")))
                            {
                                std::string passworda = CUnicodeUtils::StdGetUTF8((LPCWSTR)password);
                                std::string decrypted = CStringUtils::Decrypt(encrypted, passworda);
                                if ((decrypted.size() < 3) || (decrypted.substr(0, 3) != "***"))
                                {
                                    bPasswordMatches = false;
                                }
                            }
                        } while ((dlgret == IDOK) && !bPasswordMatches);
                        if (dlgret != IDOK)
                            return false;
                    }
                    else
                    {
                        auto passwordbuf = CStringUtils::Decrypt(CString(regPW));
                        if (passwordbuf.get())
                        {
                            password = passwordbuf.get();
                        }
                        else
                        {
                            // password does not match or it couldn't be read from
                            // the registry!
                            //
                            TaskDialog(GetExplorerHWND(), AfxGetResourceHandle(), MAKEINTRESOURCE(IDS_APPNAME), MAKEINTRESOURCE(IDS_ERR_ERROROCCURED), MAKEINTRESOURCE(IDS_SYNC_WRONGPASSWORD), TDCBF_OK_BUTTON, TD_ERROR_ICON, NULL);
                            CString sCmd = L" /command:settings /page:21";
                            CAppUtils::RunTortoiseProc(sCmd);
                            return false;
                        }
                    }
                    std::string passworda = CUnicodeUtils::StdGetUTF8((LPCWSTR)password);
                    std::string decrypted = CStringUtils::Decrypt(encrypted, passworda);
                    if (decrypted.size() >= 3)
                    {
                        if (decrypted.substr(0, 3) == "***")
                        {
                            decrypted = decrypted.substr(3);
                            // pass the decrypted data to the ini file
                            iniFile.LoadFile(decrypted.c_str(), decrypted.size());
                            int inicount = _wtoi(iniFile.GetValue(L"sync", L"synccounter", L""));
                            if (inicount != 0)
                            {
                                if (int(DWORD(regCount)) < inicount)
                                {
                                    bCloudIsNewer = true;
                                    regCount = inicount;
                                }
                            }

                            // load the auth data, but do not overwrite already stored auth data!
                            if (bSyncAuth)
                                authData.ImportAuthData(syncFolder.GetWinPathString(), password);
                        }
                        else
                        {
                            CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error decrypting, password may be wrong\n");
                            return false;
                        }
                    }
                }
            }
        }
        else
        {
            CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error opening file %s, Error %u\n", syncPath.GetWinPath(), GetLastError());
            auto lasterr = GetLastError();
            if ((lasterr != ERROR_FILE_NOT_FOUND) && (lasterr != ERROR_PATH_NOT_FOUND))
                return false;
        }
    }

    if (parser.HasKey(L"load"))
        bCloudIsNewer = true;
    if (parser.HasKey(L"save"))
        bCloudIsNewer = false;

    bool bHaveChanges = false;

    if (bWithLocals || parser.HasKey(L"local"))
    {
        // remove all blocks that are allowed for local exports
        for (const auto& allow : regBlockLocalArray)
        {
            regBlockArray.erase(std::remove(regBlockArray.begin(), regBlockArray.end(), allow), regBlockArray.end());
        }
    }
    // go through all registry values and update either the registry
    // or the ini file, depending on which is newer
    for (const auto& regname : regUseArray)
    {
        bool bChanges = HandleRegistryKey(regname, iniFile, bCloudIsNewer);
        bHaveChanges = bHaveChanges || bChanges;
    }
    if (bWithLocals || parser.HasKey(L"local"))
    {
        for (const auto& regname : regUseLocalArray)
        {
            bool bChanges = HandleRegistryKey(regname, iniFile, bCloudIsNewer);
            bHaveChanges = bHaveChanges || bChanges;
        }
    }

    if (bCloudIsNewer)
    {
        CString regpath = L"Software\\";

        CSimpleIni::TNamesDepend keys;
        iniFile.GetAllKeys(L"registry_dword", keys);
        for (const auto& k : keys)
        {
            CRegDWORD reg(regpath + k);
            reg = _wtol(iniFile.GetValue(L"registry_dword", k, L""));
        }

        keys.clear();
        iniFile.GetAllKeys(L"registry_qword", keys);
        for (const auto& k : keys)
        {
            CRegQWORD reg(regpath + k);
            reg = _wtoi64(iniFile.GetValue(L"registry_qword", k, L""));
        }

        keys.clear();
        iniFile.GetAllKeys(L"registry_string", keys);
        for (const auto& k : keys)
        {
            CRegString reg(regpath + k);
            reg = CString(iniFile.GetValue(L"registry_string", k, L""));
        }
    }
    {
        // sync project monitor settings
        CString sDataFilePath = CPathUtils::GetAppDataDirectory();
        sDataFilePath += L"\\MonitoringData.ini";
        CSimpleIni monitorIni;
        monitorIni.SetMultiLine(true);
        if (bCloudIsNewer)
        {
            CSimpleIni origMonitorIni;
            origMonitorIni.SetMultiLine(true);
            origMonitorIni.LoadFile(sDataFilePath);

            CSimpleIni::TNamesDepend keys;
            iniFile.GetAllKeys(L"ini_monitor", keys);
            for (const auto& k : keys)
            {
                CString sKey = k;
                CString sSection = sKey.Left(sKey.Find('.'));
                sKey = sKey.Mid(sKey.Find('.') + 1);
                if (sKey.CompareNoCase(L"name") == 0)
                {
                    // make sure the non-synced values are still used
                    monitorIni.SetValue(sSection, L"lastchecked", origMonitorIni.GetValue(sSection, L"lastchecked", L"0"));
                    monitorIni.SetValue(sSection, L"lastcheckedrobots", origMonitorIni.GetValue(sSection, L"lastcheckedrobots", L"0"));
                    monitorIni.SetValue(sSection, L"lastHEAD", origMonitorIni.GetValue(sSection, L"lastHEAD", L"0"));
                    monitorIni.SetValue(sSection, L"UnreadItems", origMonitorIni.GetValue(sSection, L"UnreadItems", L"0"));
                    monitorIni.SetValue(sSection, L"unreadFirst", origMonitorIni.GetValue(sSection, L"unreadFirst", L"0"));
                    monitorIni.SetValue(sSection, L"WCPathOrUrl", origMonitorIni.GetValue(sSection, L"WCPathOrUrl", L""));
                }
                CString sValue = CString(iniFile.GetValue(L"ini_monitor", k, L""));
                if ((sKey.Compare(L"username") == 0) || (sKey.Compare(L"password") == 0))
                {
                    sValue = CStringUtils::Encrypt(sValue);
                }
                monitorIni.SetValue(sSection, sKey, sValue);
            }
            FILE * pFile = NULL;
            errno_t err = 0;
            int retrycount = 5;
            CString sTempfile = CTempFiles::Instance().GetTempFilePathString();
            do
            {
                err = _tfopen_s(&pFile, sTempfile, L"wb");
                if ((err == 0) && pFile)
                {
                    monitorIni.SaveFile(pFile);
                    err = fclose(pFile);
                }
                if (err)
                {
                    CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error saving %s, retrycount %d\n", (LPCWSTR)sTempfile, retrycount);
                    Sleep(500);
                }
            } while (err && retrycount--);
            if (err == 0)
            {
                if (!CopyFile(sTempfile, sDataFilePath, FALSE))
                    CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error copying %s to %s, Error %u\n", (LPCWSTR)sTempfile, (LPCWSTR)sDataFilePath, GetLastError());
                else
                {
                    // now send a message to a possible running monitor to force it
                    // to reload the ini file. Otherwise it would overwrite the ini
                    // file without using the synced data!
                    HWND hWnd = FindWindow(NULL, CString(MAKEINTRESOURCE(IDS_MONITOR_DLGTITLE)));
                    if (hWnd)
                    {
                        UINT TSVN_COMMITMONITOR_RELOADINI = RegisterWindowMessage(L"TSVNCommitMonitor_ReloadIni");
                        PostMessage(hWnd, TSVN_COMMITMONITOR_RELOADINI, 0, 0);
                    }
                }
            }
        }
        else
        {
            CSimpleIni::TNamesDepend mitems;
            if (PathFileExists(sDataFilePath))
            {
                int retrycount = 5;
                SI_Error err = SI_OK;
                do
                {
                    err = monitorIni.LoadFile(sDataFilePath);
                    if (err == SI_FILE)
                    {
                        CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error loading %s, retrycount %d\n", (LPCWSTR)sDataFilePath, retrycount);
                        Sleep(500);
                    }
                } while ((err == SI_FILE) && retrycount--);

                if (err == SI_FILE)
                {
                    return false;
                }
                monitorIni.GetAllSections(mitems);
            }

            for (const auto& mitem : mitems)
            {
                CString sSection = mitem;
                CString Name = monitorIni.GetValue(mitem, L"Name", L"");
                if (!Name.IsEmpty())
                {
                    CString newval = monitorIni.GetValue(mitem, L"WCPathOrUrl", L"");
                    iniFile.SetValue(L"ini_monitor", sSection + L".Name", Name);
                    CString oldval = iniFile.GetValue(L"ini_monitor", sSection + L".WCPathOrUrl", L"");
                    bHaveChanges |= ((newval != oldval) && (!oldval.IsEmpty()));
                    // only save monitored working copies if local settings are included, or
                    // if the monitored path is an url.
                    // Don't save paths to working copies for non-local stores
                    if (bWithLocals || newval.IsEmpty() || !PathIsDirectory(newval))
                        iniFile.SetValue(L"ini_monitor", sSection + L".WCPathOrUrl", newval);

                    newval = monitorIni.GetValue(mitem, L"interval", L"5");
                    oldval = iniFile.GetValue(L"ini_monitor", sSection + L".interval", L"0");
                    bHaveChanges |= newval != oldval;
                    iniFile.SetValue(L"ini_monitor", sSection + L".interval", newval);

                    newval = monitorIni.GetValue(mitem, L"minminutesinterval", L"0");
                    oldval = iniFile.GetValue(L"ini_monitor", sSection + L".minminutesinterval", L"0");
                    bHaveChanges |= newval != oldval;
                    iniFile.SetValue(L"ini_monitor", sSection + L".minminutesinterval", newval);

                    newval = CStringUtils::Decrypt(monitorIni.GetValue(mitem, L"username", L"")).get();
                    oldval = iniFile.GetValue(L"ini_monitor", sSection + L".username", L"");
                    bHaveChanges |= newval != oldval;
                    iniFile.SetValue(L"ini_monitor", sSection + L".username", newval);

                    newval = CStringUtils::Decrypt(monitorIni.GetValue(mitem, L"password", L"")).get();
                    oldval = iniFile.GetValue(L"ini_monitor", sSection + L".password", L"");
                    bHaveChanges |= newval != oldval;
                    iniFile.SetValue(L"ini_monitor", sSection + L".password", newval);

                    newval = monitorIni.GetValue(mitem, L"MsgRegex", L"");
                    oldval = iniFile.GetValue(L"ini_monitor", sSection + L".MsgRegex", L"");
                    bHaveChanges |= newval != oldval;
                    iniFile.SetValue(L"ini_monitor", sSection + L".MsgRegex", newval);

                    newval = monitorIni.GetValue(mitem, L"ignoreauthors", L"");
                    oldval = iniFile.GetValue(L"ini_monitor", sSection + L".ignoreauthors", L"");
                    bHaveChanges |= newval != oldval;
                    iniFile.SetValue(L"ini_monitor", sSection + L".ignoreauthors", newval);

                    newval = monitorIni.GetValue(mitem, L"parentTreePath", L"");
                    oldval = iniFile.GetValue(L"ini_monitor", sSection + L".parentTreePath", L"");
                    bHaveChanges |= newval != oldval;
                    iniFile.SetValue(L"ini_monitor", sSection + L".parentTreePath", newval);

                    newval = monitorIni.GetValue(mitem, L"uuid", L"");
                    oldval = iniFile.GetValue(L"ini_monitor", sSection + L".uuid", L"");
                    bHaveChanges |= newval != oldval;
                    iniFile.SetValue(L"ini_monitor", sSection + L".uuid", newval);

                    newval = monitorIni.GetValue(mitem, L"root", L"");
                    oldval = iniFile.GetValue(L"ini_monitor", sSection + L".root", L"");
                    bHaveChanges |= newval != oldval;
                    iniFile.SetValue(L"ini_monitor", sSection + L".root", newval);

                    ProjectProperties ProjProps;
                    ProjProps.LoadFromIni(monitorIni, sSection);
                    ProjProps.SaveToIni(iniFile, L"ini_monitor", sSection + L".pp_");
                }
                else if (sSection.CompareNoCase(L"global") == 0)
                {
                    CString newval = monitorIni.GetValue(mitem, L"PlaySound", L"1");
                    CString oldval = iniFile.GetValue(L"ini_monitor", sSection + L".PlaySound", L"1");
                    bHaveChanges |= newval != oldval;
                    iniFile.SetValue(L"ini_monitor", sSection + L".PlaySound", newval);

                    newval = monitorIni.GetValue(mitem, L"ShowNotifications", L"1");
                    oldval = iniFile.GetValue(L"ini_monitor", sSection + L".ShowNotifications", L"1");
                    bHaveChanges |= newval != oldval;
                    iniFile.SetValue(L"ini_monitor", sSection + L".ShowNotifications", newval);
                }
            }
        }
    }

    {
        // sync TortoiseMerge regex filters
        CSimpleIni regexIni;
        regexIni.SetMultiLine(true);
        CString sDataFilePath = CPathUtils::GetAppDataDirectory();
        sDataFilePath += L"\\regexfilters.ini";

        if (bCloudIsNewer)
        {
            CSimpleIni origRegexIni;

            if (PathFileExists(sDataFilePath))
            {
                int retrycount = 5;
                SI_Error err = SI_OK;
                do
                {
                    err = origRegexIni.LoadFile(sDataFilePath);
                    if (err == SI_FILE)
                    {
                        CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error loading %s, retrycount %d\n", (LPCWSTR)sDataFilePath, retrycount);
                        Sleep(500);
                    }
                } while ((err == SI_FILE) && retrycount--);

                if (err == SI_FILE)
                {
                    return false;
                }
            }

            CSimpleIni::TNamesDepend keys;
            iniFile.GetAllKeys(L"ini_tmergeregex", keys);
            for (const auto& k : keys)
            {
                CString sKey = k;
                CString sSection = sKey.Left(sKey.Find('.'));
                sKey = sKey.Mid(sKey.Find('.') + 1);
                CString sValue = CString(iniFile.GetValue(L"ini_tmergeregex", k, L""));
                regexIni.SetValue(sSection, sKey, sValue);
            }
            FILE * pFile = NULL;
            errno_t err = 0;
            int retrycount = 5;
            CString sTempfile = CTempFiles::Instance().GetTempFilePathString();
            do
            {
                err = _tfopen_s(&pFile, sTempfile, L"wb");
                if ((err == 0) && pFile)
                {
                    regexIni.SaveFile(pFile);
                    err = fclose(pFile);
                }
                if (err)
                {
                    CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error saving %s, retrycount %d\n", (LPCWSTR)sTempfile, retrycount);
                    Sleep(500);
                }
            } while (err && retrycount--);
            if (err == 0)
            {
                if (!CopyFile(sTempfile, sDataFilePath, FALSE))
                    CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error copying %s to %s, Error: %u\n", (LPCWSTR)sTempfile, (LPCWSTR)sDataFilePath, GetLastError());
            }
        }
        else
        {
            if (PathFileExists(sDataFilePath))
            {
                int retrycount = 5;
                SI_Error err = SI_OK;
                do
                {
                    err = regexIni.LoadFile(sDataFilePath);
                    if (err == SI_FILE)
                    {
                        CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error loading %s, retrycount %d\n", (LPCWSTR)sDataFilePath, retrycount);
                        Sleep(500);
                    }
                } while ((err == SI_FILE) && retrycount--);

                if (err == SI_FILE)
                {
                    return false;
                }
            }

            CSimpleIni::TNamesDepend mitems;
            regexIni.GetAllSections(mitems);
            for (const auto& mitem : mitems)
            {
                CString sSection = mitem;

                CString newval = regexIni.GetValue(mitem, L"regex", L"");
                CString oldval = iniFile.GetValue(L"ini_tmergeregex", sSection + L".regex", L"");
                bHaveChanges |= newval != oldval;
                iniFile.SetValue(L"ini_tmergeregex", sSection + L".regex", newval);

                newval = regexIni.GetValue(mitem, L"replace", L"5");
                oldval = iniFile.GetValue(L"ini_tmergeregex", sSection + L".replace", L"0");
                bHaveChanges |= newval != oldval;
                iniFile.SetValue(L"ini_tmergeregex", sSection + L".replace", newval);
            }
        }
    }


    if (bHaveChanges)
    {
        iniFile.SetValue(L"sync", L"version", TSVN_SYNC_VERSION_STR);
        DWORD count = regCount;
        ++count;
        regCount = count;
        CString tmp;
        tmp.Format(L"%lu", count);
        iniFile.SetValue(L"sync", L"synccounter", tmp);

        // save the ini file
        std::string iniData;
        iniFile.SaveString(iniData);
        iniData = "***" + iniData;
        // encrypt the string

        CString password;
        if (parser.HasKey(L"askforpath"))
        {
            CPasswordDlg passDlg(CWnd::FromHandle(GetExplorerHWND()));
            passDlg.m_bForSave = true;
            if (passDlg.DoModal() != IDOK)
                return false;
            password = passDlg.m_sPW1;
        }
        else
        {
            CRegString regPW(L"Software\\TortoiseSVN\\SyncPW");
            auto passwordbuf = CStringUtils::Decrypt(CString(regPW));
            if (passwordbuf.get())
            {
                password = passwordbuf.get();
            }
        }

        std::string passworda = CUnicodeUtils::StdGetUTF8((LPCWSTR)password);

        std::string encrypted = CStringUtils::Encrypt(iniData, passworda);
        CPathUtils::MakeSureDirectoryPathExists(syncPath.GetContainingDirectory().GetWinPathString());
        CString sTempfile = CTempFiles::Instance().GetTempFilePathString();
        CAutoFile hFile = CreateFile(sTempfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hFile.IsValid())
        {
            DWORD written = 0;
            if (WriteFile(hFile, encrypted.c_str(), DWORD(encrypted.size()), &written, NULL))
            {
                if (hFile.CloseHandle())
                {
                    if (!CopyFile(sTempfile, syncPath.GetWinPath(), FALSE))
                    {
                        CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error copying %s to %s, Error: %u\n", (LPCWSTR)sTempfile, syncPath.GetWinPath(), GetLastError());
                    }
                    else
                        bRet = true;
                }
                else
                    CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error closing file %s, Error: %u\n", (LPCWSTR)sTempfile, GetLastError());
            }
            else
                CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error writing to file %s, Error: %u\n", (LPCWSTR)sTempfile, GetLastError());
        }
        else
            CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error creating file %s for writing, Error: %u\n", (LPCWSTR)sTempfile, GetLastError());

        if (bSyncAuth)
        {
            // now save all auth data
            CPathUtils::MakeSureDirectoryPathExists(syncFolder.GetWinPathString() + L"\\auth");
            CPathUtils::MakeSureDirectoryPathExists(syncFolder.GetWinPathString() + L"\\auth\\svn.simple");
            CPathUtils::MakeSureDirectoryPathExists(syncFolder.GetWinPathString() + L"\\auth\\svn.ssl.client-passphrase");
            CPathUtils::MakeSureDirectoryPathExists(syncFolder.GetWinPathString() + L"\\auth\\svn.ssl.server");
            CPathUtils::MakeSureDirectoryPathExists(syncFolder.GetWinPathString() + L"\\auth\\svn.username");
            authData.ExportAuthData(syncFolder.GetWinPathString(), password);
        }
    }


    return bRet;
}