فهرست منبع

add option "block mixed content" (see #804)

Gildas 4 سال پیش
والد
کامیت
fc8e0582a6

+ 4 - 0
_locales/de/messages.json

@@ -159,6 +159,10 @@
 		"message": "Muster für Inhalt des Infoknopfs",
 		"description": "Options page label: 'template of the infobar content'"
 	},
+	"optionBlockMixedContent": {
+		"message": "Blockieren gemischter Inhalte",
+		"description": "Options page label: 'block mixed content'"
+	},
 	"optionIncludeInfobar": {
 		"message": "Einfügen Inhalt des Infoknopfs in die gespeicherte Seite",
 		"description": "Options page label: 'include the infobar in the saved page'"

+ 4 - 0
_locales/en/messages.json

@@ -159,6 +159,10 @@
 		"message": "template of the infobar content",
 		"description": "Options page label: 'template of the infobar content'"
 	},
+	"optionBlockMixedContent": {
+		"message": "block mixed content",
+		"description": "Options page label: 'block mixed content'"
+	},	
 	"optionIncludeInfobar": {
 		"message": "include the infobar in the saved page",
 		"description": "Options page label: 'include the infobar in the saved page'"

+ 4 - 0
_locales/es/messages.json

@@ -159,6 +159,10 @@
 		"message": "plantilla del contenido de la barra informativa",
 		"description": "Options page label: 'template of the infobar content'"
 	},
+	"optionBlockMixedContent": {
+		"message": "bloqueo de contenido mixto",
+		"description": "Options page label: 'block mixed content'"
+	},
 	"optionIncludeInfobar": {
 		"message": "incluir la barra informativa en la página guardada",
 		"description": "Options page label: 'include the infobar in the saved page'"

+ 4 - 0
_locales/fr/messages.json

@@ -159,6 +159,10 @@
 		"message": "modèle du contenu de la barre d'information",
 		"description": "Options page label: 'template of the infobar content'"
 	},
+	"optionBlockMixedContent": {
+		"message": "bloquer les contenus mixtes",
+		"description": "Options page label: 'block mixed content'"
+	},
 	"optionIncludeInfobar": {
 		"message": "inclure la barre d'information dans la page sauvegardée",
 		"description": "Options page label: 'include the infobar in the saved page'"

+ 4 - 0
_locales/it/messages.json

@@ -159,6 +159,10 @@
 		"message": "Modello del contenuto della barra informativa",
 		"description": "Options page label: 'template of the infobar content'"
 	},
+	"optionBlockMixedContent": {
+		"message": "block mixed content",
+		"description": "Options page label: 'block mixed content'"
+	},
 	"optionIncludeInfobar": {
 		"message": "includi una barra informativa nella pagina salvata",
 		"description": "Options page label: 'include the infobar in the saved page'"

+ 4 - 0
_locales/ja/messages.json

@@ -159,6 +159,10 @@
 		"message": "infobar コンテンツのテンプレート",
 		"description": "Options page label: 'template of the infobar content'"
 	},
+	"optionBlockMixedContent": {
+		"message": "block mixed content",
+		"description": "Options page label: 'block mixed content'"
+	},
 	"optionIncludeInfobar": {
 		"message": "保存されたページに、infobar を含める",
 		"description": "Options page label: 'include the infobar in the saved page'"

+ 4 - 0
_locales/pl/messages.json

@@ -159,6 +159,10 @@
 		"message": "szablon zawartości paska informacyjnego",
 		"description": "Options page label: 'template of the infobar content'"
 	},
+	"optionBlockMixedContent": {
+		"message": "block mixed content",
+		"description": "Options page label: 'block mixed content'"
+	},
 	"optionIncludeInfobar": {
 		"message": "dołączaj pasek informacyjny do zapisanej strony",
 		"description": "Options page label: 'include the infobar in the saved page'"

+ 4 - 0
_locales/ru/messages.json

@@ -159,6 +159,10 @@
 		"message": "шаблон содержимого информационной панели",
 		"description": "Options page label: 'template of the infobar content'"
 	},
+	"optionBlockMixedContent": {
+		"message": "block mixed content",
+		"description": "Options page label: 'block mixed content'"
+	},
 	"optionIncludeInfobar": {
 		"message": "добавить информационную панель в сохраняемую страницу",
 		"description": "Options page label: 'include the infobar in the saved page'"

+ 4 - 0
_locales/uk/messages.json

@@ -159,6 +159,10 @@
 		"message": "шаблон вмісту інформаційної панелі ",
 		"description": "Options page label: 'template of the infobar content'"
 	},
