Skip to content

Commit

Permalink
fix: prevent print crash on bad deviceName (#21982)
Browse files Browse the repository at this point in the history
  • Loading branch information
trop[bot] committed Jan 31, 2020
1 parent 3b5ca91 commit 63bcbd4
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 3 deletions.
2 changes: 1 addition & 1 deletion docs/api/web-contents.md
Expand Up @@ -1259,7 +1259,7 @@ Returns [`PrinterInfo[]`](structures/printer-info.md)
* `silent` Boolean (optional) - Don't ask user for print settings. Default is `false`.
* `printBackground` Boolean (optional) - Prints the background color and image of
the web page. Default is `false`.
* `deviceName` String (optional) - Set the printer device name to use. Default is `''`.
* `deviceName` String (optional) - Set the printer device name to use. Must be the system-defined name and not the 'friendly' name, e.g 'Brother_QL_820NWB' and not 'Brother QL-820NWB'.
* `color` Boolean (optional) - Set whether the printed web page will be in color or grayscale. Default is `true`.
* `margins` Object (optional)
* `marginType` String (optional) - Can be `default`, `none`, `printableArea`, or `custom`. If `custom` is chosen, you will also need to specify `top`, `bottom`, `left`, and `right`.
Expand Down
28 changes: 28 additions & 0 deletions shell/browser/api/atom_api_web_contents.cc
Expand Up @@ -121,6 +121,10 @@
#if BUILDFLAG(ENABLE_PRINTING)
#include "chrome/browser/printing/print_view_manager_basic.h"
#include "components/printing/common/print_messages.h"

#if defined(OS_WIN)
#include "printing/backend/win_helper.h"
#endif
#endif

#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
Expand Down Expand Up @@ -350,6 +354,26 @@ base::Optional<base::TimeDelta> GetCursorBlinkInterval() {
return base::nullopt;
}

#if BUILDFLAG(ENABLE_PRINTING)
// This will return false if no printer with the provided device_name can be
// found on the network. We need to check this because Chromium does not do
// sanity checking of device_name validity and so will crash on invalid names.
bool IsDeviceNameValid(const base::string16& device_name) {
#if defined(OS_MACOSX)
base::ScopedCFTypeRef<CFStringRef> new_printer_id(
base::SysUTF16ToCFStringRef(device_name));
PMPrinter new_printer = PMPrinterCreateFromPrinterID(new_printer_id.get());
bool printer_exists = new_printer != nullptr;
PMRelease(new_printer);
return printer_exists;
#elif defined(OS_WIN)
printing::ScopedPrinterHandle printer;
return printer.OpenPrinterWithName(device_name.c_str());
#endif
return true;
}
#endif

} // namespace

WebContents::WebContents(v8::Isolate* isolate,
Expand Down Expand Up @@ -1772,6 +1796,10 @@ void WebContents::Print(mate::Arguments* args) {
// Printer device name as opened by the OS.
base::string16 device_name;
options.Get("deviceName", &device_name);
if (!device_name.empty() && !IsDeviceNameValid(device_name)) {
args->ThrowError("webContents.print(): Invalid deviceName provided.");
return;
}
settings.SetStringKey(printing::kSettingDeviceName, device_name);

int scale_factor = 100;
Expand Down
17 changes: 15 additions & 2 deletions spec-main/api-web-contents-spec.ts
Expand Up @@ -104,22 +104,35 @@ describe('webContents module', () => {
})

ifdescribe(features.isPrintingEnabled())('webContents.print()', () => {
let w: BrowserWindow

beforeEach(() => {
w = new BrowserWindow({ show: false })
})

afterEach(closeAllWindows)

it('throws when invalid settings are passed', () => {
const w = new BrowserWindow({ show: false })
expect(() => {
// @ts-ignore this line is intentionally incorrect
w.webContents.print(true)
}).to.throw('webContents.print(): Invalid print settings specified.')
})

it('throws when an invalid callback is passed', () => {
expect(() => {
// @ts-ignore this line is intentionally incorrect
w.webContents.print({}, true)
}).to.throw('webContents.print(): Invalid optional callback provided.')
})

ifit(process.platform !== 'linux')('throws when an invalid deviceName is passed', () => {
expect(() => {
w.webContents.print({ deviceName: 'i-am-a-nonexistent-printer' }, () => {})
}).to.throw('webContents.print(): Invalid deviceName provided.')
})

it('does not crash', () => {
const w = new BrowserWindow({ show: false })
expect(() => {
w.webContents.print({ silent: true })
}).to.not.throw()
Expand Down

0 comments on commit 63bcbd4

Please sign in to comment.