Skip to content

Commit

Permalink
Allow local PDF files to be viewed in local frames
Browse files Browse the repository at this point in the history
The Chrome extension enforces that local files cannot be embedded in
non-local web pages. The previous check was too strict (because the
origin of a file:-URL is "null"), and prevented local PDF from being
viewed in local files).

This patch fixes that problem, by querying the actual tab URL via the
background page.

Steps to verify:
1. Create a HTML file: `<iframe src=test.pdf width=100% height=100%>`
2. Build and load the extension.
3. Allow file access to the extension at `chrome://extensions`
4. Open the HTML file from a file:// URL.
5. VERIFY: The extension should attempt to load the PDF file.

6. Now open the following (replace ID with the extension ID, which you
   can find at `chrome://extensions`):
  `data:text/html,<iframe src="chrome-extension://ID/file:///test.pdf">`
7. VERIFY: The next error should be displayed:
   "Refused to load a local file in a non-local page for security reasons."
  • Loading branch information
Rob--W committed Jan 30, 2016
1 parent 5d797e1 commit 096e571
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 11 deletions.
26 changes: 26 additions & 0 deletions extensions/chromium/pdfHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,32 @@ chrome.extension.isAllowedFileSchemeAccess(function(isAllowedAccess) {
});

chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if (message && message.action === 'getParentOrigin') {
// getParentOrigin is used to determine whether it is safe to embed a
// sensitive (local) file in a frame.
if (!sender.tab) {
sendResponse('');
return false;
}
// TODO: This should be the URL of the parent frame, not the tab. But
// chrome-extension:-URLs are not visible in the webNavigation API
// (https://crbug.com/326768, so the next best thing is using the tab's URL
// for making security decisions.
var parentUrl = sender.tab.url;
if (!parentUrl) {
sendResponse('');
return;
}
if (parentUrl.lastIndexOf('file:', 0) === 0) {
sendResponse('file://');
return;
}
// The regexp should always match for valid URLs, but in case it doesn't,
// just give the full URL (e.g. data URLs).
var origin = /^[^:]+:\/\/[^/]+/.exec(parentUrl);
sendResponse(origin ? origin[1] : parentUrl);
return true;
}
if (message && message.action === 'isAllowedFileSchemeAccess') {
chrome.extension.isAllowedFileSchemeAccess(sendResponse);
return true;
Expand Down
43 changes: 32 additions & 11 deletions web/chromecom.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,25 +113,46 @@ var ChromeCom = (function ChromeComClosure() {
return;
}
if (/^file?:/.test(file)) {
if (top !== window && !/^file:/i.test(location.ancestorOrigins[0])) {
PDFViewerApplication.error('Blocked ' + location.ancestorOrigins[0] +
' from loading ' + file + '. Refused to load a local file in a ' +
' non-local page for security reasons.');
return;
}
isAllowedFileSchemeAccess(function(isAllowedAccess) {
if (isAllowedAccess) {
PDFViewerApplication.open(file);
} else {
requestAccessToLocalFile(file);
getEmbedderOrigin(function(origin) {
// If the origin cannot be determined, let Chrome decide whether to
// allow embedding files. Otherwise, only allow local files to be
// embedded from local files or Chrome extensions.
// Even without this check, the file load in frames is still blocked,
// but this may change in the future (https://crbug.com/550151).
if (origin && !/^file:|^chrome-extension:/.test(origin)) {
PDFViewerApplication.error('Blocked ' + origin + ' from loading ' +
file + '. Refused to load a local file in a non-local page ' +
'for security reasons.');
return;
}
isAllowedFileSchemeAccess(function(isAllowedAccess) {
if (isAllowedAccess) {
PDFViewerApplication.open(file);
} else {
requestAccessToLocalFile(file);
}
});
});
return;
}
PDFViewerApplication.open(file);
});
};

function getEmbedderOrigin(callback) {
var origin = window === top ? location.origin : location.ancestorOrigins[0];
if (origin === 'null') {
// file:-URLs, data-URLs, sandboxed frames, etc.
getParentOrigin(callback);
} else {
callback(origin);
}
}

function getParentOrigin(callback) {
ChromeCom.request('getParentOrigin', null, callback);
}

function isAllowedFileSchemeAccess(callback) {
ChromeCom.request('isAllowedFileSchemeAccess', null, callback);
}
Expand Down

0 comments on commit 096e571

Please sign in to comment.