From 5dd59a40280d81019fc373e47b3507146c6e1bb6 Mon Sep 17 00:00:00 2001 From: wbamberg Date: Fri, 14 Apr 2017 13:34:05 -0700 Subject: [PATCH] Example of the webRequest.onAuthRequired API (#206) * Example of the webRequest.onAuthRequired API * Update README, add applications.id to manifest --- stored-credentials/README.md | 32 +++++++++++++++++ stored-credentials/auth.js | 48 +++++++++++++++++++++++++ stored-credentials/icons/LICENSE | 1 + stored-credentials/icons/lock.svg | 1 + stored-credentials/manifest.json | 31 ++++++++++++++++ stored-credentials/options/options.css | 23 ++++++++++++ stored-credentials/options/options.html | 22 ++++++++++++ stored-credentials/options/options.js | 39 ++++++++++++++++++++ stored-credentials/storage.js | 27 ++++++++++++++ 9 files changed, 224 insertions(+) create mode 100644 stored-credentials/README.md create mode 100644 stored-credentials/auth.js create mode 100644 stored-credentials/icons/LICENSE create mode 100644 stored-credentials/icons/lock.svg create mode 100644 stored-credentials/manifest.json create mode 100644 stored-credentials/options/options.css create mode 100644 stored-credentials/options/options.html create mode 100644 stored-credentials/options/options.js create mode 100644 stored-credentials/storage.js diff --git a/stored-credentials/README.md b/stored-credentials/README.md new file mode 100644 index 0000000..b9d70f7 --- /dev/null +++ b/stored-credentials/README.md @@ -0,0 +1,32 @@ +# stored-credentials + +**Although this add-on uses a stored password to authenticate to a web server, +it should not be taken as an example of how to store or work securely with +passwords. It's only a demonstration of how to use the +[`webRequest.onAuthRequired`](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest/onAuthRequired) API.** + +This add-on uses the [`webRequest.onAuthRequired`](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest/onAuthRequired) API to log the user into +the demo site at https://httpbin.org/basic-auth/user/passwd using a stored +username and password. + +This add-on stores a username and password using the [`storage.local`](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/storage/local) API. +The default value is the correct value +for the demo site: + + username: "user" + password: "passwd" + +You can change the default values in the add-on's [options page](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Options_pages). + +The add-on then uses `webRequest.onAuthRequired` to intercept authentication +requests from the demo site. When it gets +such a request, it fetches the stored credentials and supplies them +asynchronously. + +To try out the add-on: + +* Before installing the add-on, visit https://httpbin.org/basic-auth/user/passwd, +and see that it asks for a username and password. +* [Install the add-on](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Temporary_Installation_in_Firefox) in Firefox 54 or later. +* Visit https://httpbin.org/basic-auth/user/passwd again, and see that authentication succeeds automatically. + diff --git a/stored-credentials/auth.js b/stored-credentials/auth.js new file mode 100644 index 0000000..a5d4778 --- /dev/null +++ b/stored-credentials/auth.js @@ -0,0 +1,48 @@ + +var target = "https://httpbin.org/basic-auth/*"; + +var pendingRequests = []; + +/* +A request has completed. We can stop worrying about it. +*/ +function completed(requestDetails) { + console.log("completed: " + requestDetails.requestId); + var index = pendingRequests.indexOf(requestDetails.requestId); + if (index > -1) { + pendingRequests.splice(index, 1); + } +} + +function provideCredentialsAsync(requestDetails) { + // If we have seen this request before, + // then assume our credentials were bad, + // and give up. + if (pendingRequests.indexOf(requestDetails.requestId) != -1) { + console.log("bad credentials for: " + requestDetails.requestId); + return {cancel: true}; + + } else { + pendingRequests.push(requestDetails.requestId); + console.log("providing credentials for: " + requestDetails.requestId); + // we can return a promise that will be resolved + // with the stored credentials + return browser.storage.local.get(null); + } +} + +browser.webRequest.onAuthRequired.addListener( + provideCredentialsAsync, + {urls: [target]}, + ["blocking"] + ); + +browser.webRequest.onCompleted.addListener( + completed, + {urls: [target]} +); + +browser.webRequest.onErrorOccurred.addListener( + completed, + {urls: [target]} +); diff --git a/stored-credentials/icons/LICENSE b/stored-credentials/icons/LICENSE new file mode 100644 index 0000000..f39164e --- /dev/null +++ b/stored-credentials/icons/LICENSE @@ -0,0 +1 @@ +The "lock".svg" icon is taken from the Material Core iconset and is used under the terms of its license: https://www.iconfinder.com/iconsets/material-core. diff --git a/stored-credentials/icons/lock.svg b/stored-credentials/icons/lock.svg new file mode 100644 index 0000000..1037a7d --- /dev/null +++ b/stored-credentials/icons/lock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/stored-credentials/manifest.json b/stored-credentials/manifest.json new file mode 100644 index 0000000..3e19a85 --- /dev/null +++ b/stored-credentials/manifest.json @@ -0,0 +1,31 @@ +{ + "description": "Performs basic authentication by supplying stored credentials.", + "manifest_version": 2, + "name": "stored-credentials", + "version": "2.0", + "homepage_url": "https://github.com/mdn/webextensions-examples/tree/master/stored-credentials", + "icons": { + "48": "icons/lock.svg" + }, + + "applications": { + "gecko": { + "strict_min_version": "54.0a1" + } + }, + + "background": { + "scripts": ["storage.js", "auth.js"] + }, + + "options_ui": { + "page": "options/options.html" + }, + + "permissions": [ + "webRequest", + "webRequestBlocking", + "storage", + "https://httpbin.org/basic-auth/*" + ] +} diff --git a/stored-credentials/options/options.css b/stored-credentials/options/options.css new file mode 100644 index 0000000..f54cbcf --- /dev/null +++ b/stored-credentials/options/options.css @@ -0,0 +1,23 @@ + +body { + width: 25em; + font-family: "Open Sans Light", sans-serif; + font-size: 0.9em; + font-weight: 300; +} + + +.title { + font-size: 1.2em; + margin-bottom: 0.5em; +} + +label { + float: right; +} + +input { + margin: 0.5em; + width: 200px; + height: 2.5em; +} diff --git a/stored-credentials/options/options.html b/stored-credentials/options/options.html new file mode 100644 index 0000000..235dd6a --- /dev/null +++ b/stored-credentials/options/options.html @@ -0,0 +1,22 @@ + + + + + + + + + + +
+
Username and password
+ + + + +
+ + + + + diff --git a/stored-credentials/options/options.js b/stored-credentials/options/options.js new file mode 100644 index 0000000..bb0477d --- /dev/null +++ b/stored-credentials/options/options.js @@ -0,0 +1,39 @@ +const usernameInput = document.querySelector("#username"); +const passwordInput = document.querySelector("#password"); + +/* +Store the currently selected settings using browser.storage.local. +*/ +function storeSettings() { + browser.storage.local.set({ + authCredentials: { + username: usernameInput.value, + password: passwordInput.value + } + }); +} + +/* +Update the options UI with the settings values retrieved from storage, +or the default settings if the stored settings are empty. +*/ +function updateUI(restoredSettings) { + usernameInput.value = restoredSettings.authCredentials.username || ""; + passwordInput.value = restoredSettings.authCredentials.password || ""; +} + +function onError(e) { + console.error(e); +} + +/* +On opening the options page, fetch stored settings and update the UI with them. +*/ +const gettingStoredSettings = browser.storage.local.get(); +gettingStoredSettings.then(updateUI, onError); + +/* +On blur, save the currently selected settings. +*/ +usernameInput.addEventListener("blur", storeSettings); +passwordInput.addEventListener("blur", storeSettings); diff --git a/stored-credentials/storage.js b/stored-credentials/storage.js new file mode 100644 index 0000000..53cfa0a --- /dev/null +++ b/stored-credentials/storage.js @@ -0,0 +1,27 @@ +/* +Default settings. Initialize storage to these values. +*/ +var authCredentials = { + username: "user", + password: "passwd" +} + +/* +Generic error logger. +*/ +function onError(e) { + console.error(e); +} + +/* +On startup, check whether we have stored settings. +If we don't, then store the default settings. +*/ +function checkStoredSettings(storedSettings) { + if (!storedSettings.authCredentials) { + browser.storage.local.set({authCredentials}); + } +} + +const gettingStoredSettings = browser.storage.local.get(); +gettingStoredSettings.then(checkStoredSettings, onError);