зеркало из https://github.com/mozilla/gecko-dev.git
bug 1332681 - part 3/4 - convert authentication.makeCredential to credentials.create r=jcj,qdot
MozReview-Commit-ID: 1xfsQqGCEcl --HG-- rename : dom/webauthn/WebAuthentication.cpp => dom/credentialmanagement/CredentialsContainer.cpp rename : dom/webauthn/WebAuthentication.h => dom/credentialmanagement/CredentialsContainer.h extra : rebase_source : d92546a7f6a3780c6ec8790dfabb23a9ea29efbe
This commit is contained in:
Родитель
0ecb59e4a9
Коммит
abac00aea3
|
@ -33,6 +33,7 @@
|
|||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "BatteryManager.h"
|
||||
#include "mozilla/dom/CredentialsContainer.h"
|
||||
#include "mozilla/dom/GamepadServiceTest.h"
|
||||
#include "mozilla/dom/PowerManager.h"
|
||||
#include "mozilla/dom/WakeLock.h"
|
||||
|
@ -206,6 +207,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
|
|||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStorageManager)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAuthentication)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCredentials)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaDevices)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTimeManager)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerContainer)
|
||||
|
@ -2010,5 +2012,14 @@ Navigator::Authentication()
|
|||
return mAuthentication;
|
||||
}
|
||||
|
||||
CredentialsContainer*
|
||||
Navigator::Credentials()
|
||||
{
|
||||
if (!mCredentials) {
|
||||
mCredentials = new CredentialsContainer(GetWindow());
|
||||
}
|
||||
return mCredentials;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -43,6 +43,7 @@ class DOMRequest;
|
|||
struct FlyWebPublishOptions;
|
||||
struct FlyWebFilter;
|
||||
class WebAuthentication;
|
||||
class CredentialsContainer;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -226,6 +227,7 @@ public:
|
|||
already_AddRefed<ServiceWorkerContainer> ServiceWorker();
|
||||
|
||||
mozilla::dom::WebAuthentication* Authentication();
|
||||
mozilla::dom::CredentialsContainer* Credentials();
|
||||
|
||||
void GetLanguages(nsTArray<nsString>& aLanguages);
|
||||
|
||||
|
@ -295,6 +297,7 @@ private:
|
|||
RefPtr<PowerManager> mPowerManager;
|
||||
RefPtr<network::Connection> mConnection;
|
||||
RefPtr<WebAuthentication> mAuthentication;
|
||||
RefPtr<CredentialsContainer> mCredentials;
|
||||
RefPtr<MediaDevices> mMediaDevices;
|
||||
RefPtr<time::TimeManager> mTimeManager;
|
||||
RefPtr<ServiceWorkerContainer> mServiceWorkerContainer;
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/CredentialsContainer.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/WebAuthnManager.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CredentialsContainer, mParent)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(CredentialsContainer)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(CredentialsContainer)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CredentialsContainer)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
CredentialsContainer::CredentialsContainer(nsPIDOMWindowInner* aParent) :
|
||||
mParent(aParent)
|
||||
{
|
||||
MOZ_ASSERT(aParent);
|
||||
}
|
||||
|
||||
CredentialsContainer::~CredentialsContainer()
|
||||
{}
|
||||
|
||||
JSObject*
|
||||
CredentialsContainer::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return CredentialsContainerBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
CredentialsContainer::Create(const CredentialCreationOptions& aOptions)
|
||||
{
|
||||
RefPtr<WebAuthnManager> mgr = WebAuthnManager::GetOrCreate();
|
||||
MOZ_ASSERT(mgr);
|
||||
return mgr->MakeCredential(mParent, aOptions.mPublicKey);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,45 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_CredentialsContainer_h
|
||||
#define mozilla_dom_CredentialsContainer_h
|
||||
|
||||
#include "mozilla/dom/CredentialManagementBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class CredentialsContainer final : public nsISupports
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CredentialsContainer)
|
||||
|
||||
explicit CredentialsContainer(nsPIDOMWindowInner* aParent);
|
||||
|
||||
nsPIDOMWindowInner*
|
||||
GetParentObject() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Create(const CredentialCreationOptions& aOptions);
|
||||
|
||||
private:
|
||||
~CredentialsContainer();
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> mParent;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_CredentialsContainer_h
|
|
@ -9,10 +9,14 @@ with Files("**"):
|
|||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'Credential.h',
|
||||
'CredentialsContainer.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'Credential.cpp',
|
||||
'CredentialsContainer.cpp',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
|
|
@ -20,11 +20,7 @@ namespace mozilla {
|
|||
namespace dom {
|
||||
|
||||
struct WebAuthnScopedCredentialDescriptor {
|
||||
// Converted from mozilla::dom::ScopedCredentialType enum
|
||||
uint32_t type;
|
||||
uint8_t[] id;
|
||||
// Converted from mozilla::dom::WebAuthnTransport enum
|
||||
uint32_t[] transports;
|
||||
};
|
||||
|
||||
struct WebAuthnExtension {
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/ScopedCredential.h"
|
||||
#include "mozilla/dom/WebAuthenticationBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
// Only needed for refcounted objects.
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ScopedCredential, mParent)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(ScopedCredential)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(ScopedCredential)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ScopedCredential)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
ScopedCredential::ScopedCredential(nsPIDOMWindowInner* aParent)
|
||||
: mParent(aParent)
|
||||
, mType(ScopedCredentialType::ScopedCred)
|
||||
{}
|
||||
|
||||
ScopedCredential::~ScopedCredential()
|
||||
{}
|
||||
|
||||
JSObject*
|
||||
ScopedCredential::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return ScopedCredentialBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
ScopedCredentialType
|
||||
ScopedCredential::Type() const
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
void
|
||||
ScopedCredential::GetId(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aRetVal) const
|
||||
{
|
||||
aRetVal.set(mIdBuffer.ToUint8Array(aCx));
|
||||
}
|
||||
|
||||
nsresult
|
||||
ScopedCredential::SetType(ScopedCredentialType aType)
|
||||
{
|
||||
mType = aType;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ScopedCredential::SetId(CryptoBuffer& aBuffer)
|
||||
{
|
||||
if (!mIdBuffer.Assign(aBuffer)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -1,66 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_ScopedCredential_h
|
||||
#define mozilla_dom_ScopedCredential_h
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/CryptoBuffer.h"
|
||||
#include "mozilla/dom/WebAuthenticationBinding.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ScopedCredential final : public nsISupports
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ScopedCredential)
|
||||
|
||||
public:
|
||||
explicit ScopedCredential(nsPIDOMWindowInner* aParent);
|
||||
|
||||
protected:
|
||||
~ScopedCredential();
|
||||
|
||||
public:
|
||||
nsISupports*
|
||||
GetParentObject() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
ScopedCredentialType
|
||||
Type() const;
|
||||
|
||||
void
|
||||
GetId(JSContext* aCx, JS::MutableHandle<JSObject*> aRetVal) const;
|
||||
|
||||
nsresult
|
||||
SetType(ScopedCredentialType aType);
|
||||
|
||||
nsresult
|
||||
SetId(CryptoBuffer& aBuffer);
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsPIDOMWindowInner> mParent;
|
||||
CryptoBuffer mIdBuffer;
|
||||
ScopedCredentialType mType;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_ScopedCredential_h
|
|
@ -34,17 +34,6 @@ WebAuthentication::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|||
return WebAuthenticationBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
WebAuthentication::MakeCredential(JSContext* aCx, const Account& aAccount,
|
||||
const Sequence<ScopedCredentialParameters>& aCryptoParameters,
|
||||
const ArrayBufferViewOrArrayBuffer& aChallenge,
|
||||
const ScopedCredentialOptions& aOptions)
|
||||
{
|
||||
RefPtr<WebAuthnManager> mgr = WebAuthnManager::GetOrCreate();
|
||||
MOZ_ASSERT(mgr);
|
||||
return mgr->MakeCredential(mParent, aCx, aAccount, aCryptoParameters, aChallenge, aOptions);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
WebAuthentication::GetAssertion(const ArrayBufferViewOrArrayBuffer& aChallenge,
|
||||
const AssertionOptions& aOptions)
|
||||
|
|
|
@ -42,12 +42,6 @@ public:
|
|||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
already_AddRefed<Promise>
|
||||
MakeCredential(JSContext* aCx, const Account& accountInformation,
|
||||
const Sequence<ScopedCredentialParameters>& cryptoParameters,
|
||||
const ArrayBufferViewOrArrayBuffer& attestationChallenge,
|
||||
const ScopedCredentialOptions& options);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
GetAssertion(const ArrayBufferViewOrArrayBuffer& assertionChallenge,
|
||||
const AssertionOptions& options);
|
||||
|
|
|
@ -40,7 +40,7 @@ NS_IMPL_ISUPPORTS(WebAuthnManager, nsIIPCBackgroundChildCreateCallback);
|
|||
|
||||
template<class OOS>
|
||||
static nsresult
|
||||
GetAlgorithmName(JSContext* aCx, const OOS& aAlgorithm,
|
||||
GetAlgorithmName(const OOS& aAlgorithm,
|
||||
/* out */ nsString& aName)
|
||||
{
|
||||
MOZ_ASSERT(aAlgorithm.IsString()); // TODO: remove assertion when we coerce.
|
||||
|
@ -100,10 +100,10 @@ AssembleClientData(const nsAString& aOrigin, const CryptoBuffer& aChallenge,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
WebAuthnClientData clientDataObject;
|
||||
clientDataObject.mOrigin.Assign(aOrigin);
|
||||
clientDataObject.mHashAlg.SetAsString().Assign(NS_LITERAL_STRING("S256"));
|
||||
CollectedClientData clientDataObject;
|
||||
clientDataObject.mChallenge.Assign(challengeBase64);
|
||||
clientDataObject.mOrigin.Assign(aOrigin);
|
||||
clientDataObject.mHashAlg.Assign(NS_LITERAL_STRING("S256"));
|
||||
|
||||
nsAutoString temp;
|
||||
if (NS_WARN_IF(!clientDataObject.ToJSON(temp))) {
|
||||
|
@ -215,11 +215,8 @@ WebAuthnManager::Get()
|
|||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent, JSContext* aCx,
|
||||
const Account& aAccountInformation,
|
||||
const Sequence<ScopedCredentialParameters>& aCryptoParameters,
|
||||
const ArrayBufferViewOrArrayBuffer& aChallenge,
|
||||
const ScopedCredentialOptions& aOptions)
|
||||
WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent,
|
||||
const MakeCredentialOptions& aOptions)
|
||||
{
|
||||
MOZ_ASSERT(aParent);
|
||||
|
||||
|
@ -245,15 +242,15 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent, JSContext* aCx,
|
|||
// closest value lying within that range.
|
||||
|
||||
double adjustedTimeout = 30.0;
|
||||
if (aOptions.mTimeoutSeconds.WasPassed()) {
|
||||
adjustedTimeout = aOptions.mTimeoutSeconds.Value();
|
||||
if (aOptions.mTimeout.WasPassed()) {
|
||||
adjustedTimeout = aOptions.mTimeout.Value();
|
||||
adjustedTimeout = std::max(15.0, adjustedTimeout);
|
||||
adjustedTimeout = std::min(120.0, adjustedTimeout);
|
||||
}
|
||||
|
||||
nsCString rpId;
|
||||
if (!aOptions.mRpId.WasPassed()) {
|
||||
// If rpId is not specified, then set rpId to callerOrigin, and rpIdHash to
|
||||
if (!aOptions.mRp.mId.WasPassed()) {
|
||||
// If rp.id is not specified, then set rpId to callerOrigin, and rpIdHash to
|
||||
// the SHA-256 hash of rpId.
|
||||
rpId.Assign(NS_ConvertUTF16toUTF8(origin));
|
||||
} else {
|
||||
|
@ -265,7 +262,7 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent, JSContext* aCx,
|
|||
// Otherwise, reject promise with a DOMException whose name is
|
||||
// "SecurityError", and terminate this algorithm.
|
||||
|
||||
if (NS_FAILED(RelaxSameOrigin(aParent, aOptions.mRpId.Value(), rpId))) {
|
||||
if (NS_FAILED(RelaxSameOrigin(aParent, aOptions.mRp.mId.Value(), rpId))) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
@ -293,15 +290,15 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent, JSContext* aCx,
|
|||
|
||||
// Process each element of cryptoParameters using the following steps, to
|
||||
// produce a new sequence normalizedParameters.
|
||||
nsTArray<ScopedCredentialParameters> normalizedParams;
|
||||
for (size_t a = 0; a < aCryptoParameters.Length(); ++a) {
|
||||
nsTArray<PublicKeyCredentialParameters> normalizedParams;
|
||||
for (size_t a = 0; a < aOptions.mParameters.Length(); ++a) {
|
||||
// Let current be the currently selected element of
|
||||
// cryptoParameters.
|
||||
|
||||
// If current.type does not contain a ScopedCredentialType
|
||||
// If current.type does not contain a PublicKeyCredentialType
|
||||
// supported by this implementation, then stop processing current and move
|
||||
// on to the next element in cryptoParameters.
|
||||
if (aCryptoParameters[a].mType != ScopedCredentialType::ScopedCred) {
|
||||
if (aOptions.mParameters[a].mType != PublicKeyCredentialType::Public_key) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -312,16 +309,16 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent, JSContext* aCx,
|
|||
// element in cryptoParameters.
|
||||
|
||||
nsString algName;
|
||||
if (NS_FAILED(GetAlgorithmName(aCx, aCryptoParameters[a].mAlgorithm,
|
||||
if (NS_FAILED(GetAlgorithmName(aOptions.mParameters[a].mAlgorithm,
|
||||
algName))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add a new object of type ScopedCredentialParameters to
|
||||
// Add a new object of type PublicKeyCredentialParameters to
|
||||
// normalizedParameters, with type set to current.type and algorithm set to
|
||||
// normalizedAlgorithm.
|
||||
ScopedCredentialParameters normalizedObj;
|
||||
normalizedObj.mType = aCryptoParameters[a].mType;
|
||||
PublicKeyCredentialParameters normalizedObj;
|
||||
normalizedObj.mType = aOptions.mParameters[a].mType;
|
||||
normalizedObj.mAlgorithm.SetAsString().Assign(algName);
|
||||
|
||||
if (!normalizedParams.AppendElement(normalizedObj, mozilla::fallible)){
|
||||
|
@ -333,7 +330,7 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent, JSContext* aCx,
|
|||
// If normalizedAlgorithm is empty and cryptoParameters was not empty, cancel
|
||||
// the timer started in step 2, reject promise with a DOMException whose name
|
||||
// is "NotSupportedError", and terminate this algorithm.
|
||||
if (normalizedParams.IsEmpty() && !aCryptoParameters.IsEmpty()) {
|
||||
if (normalizedParams.IsEmpty() && !aOptions.mParameters.IsEmpty()) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
@ -341,16 +338,17 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent, JSContext* aCx,
|
|||
// TODO: The following check should not be here. This is checking for
|
||||
// parameters specific to the soft key, and should be put in the soft key
|
||||
// manager in the parent process. Still need to serialize
|
||||
// ScopedCredentialParameters first.
|
||||
// PublicKeyCredentialParameters first.
|
||||
|
||||
// Check if at least one of the specified combinations of ScopedCredentialType
|
||||
// and cryptographic parameters is supported. If not, return an error code
|
||||
// equivalent to NotSupportedError and terminate the operation.
|
||||
// Check if at least one of the specified combinations of
|
||||
// PublicKeyCredentialParameters and cryptographic parameters is supported. If
|
||||
// not, return an error code equivalent to NotSupportedError and terminate the
|
||||
// operation.
|
||||
|
||||
bool isValidCombination = false;
|
||||
|
||||
for (size_t a = 0; a < normalizedParams.Length(); ++a) {
|
||||
if (normalizedParams[a].mType == ScopedCredentialType::ScopedCred &&
|
||||
if (normalizedParams[a].mType == PublicKeyCredentialType::Public_key &&
|
||||
normalizedParams[a].mAlgorithm.IsString() &&
|
||||
normalizedParams[a].mAlgorithm.GetAsString().EqualsLiteral(
|
||||
WEBCRYPTO_NAMED_CURVE_P256)) {
|
||||
|
@ -379,7 +377,7 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent, JSContext* aCx,
|
|||
// and compute the clientDataJSON and clientDataHash.
|
||||
|
||||
CryptoBuffer challenge;
|
||||
if (!challenge.Assign(aChallenge)) {
|
||||
if (!challenge.Assign(aOptions.mChallenge)) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
@ -407,15 +405,9 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent, JSContext* aCx,
|
|||
if (aOptions.mExcludeList.WasPassed()) {
|
||||
for (const auto& s: aOptions.mExcludeList.Value()) {
|
||||
WebAuthnScopedCredentialDescriptor c;
|
||||
c.type() = static_cast<uint32_t>(s.mType);
|
||||
CryptoBuffer cb;
|
||||
cb.Assign(s.mId);
|
||||
c.id() = cb;
|
||||
if (s.mTransports.WasPassed()) {
|
||||
for (const auto& t: s.mTransports.Value()) {
|
||||
c.transports().AppendElement(static_cast<uint32_t>(t));
|
||||
}
|
||||
}
|
||||
excludeList.AppendElement(c);
|
||||
}
|
||||
}
|
||||
|
@ -576,15 +568,9 @@ WebAuthnManager::GetAssertion(nsPIDOMWindowInner* aParent,
|
|||
nsTArray<WebAuthnScopedCredentialDescriptor> allowList;
|
||||
for (const auto& s: aOptions.mAllowList.Value()) {
|
||||
WebAuthnScopedCredentialDescriptor c;
|
||||
c.type() = static_cast<uint32_t>(s.mType);
|
||||
CryptoBuffer cb;
|
||||
cb.Assign(s.mId);
|
||||
c.id() = cb;
|
||||
if (s.mTransports.WasPassed()) {
|
||||
for (const auto& t: s.mTransports.Value()) {
|
||||
c.transports().AppendElement(static_cast<uint32_t>(t));
|
||||
}
|
||||
}
|
||||
allowList.AppendElement(c);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
#ifndef mozilla_dom_WebAuthnManager_h
|
||||
#define mozilla_dom_WebAuthnManager_h
|
||||
|
||||
#include "nsIIPCBackgroundChildCreateCallback.h"
|
||||
#include "mozilla/MozPromise.h"
|
||||
#include "mozilla/dom/PWebAuthnTransaction.h"
|
||||
#include "nsIIPCBackgroundChildCreateCallback.h"
|
||||
|
||||
/*
|
||||
* Content process manager for the WebAuthn protocol. Created on calls to the
|
||||
|
@ -73,11 +73,8 @@ public:
|
|||
Cancel(const nsresult& aError);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
MakeCredential(nsPIDOMWindowInner* aParent, JSContext* aCx,
|
||||
const Account& aAccountInformation,
|
||||
const Sequence<ScopedCredentialParameters>& aCryptoParameters,
|
||||
const ArrayBufferViewOrArrayBuffer& aAttestationChallenge,
|
||||
const ScopedCredentialOptions& aOptions);
|
||||
MakeCredential(nsPIDOMWindowInner* aParent,
|
||||
const MakeCredentialOptions& aOptions);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
GetAssertion(nsPIDOMWindowInner* aParent,
|
||||
|
|
|
@ -17,7 +17,6 @@ EXPORTS.mozilla.dom += [
|
|||
'AuthenticatorResponse.h',
|
||||
'NSSU2FTokenRemote.h',
|
||||
'PublicKeyCredential.h',
|
||||
'ScopedCredential.h',
|
||||
'U2FSoftTokenManager.h',
|
||||
'U2FTokenManager.h',
|
||||
'U2FTokenTransport.h',
|
||||
|
@ -35,7 +34,6 @@ UNIFIED_SOURCES += [
|
|||
'AuthenticatorResponse.cpp',
|
||||
'NSSU2FTokenRemote.cpp',
|
||||
'PublicKeyCredential.cpp',
|
||||
'ScopedCredential.cpp',
|
||||
'U2FSoftTokenManager.cpp',
|
||||
'U2FTokenManager.cpp',
|
||||
'WebAuthentication.cpp',
|
||||
|
|
|
@ -43,8 +43,10 @@
|
|||
|
||||
function runTests() {
|
||||
isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
|
||||
isnot(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint must exist");
|
||||
isnot(navigator.credentials, undefined, "Credential Management API endpoint must exist");
|
||||
is(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint does not exist any longer");
|
||||
isnot(navigator.authentication.getAssertion, undefined, "WebAuthn getAssertion API endpoint must exist");
|
||||
isnot(navigator.credentials.create, undefined, "CredentialManagement create API endpoint must exist");
|
||||
|
||||
let authn = navigator.authentication;
|
||||
|
||||
|
|
|
@ -26,10 +26,13 @@ SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
|
|||
["security.webauth.webauthn_enable_usbtoken", false]]},
|
||||
function() {
|
||||
isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
|
||||
isnot(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint must exist");
|
||||
isnot(navigator.credentials, undefined, "Credential Management API endpoint must exist");
|
||||
is(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint does not exist any longer");
|
||||
isnot(navigator.authentication.getAssertion, undefined, "WebAuthn getAssertion API endpoint must exist");
|
||||
isnot(navigator.credentials.create, undefined, "CredentialManagement create API endpoint must exist");
|
||||
|
||||
let authn = navigator.authentication;
|
||||
let credm = navigator.credentials;
|
||||
|
||||
let gCredentialChallenge = new Uint8Array(16);
|
||||
window.crypto.getRandomValues(gCredentialChallenge);
|
||||
|
@ -103,10 +106,16 @@ function() {
|
|||
}
|
||||
|
||||
function testMakeCredential() {
|
||||
let acct = {rpDisplayName: "none", displayName: "none", id: "none"};
|
||||
let param = {type: "ScopedCred", algorithm: "p-256"};
|
||||
|
||||
authn.makeCredential(acct, [param], gCredentialChallenge)
|
||||
let rp = {id: document.origin, name: "none", icon: "none"};
|
||||
let user = {id: "none", name: "none", icon: "none", displayName: "none"};
|
||||
let param = {type: "public-key", algorithm: "P-256"};
|
||||
let makeCredentialOptions = {
|
||||
rp: rp,
|
||||
user: user,
|
||||
challenge: gCredentialChallenge,
|
||||
parameters: [param]
|
||||
};
|
||||
credm.create({publicKey: makeCredentialOptions})
|
||||
.then(checkCredentialValid)
|
||||
.then(testMakeDuplicate)
|
||||
.catch(function(aReason) {
|
||||
|
@ -116,14 +125,18 @@ function() {
|
|||
}
|
||||
|
||||
function testMakeDuplicate(aCredInfo) {
|
||||
let acct = {rpDisplayName: "none", displayName: "none", id: "none"};
|
||||
let param = {type: "ScopedCred", algorithm: "p-256"};
|
||||
let options = {rpId: document.origin,
|
||||
excludeList: [{type: "ScopedCred",
|
||||
id: Uint8Array.from(aCredInfo.rawId),
|
||||
transports: ["usb"]}]};
|
||||
|
||||
authn.makeCredential(acct, [param], gCredentialChallenge, options)
|
||||
let rp = {id: document.origin, name: "none", icon: "none"};
|
||||
let user = {id: "none", name: "none", icon: "none", displayName: "none"};
|
||||
let param = {type: "public-key", algorithm: "P-256"};
|
||||
let makeCredentialOptions = {
|
||||
rp: rp,
|
||||
user: user,
|
||||
challenge: gCredentialChallenge,
|
||||
parameters: [param],
|
||||
excludeList: [{type: "public-key", id: Uint8Array.from(aCredInfo.rawId),
|
||||
transports: ["usb"]}]
|
||||
};
|
||||
credm.create({publicKey: makeCredentialOptions})
|
||||
.then(function() {
|
||||
// We should have errored here!
|
||||
ok(false, "The excludeList didn't stop a duplicate being created!");
|
||||
|
|
|
@ -16,179 +16,233 @@
|
|||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1309284">Mozilla Bug 1309284</a>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
// Execute the full-scope test
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
// Execute the full-scope test
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function arrivingHereIsGood(aResult) {
|
||||
ok(true, "Good result! Received a: " + aResult);
|
||||
return Promise.resolve();
|
||||
}
|
||||
function arrivingHereIsGood(aResult) {
|
||||
ok(true, "Good result! Received a: " + aResult);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function arrivingHereIsBad(aResult) {
|
||||
ok(false, "Bad result! Received a: " + aResult);
|
||||
return Promise.resolve();
|
||||
}
|
||||
function arrivingHereIsBad(aResult) {
|
||||
ok(false, "Bad result! Received a: " + aResult);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function expectNotAllowedError(aResult) {
|
||||
ok(aResult.toString().startsWith("NotAllowedError"), "Expecting a NotAllowedError");
|
||||
return Promise.resolve();
|
||||
}
|
||||
function expectNotAllowedError(aResult) {
|
||||
ok(aResult.toString().startsWith("NotAllowedError"), "Expecting a NotAllowedError");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function expectTypeError(aResult) {
|
||||
ok(aResult.toString().startsWith("TypeError"), "Expecting a TypeError");
|
||||
return Promise.resolve();
|
||||
}
|
||||
function expectTypeError(aResult) {
|
||||
ok(aResult.toString().startsWith("TypeError"), "Expecting a TypeError");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function expectNotSupportedError(aResult) {
|
||||
ok(aResult.toString().startsWith("NotSupportedError"), "Expecting a NotSupportedError");
|
||||
return Promise.resolve();
|
||||
}
|
||||
function expectNotSupportedError(aResult) {
|
||||
ok(aResult.toString().startsWith("NotSupportedError"), "Expecting a NotSupportedError");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
|
||||
["security.webauth.webauthn_enable_softtoken", true],
|
||||
["security.webauth.webauthn_enable_usbtoken", false]]}, runTests);
|
||||
function runTests() {
|
||||
isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
|
||||
isnot(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint must exist");
|
||||
isnot(navigator.authentication.getAssertion, undefined, "WebAuthn getAssertion API endpoint must exist");
|
||||
SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
|
||||
["security.webauth.webauthn_enable_softtoken", true],
|
||||
["security.webauth.webauthn_enable_usbtoken", false]]}, runTests);
|
||||
function runTests() {
|
||||
isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
|
||||
isnot(navigator.credentials, undefined, "Credential Management API endpoint must exist");
|
||||
is(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint does not exist any longer");
|
||||
isnot(navigator.authentication.getAssertion, undefined, "WebAuthn getAssertion API endpoint must exist");
|
||||
isnot(navigator.credentials.create, undefined, "CredentialManagement create API endpoint must exist");
|
||||
|
||||
let authn = navigator.authentication;
|
||||
let authn = navigator.authentication;
|
||||
let credm = navigator.credentials;
|
||||
|
||||
let gCredentialChallenge = new Uint8Array(16);
|
||||
window.crypto.getRandomValues(gCredentialChallenge);
|
||||
let gCredentialChallenge = new Uint8Array(16);
|
||||
window.crypto.getRandomValues(gCredentialChallenge);
|
||||
|
||||
let acct = {rpDisplayName: "none", displayName: "none", id: "none"};
|
||||
let param = {type: "ScopedCred", algorithm: "p-256"};
|
||||
let unsupportedParam = {type: "ScopedCred", algorithm: "3DES"};
|
||||
let badParam = {type: "SimplePassword", algorithm: "MaxLength=2"};
|
||||
let rp = {id: "none", name: "none", icon: "none"};
|
||||
let user = {id: "none", name: "none", icon: "none", displayName: "none"};
|
||||
let param = {type: "public-key", algorithm: "p-256"};
|
||||
let unsupportedParam = {type: "public-key", algorithm: "3DES"};
|
||||
let badParam = {type: "SimplePassword", algorithm: "MaxLength=2"};
|
||||
|
||||
var testFuncs = [
|
||||
// Test basic good call
|
||||
function() {
|
||||
return authn.makeCredential(acct, [param], gCredentialChallenge)
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
},
|
||||
var testFuncs = [
|
||||
// Test basic good call
|
||||
function() {
|
||||
let makeCredentialOptions = {
|
||||
rp: rp, user: user, challenge: gCredentialChallenge, parameters: [param]
|
||||
};
|
||||
return credm.create({publicKey: makeCredentialOptions})
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
},
|
||||
|
||||
// Test empty account
|
||||
function() {
|
||||
return authn.makeCredential({}, [param], gCredentialChallenge)
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError);
|
||||
},
|
||||
// Test empty account
|
||||
function() {
|
||||
let makeCredentialOptions = {
|
||||
challenge: gCredentialChallenge, parameters: [param]
|
||||
};
|
||||
return credm.create({publicKey: makeCredentialOptions})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError);
|
||||
},
|
||||
|
||||
// Test without a parameter
|
||||
function() {
|
||||
return authn.makeCredential(acct, [], gCredentialChallenge)
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectNotSupportedError);
|
||||
},
|
||||
// Test without a parameter
|
||||
function() {
|
||||
let makeCredentialOptions = {
|
||||
rp: rp, user: user, challenge: gCredentialChallenge, parameters: []
|
||||
};
|
||||
return credm.create({publicKey: makeCredentialOptions})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectNotSupportedError);
|
||||
},
|
||||
|
||||
// Test without a parameter array at all
|
||||
function() {
|
||||
return authn.makeCredential(acct, null, gCredentialChallenge)
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError);
|
||||
},
|
||||
// Test without a parameter array at all
|
||||
function() {
|
||||
let makeCredentialOptions = {
|
||||
rp: rp, user: user, challenge: gCredentialChallenge
|
||||
};
|
||||
return credm.create({publicKey: makeCredentialOptions})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError);
|
||||
},
|
||||
|
||||
// Test with an unsupported parameter
|
||||
function() {
|
||||
return authn.makeCredential(acct, [unsupportedParam], gCredentialChallenge)
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectNotSupportedError);
|
||||
},
|
||||
// Test with an unsupported parameter
|
||||
function() {
|
||||
let makeCredentialOptions = {
|
||||
rp: rp, user: user, challenge: gCredentialChallenge, parameters: [unsupportedParam]
|
||||
};
|
||||
return credm.create({publicKey: makeCredentialOptions})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectNotSupportedError);
|
||||
},
|
||||
|
||||
// Test with an unsupported parameter and a good one
|
||||
function() {
|
||||
return authn.makeCredential(acct, [unsupportedParam, param], gCredentialChallenge)
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
},
|
||||
// Test with an unsupported parameter and a good one
|
||||
function() {
|
||||
let makeCredentialOptions = {
|
||||
rp: rp, user: user, challenge: gCredentialChallenge,
|
||||
parameters: [param, unsupportedParam]
|
||||
};
|
||||
return credm.create({publicKey: makeCredentialOptions})
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
},
|
||||
|
||||
// Test with a bad parameter
|
||||
function() {
|
||||
return authn.makeCredential(acct, [badParam], gCredentialChallenge)
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError);
|
||||
},
|
||||
// Test with a bad parameter
|
||||
function() {
|
||||
let makeCredentialOptions = {
|
||||
rp: rp, user: user, challenge: gCredentialChallenge, parameters: [badParam]
|
||||
};
|
||||
return credm.create({publicKey: makeCredentialOptions})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError);
|
||||
},
|
||||
|
||||
// Test with an unsupported parameter, and a bad one
|
||||
function() {
|
||||
return authn.makeCredential(acct, [unsupportedParam, badParam],
|
||||
gCredentialChallenge)
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError);
|
||||
},
|
||||
// Test with an unsupported parameter, and a bad one
|
||||
function() {
|
||||
let makeCredentialOptions = {
|
||||
rp: rp, user: user, challenge: gCredentialChallenge,
|
||||
parameters: [unsupportedParam, badParam]
|
||||
};
|
||||
return credm.create({publicKey: makeCredentialOptions})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError);
|
||||
},
|
||||
|
||||
// Test with an unsupported parameter, a bad one, and a good one. This
|
||||
// should still fail, as anything with a badParam should fail.
|
||||
function() {
|
||||
return authn.makeCredential(acct, [unsupportedParam, badParam, param],
|
||||
gCredentialChallenge)
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError);
|
||||
},
|
||||
// Test with an unsupported parameter, a bad one, and a good one. This
|
||||
// should still fail, as anything with a badParam should fail.
|
||||
function() {
|
||||
let makeCredentialOptions = {
|
||||
rp: rp, user: user, challenge: gCredentialChallenge,
|
||||
parameters: [param, unsupportedParam, badParam]
|
||||
};
|
||||
return credm.create({publicKey: makeCredentialOptions})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError);
|
||||
},
|
||||
|
||||
// Test without a challenge
|
||||
function() {
|
||||
return authn.makeCredential(acct, [param], null)
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError);
|
||||
},
|
||||
// Test without a challenge
|
||||
function() {
|
||||
let makeCredentialOptions = {
|
||||
rp: rp, user: user, parameters: [param]
|
||||
};
|
||||
return credm.create({publicKey: makeCredentialOptions})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError);
|
||||
},
|
||||
|
||||
// Test with an invalid challenge
|
||||
function() {
|
||||
return authn.makeCredential(acct, [param], "begone, thou ill-fitting moist glove!")
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError);
|
||||
},
|
||||
// Test with an invalid challenge
|
||||
function() {
|
||||
let makeCredentialOptions = {
|
||||
rp: rp, user: user, challenge: "begone, thou ill-fitting moist glove!",
|
||||
parameters: [unsupportedParam]
|
||||
};
|
||||
return credm.create({publicKey: makeCredentialOptions})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError);
|
||||
},
|
||||
|
||||
// Test with duplicate parameters
|
||||
function() {
|
||||
return authn.makeCredential(acct, [param, param, param], gCredentialChallenge)
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
},
|
||||
// Test with duplicate parameters
|
||||
function() {
|
||||
let makeCredentialOptions = {
|
||||
rp: rp, user: user, challenge: gCredentialChallenge,
|
||||
parameters: [param, param, param]
|
||||
};
|
||||
return credm.create({publicKey: makeCredentialOptions})
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
},
|
||||
|
||||
// Test an incomplete account
|
||||
function() {
|
||||
return authn.makeCredential({id: "none"
|
||||
}, [param], gCredentialChallenge)
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError);
|
||||
},
|
||||
// Test with missing rp
|
||||
function() {
|
||||
let makeCredentialOptions = {
|
||||
user: user, challenge: gCredentialChallenge, parameters: [param]
|
||||
};
|
||||
return credm.create({publicKey: makeCredentialOptions})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError);
|
||||
},
|
||||
|
||||
function() {
|
||||
return authn.makeCredential({name: "none", imageURL: "http://example.com/404"},
|
||||
[param], gCredentialChallenge)
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError);
|
||||
},
|
||||
// Test with missing user
|
||||
function() {
|
||||
let makeCredentialOptions = {
|
||||
rp: rp, challenge: gCredentialChallenge, parameters: [param]
|
||||
};
|
||||
return credm.create({publicKey: makeCredentialOptions})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectTypeError);
|
||||
},
|
||||
|
||||
// Test a complete account
|
||||
function() {
|
||||
return authn.makeCredential({rpDisplayName: "Foxxy", displayName: "Foxxy V",
|
||||
id: "foxes_are_the_best@example.com",
|
||||
name: "Fox F. Foxington",
|
||||
imageURL: "https://example.com/fox.svg"},
|
||||
[param], gCredentialChallenge)
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
}];
|
||||
// Test a complete account
|
||||
function() {
|
||||
let completeRP = {id: "Foxxy RP", name: "Foxxy Name",
|
||||
icon: "https://example.com/fox.svg"};
|
||||
let completeUser = {id: "foxes_are_the_best@example.com",
|
||||
name: "Fox F. Foxington",
|
||||
icon: "https://example.com/fox.svg",
|
||||
displayName: "Foxxy V"};
|
||||
let makeCredentialOptions = {
|
||||
rp: completeRP, user: completeUser, challenge: gCredentialChallenge,
|
||||
parameters: [param]
|
||||
};
|
||||
return credm.create({publicKey: makeCredentialOptions})
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
}];
|
||||
|
||||
var i = 0;
|
||||
var runNextTest = () => {
|
||||
if (i == testFuncs.length) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
testFuncs[i]().then(() => { runNextTest(); });
|
||||
i = i + 1;
|
||||
};
|
||||
runNextTest();
|
||||
};
|
||||
var i = 0;
|
||||
var runNextTest = () => {
|
||||
if (i == testFuncs.length) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
testFuncs[i]().then(() => { runNextTest(); });
|
||||
i = i + 1;
|
||||
};
|
||||
runNextTest();
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
|
|
|
@ -27,10 +27,13 @@ SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
|
|||
["security.webauth.webauthn_enable_usbtoken", false]]},
|
||||
function() {
|
||||
isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
|
||||
isnot(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint must exist");
|
||||
isnot(navigator.credentials, undefined, "Credential Management API endpoint must exist");
|
||||
is(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint does not exist any longer");
|
||||
isnot(navigator.authentication.getAssertion, undefined, "WebAuthn getAssertion API endpoint must exist");
|
||||
isnot(navigator.credentials.create, undefined, "CredentialManagement create API endpoint must exist");
|
||||
|
||||
let authn = navigator.authentication;
|
||||
let credm = navigator.credentials;
|
||||
|
||||
let credentialChallenge = new Uint8Array(16);
|
||||
window.crypto.getRandomValues(credentialChallenge);
|
||||
|
@ -42,9 +45,13 @@ function() {
|
|||
testMakeCredential();
|
||||
|
||||
function testMakeCredential() {
|
||||
let acct = {rpDisplayName: "none", displayName: "none", id: "none"};
|
||||
let param = {type: "ScopedCred", algorithm: "p-256"};
|
||||
authn.makeCredential(acct, [param], credentialChallenge)
|
||||
let rp = {id: "none", name: "none", icon: "none"};
|
||||
let user = {id: "none", name: "none", icon: "none", displayName: "none"};
|
||||
let param = {type: "public-key", algorithm: "p-256"};
|
||||
let makeCredentialOptions = {
|
||||
rp: rp, user: user, challenge: credentialChallenge, parameters: [param]
|
||||
};
|
||||
credm.create({publicKey: makeCredentialOptions})
|
||||
.then(function(aResult) {
|
||||
ok(false, "Should have failed.");
|
||||
testAssertion();
|
||||
|
@ -59,10 +66,10 @@ function() {
|
|||
let newCredential = {
|
||||
type: "ScopedCred",
|
||||
id: credentialId,
|
||||
transports: [ "usb" ],
|
||||
transports: ["usb"],
|
||||
}
|
||||
let assertOptions = {rpId: document.origin, timeoutSeconds: 5,
|
||||
allowList: [ newCredential ]};
|
||||
allowList: [newCredential]};
|
||||
authn.getAssertion(assertionChallenge, assertOptions)
|
||||
.then(function(aResult) {
|
||||
ok(false, "Should have failed.");
|
||||
|
|
|
@ -16,169 +16,195 @@
|
|||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1309284">Mozilla Bug 1309284</a>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
// Execute the full-scope test
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
// Execute the full-scope test
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var gTrackedCredential = {};
|
||||
var gTrackedCredential = {};
|
||||
|
||||
function arrivingHereIsGood(aResult) {
|
||||
ok(true, "Good result! Received a: " + aResult);
|
||||
return Promise.resolve();
|
||||
}
|
||||
function arrivingHereIsGood(aResult) {
|
||||
ok(true, "Good result! Received a: " + aResult);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function arrivingHereIsBad(aResult) {
|
||||
// TODO: Change to `ok` when Bug 1329764 lands
|
||||
todo(false, "Bad result! Received a: " + aResult);
|
||||
return Promise.resolve();
|
||||
}
|
||||
function arrivingHereIsBad(aResult) {
|
||||
// TODO: Change to `ok` when Bug 1329764 lands
|
||||
todo(false, "Bad result! Received a: " + aResult);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function expectSecurityError(aResult) {
|
||||
// TODO: Change to `ok` when Bug 1329764 lands
|
||||
todo(aResult.toString().startsWith("SecurityError"), "Expecting a SecurityError");
|
||||
return Promise.resolve();
|
||||
}
|
||||
function expectSecurityError(aResult) {
|
||||
// TODO: Change to `ok` when Bug 1329764 lands
|
||||
todo(aResult.toString().startsWith("SecurityError"), "Expecting a SecurityError");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function keepThisPublicKeyCredential(aPublicKeyCredential) {
|
||||
gTrackedCredential = {
|
||||
type: "ScopedCred",
|
||||
id: Uint8Array.from(aPublicKeyCredential.rawId),
|
||||
transports: [ "usb" ],
|
||||
}
|
||||
return Promise.resolve(aPublicKeyCredential);
|
||||
}
|
||||
function keepThisPublicKeyCredential(aPublicKeyCredential) {
|
||||
gTrackedCredential = {
|
||||
type: "ScopedCred",
|
||||
id: Uint8Array.from(aPublicKeyCredential.rawId),
|
||||
transports: [ "usb" ],
|
||||
}
|
||||
return Promise.resolve(aPublicKeyCredential);
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
|
||||
isnot(navigator.authentication.makeCredential, undefined,
|
||||
"WebAuthn makeCredential API endpoint must exist");
|
||||
isnot(navigator.authentication.getAssertion, undefined,
|
||||
"WebAuthn getAssertion API endpoint must exist");
|
||||
function runTests() {
|
||||
isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
|
||||
isnot(navigator.credentials, undefined, "Credential Management API endpoint must exist");
|
||||
is(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint does not exist any longer");
|
||||
isnot(navigator.authentication.getAssertion, undefined, "WebAuthn getAssertion API endpoint must exist");
|
||||
isnot(navigator.credentials.create, undefined, "CredentialManagement create API endpoint must exist");
|
||||
|
||||
let authn = navigator.authentication;
|
||||
let authn = navigator.authentication;
|
||||
let credm = navigator.credentials;
|
||||
|
||||
let chall = new Uint8Array(16);
|
||||
window.crypto.getRandomValues(chall);
|
||||
let chall = new Uint8Array(16);
|
||||
window.crypto.getRandomValues(chall);
|
||||
|
||||
let acct = {rpDisplayName: "none", displayName: "none", id: "none"};
|
||||
let param = {type: "ScopedCred", algorithm: "p-256"};
|
||||
let user = {id: "none", name: "none", icon: "none", displayName: "none"};
|
||||
let param = {type: "public-key", algorithm: "p-256"};
|
||||
|
||||
var testFuncs = [
|
||||
function() {
|
||||
// Test basic good call
|
||||
return authn.makeCredential(acct, [param], chall, {rpId: document.origin})
|
||||
.then(keepThisPublicKeyCredential)
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
},
|
||||
var testFuncs = [
|
||||
function() {
|
||||
// Test basic good call
|
||||
let rp = {id: document.origin};
|
||||
let makeCredentialOptions = {
|
||||
rp: rp, user: user, challenge: chall, parameters: [param]
|
||||
};
|
||||
return credm.create({publicKey: makeCredentialOptions})
|
||||
.then(keepThisPublicKeyCredential)
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
},
|
||||
|
||||
function() {
|
||||
// Test rpId being unset
|
||||
return authn.makeCredential(acct, [param], chall, {})
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
},
|
||||
function() {
|
||||
// Test this origin with optional fields
|
||||
return authn.makeCredential(acct, [param], chall,
|
||||
{rpId: "user:pass@" + document.origin + ":8888"})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError);
|
||||
},
|
||||
function() {
|
||||
// Test blank rpId
|
||||
return authn.makeCredential(acct, [param], chall, {rpId: ""})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError);
|
||||
},
|
||||
function() {
|
||||
// Test subdomain of this origin
|
||||
return authn.makeCredential(acct, [param], chall,
|
||||
{rpId: "subdomain." + document.origin})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError);
|
||||
},
|
||||
function() {
|
||||
// Test another origin
|
||||
return authn.makeCredential(acct, [param], chall, {rpId: "example.com"})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError);
|
||||
},
|
||||
function () {
|
||||
// est a different domain within the same TLD
|
||||
return authn.makeCredential(acct, [param], chall, {rpId: "alt.test"})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError);
|
||||
},
|
||||
function () {
|
||||
// Test basic good call
|
||||
return authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
|
||||
rpId: document.origin})
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
},
|
||||
function () {
|
||||
// Test rpId being unset
|
||||
return authn.getAssertion(chall, {allowList: [ gTrackedCredential ]})
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
},
|
||||
function () {
|
||||
// Test this origin with optional fields
|
||||
return authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
|
||||
rpId: "user:pass@" + document.origin + ":8888"})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError);
|
||||
},
|
||||
function () {
|
||||
// Test blank rpId
|
||||
return authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
|
||||
rpId: ""})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError);
|
||||
},
|
||||
function () {
|
||||
// Test subdomain of this origin
|
||||
return authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
|
||||
rpId: "subdomain." + document.origin})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError);
|
||||
},
|
||||
function () {
|
||||
// Test another origin
|
||||
return authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
|
||||
rpId: "example.com"})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError);
|
||||
},
|
||||
function () {
|
||||
// Test a different domain within the same TLD
|
||||
return authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
|
||||
rpId: "alt.test"})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError)
|
||||
},
|
||||
function () {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
];
|
||||
var i = 0;
|
||||
var runNextTest = () => {
|
||||
if (i == testFuncs.length) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
console.log(i);
|
||||
testFuncs[i]().then(() => { runNextTest(); });
|
||||
i = i + 1;
|
||||
};
|
||||
runNextTest();
|
||||
};
|
||||
SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
|
||||
["security.webauth.webauthn_enable_softtoken", true],
|
||||
["security.webauth.webauthn_enable_usbtoken", false]]},
|
||||
runTests);
|
||||
function() {
|
||||
// Test rp.id being unset
|
||||
let makeCredentialOptions = {
|
||||
rp: {}, user: user, challenge: chall, parameters: [param]
|
||||
};
|
||||
return credm.create({publicKey: makeCredentialOptions})
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
},
|
||||
function() {
|
||||
// Test this origin with optional fields
|
||||
let rp = {id: "user:pass@" + document.origin + ":8888"};
|
||||
let makeCredentialOptions = {
|
||||
rp: rp, user: user, challenge: chall, parameters: [param]
|
||||
};
|
||||
return credm.create({publicKey: makeCredentialOptions})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError);
|
||||
},
|
||||
function() {
|
||||
// Test blank rp.id
|
||||
let rp = {id: ""};
|
||||
let makeCredentialOptions = {
|
||||
rp: rp, user: user, challenge: chall, parameters: [param]
|
||||
};
|
||||
return credm.create({publicKey: makeCredentialOptions})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError);
|
||||
},
|
||||
function() {
|
||||
// Test subdomain of this origin
|
||||
let rp = {id: "subdomain." + document.origin};
|
||||
let makeCredentialOptions = {
|
||||
rp: rp, user: user, challenge: chall, parameters: [param]
|
||||
};
|
||||
return credm.create({publicKey: makeCredentialOptions})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError);
|
||||
},
|
||||
function() {
|
||||
// Test another origin
|
||||
let rp = {id: "example.com"};
|
||||
let makeCredentialOptions = {
|
||||
rp: rp, user: user, challenge: chall, parameters: [param]
|
||||
};
|
||||
return credm.create({publicKey: makeCredentialOptions})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError);
|
||||
},
|
||||
function () {
|
||||
// Test a different domain within the same TLD
|
||||
let rp = {id: "alt.test"};
|
||||
let makeCredentialOptions = {
|
||||
rp: rp, user: user, challenge: chall, parameters: [param]
|
||||
};
|
||||
return credm.create({publicKey: makeCredentialOptions})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError);
|
||||
},
|
||||
function () {
|
||||
// Test basic good call
|
||||
return authn.getAssertion(chall, {allowList: [gTrackedCredential],
|
||||
rpId: document.origin})
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
},
|
||||
function () {
|
||||
// Test rpId being unset
|
||||
return authn.getAssertion(chall, {allowList: [gTrackedCredential]})
|
||||
.then(arrivingHereIsGood)
|
||||
.catch(arrivingHereIsBad);
|
||||
},
|
||||
function () {
|
||||
// Test this origin with optional fields
|
||||
return authn.getAssertion(chall, {allowList: [gTrackedCredential],
|
||||
rpId: "user:pass@" + document.origin + ":8888"})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError);
|
||||
},
|
||||
function () {
|
||||
// Test blank rpId
|
||||
return authn.getAssertion(chall, {allowList: [gTrackedCredential],
|
||||
rpId: ""})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError);
|
||||
},
|
||||
function () {
|
||||
// Test subdomain of this origin
|
||||
return authn.getAssertion(chall, {allowList: [gTrackedCredential],
|
||||
rpId: "subdomain." + document.origin})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError);
|
||||
},
|
||||
function () {
|
||||
// Test another origin
|
||||
return authn.getAssertion(chall, {allowList: [gTrackedCredential],
|
||||
rpId: "example.com"})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError);
|
||||
},
|
||||
function () {
|
||||
// Test a different domain within the same TLD
|
||||
return authn.getAssertion(chall, {allowList: [gTrackedCredential],
|
||||
rpId: "alt.test"})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectSecurityError)
|
||||
},
|
||||
function () {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
];
|
||||
var i = 0;
|
||||
var runNextTest = () => {
|
||||
if (i == testFuncs.length) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
console.log(i);
|
||||
testFuncs[i]().then(() => { runNextTest(); });
|
||||
i = i + 1;
|
||||
};
|
||||
runNextTest();
|
||||
};
|
||||
SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
|
||||
["security.webauth.webauthn_enable_softtoken", true],
|
||||
["security.webauth.webauthn_enable_usbtoken", false]]},
|
||||
runTests);
|
||||
|
||||
</script>
|
||||
|
||||
|
|
|
@ -12,3 +12,12 @@ interface Credential {
|
|||
readonly attribute USVString id;
|
||||
readonly attribute DOMString type;
|
||||
};
|
||||
|
||||
[Exposed=Window, SecureContext, Pref="security.webauth.webauthn"]
|
||||
interface CredentialsContainer {
|
||||
Promise<Credential?> create(optional CredentialCreationOptions options);
|
||||
};
|
||||
|
||||
dictionary CredentialCreationOptions {
|
||||
MakeCredentialOptions publicKey;
|
||||
};
|
||||
|
|
|
@ -373,3 +373,8 @@ partial interface Navigator {
|
|||
[Pref="security.webauth.webauthn", SameObject]
|
||||
readonly attribute WebAuthentication authentication;
|
||||
};
|
||||
|
||||
partial interface Navigator {
|
||||
[Pref="security.webauth.webauthn", SameObject]
|
||||
readonly attribute CredentialsContainer credentials;
|
||||
};
|
||||
|
|
|
@ -27,28 +27,67 @@ interface AuthenticatorAttestationResponse : AuthenticatorResponse {
|
|||
readonly attribute ArrayBuffer attestationObject;
|
||||
};
|
||||
|
||||
dictionary Account {
|
||||
required DOMString rpDisplayName;
|
||||
required DOMString displayName;
|
||||
required DOMString id;
|
||||
DOMString name;
|
||||
DOMString imageURL;
|
||||
dictionary PublicKeyCredentialParameters {
|
||||
required PublicKeyCredentialType type;
|
||||
required WebAuthnAlgorithmID algorithm; // NOTE: changed from AllgorithmIdentifier because typedef (object or DOMString) not serializable
|
||||
};
|
||||
|
||||
dictionary PublicKeyCredentialUserEntity : PublicKeyCredentialEntity {
|
||||
DOMString displayName;
|
||||
};
|
||||
|
||||
dictionary MakeCredentialOptions {
|
||||
required PublicKeyCredentialEntity rp;
|
||||
required PublicKeyCredentialUserEntity user;
|
||||
|
||||
required BufferSource challenge;
|
||||
required sequence<PublicKeyCredentialParameters> parameters;
|
||||
|
||||
unsigned long timeout;
|
||||
sequence<PublicKeyCredentialDescriptor> excludeList;
|
||||
AuthenticatorSelectionCriteria authenticatorSelection;
|
||||
// Extensions are not supported yet.
|
||||
// AuthenticationExtensions extensions;
|
||||
};
|
||||
|
||||
dictionary PublicKeyCredentialEntity {
|
||||
DOMString id;
|
||||
DOMString name;
|
||||
USVString icon;
|
||||
};
|
||||
|
||||
dictionary AuthenticatorSelectionCriteria {
|
||||
Attachment attachment;
|
||||
boolean requireResidentKey = false;
|
||||
};
|
||||
|
||||
enum Attachment {
|
||||
"platform",
|
||||
"cross-platform"
|
||||
};
|
||||
|
||||
dictionary CollectedClientData {
|
||||
required DOMString challenge;
|
||||
required DOMString origin;
|
||||
required DOMString hashAlg;
|
||||
DOMString tokenBinding;
|
||||
// Extensions are not supported yet.
|
||||
// AuthenticationExtensions clientExtensions;
|
||||
// AuthenticationExtensions authenticatorExtensions;
|
||||
};
|
||||
|
||||
enum PublicKeyCredentialType {
|
||||
"public-key"
|
||||
};
|
||||
|
||||
dictionary PublicKeyCredentialDescriptor {
|
||||
required PublicKeyCredentialType type;
|
||||
required BufferSource id;
|
||||
sequence<WebAuthnTransport> transports;
|
||||
};
|
||||
|
||||
typedef (boolean or DOMString) WebAuthnAlgorithmID; // Fix when upstream there's a definition of how to serialize AlgorithmIdentifier
|
||||
|
||||
dictionary ScopedCredentialParameters {
|
||||
required ScopedCredentialType type;
|
||||
required WebAuthnAlgorithmID algorithm; // NOTE: changed from AllgorithmIdentifier because typedef (object or DOMString) not serializable
|
||||
};
|
||||
|
||||
dictionary ScopedCredentialOptions {
|
||||
unsigned long timeoutSeconds;
|
||||
USVString rpId;
|
||||
sequence<ScopedCredentialDescriptor> excludeList;
|
||||
WebAuthnExtensions extensions;
|
||||
};
|
||||
|
||||
[SecureContext, Pref="security.webauth.webauthn"]
|
||||
interface AuthenticatorAssertionResponse : AuthenticatorResponse {
|
||||
readonly attribute ArrayBuffer authenticatorData;
|
||||
|
@ -65,25 +104,10 @@ dictionary AssertionOptions {
|
|||
dictionary WebAuthnExtensions {
|
||||
};
|
||||
|
||||
// Renamed from "ClientData" to avoid a collision with U2F
|
||||
dictionary WebAuthnClientData {
|
||||
required DOMString challenge;
|
||||
required DOMString origin;
|
||||
required WebAuthnAlgorithmID hashAlg; // NOTE: changed from AllgorithmIdentifier because typedef (object or DOMString) not serializable
|
||||
DOMString tokenBinding;
|
||||
WebAuthnExtensions extensions;
|
||||
};
|
||||
|
||||
enum ScopedCredentialType {
|
||||
"ScopedCred"
|
||||
};
|
||||
|
||||
[SecureContext, Pref="security.webauth.webauthn"]
|
||||
interface ScopedCredential {
|
||||
readonly attribute ScopedCredentialType type;
|
||||
readonly attribute ArrayBuffer id;
|
||||
};
|
||||
|
||||
dictionary ScopedCredentialDescriptor {
|
||||
required ScopedCredentialType type;
|
||||
required BufferSource id;
|
||||
|
@ -101,13 +125,6 @@ enum WebAuthnTransport {
|
|||
|
||||
[SecureContext, Pref="security.webauth.webauthn"]
|
||||
interface WebAuthentication {
|
||||
Promise<PublicKeyCredential> makeCredential (
|
||||
Account accountInformation,
|
||||
sequence<ScopedCredentialParameters> cryptoParameters,
|
||||
BufferSource attestationChallenge,
|
||||
optional ScopedCredentialOptions options
|
||||
);
|
||||
|
||||
Promise<PublicKeyCredential> getAssertion (
|
||||
BufferSource assertionChallenge,
|
||||
optional AssertionOptions options
|
||||
|
|
Загрузка…
Ссылка в новой задаче