+	"optionBlockMixedContent": {
+		"message": "block mixed content",
+		"description": "Options page label: 'block mixed content'"
+	},
 	"optionIncludeInfobar": {
 		"message": "додавати інформ. панель в сторінку що зберігається",
 		"description": "Options page label: 'include the infobar in the saved page'"

+ 4 - 0
_locales/zh_CN/messages.json

@@ -159,6 +159,10 @@
 		"message": "信息栏内容模板",
 		"description": "Options page label: 'template of the infobar content'"
 	},
+	"optionBlockMixedContent": {
+		"message": "block mixed content",
+		"description": "Options page label: 'block mixed content'"
+	},
 	"optionIncludeInfobar": {
 		"message": "在已保存页面中将信息栏包括在内",
 		"description": "Options page label: 'include the infobar in the saved page'"

+ 4 - 0
_locales/zh_TW/messages.json

@@ -159,6 +159,10 @@
 		"message": "信息欄內容模板",
 		"description": "Options page label: 'template of the infobar content'"
 	},
+	"optionBlockMixedContent": {
+		"message": "block mixed content",
+		"description": "Options page label: 'block mixed content'"
+	},
 	"optionIncludeInfobar": {
 		"message": "在已保存頁面中將信息欄包括在內",
 		"description": "Options page label: 'include the infobar in the saved page'"

+ 1 - 0
extension/core/bg/config.js

@@ -112,6 +112,7 @@ const DEFAULT_CONFIG = {
 	insertMetaCSP: true,
 	passReferrerOnError: false,
 	insertSingleFileComment: true,
+	blockMixedContent: false,
 	woleetKey: ""
 };
 

+ 5 - 0
extension/ui/bg/ui-options.js

@@ -113,6 +113,7 @@ const defaultEditorModeLabel = document.getElementById("defaultEditorModeLabel")
 const applySystemThemeLabel = document.getElementById("applySystemThemeLabel");
 const warnUnsavedPageLabel = document.getElementById("warnUnsavedPageLabel");
 const infobarTemplateLabel = document.getElementById("infobarTemplateLabel");
+const blockMixedContentLabel = document.getElementById("blockMixedContentLabel");
 const includeInfobarLabel = document.getElementById("includeInfobarLabel");
 const miscLabel = document.getElementById("miscLabel");
 const helpLabel = document.getElementById("helpLabel");
@@ -181,6 +182,7 @@ const allowedBookmarkFoldersInput = document.getElementById("allowedBookmarkFold
 const ignoredBookmarkFoldersInput = document.getElementById("ignoredBookmarkFoldersInput");
 const groupDuplicateImagesInput = document.getElementById("groupDuplicateImagesInput");
 const infobarTemplateInput = document.getElementById("infobarTemplateInput");
+const blockMixedContentInput = document.getElementById("blockMixedContentInput");
 const includeInfobarInput = document.getElementById("includeInfobarInput");
 const confirmInfobarInput = document.getElementById("confirmInfobarInput");
 const autoCloseInput = document.getElementById("autoCloseInput");
@@ -543,6 +545,7 @@ autoSaveLabel.textContent = browser.i18n.getMessage("optionsAutoSaveSubTitle");
 miscLabel.textContent = browser.i18n.getMessage("optionsMiscSubTitle");
 helpLabel.textContent = browser.i18n.getMessage("optionsHelpLink");
 infobarTemplateLabel.textContent = browser.i18n.getMessage("optionInfobarTemplate");
+blockMixedContentLabel.textContent = browser.i18n.getMessage("optionBlockMixedContent");
 includeInfobarLabel.textContent = browser.i18n.getMessage("optionIncludeInfobar");
 confirmInfobarLabel.textContent = browser.i18n.getMessage("optionConfirmInfobar");
 autoCloseLabel.textContent = browser.i18n.getMessage("optionAutoClose");
@@ -752,6 +755,7 @@ async function refresh(profileName) {
 	ignoredBookmarkFoldersInput.value = profileOptions.ignoredBookmarkFolders.map(folder => folder.replace(/,/g, "\\,")).join(","); // eslint-disable-line no-useless-escape
 	ignoredBookmarkFoldersInput.disabled = !profileOptions.saveCreatedBookmarks;
 	infobarTemplateInput.value = profileOptions.infobarTemplate;
+	blockMixedContentInput.checked = profileOptions.blockMixedContent;
 	includeInfobarInput.checked = profileOptions.includeInfobar;
 	confirmInfobarInput.checked = profileOptions.confirmInfobarContent;
 	autoCloseInput.checked = profileOptions.autoClose;
@@ -832,6 +836,7 @@ async function update() {
 			ignoredBookmarkFolders: ignoredBookmarkFoldersInput.value.replace(/([^\\]),/g, "$1 ,").split(/[^\\],/).map(folder => folder.replace(/\\,/g, ",")),
 			groupDuplicateImages: groupDuplicateImagesInput.checked,
 			infobarTemplate: infobarTemplateInput.value,
+			blockMixedContent: blockMixedContentInput.checked,
 			includeInfobar: includeInfobarInput.checked,
 			confirmInfobarContent: confirmInfobarInput.checked,
 			autoClose: autoCloseInput.checked,

+ 7 - 0
extension/ui/pages/help.html

@@ -219,6 +219,13 @@
 							considerably reduce the size of the file without altering the document most of the time. It
 							may also decrease the time needed to save a page.</p>
 					</li>
+					<li data-options-label="blockMixedContentLabel"> <span class="option"></span>Option: block mixed
+						contents</span>
+						<p>Check this option to block active content served from HTTP when viewing a page in HTTPS. You
+							can find more information about mixed content pages <a
+								href="https://developer.mozilla.org/docs/Web/Security/Mixed_content"
+								target="_blank">here</a>.</p>
+					</li>
 					<li data-options-label="includeInfobarLabel"> <span class="option"></span>Option: include infobar in
 						the saved page</span>
 						<p>Check this

+ 4 - 0
extension/ui/pages/options.html

@@ -102,6 +102,10 @@
 				<label for="removeFramesInput" id="removeFramesLabel"></label>
 				<input type="checkbox" id="removeFramesInput">
 			</div>
+			<div class="option">
+				<label for="blockMixedContentInput" id="blockMixedContentLabel"></label>
+				<input type="checkbox" id="blockMixedContentInput">
+			</div>
 			<div class="option">
 				<label for="includeInfobarInput" id="includeInfobarLabel"></label>
 				<input type="checkbox" id="includeInfobarInput">

+ 27 - 13
lib/single-file/single-file-core.js

@@ -316,9 +316,9 @@ class BatchRequest {
 		this.duplicates = new Map();
 	}
 
-	addURL(resourceURL, asBinary, expectedType, groupDuplicates) {
+	addURL(resourceURL, { asBinary, expectedType, groupDuplicates, baseURI, blockMixedContent }) {
 		return new Promise((resolve, reject) => {
-			const requestKey = JSON.stringify([resourceURL, asBinary, expectedType]);
+			const requestKey = JSON.stringify([resourceURL, asBinary, expectedType, baseURI, blockMixedContent]);
 			let resourceRequests = this.requests.get(requestKey);
 			if (!resourceRequests) {
 				resourceRequests = [];
@@ -345,7 +345,7 @@ class BatchRequest {
 		const resourceURLs = [...this.requests.keys()];
 		let indexResource = 0;
 		return Promise.all(resourceURLs.map(async requestKey => {
-			const [resourceURL, asBinary, expectedType] = JSON.parse(requestKey);
+			const [resourceURL, asBinary, expectedType, baseURI, blockMixedContent] = JSON.parse(requestKey);
 			const resourceRequests = this.requests.get(requestKey);
 			try {
 				const currentIndexResource = indexResource;
@@ -356,7 +356,9 @@ class BatchRequest {
 					maxResourceSize: options.maxResourceSize,
 					maxResourceSizeEnabled: options.maxResourceSizeEnabled,
 					frameId: options.windowId,
-					resourceReferrer: options.resourceReferrer
+					resourceReferrer: options.resourceReferrer,
+					baseURI,
+					blockMixedContent
 				});
 				onloadListener({ url: resourceURL });
 				if (!this.cancelled) {
@@ -930,7 +932,8 @@ class Processor {
 				updatedResources: this.options.updatedResources,
 				rootDocument: this.options.rootDocument,
 				frameId: this.options.windowId,
-				resourceReferrer: this.options.resourceReferrer
+				resourceReferrer: this.options.resourceReferrer,
+				blockMixedContent: this.options.blockMixedContent
 			};
 			let mediaText;
 			if (element.media) {
@@ -1225,7 +1228,9 @@ class Processor {
 					maxResourceSize: this.options.maxResourceSize,
 					maxResourceSizeEnabled: this.options.maxResourceSizeEnabled,
 					frameId: this.options.windowId,
-					resourceReferrer: this.options.resourceReferrer
+					resourceReferrer: this.options.resourceReferrer,
+					baseURI: this.options.baseURI,
+					blockMixedContent: this.options.blockMixedContent
 				});
 				content.data = getUpdatedResourceContent(resourceURL, content, this.options);
 				if (element.tagName == "SCRIPT") {
@@ -1637,7 +1642,9 @@ class ProcessorHelper {
 				validateTextContentType: true,
 				frameId: options.frameId,
 				charset: options.charset,
-				resourceReferrer: options.resourceReferrer
+				resourceReferrer: options.resourceReferrer,
+				baseURI: options.baseURI,
+				blockMixedContent: options.blockMixedContent
 			});
 			if (!matchCharsetEquals(content.data, content.charset || options.charset)) {
 				options = Object.assign({}, options, { charset: getCharset(content.data) });
@@ -1647,7 +1654,9 @@ class ProcessorHelper {
 					validateTextContentType: true,
 					frameId: options.frameId,
 					charset: options.charset,
-					resourceReferrer: options.resourceReferrer
+					resourceReferrer: options.resourceReferrer,
+					baseURI: options.baseURI,
+					blockMixedContent: options.blockMixedContent
 				});
 			} else {
 				return content;
@@ -1704,7 +1713,9 @@ class ProcessorHelper {
 				charset: options.charset,
 				frameId: options.frameId,
 				resourceReferrer: options.resourceReferrer,
-				validateTextContentType: true
+				validateTextContentType: true,
+				baseURI: baseURI,
+				blockMixedContent: options.blockMixedContent
 			});
 			if (!matchCharsetEquals(content.data, content.charset || options.charset)) {
 				options = Object.assign({}, options, { charset: getCharset(content.data) });
@@ -1753,7 +1764,8 @@ class ProcessorHelper {
 						const resourceURL = normalizeURL(originalResourceURL);
 						if (!testIgnoredPath(resourceURL)) {
 							if (testValidURL(resourceURL)) {
-								let { content } = await batchRequest.addURL(resourceURL, true, "font");
+								let { content } = await batchRequest.addURL(resourceURL,
+									{ asBinary: true, expectedType: "font", baseURI, blockMixedContent: options.blockMixedContent });
 								let resourceURLs = fontURLs.get(declaration);
 								if (!resourceURLs) {
 									resourceURLs = [];
@@ -1793,7 +1805,8 @@ class ProcessorHelper {
 					const resourceURL = normalizeURL(originalResourceURL);
 					if (!testIgnoredPath(resourceURL)) {
 						if (testValidURL(resourceURL)) {
-							let { content, indexResource, duplicate } = await batchRequest.addURL(resourceURL, true, "image", true);
+							let { content, indexResource, duplicate } = await batchRequest.addURL(resourceURL,
+								{ asBinary: true, expectedType: "image", groupDuplicates: options.groupDuplicateImages });
 							let variableDefined;
 							const tokens = [];
 							findURLToken(originalResourceURL, declaration.value.children, (token, parent, rootFunction) => {
@@ -1845,7 +1858,8 @@ class ProcessorHelper {
 							// ignored
 						}
 						if (testValidURL(resourceURL)) {
-							let { content, indexResource, duplicate } = await batchRequest.addURL(resourceURL, true, "image", resourceElement.tagName == "IMG" && attributeName == "src");
+							let { content, indexResource, duplicate } = await batchRequest.addURL(resourceURL,
+								{ asBinary: true, expectedType: "image", groupDuplicates: options.groupDuplicateImages && resourceElement.tagName == "IMG" && attributeName == "src" });
 							if (originURL) {
 								if (content == EMPTY_DATA_URI) {
 									try {
@@ -1953,7 +1967,7 @@ class ProcessorHelper {
 							// ignored
 						}
 						if (testValidURL(resourceURL)) {
-							const { content } = await batchRequest.addURL(resourceURL, true, "image");
+							const { content } = await batchRequest.addURL(resourceURL, { asBinary: true, expectedType: "image" });
 							const forbiddenPrefixFound = PREFIXES_FORBIDDEN_DATA_URI.filter(prefixDataURI => content.startsWith(prefixDataURI)).length;
 							if (forbiddenPrefixFound) {
 								return "";

+ 3 - 0
lib/single-file/single-file-util.js

@@ -194,6 +194,9 @@ function getInstance(utilOptions) {
 			startTime = Date.now();
 			log("  // STARTED download url =", resourceURL, "asBinary =", options.asBinary);
 		}
+		if (options.blockMixedContent && /^https:/i.test(options.baseURI) && !/^https:/i.test(resourceURL)) {
+			return { data: options.asBinary ? "data:null;base64," : "", resourceURL };
+		}
 		try {
 			if (options.frameId) {
 				try {