Skip to content

Commit

Permalink
[RAPPS] Fix SSL certificate pinning, allow HTTPS links, add URL args …
Browse files Browse the repository at this point in the history
…support, some UX fixes, comment improvements and fix stopping the download process when pressing cancel. By Ismael Ferreras Morezuelas. CORE-9060 CORE-10289

svn path=/trunk/; revision=69429
  • Loading branch information
AmineKhaldi committed Oct 3, 2015
1 parent a2871b3 commit 161dd35
Showing 1 changed file with 149 additions and 36 deletions.
185 changes: 149 additions & 36 deletions reactos/base/applications/rapps/loaddlg.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "rapps.h"
#include <wininet.h>
#include <shellapi.h>
#include <windowsx.h>

static PAPPLICATION_INFO AppInfo;

Expand All @@ -39,6 +40,7 @@ typedef struct _IBindStatusCallbackImpl
HWND hDialog;
BOOL *pbCancelled;
BOOL UrlHasBeenCopied;
WCHAR ProgressText[MAX_PATH];
} IBindStatusCallbackImpl;

static
Expand Down Expand Up @@ -117,7 +119,20 @@ dlOnProgress(IBindStatusCallback* iface,
Item = GetDlgItem(This->hDialog, IDC_DOWNLOAD_PROGRESS);
if (Item && ulProgressMax)
{
SendMessageW(Item, PBM_SETPOS, ((ULONGLONG)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, sizeof(szProgress));
StrFormatByteSizeW(ulProgressMax, szProgressMax, sizeof(szProgressMax));

/* ...and post all of it to our subclassed progress bar text subroutine */
swprintf(This->ProgressText, L"%u%% — %s / %s", uiPercentage, szProgress, szProgressMax);
SendMessageW(Item, WM_SETTEXT, 0, (LPARAM)This->ProgressText);
}

Item = GetDlgItem(This->hDialog, IDC_DOWNLOAD_STATUS);
Expand Down Expand Up @@ -227,35 +242,35 @@ static BOOL CertIsValid(HINTERNET hInternet, LPWSTR lpszHostName)
BOOL Ret = FALSE;
INTERNET_CERTIFICATE_INFOW certInfo;

hConnect = InternetConnectW(hInternet, lpszHostName, INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, INTERNET_FLAG_SECURE, 0);
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)
{
if (Ret)
{
certInfoLength = sizeof(INTERNET_CERTIFICATE_INFOW);
Ret = InternetQueryOptionW(hRequest,
INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT,
&certInfo,
&certInfoLength);
if (Ret)
{
if (certInfo.lpszEncryptionAlgName)
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)
if (certInfo.lpszProtocolName)
LocalFree(certInfo.lpszProtocolName);
if (certInfo.lpszSignatureAlgName)
if (certInfo.lpszSignatureAlgName)
LocalFree(certInfo.lpszSignatureAlgName);
if (certInfo.lpszSubjectInfo)
if (certInfo.lpszSubjectInfo)
{
if (strcmp((LPSTR)certInfo.lpszSubjectInfo, CERT_SUBJECT_INFO) != 0)
Ret = FALSE;
Expand All @@ -276,7 +291,7 @@ ThreadFunc(LPVOID Context)
{
IBindStatusCallback *dl = NULL;
WCHAR path[MAX_PATH];
LPWSTR p;
PWSTR p, q;
HWND Dlg = (HWND) Context;
DWORD dwContentLen, dwBytesWritten, dwBytesRead, dwStatus;
DWORD dwCurrentBytesRead = 0;
Expand All @@ -290,45 +305,58 @@ ThreadFunc(LPVOID Context)
unsigned char lpBuffer[4096];
const LPWSTR lpszAgent = L"RApps/1.0";
URL_COMPONENTS urlComponents;
size_t urlLength;
size_t urlLength, filenameLength;

/* built the path for the download */
/* 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;

/* download it */
/* create an async download context for it */
bTempfile = TRUE;
dl = CreateDl(Context, &bCancelled);

if (dl == NULL)
goto end;

/* FIXME: this should just be using the system-wide proxy settings */
switch(SettingsInfo.Proxy)
{
case 0: /* preconfig */
Expand All @@ -348,7 +376,7 @@ ThreadFunc(LPVOID Context)
if (!hOpen)
goto end;

hFile = InternetOpenUrlW(hOpen, AppInfo->szUrlDownload, NULL, 0, INTERNET_FLAG_PRAGMA_NOCACHE|INTERNET_FLAG_KEEP_CONNECTION, 0);
hFile = InternetOpenUrlW(hOpen, AppInfo->szUrlDownload, NULL, 0, INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_KEEP_CONNECTION, 0);
if (!hFile)
goto end;

Expand All @@ -373,30 +401,33 @@ ThreadFunc(LPVOID Context)

if(FAILED(StringCbLengthW(AppInfo->szUrlDownload, sizeof(AppInfo->szUrlDownload), &urlLength)))
goto end;

urlComponents.dwSchemeLength = urlLength*sizeof(WCHAR);
urlComponents.lpszScheme = malloc(urlComponents.dwSchemeLength);
urlComponents.dwHostNameLength = urlLength*sizeof(WCHAR);
urlComponents.lpszHostName = malloc(urlComponents.dwHostNameLength);

if(!InternetCrackUrlW(AppInfo->szUrlDownload, urlLength+1, ICU_DECODE | ICU_ESCAPE, &urlComponents))
goto end;

if(urlComponents.nScheme == INTERNET_SCHEME_HTTP || urlComponents.nScheme == INTERNET_SCHEME_HTTPS)
HttpQueryInfo(hFile, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &dwContentLen, &dwStatus, 0);

if(urlComponents.nScheme == INTERNET_SCHEME_FTP)
dwContentLen = FtpGetFileSize(hFile, &dwStatus);

#ifdef USE_CERT_PINNING
if ((urlComponents.nScheme == INTERNET_SCHEME_HTTPS) && (!CertIsValid(hOpen, urlComponents.lpszHostName)))
/* 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(hMainWnd, szMsgText, NULL, MB_OK | MB_ICONERROR);
MessageBoxW(Dlg, szMsgText, NULL, MB_OK | MB_ICONERROR);
goto end;
}
#endif
Expand All @@ -416,7 +447,7 @@ ThreadFunc(LPVOID Context)
dwCurrentBytesRead += dwBytesRead;
IBindStatusCallback_OnProgress(dl, dwCurrentBytesRead, dwContentLen, 0, AppInfo->szUrlDownload);
}
while (dwBytesRead);
while (dwBytesRead && !bCancelled);

CloseHandle(hOut);
hOut = INVALID_HANDLE_VALUE;
Expand Down Expand Up @@ -451,15 +482,88 @@ ThreadFunc(LPVOID Context)
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)
wcscpy(szProgressText, (WCHAR *)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, MAX_STR_LEN);
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:
{
Expand All @@ -478,16 +582,25 @@ DownloadDlgProc(HWND Dlg, UINT Msg, WPARAM wParam, LPARAM lParam)
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"• • •");

Thread = CreateThread(NULL, 0, ThreadFunc, Dlg, 0, &ThreadId);
if (!Thread) return FALSE;
if (!Thread)
return FALSE;

CloseHandle(Thread);
return TRUE;
}

case WM_COMMAND:
if (wParam == IDCANCEL)
{
Expand Down

0 comments on commit 161dd35

Please sign in to comment.