Author: zguo Date: Fri Mar 25 02:10:08 2016 New Revision: 71044
URL: http://svn.reactos.org/svn/reactos?rev=71044&view=rev Log: Additional rapps sync involving SSL certs. Porting done by Mark Jensen. Original code from Ismael Ferreras Morezuelas. CORE-10986
Modified: trunk/reactos/base/applications/rapps_new/CMakeLists.txt trunk/reactos/base/applications/rapps_new/loaddlg.cpp trunk/reactos/base/applications/rapps_new/rapps.h
Modified: trunk/reactos/base/applications/rapps_new/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/rapps_new... ============================================================================== --- trunk/reactos/base/applications/rapps_new/CMakeLists.txt [iso-8859-1] (original) +++ trunk/reactos/base/applications/rapps_new/CMakeLists.txt [iso-8859-1] Fri Mar 25 02:10:08 2016 @@ -18,6 +18,7 @@ winmain.cpp rapps.h)
+add_definitions(-DUSE_CERT_PINNING) file(GLOB_RECURSE rapps_new_rc_deps res/*.*) add_rc_deps(rapps.rc ${rapps_new_rc_deps}) add_executable(rapps_new ${SOURCE} rapps.rc)
Modified: trunk/reactos/base/applications/rapps_new/loaddlg.cpp URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/rapps_new... ============================================================================== --- trunk/reactos/base/applications/rapps_new/loaddlg.cpp [iso-8859-1] (original) +++ trunk/reactos/base/applications/rapps_new/loaddlg.cpp [iso-8859-1] Fri Mar 25 02:10:08 2016 @@ -6,6 +6,7 @@ * Copyright 2004 Mike McCormack (for CodeWeavers) * Copyright 2005 Ge van Geldorp (gvg@reactos.org) * Copyright 2009 Dmitry Chapyshev (dmitry@reactos.org) + * Copyright 2015 Ismael Ferreras Morezuelas (swyterzone+ros@gmail.com) */ /* * Based on Wine dlls/shdocvw/shdocvw_main.c @@ -34,6 +35,7 @@ #include <atlcom.h> #include <wininet.h> #include <shellutils.h> +#include <windowsx.h>
static PAPPLICATION_INFO AppInfo;
@@ -43,6 +45,9 @@ { HWND m_hDialog; PBOOL m_pbCancelled; + BOOL m_UrlHasBeenCopied; + WCHAR m_ProgressText[MAX_PATH]; +
public: ~CDownloadDialog() @@ -54,6 +59,7 @@ { m_hDialog = Dlg; m_pbCancelled = pbCancelled; + m_UrlHasBeenCopied = FALSE; return S_OK; }
@@ -84,21 +90,55 @@ { HWND Item; LONG r; - WCHAR OldText[100];
Item = GetDlgItem(m_hDialog, IDC_DOWNLOAD_PROGRESS); if (Item && ulProgressMax) { - SendMessageW(Item, PBM_SETPOS, MulDiv(ulProgress, 100, ulProgressMax), 0); + WCHAR szProgress[100]; + WCHAR szProgressMax[100]; + UINT uiPercentage = ((ULONGLONG)ulProgress * 100) / ulProgressMax; + + /* send the current progress to the progress bar */ + SendMessageW(Item, PBM_SETPOS, uiPercentage, 0); + + /* format the bits and bytes into pretty and accesible units... */ + StrFormatByteSizeW(ulProgress, szProgress, _countof(szProgress)); + StrFormatByteSizeW(ulProgressMax, szProgressMax, _countof(szProgressMax)); + + /* ...and post all of it to our subclassed progress bar text subroutine */ + StringCbPrintfW(m_ProgressText, + sizeof(m_ProgressText), + L"%u%% \x2014 %ls / %ls", + uiPercentage, + szProgress, + szProgressMax); + SendMessageW(Item, WM_SETTEXT, 0, (LPARAM)m_ProgressText); }
Item = GetDlgItem(m_hDialog, IDC_DOWNLOAD_STATUS); - if (Item && szStatusText) - { - SendMessageW(Item, WM_GETTEXT, sizeof(OldText) / sizeof(OldText[0]), (LPARAM) OldText); - if (sizeof(OldText) / sizeof(OldText[0]) - 1 <= wcslen(OldText) || 0 != wcscmp(OldText, szStatusText)) - { - SendMessageW(Item, WM_SETTEXT, 0, (LPARAM) szStatusText); + if (Item && szStatusText && wcslen(szStatusText) > 0 && m_UrlHasBeenCopied == FALSE) + { + DWORD len = wcslen(szStatusText) + 1; + PWSTR buf = (PWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR)); + + if (buf) + { + /* beautify our url for display purposes */ + InternetCanonicalizeUrl(szStatusText, buf, &len, ICU_DECODE | ICU_NO_ENCODE); + } + else + { + /* just use the original */ + buf = (PWSTR)szStatusText; + } + + /* paste it into our dialog and don't do it again in this instance */ + SendMessageW(Item, WM_SETTEXT, 0, (LPARAM)buf); + m_UrlHasBeenCopied = TRUE; + + if (buf != szStatusText) + { + HeapFree(GetProcessHeap(), 0, buf); } }
@@ -154,13 +194,67 @@ return ShellObjectCreatorInit<CDownloadDialog>(Dlg, pbCancelled, riid, ppv); }
+#ifdef USE_CERT_PINNING +static BOOL CertIsValid(HINTERNET hInternet, LPWSTR lpszHostName) +{ + HINTERNET hConnect; + HINTERNET hRequest; + DWORD certInfoLength; + BOOL Ret = FALSE; + INTERNET_CERTIFICATE_INFOW certInfo; + + hConnect = InternetConnectW(hInternet, lpszHostName, INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, INTERNET_FLAG_SECURE, 0); + if (hConnect) + { + hRequest = HttpOpenRequestW(hConnect, L"HEAD", NULL, NULL, NULL, NULL, INTERNET_FLAG_SECURE, 0); + if (hRequest != NULL) + { + Ret = HttpSendRequestW(hRequest, L"", 0, NULL, 0); + if (Ret) + { + certInfoLength = sizeof(INTERNET_CERTIFICATE_INFOW); + Ret = InternetQueryOptionW(hRequest, + INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT, + &certInfo, + &certInfoLength); + if (Ret) + { + if (certInfo.lpszEncryptionAlgName) + LocalFree(certInfo.lpszEncryptionAlgName); + if (certInfo.lpszIssuerInfo) + { + if (strcmp((LPSTR)certInfo.lpszIssuerInfo, CERT_ISSUER_INFO) != 0) + Ret = FALSE; + LocalFree(certInfo.lpszIssuerInfo); + } + if (certInfo.lpszProtocolName) + LocalFree(certInfo.lpszProtocolName); + if (certInfo.lpszSignatureAlgName) + LocalFree(certInfo.lpszSignatureAlgName); + if (certInfo.lpszSubjectInfo) + { + if (strcmp((LPSTR)certInfo.lpszSubjectInfo, CERT_SUBJECT_INFO) != 0) + Ret = FALSE; + LocalFree(certInfo.lpszSubjectInfo); + } + } + } + InternetCloseHandle(hRequest); + } + InternetCloseHandle(hConnect); + } + return Ret; +} +#endif + + static DWORD WINAPI ThreadFunc(LPVOID Context) { CComPtr<IBindStatusCallback> dl; WCHAR path[MAX_PATH]; - LPWSTR p; + PWSTR p, q; HWND Dlg = (HWND) Context; ULONG dwContentLen, dwBytesWritten, dwBytesRead, dwStatus; ULONG dwCurrentBytesRead = 0; @@ -174,36 +268,48 @@ unsigned char lpBuffer[4096]; PCWSTR lpszAgent = L"RApps/1.0"; URL_COMPONENTS urlComponents; - size_t urlLength; - - /* built the path for the download */ + size_t urlLength, filenameLength; + + /* build the path for the download */ p = wcsrchr(AppInfo->szUrlDownload, L'/'); - + q = wcsrchr(AppInfo->szUrlDownload, L'?'); + + /* do we have a final slash separator? */ if (!p) goto end;
- if (wcscmp(AppInfo->szUrlDownload, APPLICATION_DATABASE_URL) == 0) - { - bCab = TRUE; - if (!GetStorageDirectory(path, sizeof(path) / sizeof(path[0]))) - goto end; - } - else - { - if (FAILED(StringCbCopyW(path, sizeof(path), SettingsInfo.szDownloadDir))) - goto end; - } - - + /* prepare the tentative length of the filename, maybe we've to remove part of it later on */ + filenameLength = wcslen(p) * sizeof(WCHAR); + + /* do we have query arguments in the target URL after the filename? account for them + (e.g. https://example.org/myfile.exe?no_adware_plz) */ + if (q && q > p && (q - p) > 0) + filenameLength -= wcslen(q - 1) * sizeof(WCHAR); + + /* is this URL an update package for RAPPS? if so store it in a different place */ + if (wcscmp(AppInfo->szUrlDownload, APPLICATION_DATABASE_URL) == 0) + { + bCab = TRUE; + if (!GetStorageDirectory(path, _countof(path))) + goto end; + } + else + { + if (FAILED(StringCbCopyW(path, sizeof(path), SettingsInfo.szDownloadDir))) + goto end; + } + + /* is the path valid? can we access it? */ if (GetFileAttributesW(path) == INVALID_FILE_ATTRIBUTES) { if (!CreateDirectoryW(path, NULL)) goto end; }
+ /* append a \ to the provided file system path, and the filename portion from the URL after that */ if (FAILED(StringCbCatW(path, sizeof(path), L"\"))) goto end; - if (FAILED(StringCbCatW(path, sizeof(path), p + 1))) + if (FAILED(StringCbCatNW(path, sizeof(path), p + 1, filenameLength))) goto end;
if (!bCab && AppInfo->szSHA1[0] != 0 && GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES) @@ -220,6 +326,7 @@ if (dl == NULL) goto end;
+ /* FIXME: this should just be using the system-wide proxy settings */ switch(SettingsInfo.Proxy) { case 0: /* preconfig */ @@ -264,10 +371,13 @@
if(FAILED(StringCbLengthW(AppInfo->szUrlDownload, sizeof(AppInfo->szUrlDownload), &urlLength))) goto end; - - urlComponents.dwSchemeLength = urlLength*sizeof(WCHAR); - urlComponents.lpszScheme = (PWSTR)malloc(urlComponents.dwSchemeLength); - + + urlLength /= sizeof(WCHAR); + urlComponents.dwSchemeLength = urlLength + 1; + urlComponents.lpszScheme = (LPWSTR)malloc(urlComponents.dwSchemeLength * sizeof(WCHAR)); + urlComponents.dwHostNameLength = urlLength + 1; + urlComponents.lpszHostName = (LPWSTR)malloc(urlComponents.dwHostNameLength * sizeof(WCHAR)); + if(!InternetCrackUrlW(AppInfo->szUrlDownload, urlLength+1, ICU_DECODE | ICU_ESCAPE, &urlComponents)) goto end;
@@ -277,7 +387,24 @@ if(urlComponents.nScheme == INTERNET_SCHEME_FTP) dwContentLen = FtpGetFileSize(hFile, &dwStatus);
+#ifdef USE_CERT_PINNING + /* are we using HTTPS to download the RAPPS update package? check if the certificate is original */ + if ((urlComponents.nScheme == INTERNET_SCHEME_HTTPS) && + (wcscmp(AppInfo->szUrlDownload, APPLICATION_DATABASE_URL) == 0) && + (!CertIsValid(hOpen, urlComponents.lpszHostName))) + { + WCHAR szMsgText[MAX_STR_LEN]; + + if (!LoadStringW(hInst, IDS_CERT_DOES_NOT_MATCH, szMsgText, sizeof(szMsgText) / sizeof(WCHAR))) + goto end; + + MessageBoxW(Dlg, szMsgText, NULL, MB_OK | MB_ICONERROR); + goto end; + } +#endif + free(urlComponents.lpszScheme); + free(urlComponents.lpszHostName);
hOut = CreateFileW(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
@@ -291,7 +418,7 @@ dwCurrentBytesRead += dwBytesRead; dl->OnProgress(dwCurrentBytesRead, dwContentLen, 0, AppInfo->szUrlDownload); } - while (dwBytesRead); + while (dwBytesRead && !bCancelled);
CloseHandle(hOut); hOut = INVALID_HANDLE_VALUE; @@ -347,15 +474,92 @@ return 0; }
+ +LRESULT CALLBACK +DownloadProgressProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) +{ + static WCHAR szProgressText[MAX_STR_LEN] = {0}; + + switch (uMsg) + { + case WM_SETTEXT: + { + if (lParam) + { + StringCbCopyW(szProgressText, + sizeof(szProgressText), + (PCWSTR)lParam); + } + } + + case WM_ERASEBKGND: + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hDC = BeginPaint(hWnd, &ps), hdcMem; + HBITMAP hbmMem; + HANDLE hOld; + RECT myRect; + UINT win_width, win_height; + + GetClientRect(hWnd, &myRect); + + /* grab the progress bar rect size */ + win_width = myRect.right - myRect.left; + win_height = myRect.bottom - myRect.top; + + /* create an off-screen DC for double-buffering */ + hdcMem = CreateCompatibleDC(hDC); + hbmMem = CreateCompatibleBitmap(hDC, win_width, win_height); + + hOld = SelectObject(hdcMem, hbmMem); + + /* call the original draw code and redirect it to our memory buffer */ + DefSubclassProc(hWnd, uMsg, (WPARAM)hdcMem, lParam); + + /* draw our nifty progress text over it */ + SelectFont(hdcMem, GetStockFont(DEFAULT_GUI_FONT)); + DrawShadowText(hdcMem, szProgressText, wcslen(szProgressText), + &myRect, + DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE, + GetSysColor(COLOR_CAPTIONTEXT), + GetSysColor(COLOR_3DSHADOW), + 1, 1); + + /* transfer the off-screen DC to the screen */ + BitBlt(hDC, 0, 0, win_width, win_height, hdcMem, 0, 0, SRCCOPY); + + /* free the off-screen DC */ + SelectObject(hdcMem, hOld); + DeleteObject(hbmMem); + DeleteDC(hdcMem); + + EndPaint(hWnd, &ps); + return 0; + } + + /* Raymond Chen says that we should safely unsubclass all the things! + (http://blogs.msdn.com/b/oldnewthing/archive/2003/11/11/55653.aspx) */ + case WM_NCDESTROY: + { + ZeroMemory(szProgressText, sizeof(szProgressText)); + RemoveWindowSubclass(hWnd, DownloadProgressProc, uIdSubclass); + } + + default: + return DefSubclassProc(hWnd, uMsg, wParam, lParam); + } +} + static INT_PTR CALLBACK -DownloadDlgProc(HWND Dlg, UINT Msg, WPARAM wParam, LPARAM lParam) +DownloadDlgProc(HWND Dlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { HANDLE Thread; DWORD ThreadId; HWND Item;
- switch (Msg) + switch (uMsg) { case WM_INITDIALOG: { @@ -374,12 +578,21 @@ Item = GetDlgItem(Dlg, IDC_DOWNLOAD_PROGRESS); if (Item) { + /* initialize the default values for our nifty progress bar + and subclass it so that it learns to print a status text */ SendMessageW(Item, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); SendMessageW(Item, PBM_SETPOS, 0, 0); - } + + SetWindowSubclass(Item, DownloadProgressProc, 0, 0); + } + + /* add a neat placeholder until the download URL is retrieved */ + Item = GetDlgItem(Dlg, IDC_DOWNLOAD_STATUS); + SendMessageW(Item, WM_SETTEXT, 0, (LPARAM)L"\x2022 \x2022 \x2022");
Thread = CreateThread(NULL, 0, ThreadFunc, Dlg, 0, &ThreadId); - if (!Thread) return FALSE; + if (!Thread) + return FALSE; CloseHandle(Thread); return TRUE; }
Modified: trunk/reactos/base/applications/rapps_new/rapps.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/rapps_new... ============================================================================== --- trunk/reactos/base/applications/rapps_new/rapps.h [iso-8859-1] (original) +++ trunk/reactos/base/applications/rapps_new/rapps.h [iso-8859-1] Fri Mar 25 02:10:08 2016 @@ -28,8 +28,12 @@
#include "resource.h"
-/* FIXME: this should be downloaded by HTTPS once is supported */ -#define APPLICATION_DATABASE_URL L"http://svn.reactos.org/packages/rappmgr.cab" +#ifdef USE_CERT_PINNING + #define CERT_ISSUER_INFO "BE\r\nGlobalSign nv-sa\r\nGlobalSign Domain Validation CA - SHA256 - G2" + #define CERT_SUBJECT_INFO "Domain Control Validated\r\n*.reactos.org" +#endif + +#define APPLICATION_DATABASE_URL L"https://svn.reactos.org/packages/rappmgr.cab"
#define SPLIT_WIDTH 4 #define MAX_STR_LEN 256