зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1788220 - Add source documentation for FedCM - r=timhuang
Also, I've added some function comments to Gecko code. Overall, I think returning to FedCM code after 3 months away will be feasible with this documentation in place. Differential Revision: https://phabricator.services.mozilla.com/D167958
This commit is contained in:
Родитель
86d43cae15
Коммит
8b357e66c9
|
@ -15,8 +15,18 @@
|
|||
|
||||
namespace mozilla::dom {
|
||||
|
||||
// This is the primary starting point for FedCM in the platform.
|
||||
// This class is the implementation of the IdentityCredential object
|
||||
// that is the value returned from the navigator.credentials.get call
|
||||
// with an "identity" argument. It also includes static functions that
|
||||
// perform operations that are used in constructing the credential.
|
||||
class IdentityCredential final : public Credential {
|
||||
public:
|
||||
// These are promise types, all used to support the async implementation of
|
||||
// this API. All are of the form MozPromise<RefPtr<T>, nsresult>.
|
||||
// Tuples are included to shuffle additional values along, so that the
|
||||
// intermediate state is entirely in the promise chain and we don't have to
|
||||
// capture an early step's result into a callback for a subsequent promise.
|
||||
typedef MozPromise<RefPtr<IdentityCredential>, nsresult, true>
|
||||
GetIdentityCredentialPromise;
|
||||
typedef MozPromise<IPCIdentityCredential, nsresult, true>
|
||||
|
@ -36,6 +46,7 @@ class IdentityCredential final : public Credential {
|
|||
GetAccountPromise;
|
||||
typedef MozPromise<IdentityClientMetadata, nsresult, true> GetMetadataPromise;
|
||||
|
||||
// This needs to be constructed in the context of a window
|
||||
explicit IdentityCredential(nsPIDOMWindowInner* aParent);
|
||||
|
||||
protected:
|
||||
|
@ -45,22 +56,60 @@ class IdentityCredential final : public Credential {
|
|||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// This builds a value from an IPC-friendly version. This type is returned
|
||||
// to the caller of navigator.credentials.get, however we get an IPC friendly
|
||||
// version back from the main process to the content process.
|
||||
// This is a deep copy of the token, ID, and type.
|
||||
void CopyValuesFrom(const IPCIdentityCredential& aOther);
|
||||
|
||||
// This is the inverse of CopyValuesFrom. Included for completeness.
|
||||
IPCIdentityCredential MakeIPCIdentityCredential();
|
||||
|
||||
// Getter and setter for the token member of this class
|
||||
void GetToken(nsAString& aToken) const;
|
||||
void SetToken(const nsAString& aToken);
|
||||
|
||||
// This function allows a relying party to send one last credentialed request
|
||||
// to the IDP when logging out. This only works if the current account state
|
||||
// in the IdentityCredentialStorageService allows logouts and clears that bit
|
||||
// when a request is sent.
|
||||
//
|
||||
// Arguments:
|
||||
// aGlobal: the global of the window calling this function
|
||||
// aLogoutRequest: all of the logout requests to try to send.
|
||||
// This is pairs of the IDP's logout url and the account
|
||||
// ID for that IDP.
|
||||
// Return value:
|
||||
// a promise resolving to undefined
|
||||
// Side effects:
|
||||
// Will send a network request to each IDP that have a state allowing
|
||||
// logouts and disables that bit.
|
||||
static already_AddRefed<Promise> LogoutRPs(
|
||||
GlobalObject& aGlobal,
|
||||
const Sequence<IdentityCredentialLogoutRPsRequest>& aLogoutRequests,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// This is the main static function called when a credential needs to be
|
||||
// fetched from the IDP. Called in the content process.
|
||||
// This is mostly a passthrough to `DiscoverFromExternalSourceInMainProcess`.
|
||||
static RefPtr<GetIdentityCredentialPromise> DiscoverFromExternalSource(
|
||||
nsPIDOMWindowInner* aParent, const CredentialRequestOptions& aOptions,
|
||||
bool aSameOriginWithAncestors);
|
||||
|
||||
// Start the FedCM flow. This will start the timeout timer, fire initial
|
||||
// network requests, prompt the user, and call into CreateCredential.
|
||||
//
|
||||
// Arguments:
|
||||
// aPrincipal: the caller of navigator.credentials.get()'s principal
|
||||
// aBrowsingContext: the BC of the caller of navigator.credentials.get()
|
||||
// aOptions: argument passed to navigator.credentials.get()
|
||||
// Return value:
|
||||
// a promise resolving to an IPC credential with type "identity", id
|
||||
// constructed to identify it, and token corresponding to the token
|
||||
// fetched in FetchToken. This promise may reject with nsresult errors.
|
||||
// Side effects:
|
||||
// Will send network requests to the IDP. The details of which are in the
|
||||
// other static methods here.
|
||||
static RefPtr<GetIPCIdentityCredentialPromise>
|
||||
DiscoverFromExternalSourceInMainProcess(
|
||||
nsIPrincipal* aPrincipal, CanonicalBrowsingContext* aBrowsingContext,
|
||||
|
@ -72,6 +121,7 @@ class IdentityCredential final : public Credential {
|
|||
//
|
||||
// Arguments:
|
||||
// aPrincipal: the caller of navigator.credentials.get()'s principal
|
||||
// aBrowsingContext: the BC of the caller of navigator.credentials.get()
|
||||
// aProvider: the provider to validate the root manifest of
|
||||
// Return value:
|
||||
// a promise resolving to an IPC credential with type "identity", id
|
||||
|
@ -160,24 +210,84 @@ class IdentityCredential final : public Credential {
|
|||
const IdentityInternalManifest& aManifest,
|
||||
const IdentityAccount& aAccount);
|
||||
|
||||
// Performs a Fetch for links to legal info about the identity provider.
|
||||
// The returned promise resolves with the information in an object.
|
||||
//
|
||||
// Arguments:
|
||||
// aPrincipal: the caller of navigator.credentials.get()'s principal
|
||||
// aProvider: the identity provider to get information from
|
||||
// aManfiest: the identity provider's manifest
|
||||
// Return value:
|
||||
// promise that resolves with an object containing legal information for
|
||||
// aProvider
|
||||
// Side effects:
|
||||
// Network request to the provider supplied token endpoint with
|
||||
// credentials and including information about the requesting principal.
|
||||
//
|
||||
static RefPtr<GetMetadataPromise> FetchMetadata(
|
||||
nsIPrincipal* aPrincipal, const IdentityProvider& aProvider,
|
||||
const IdentityInternalManifest& aManifest);
|
||||
|
||||
// Show the user a dialog to select what identity provider they would like
|
||||
// to try to log in with.
|
||||
//
|
||||
// Arguments:
|
||||
// aBrowsingContext: the BC of the caller of navigator.credentials.get()
|
||||
// aProviders: the providers to let the user select from
|
||||
// Return value:
|
||||
// a promise resolving to an identity provider that the user took action
|
||||
// to select. This promise may reject with nsresult errors.
|
||||
// Side effects:
|
||||
// Will show a dialog to the user.
|
||||
static RefPtr<GetIdentityProviderPromise> PromptUserToSelectProvider(
|
||||
BrowsingContext* aBrowsingContext,
|
||||
const Sequence<IdentityProvider>& aProviders);
|
||||
|
||||
// Show the user a dialog to select what account they would like
|
||||
// to try to log in with.
|
||||
//
|
||||
// Arguments:
|
||||
// aBrowsingContext: the BC of the caller of navigator.credentials.get()
|
||||
// aAccounts: the accounts to let the user select from
|
||||
// aManifest: the identity provider that was chosen's manifest
|
||||
// Return value:
|
||||
// a promise resolving to an account that the user took action
|
||||
// to select (and aManifest). This promise may reject with nsresult errors.
|
||||
// Side effects:
|
||||
// Will show a dialog to the user.
|
||||
static RefPtr<GetAccountPromise> PromptUserToSelectAccount(
|
||||
BrowsingContext* aBrowsingContext, const IdentityAccountList& aAccounts,
|
||||
const IdentityInternalManifest& aManifest);
|
||||
|
||||
// Show the user a dialog to select what account they would like
|
||||
// to try to log in with.
|
||||
//
|
||||
// Arguments:
|
||||
// aBrowsingContext: the BC of the caller of navigator.credentials.get()
|
||||
// aAccount: the accounts the user chose
|
||||
// aManifest: the identity provider that was chosen's manifest
|
||||
// aProvider: the identity provider that was chosen
|
||||
// Return value:
|
||||
// a promise resolving to an account that the user agreed to use (and
|
||||
// aManifest). This promise may reject with nsresult errors. This includes
|
||||
// if the user denied the terms and privacy policy
|
||||
// Side effects:
|
||||
// Will show a dialog to the user. Will send a network request to the
|
||||
// identity provider. Modifies the IdentityCredentialStorageService state
|
||||
// for this account.
|
||||
static RefPtr<GetAccountPromise> PromptUserWithPolicy(
|
||||
BrowsingContext* aBrowsingContext, nsIPrincipal* aPrincipal,
|
||||
const IdentityAccount& aAccount,
|
||||
const IdentityInternalManifest& aManifest,
|
||||
const IdentityProvider& aProvider);
|
||||
|
||||
// Close all dialogs associated with IdentityCredential generation on the
|
||||
// provided browsing context
|
||||
//
|
||||
// Arguments:
|
||||
// aBrowsingContext: the BC of the caller of navigator.credentials.get()
|
||||
// Side effects:
|
||||
// Will close a dialog shown to the user.
|
||||
static void CloseUserInterface(BrowsingContext* aBrowsingContext);
|
||||
|
||||
private:
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
namespace mozilla::dom {
|
||||
|
||||
// Helper to get a JSON structure via a Fetch.
|
||||
// The Request must already be built and T should be a webidl type with
|
||||
// annotation GenerateConversionToJS so it has an Init method.
|
||||
template <typename T, typename TPromise = MozPromise<T, nsresult, true>>
|
||||
RefPtr<TPromise> FetchJSONStructure(Request* aRequest) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
===============================
|
||||
Federated Credential Management
|
||||
===============================
|
||||
|
||||
FedCM, as it is abbreviated, is a platform feature that requires a full-stack implementation.
|
||||
As such, its code is scattered throughout the codebase and it can be hard to follow the flow of execution.
|
||||
This documentation aims to make those two points easier.
|
||||
|
||||
Code sites
|
||||
==========
|
||||
|
||||
Code relevant to it can be found in all of the following places.
|
||||
|
||||
The webidl for this spec lives in ``dom/webidl/IdentityCredential.webidl``
|
||||
|
||||
Core spec algorithm logic and the implementation of the ``IdentityCredential`` live in ``dom/credentialmanagement/identity/IdentityCredential.{cpp,h}``. The static functions of ``IdentityCredential`` are the spec algorithm logic. Helpers for managing the ``IdentityCredential.webidl`` objects are in the other files in ``dom/credentialmanagement/identity/``. The IPC is defined on the WindowGlobal in ``dom/ipc/PWindowGlobal.ipdl`` and ``dom/ipc/WindowGlobalParent.cpp``, and is a very thin layer.
|
||||
|
||||
The service for managing state associated with IdentityCredentials is ``IdentityCredentialStorageService`` and the service for managing the UI prompts associated with IdentityCredentials is ``IdentityCredentialPromptService``. Both definitions and implementations are in ``toolkit/components/credentialmanagement``.
|
||||
|
||||
The UI panel is spread around a little. The actual DOM elements are in the HTML subtree with root at ``#identity-credential-notification`` in ``browser/base/content/popup-notifications.inc``. But the CSS describing it is spread through ``browser/themes/shared/customizableui/panelUI-shared.css``, ``browser/themes/shared/identity-credential-notification.css``, and ``browser/themes/shared/notification-icons.css``. Generally speaking, search for ``identity-credential`` in those files to find the relevant ids and classes.
|
||||
|
||||
Temporary content strings, which will be moved when included in i18n: ``browser/components/credentialmanager/identityCredentialNotification.ftl``, for now. This will eventually be moved to ``browser/locales/en-US/browser/``.
|
||||
|
||||
All of this is entered from the ``navigator.credentials`` object, implemented in ``dom/credentialmanagement/CredentialsContainer.{cpp,h}``.
|
||||
|
||||
Flow of Execution
|
||||
=================
|
||||
|
||||
This is the general flow through code relevant to the core spec algorithms, which happens to be the complicated parts imo.
|
||||
|
||||
A few notes:
|
||||
|
||||
- All functions without a class specified are in ``IdentityCredential``.
|
||||
- Functions in ``IdentityCredentialPromptService`` mutate the Chrome DOM
|
||||
- FetchT functions send network requests via ``mozilla::dom::FetchJSONStructure<T>``.
|
||||
- A call to ``IdentityCredentialStorageService`` is made in ``PromptUserWithPolicy``
|
||||
|
||||
.. graphviz::
|
||||
|
||||
digraph fedcm {
|
||||
"RP (visited page) calls ``navigator.credentials.get()``" -> "CredentialsContainer::Get"
|
||||
"CredentialsContainer::Get" -> "DiscoverFromExternalSource"
|
||||
"DiscoverFromExternalSource" -> "DiscoverFromExternalSourceInMainProcess" [label="IPC via WindowGlobal's DiscoverIdentityCredentialFromExternalSource"]
|
||||
"DiscoverFromExternalSourceInMainProcess" -> "anonymous timeout callback" -> "CloseUserInterface" -> "IdentityCredentialPromptService::Close"
|
||||
"DiscoverFromExternalSourceInMainProcess" -> "PromptUserToSelectProvider"
|
||||
"PromptUserToSelectProvider" -> "IdentityCredentialPromptService::ShowProviderPrompt"
|
||||
"IdentityCredentialPromptService::ShowProviderPrompt" -> "CreateCredential" [label="via promise chain in DiscoverFromExternalSourceInMainProcess"]
|
||||
"CreateCredential" -> "CheckRootManifest"
|
||||
"CheckRootManifest" -> "FetchInternalManifest" [label="via promise chain in CreateCredential"]
|
||||
"FetchInternalManifest" -> "FetchAccountList" [label="via promise chain in CreateCredential"]
|
||||
"FetchAccountList" -> "PromptUserToSelectAccount" [label="via promise chain in CreateCredential"]
|
||||
"PromptUserToSelectAccount" -> "IdentityCredentialPromptService::ShowAccountListPrompt"
|
||||
"IdentityCredentialPromptService::ShowAccountListPrompt" -> "PromptUserWithPolicy" [label="via promise chain in CreateCredential"]
|
||||
"PromptUserWithPolicy" -> "FetchMetadata"
|
||||
"FetchMetadata" -> "IdentityCredentialPromptService::ShowPolicyPrompt" [label="via promise chain in PromptUserWithPolicy"]
|
||||
"IdentityCredentialPromptService::ShowPolicyPrompt" -> "FetchToken" [label="via promise chain in CreateCredential"]
|
||||
"FetchToken" -> "cancel anonymous timeout callback"
|
||||
"FetchToken" -> "CreateCredential inline anonymous callback"
|
||||
"CreateCredential inline anonymous callback" -> "DiscoverFromExternalSourceInMainProcess inline anonymous callback"
|
||||
"DiscoverFromExternalSourceInMainProcess inline anonymous callback" -> "DiscoverFromExternalSource inline anonymous callback" [label="Resolving IPC via WindowGlobal's DiscoverIdentityCredentialFromExternalSource"]
|
||||
"DiscoverFromExternalSource inline anonymous callback" -> "CredentialsContainer::Get inline anonymous callback"
|
||||
"CredentialsContainer::Get inline anonymous callback" -> "RP (visited page) gets the credential"
|
||||
}
|
|
@ -13,3 +13,4 @@ These linked pages contain design documents for the DOM implementation in Gecko.
|
|||
workersAndStorage/index
|
||||
webIdlBindings/index
|
||||
ioutils_migration
|
||||
fedcm
|
||||
|
|
Загрузка…
Ссылка в новой задаче