summaryrefslogtreecommitdiffstats
path: root/other-licenses/nsis/Contrib/WebBrowser/main.cpp
blob: e0589531ee96a0af5ac382b709b78af7387a7493 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0.If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include <windows.h>
#include "resource.h"
#include "WebBrowser.h"
#include "exdll.h"

// These variables are global because they're needed by more than one of
// our plugin methods. The expectation is that these are safe because the
// NSIS framework doesn't really support more than one dialog or thread
// at a time, and that means we don't have to either.

// Instance handle for this DLL
HINSTANCE gHInst = nullptr;
// Parent window proc which we'll need to override and then restore
WNDPROC gWndProcOld = nullptr;
// Handle to the dialog we'll create
HWND gHwnd = nullptr;
// Set to true when our dialog should be destroyed
bool gDone = false;
// Web browser OLE site
WebBrowser* gBrowser = nullptr;

// Set web browser control feature flags that are configured on a per-process
// basis, not for individual instances of the control. This mainly means
// disabling things that could turn into security holes.
static void ConfigurePerProcessBrowserFeatures() {
  // For most of the features we're configuring, setting them to TRUE means
  // we're disabling something, but for a few setting them to FALSE disables the
  // thing. We don't necessarily care about *every* feature that's in the
  // INTERNETFEATURELIST enum, but it seems safer to set them all anyway, to
  // make sure we don't miss anything we *do* care about.
  struct Feature {
    INTERNETFEATURELIST id;
    BOOL value;
  } features[] = {{FEATURE_OBJECT_CACHING, TRUE},
                  {FEATURE_ZONE_ELEVATION, TRUE},
                  {FEATURE_MIME_HANDLING, TRUE},
                  {FEATURE_MIME_SNIFFING, FALSE},
                  {FEATURE_WINDOW_RESTRICTIONS, TRUE},
                  {FEATURE_WEBOC_POPUPMANAGEMENT, TRUE},
                  {FEATURE_BEHAVIORS, TRUE},
                  {FEATURE_DISABLE_MK_PROTOCOL, TRUE},
                  // It isn't possible to set FEATURE_LOCALMACHINE_LOCKDOWN
                  // using the SET_FEATURE_ON_PROCESS mode; see the MSDN page
                  // on CoInternetSetFeatureEnabled for the explanation.
                  //{FEATURE_LOCALMACHINE_LOCKDOWN, TRUE},
                  {FEATURE_SECURITYBAND, FALSE},
                  {FEATURE_RESTRICT_ACTIVEXINSTALL, TRUE},
                  {FEATURE_VALIDATE_NAVIGATE_URL, TRUE},
                  {FEATURE_RESTRICT_FILEDOWNLOAD, TRUE},
                  {FEATURE_ADDON_MANAGEMENT, TRUE},
                  {FEATURE_PROTOCOL_LOCKDOWN, TRUE},
                  {FEATURE_HTTP_USERNAME_PASSWORD_DISABLE, TRUE},
                  {FEATURE_SAFE_BINDTOOBJECT, TRUE},
                  {FEATURE_UNC_SAVEDFILECHECK, TRUE},
                  {FEATURE_GET_URL_DOM_FILEPATH_UNENCODED, FALSE},
                  {FEATURE_TABBED_BROWSING, FALSE},
                  {FEATURE_SSLUX, FALSE},
                  {FEATURE_DISABLE_NAVIGATION_SOUNDS, TRUE},
                  {FEATURE_DISABLE_LEGACY_COMPRESSION, TRUE},
                  {FEATURE_FORCE_ADDR_AND_STATUS, FALSE},
                  {FEATURE_XMLHTTP, FALSE},
                  {FEATURE_DISABLE_TELNET_PROTOCOL, TRUE},
                  {FEATURE_FEEDS, FALSE},
                  {FEATURE_BLOCK_INPUT_PROMPTS, TRUE}};

  for (Feature feature : features) {
    CoInternetSetFeatureEnabled(feature.id, SET_FEATURE_ON_PROCESS,
                                feature.value);
  }
}

BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID) {
  if (reason == DLL_PROCESS_ATTACH) {
    gHInst = instance;
    (void)OleInitialize(nullptr);
    ConfigurePerProcessBrowserFeatures();
  }
  return TRUE;
}

UINT_PTR __cdecl NSISPluginCallback(NSPIM msg) {
  if (msg == NSPIM_UNLOAD) {
    OleUninitialize();
  }
  return 0;
}

BOOL CALLBACK ParentWndProc(HWND hwnd, UINT message, WPARAM wParam,
                            LPARAM lParam) {
  BOOL bRes =
      CallWindowProc((WNDPROC)gWndProcOld, hwnd, message, wParam, lParam);
  if (!bRes && message == WM_NOTIFY_OUTER_NEXT) {
    gDone = true;
    PostMessage(gHwnd, WM_CLOSE, 0, 0);
  }
  return bRes;
}

BOOL CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  return FALSE;
}

void Init(HWND hWndParent, int string_size, TCHAR* variables,
          stack_t** stacktop, extra_parameters* extra) {
  EXDLL_INIT();
  extra->RegisterPluginCallback(gHInst, NSISPluginCallback);

  HWND hwndChild = GetDlgItem(hWndParent, 1018);
  if (!hwndChild) {
    return;
  }

  HWND hwnd =
      CreateDialog(gHInst, MAKEINTRESOURCE(IDD_DIALOG1), hWndParent, DlgProc);
  if (!hwnd) {
    gDone = true;
  } else {
    gDone = false;
    gWndProcOld =
        (WNDPROC)SetWindowLong(hWndParent, DWL_DLGPROC, (LONG)ParentWndProc);

    // Tell NSIS to replace its inner dialog with ours.
    SendMessage(hWndParent, WM_NOTIFY_CUSTOM_READY, (WPARAM)hwnd, 0);

    // Initialize the browser control.
    if (gBrowser) {
      gBrowser->Shutdown();
      gBrowser->Release();
    }
    gBrowser = new WebBrowser(hwnd);

    if (!gBrowser || !gBrowser->IsInitialized()) {
      return;
    }

    gHwnd = hwnd;

    // Move our dialog to match the size of the parent.
    RECT r;
    GetClientRect(hwndChild, &r);
    MoveWindow(hwnd, r.left, r.top, r.right - r.left, r.bottom - r.top, FALSE);
    gBrowser->SetRect(r);
  }
}

PLUGINFUNCTION(ShowPage) {
  if (!gBrowser) {
    Init(hWndParent, string_size, variables, stacktop, extra);
  }

  if (!gBrowser->IsInitialized()) {
    return;
  }

  TCHAR* sUrl =
      (TCHAR*)HeapAlloc(GetProcessHeap(), 0, g_stringsize * sizeof(TCHAR));
  popstring(sUrl);

  if (gBrowser) {
    gBrowser->Navigate(sUrl);

    ShowWindow(gHwnd, SW_SHOWNA);
    UpdateWindow(gHwnd);

    while (!gDone) {
      // This explicit wait call is needed rather than just a blocking
      // GetMessage because we need this thread to be alertable so that our
      // timers can wake it up and run their callbacks.
      MsgWaitForMultipleObjectsEx(0, nullptr, 100, QS_ALLINPUT,
                                  MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
      MSG msg;
      if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
        bool tab = msg.message == WM_KEYDOWN && msg.wParam == VK_TAB;

        if (gBrowser->ActiveObjectTranslateAccelerator(tab, &msg) != S_OK &&
            !IsDialogMessage(gHwnd, &msg) &&
            !IsDialogMessage(g_hwndParent, &msg)) {
          TranslateMessage(&msg);
          DispatchMessage(&msg);
        }
      }
    }

    SetWindowLong(g_hwndParent, DWL_DLGPROC, (LONG)gWndProcOld);
    if (gHwnd) {
      DestroyWindow(gHwnd);
    }

    gBrowser->Shutdown();
    gBrowser->Release();
    gBrowser = nullptr;
  }

  HeapFree(GetProcessHeap(), 0, (char*)sUrl);
}