Index: ios/chrome/browser/passwords/resources/credential_manager.js |
diff --git a/ios/chrome/browser/passwords/resources/credential_manager.js b/ios/chrome/browser/passwords/resources/credential_manager.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..8e2e84079be137d63d21d310c74443f285f0f8e1 |
--- /dev/null |
+++ b/ios/chrome/browser/passwords/resources/credential_manager.js |
@@ -0,0 +1,574 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+/** |
+ * @fileoverview JavaScript implementation of the credential management API |
+ * defined at http://w3c.github.io/webappsec/specs/credentialmanagement. |
+ * This is a minimal implementation that sends data to the app side to |
+ * integrate with the password manager. When loaded, installs the API onto |
+ * the window.navigator object. |
+ */ |
+ |
+// Namespace for all credential management stuff. __gCrWeb must have already |
+// been defined. |
+__gCrWeb['credentialManager'] = { |
+ /** |
+ * The next ID for forwarding a call from JS to the App and tracking its |
+ * associated Promise resolvers and rejecters. |
+ * @private {number} |
+ */ |
+ nextId_: 0, |
+ |
+ /** |
+ * Tracks navigator.credentials Promise resolvers. |
+ * @type {!Object<number, function(?Credential|undefined)>} |
+ * @private |
+ */ |
+ resolvers_: {}, |
+ |
+ /** |
+ * Tracks navigator.credentials Promise rejecters. |
+ * @type {!Object<number, function(?Error)>} |
+ * @private |
+ */ |
+ rejecters_: {} |
+}; |
+ |
+ |
+/** @enum {string} */ |
+__gCrWeb.credentialManager.CredentialType = { |
+ CREDENTIAL: 'Credential', |
+ PASSWORD_CREDENTIAL: 'PasswordCredential', |
+ FEDERATED_CREDENTIAL: 'FederatedCredential', |
+ PENDING_CREDENTIAL: 'PendingCredential' |
+}; |
+ |
+ |
+/** @typedef { |
+ * type: __gCrWeb.credentialManager.CredentialType, |
+ * id: string, |
+ * name: (string|undefined), |
+ * avatarURL: (string|undefined), |
+ * federation: (string|undefined) |
+ * } |
+ */ |
+__gCrWeb.credentialManager.SerializedCredential; |
+ |
+ |
+/** |
+ * Creates and returns a Promise whose resolver and rejecter functions are |
+ * stored with the associated |requestId|. They can be accessed by calling |
+ * |resolve| or |reject| on __gCrWeb['credentialManager'] with that ID. |
+ * @param {number} requestId An identifier to track the resolver and rejecter |
+ * associated with the returned Promise. |
+ * @return {!Promise<?Credential|undefined>} A new Promise. |
+ * @private |
+ */ |
+__gCrWeb['credentialManager'].createPromise_ = function(requestId) { |
+ return new Promise(function(resolve, reject) { |
+ __gCrWeb['credentialManager'].resolvers_[requestId] = resolve; |
+ __gCrWeb['credentialManager'].rejecters_[requestId] = reject; |
+ }); |
+}; |
+ |
+ |
+/** |
+ * Deletes the resolver and rejecter of the Promise associated with |requestId|. |
+ * @param {number} requestId The identifier of the Promise. |
+ * @private |
+ */ |
+__gCrWeb['credentialManager'].removePromise_ = function(requestId) { |
+ delete __gCrWeb['credentialManager'].rejecters_[requestId]; |
+ delete __gCrWeb['credentialManager'].resolvers_[requestId]; |
+}; |
+ |
+ |
+/** |
+ * Parses |credentialData| into a Credential object. |
+ * @param {!__gCrWeb.credentialManager.SerializedCredential} credentialData A |
+ * simple object representation of a Credential like might be obtained from |
+ * Credential.prototype.serialize. |
+ * @return {?Credential} A Credential object, or null if parsing was |
+ * unsuccessful. |
+ * @private |
+ */ |
+__gCrWeb['credentialManager'].parseCredential_ = function(credentialData) { |
+ var CredentialType = __gCrWeb.credentialManager.CredentialType; |
+ switch (credentialData['type']) { |
+ case CredentialType.CREDENTIAL: |
+ return Credential.parse(credentialData); |
+ case CredentialType.PASSWORD_CREDENTIAL: |
+ return PasswordCredential.parse(credentialData); |
+ case CredentialType.FEDERATED_CREDENTIAL: |
+ return FederatedCredential.parse(credentialData); |
+ case CredentialType.PENDING_CREDENTIAL: |
+ return PendingCredential.parse(credentialData); |
+ default: |
+ return null; |
+ } |
+}; |
+ |
+ |
+/** |
+ * Resolves the Promise that was created with the given |requestId| with a |
+ * Credential object parsed from |opt_credentialData| and removes that promise |
+ * from the global state. Future attempts to resolve or reject the Promise will |
+ * fail. |
+ * @param {number} requestId The identifier of the Promise to resolve. |
+ * @param {Object=} opt_credentialData An object describing a credential. If |
+ * provided, this parameter will be parsed into the appropriate Credential |
+ * type. |
+ * @return {boolean} Indicates whether the Promise was successfully resolved. |
+ */ |
+__gCrWeb['credentialManager'].resolve = function(requestId, |
+ opt_credentialData) { |
+ var resolver = __gCrWeb['credentialManager'].resolvers_[requestId]; |
+ if (!resolver) { |
+ return false; |
+ } |
+ if (opt_credentialData) { |
+ var credential = null; |
+ try { |
+ credential = |
+ __gCrWeb['credentialManager'].parseCredential_(opt_credentialData); |
+ } catch (e) { |
+ // Failed to parse |opt_credentialData|. The app side sent bad data. |
+ return false; |
+ } |
+ resolver(credential); |
+ } else { |
+ resolver(); |
+ } |
+ __gCrWeb['credentialManager'].removePromise_(requestId); |
+ return true; |
+}; |
+ |
+ |
+/** |
+ * Rejects the Promise that was created with the given |requestId| and cleans up |
+ * that Promise. |
+ * @param {number} requestId The identifier of the Promise to resolve. |
+ * @param {string} errorType The type of the Error to pass to the rejecter |
+ * function. If not recognized, a standard JavaScript Error will be used. |
+ * @param {string} message A human-readable description of the error. |
+ * @return {boolean} Indicates whether the Promise was successfully rejected. |
+ */ |
+__gCrWeb['credentialManager'].reject = function(requestId, errorType, message) { |
+ var rejecter = __gCrWeb['credentialManager'].rejecters_[requestId]; |
+ if (!rejecter) { |
+ return false; |
+ } |
+ var error = null; |
+ if (errorType == 'SecurityError') { |
+ error = new SecurityError(message); |
+ } else if (errorType == 'InvalidStateError') { |
+ error = new InvalidStateError(message); |
+ } else { |
+ error = new Error(message); |
+ } |
+ rejecter(error); |
+ __gCrWeb['credentialManager'].removePromise_(requestId); |
+ return true; |
+}; |
+ |
+ |
+/** |
+ * Sends a command representing |method| of navigator.credentials to the app |
+ * side with the given |opt_options|. |
+ * @param {string} command The name of the command being sent. |
+ * @param {Object=} opt_options A dictionary of additional properties to forward |
+ * to the app. |
+ * @return {!Promise<?Credential|undefined>} A promise for the result. |
+ * @private |
+ */ |
+__gCrWeb['credentialManager'].invokeOnHost_ = function(command, opt_options) { |
+ var requestId = __gCrWeb['credentialManager'].nextId_++; |
+ var message = { |
+ 'command': command, |
+ 'requestId': requestId |
+ }; |
+ if (opt_options) { |
+ Object.keys(opt_options).forEach(function(key) { |
+ message[key] = opt_options[key]; |
+ }); |
+ } |
+ __gCrWeb.message.invokeOnHost(message); |
+ return __gCrWeb['credentialManager'].createPromise_(requestId); |
+}; |
+ |
+ |
+ |
+/** |
+ * Creates a new SecurityError to represent failures caused by violating |
+ * security requirements of the API. |
+ * @param {string} message A human-readable message describing this error. |
+ * @extends {Error} |
+ * @constructor |
+ */ |
+function SecurityError(message) { |
+ Error.call(this, message); |
+ this.name = 'SecurityError'; |
+ this.message = message; |
+} |
+SecurityError.prototype = Object.create(Error.prototype); |
+SecurityError.prototype.constructor = SecurityError; |
+ |
+ |
+ |
+/** |
+ * Creates a new InvalidStateError to represent failures caused by inconsistent |
+ * internal state. |
+ * @param {string} message A human-readable message describing this error. |
+ * @extends {Error} |
+ * @constructor |
+ */ |
+function InvalidStateError(message) { |
+ Error.call(this, message); |
+ this.name = 'InvalidStateError'; |
+ this.message = message; |
+} |
+InvalidStateError.prototype = Object.create(Error.prototype); |
+InvalidStateError.prototype.constructor = InvalidStateError; |
+ |
+ |
+ |
+/** |
+ * Creates a new Credential object. For more information, see |
+ * https://w3c.github.io/webappsec/specs/credentialmanagement/#credential |
+ * @param {string} id The credential’s identifier. This might be a username or |
+ * email address, for instance. |
+ * @param {string=} opt_name A name associated with the credential, intended as |
+ * a human-understandable public name. |
+ * @param {string=} opt_avatarUrl A URL pointing to an avatar image for the |
+ * user. This URL MUST NOT be an a priori insecure URL. |
+ * @constructor |
+ */ |
+function Credential(id, opt_name, opt_avatarUrl) { |
+ if (id === null || id === undefined) |
+ throw new TypeError('id must be provided'); |
+ /** |
+ * The credential's identifier. Read-only. |
+ * @type {string} |
+ */ |
+ this.id; |
+ Object.defineProperty(this, 'id', { |
+ configurable: false, |
+ enumerable: true, |
+ value: id, |
+ writable: false |
+ }); |
+ /** |
+ * A human-understandable public name associated with the credential. |
+ * Read-only. |
+ * @type {string} |
+ */ |
+ this.name; |
+ Object.defineProperty(this, 'name', { |
+ configurable: false, |
+ enumerable: true, |
+ value: opt_name || '', |
+ writable: false |
+ }); |
+ /** |
+ * A URL pointing to an avatar image for the user. Read-only. |
+ * NOTE: This property name deviates from the Google JavaScript style guide |
+ * in order to meet the public API specification. |
+ * @type {string} |
+ */ |
+ this.avatarURL; |
+ Object.defineProperty(this, 'avatarURL', { |
+ configurable: false, |
+ enumerable: true, |
+ value: opt_avatarUrl || '', |
+ writable: false |
+ }); |
+} |
+ |
+ |
+/** |
+ * Returns a simple object representation of this credential suitable for |
+ * sending to the app side. |
+ * @return {__gCrWeb.credentialManager.SerializedCredential} An object |
+ * representing this credential. |
+ */ |
+Credential.prototype.serialize = function() { |
+ var serialized = { |
+ 'type': this.constructor.name, |
+ 'id': this.id, |
+ 'name': this.name |
+ }; |
+ if (this.avatarURL && this.avatarURL.length > 0) |
+ serialized['avatarURL'] = this.avatarURL; |
+ return serialized; |
+}; |
+ |
+ |
+/** |
+ * Parses |credentialData| into a Credential object. |
+ * @param {!__gCrWeb.credentialManager.SerializedCredential} credentialData A |
+ * simple object representation of a Credential like might be obtained from |
+ * Credential.prototype.serialize. |
+ * @return {Credential} A Credential object. |
+ */ |
+Credential.parse = function(credentialData) { |
+ return new Credential(credentialData['id'], |
+ credentialData['name'], |
+ credentialData['avatarURL']); |
+}; |
+ |
+ |
+ |
+/** |
+ * Creates a new PasswordCredential object. For more information, see |
+ * https://w3c.github.io/webappsec/specs/credentialmanagement/#localcredential |
+ * @param {string} id The credential’s identifier. This might be a username or |
+ * email address, for instance. |
+ * @param {string} password The credential's password. |
+ * @param {string=} opt_name A name associated with the credential, intended as |
+ * a human-understandable public name. |
+ * @param {string=} opt_avatarUrl A URL pointing to an avatar image for the |
+ * user. This URL MUST NOT be an a priori insecure URL. |
+ * @constructor |
+ * @extends {Credential} |
+ */ |
+function PasswordCredential(id, password, opt_name, opt_avatarUrl) { |
+ if (password === null || password === undefined) |
+ throw new TypeError('password must be provided'); |
+ Credential.call(this, id, opt_name, opt_avatarUrl); |
+ var formData = new FormData(); |
+ formData.append('username', id); |
+ formData.append('password', password); |
+ /** |
+ * A FormData object, containing two entries: one named username, the other |
+ * named password. Read-only. |
+ * @type {FormData} |
+ */ |
+ this.formData; |
+ Object.defineProperty(this, 'formData', { |
+ configurable: false, |
+ enumerable: true, |
+ value: formData, |
+ writable: false |
+ }); |
+ /** |
+ * The credential's password. |
+ * @type {string} |
+ * @private |
+ */ |
+ this.password_; |
+ Object.defineProperty(this, 'password_', { |
+ configurable: false, |
+ enumerable: false, |
+ value: password, |
+ writable: false |
+ }); |
+} |
+PasswordCredential.prototype = Object.create(Credential.prototype); |
+PasswordCredential.prototype.constructor = PasswordCredential; |
+ |
+ |
+/** |
+ * Returns a simple object representation of this credential suitable for |
+ * sending to the app side. |
+ * @return {__gCrWeb.credentialManager.SerializedCredential} An object |
+ * representing this credential. |
+ */ |
+PasswordCredential.prototype.serialize = function() { |
+ var obj = Credential.prototype.serialize.call(this); |
+ obj.password = this.password_; |
+ return obj; |
+}; |
+ |
+ |
+/** |
+ * Parses |credentialData| into a PasswordCredential object. |
+ * @param {!__gCrWeb.credentialManager.SerializedCredential} credentialData A |
+ * simple object representation of a PasswordCredential like might be |
+ * obtained from PasswordCredential.prototype.serialize. |
+ * @return {PasswordCredential} A PasswordCredential object. |
+ */ |
+PasswordCredential.parse = function(credentialData) { |
+ return new PasswordCredential(credentialData['id'], |
+ credentialData['password'], |
+ credentialData['name'], |
+ credentialData['avatarURL']); |
+}; |
+ |
+ |
+ |
+/** |
+ * Creates a new FederatedCredential object. For more information, see |
+ * https://w3c.github.io/webappsec/specs/credentialmanagement/#federatedcredential |
+ * @param {string} id The credential’s identifier. This might be a username or |
+ * email address, for instance. |
+ * @param {string} federation The credential’s federation. For details regarding |
+ * valid formats, see https://w3c.github.io/webappsec/specs/credentialmanagement/#identifying-federations |
+ * @param {string=} opt_name A name associated with the credential, intended as |
+ * a human-understandable public name. |
+ * @param {string=} opt_avatarUrl A URL pointing to an avatar image for the |
+ * user. This URL MUST NOT be an a priori insecure URL. |
+ * @constructor |
+ * @extends {Credential} |
+ */ |
+function FederatedCredential(id, federation, opt_name, opt_avatarUrl) { |
+ if (federation === null || federation === undefined) |
+ throw new TypeError('federation must be provided'); |
+ Credential.call(this, id, opt_name, opt_avatarUrl); |
+ /** |
+ * The credential’s federation. Read-only. |
+ * @type {string} |
+ */ |
+ this.federation; |
+ Object.defineProperty(this, 'federation', { |
+ configurable: false, |
+ enumerable: true, |
+ value: federation, |
+ writable: false |
+ }); |
+} |
+FederatedCredential.prototype = Object.create(Credential.prototype); |
+FederatedCredential.prototype.constructor = FederatedCredential; |
+ |
+ |
+/** |
+ * Returns a simple object representation of this credential suitable for |
+ * sending to the app side. |
+ * @return {__gCrWeb.credentialManager.SerializedCredential} An object |
+ * representing this credential. |
+ */ |
+FederatedCredential.prototype.serialize = function() { |
+ var obj = Credential.prototype.serialize.call(this); |
+ obj.federation = this.federation; |
+ return obj; |
+}; |
+ |
+ |
+/** |
+ * Parses |credentialData| into a FederatedCredential object. |
+ * @param {!__gCrWeb.credentialManager.SerializedCredential} credentialData A |
+ * simple object representation of a FederatedCredential like might be |
+ * obtained from FederatedCredential.prototype.serialize. |
+ * @return {!FederatedCredential} A FederatedCredential object. |
+ */ |
+FederatedCredential.parse = function(credentialData) { |
+ return new FederatedCredential(credentialData['id'], |
+ credentialData['federation'], |
+ credentialData['name'], |
+ credentialData['avatarURL']); |
+}; |
+ |
+ |
+ |
+/** |
+ * Creates a new PendingCredential object. For more information, see |
+ * https://w3c.github.io/webappsec/specs/credentialmanagement/#pendingcredential |
+ * @param {string} id The credential’s identifier. This might be a username or |
+ * email address, for instance. |
+ * @param {string=} opt_name A name associated with the credential, intended as |
+ * a human-understandable public name. |
+ * @param {string=} opt_avatarUrl A URL pointing to an avatar image for the |
+ * user. This URL MUST NOT be an a priori insecure URL. |
+ * @constructor |
+ * @extends {Credential} |
+ */ |
+function PendingCredential(id, opt_name, opt_avatarUrl) { |
+ Credential.call(this, id, opt_name, opt_avatarUrl); |
+} |
+PendingCredential.prototype = Object.create(Credential.prototype); |
+PendingCredential.prototype.constructor = PendingCredential; |
+ |
+ |
+/** |
+ * Parses |credentialData| into a PendingCredential object. |
+ * @param {!__gCrWeb.credentialManager.SerializedCredential} credentialData A |
+ * simple object representation of a PendingCredential like might be |
+ * obtained from PendingCredential.prototype.serialize. |
+ * @return {!Credential} A PendingCredential object. |
+ */ |
+PendingCredential.parse = function(credentialData) { |
+ return new PendingCredential(credentialData['id'], |
+ credentialData['name'], |
+ credentialData['avatarURL']); |
+}; |
+ |
+ |
+ |
+/** |
+ * Implements the public Credential Management API. For more information, see |
+ * http://w3c.github.io/webappsec/specs/credentialmanagement/#interfaces-credential-manager |
+ * @constructor |
+ */ |
+function CredentialsContainer() { |
+} |
+ |
+ |
+/** |
+ * Requests a credential from the credential manager. |
+ * @param {{suppressUI: boolean, federations: Array<string>}=} opt_options An |
+ * optional dictionary of parameters for the request. If |suppressUI| is |
+ * true, the returned promise will only be resolved with a credential if |
+ * this is possible without user interaction; otherwise, the returned |
+ * promise will be resolved with |undefined|. |federations| specifies a |
+ * list of acceptable federation providers. For more information, see |
+ * https://w3c.github.io/webappsec/specs/credentialmanagement/#interfaces-request-options |
+ * @return {!Promise<?Credential|undefined>} A promise for retrieving the result |
+ * of the request. |
+ */ |
+CredentialsContainer.prototype.request = function(opt_options) { |
+ var options = { |
+ 'suppressUI': !!opt_options && !!opt_options['suppressUI'], |
+ 'federations': (!!opt_options && opt_options['federations']) || [] |
+ }; |
+ return __gCrWeb['credentialManager'].invokeOnHost_( |
+ 'navigator.credentials.request', options); |
+}; |
+ |
+ |
+/** |
+ * Notifies the browser that the user has successfully signed in. |
+ * @param {Credential=} opt_successfulCredential The credential that was used |
+ * to sign in. |
+ * @return {!Promise<?Credential|undefined>} A promise to wait for |
+ * acknowledgement from the browser. |
+ */ |
+CredentialsContainer.prototype.notifySignedIn = function( |
+ opt_successfulCredential) { |
+ var options = opt_successfulCredential && { |
+ 'credential': opt_successfulCredential.serialize() |
+ }; |
+ return __gCrWeb['credentialManager'].invokeOnHost_( |
+ 'navigator.credentials.notifySignedIn', options); |
+}; |
+ |
+ |
+/** |
+ * Notifies the browser that the user failed to sign in. |
+ * @param {Credential=} opt_failedCredential The credential that failed to |
+ * sign in. |
+ * @return {!Promise<?Credential|undefined>} A promise to wait for |
+ * acknowledgement from the browser. |
+ */ |
+CredentialsContainer.prototype.notifyFailedSignIn = function( |
+ opt_failedCredential) { |
+ var options = opt_failedCredential && { |
+ 'credential': opt_failedCredential.serialize() |
+ }; |
+ return __gCrWeb['credentialManager'].invokeOnHost_( |
+ 'navigator.credentials.notifyFailedSignIn', options); |
+}; |
+ |
+ |
+/** |
+ * Notifies the browser that the user signed out. |
+ * @return {!Promise<?Credential|undefined>} A promise to wait for |
+ * acknowledgement from the browser. |
+ */ |
+CredentialsContainer.prototype.notifySignedOut = function() { |
+ return __gCrWeb['credentialManager'].invokeOnHost_( |
+ 'navigator.credentials.notifySignedOut'); |
+}; |
+ |
+ |
+// Install the public interface. |
+window.navigator.credentials = new CredentialsContainer(); |