Bug 1842303 - remove some unused nsIOSKeyStore functions r=nkulatova

Differential Revision: https://phabricator.services.mozilla.com/D183054
This commit is contained in:
Dana Keeler 2023-07-11 16:47:11 +00:00
Родитель 3efc235517
Коммит f149487bb4
12 изменённых файлов: 4 добавлений и 465 удалений

Просмотреть файл

@ -39,17 +39,6 @@ CredentialManagerSecret::CredentialManagerSecret() {}
CredentialManagerSecret::~CredentialManagerSecret() {}
nsresult CredentialManagerSecret::Lock() {
// The Windows credential manager can't be locked.
return NS_OK;
}
nsresult CredentialManagerSecret::Unlock() {
// The Windows credential manager is always unlocked when the user is logged
// in.
return NS_OK;
}
nsresult CredentialManagerSecret::StoreSecret(const nsACString& aSecret,
const nsACString& aLabel) {
if (aSecret.Length() > CRED_MAX_CREDENTIAL_BLOB_SIZE) {

Просмотреть файл

@ -19,8 +19,6 @@ class CredentialManagerSecret final : public AbstractOSKeyStore {
virtual nsresult StoreSecret(const nsACString& secret,
const nsACString& label) override;
virtual nsresult DeleteSecret(const nsACString& label) override;
virtual nsresult Lock() override;
virtual nsresult Unlock() override;
virtual ~CredentialManagerSecret();
};

Просмотреть файл

@ -21,32 +21,6 @@ KeychainSecret::KeychainSecret() {}
KeychainSecret::~KeychainSecret() {}
nsresult KeychainSecret::Lock() {
// https://developer.apple.com/documentation/security/1402180-seckeychainlock
// Passing `nullptr` locks the default keychain.
OSStatus rv = SecKeychainLock(nullptr);
if (rv != errSecSuccess) {
MOZ_LOG(gKeychainSecretLog, LogLevel::Debug,
("SecKeychainLock failed: %d", rv));
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult KeychainSecret::Unlock() {
// https://developer.apple.com/documentation/security/1400341-seckeychainunlock
// This attempts to unlock the default keychain. Using `false` indicates we
// aren't passing in a password (if the keychain is locked, a dialog will
// appear for the user).
OSStatus rv = SecKeychainUnlock(nullptr, 0, nullptr, false);
if (rv != errSecSuccess) {
MOZ_LOG(gKeychainSecretLog, LogLevel::Debug,
("SecKeychainUnlock failed: %d", rv));
return NS_ERROR_FAILURE;
}
return NS_OK;
}
ScopedCFType<CFStringRef> MozillaStringToCFString(const nsACString& stringIn) {
// https://developer.apple.com/documentation/corefoundation/1543419-cfstringcreatewithbytes
ScopedCFType<CFStringRef> stringOut(CFStringCreateWithBytes(

Просмотреть файл

@ -40,8 +40,6 @@ class KeychainSecret final : public AbstractOSKeyStore {
virtual nsresult StoreSecret(const nsACString& secret,
const nsACString& label) override;
virtual nsresult DeleteSecret(const nsACString& label) override;
virtual nsresult Lock() override;
virtual nsresult Unlock() override;
virtual ~KeychainSecret();
};

Просмотреть файл

@ -84,10 +84,6 @@ typedef SecretCollection* (*secret_collection_for_alias_sync_fn)(
GError**);
typedef SecretService* (*secret_service_get_sync_fn)(SecretServiceFlags,
GCancellable*, GError**);
typedef gint (*secret_service_lock_sync_fn)(SecretService*, GList*,
GCancellable*, GList**, GError**);
typedef gint (*secret_service_unlock_sync_fn)(SecretService*, GList*,
GCancellable*, GList**, GError**);
typedef gboolean (*secret_password_clear_sync_fn)(const SecretSchema*,
GCancellable*, GError**, ...);
typedef gchar* (*secret_password_lookup_sync_fn)(const SecretSchema*,
@ -102,8 +98,6 @@ typedef GQuark (*secret_error_get_quark_fn)();
static secret_collection_for_alias_sync_fn secret_collection_for_alias_sync =
nullptr;
static secret_service_get_sync_fn secret_service_get_sync = nullptr;
static secret_service_lock_sync_fn secret_service_lock_sync = nullptr;
static secret_service_unlock_sync_fn secret_service_unlock_sync = nullptr;
static secret_password_clear_sync_fn secret_password_clear_sync = nullptr;
static secret_password_lookup_sync_fn secret_password_lookup_sync = nullptr;
static secret_password_store_sync_fn secret_password_store_sync = nullptr;
@ -142,8 +136,6 @@ nsresult MaybeLoadLibSecret() {
}
FIND_FUNCTION_SYMBOL(secret_collection_for_alias_sync);
FIND_FUNCTION_SYMBOL(secret_service_get_sync);
FIND_FUNCTION_SYMBOL(secret_service_lock_sync);
FIND_FUNCTION_SYMBOL(secret_service_unlock_sync);
FIND_FUNCTION_SYMBOL(secret_password_clear_sync);
FIND_FUNCTION_SYMBOL(secret_password_lookup_sync);
FIND_FUNCTION_SYMBOL(secret_password_store_sync);
@ -201,8 +193,6 @@ LibSecret::~LibSecret() {
if (libsecret) {
secret_collection_for_alias_sync = nullptr;
secret_service_get_sync = nullptr;
secret_service_lock_sync = nullptr;
secret_service_unlock_sync = nullptr;
secret_password_clear_sync = nullptr;
secret_password_lookup_sync = nullptr;
secret_password_store_sync = nullptr;
@ -250,60 +240,6 @@ nsresult GetScopedServices(ScopedSecretService& aSs,
return NS_OK;
}
nsresult LibSecret::Lock() {
MOZ_ASSERT(secret_service_lock_sync);
if (!secret_service_lock_sync) {
return NS_ERROR_FAILURE;
}
ScopedSecretService ss;
ScopedSecretCollection sc;
if (NS_FAILED(GetScopedServices(ss, sc))) {
return NS_ERROR_FAILURE;
}
GError* raw_error = nullptr;
GList* collections = nullptr;
ScopedGList collectionList(g_list_append(collections, sc.get()));
int numLocked = secret_service_lock_sync(ss.get(), collectionList.get(),
nullptr, // GCancellable
nullptr, // list of locked items
&raw_error);
ScopedGError error(raw_error);
if (numLocked != 1) {
MOZ_LOG(gLibSecretLog, LogLevel::Debug,
("Couldn't lock secret collection"));
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult LibSecret::Unlock() {
MOZ_ASSERT(secret_service_unlock_sync);
if (!secret_service_unlock_sync) {
return NS_ERROR_FAILURE;
}
// Accessing the secret service might unlock it.
ScopedSecretService ss;
ScopedSecretCollection sc;
if (NS_FAILED(GetScopedServices(ss, sc))) {
return NS_ERROR_FAILURE;
}
GError* raw_error = nullptr;
GList* collections = nullptr;
ScopedGList collectionList(g_list_append(collections, sc.get()));
int numLocked = secret_service_unlock_sync(ss.get(), collectionList.get(),
nullptr, // GCancellable
nullptr, // list of unlocked items
&raw_error);
ScopedGError error(raw_error);
if (numLocked != 1) {
MOZ_LOG(gLibSecretLog, LogLevel::Debug,
("Couldn't unlock secret collection"));
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult LibSecret::StoreSecret(const nsACString& aSecret,
const nsACString& aLabel) {
MOZ_ASSERT(secret_password_store_sync);

Просмотреть файл

@ -22,8 +22,6 @@ class LibSecret final : public AbstractOSKeyStore {
virtual nsresult StoreSecret(const nsACString& secret,
const nsACString& label) override;
virtual nsresult DeleteSecret(const nsACString& label) override;
virtual nsresult Lock() override;
virtual nsresult Unlock() override;
virtual ~LibSecret();
};

Просмотреть файл

@ -48,71 +48,9 @@ nsresult NSSKeyStore::InitToken() {
return NS_OK;
}
nsresult NSSKeyStoreMainThreadLock(PK11SlotInfo* aSlot) {
nsCOMPtr<nsIPK11Token> token = new nsPK11Token(aSlot);
return token->LogoutSimple();
}
nsresult NSSKeyStore::Lock() {
NS_ENSURE_STATE(mSlot);
if (!NS_IsMainThread()) {
nsCOMPtr<nsIThread> mainThread;
nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread));
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
// Forward to the main thread synchronously.
SyncRunnable::DispatchToThread(
mainThread, NS_NewRunnableFunction("NSSKeyStoreMainThreadLock",
[slot = mSlot.get()]() {
NSSKeyStoreMainThreadLock(slot);
}));
return NS_OK;
}
return NSSKeyStoreMainThreadLock(mSlot.get());
}
nsresult NSSKeyStoreMainThreadUnlock(PK11SlotInfo* aSlot) {
nsCOMPtr<nsIPK11Token> token = new nsPK11Token(aSlot);
return NS_FAILED(token->Login(false /* force */)) ? NS_ERROR_FAILURE : NS_OK;
}
nsresult NSSKeyStore::Unlock() {
NS_ENSURE_STATE(mSlot);
if (!NS_IsMainThread()) {
nsCOMPtr<nsIThread> mainThread;
nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread));
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
// Forward to the main thread synchronously.
nsresult result = NS_ERROR_FAILURE;
SyncRunnable::DispatchToThread(
mainThread,
NS_NewRunnableFunction("NSSKeyStoreMainThreadUnlock",
[slot = mSlot.get(), result = &result]() {
*result = NSSKeyStoreMainThreadUnlock(slot);
}));
return result;
}
return NSSKeyStoreMainThreadUnlock(mSlot.get());
}
nsresult NSSKeyStore::StoreSecret(const nsACString& aSecret,
const nsACString& aLabel) {
NS_ENSURE_STATE(mSlot);
if (NS_FAILED(Unlock())) {
MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error unlocking NSS key db"));
return NS_ERROR_FAILURE;
}
// It is possible for multiple keys to have the same nickname in NSS. To
// prevent the problem of not knowing which key to use in the future, simply
@ -159,10 +97,6 @@ nsresult NSSKeyStore::StoreSecret(const nsACString& aSecret,
nsresult NSSKeyStore::DeleteSecret(const nsACString& aLabel) {
NS_ENSURE_STATE(mSlot);
if (NS_FAILED(Unlock())) {
MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error unlocking NSS key db"));
return NS_ERROR_FAILURE;
}
UniquePK11SymKey symKey(PK11_ListFixedKeysInSlot(
mSlot.get(), const_cast<char*>(PromiseFlatCString(aLabel).get()),
@ -185,10 +119,6 @@ bool NSSKeyStore::SecretAvailable(const nsACString& aLabel) {
if (!mSlot) {
return false;
}
if (NS_FAILED(Unlock())) {
MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error unlocking NSS key db"));
return false;
}
UniquePK11SymKey symKey(PK11_ListFixedKeysInSlot(
mSlot.get(), const_cast<char*>(PromiseFlatCString(aLabel).get()),
@ -204,10 +134,6 @@ nsresult NSSKeyStore::EncryptDecrypt(const nsACString& aLabel,
std::vector<uint8_t>& outBytes,
bool encrypt) {
NS_ENSURE_STATE(mSlot);
if (NS_FAILED(Unlock())) {
MOZ_LOG(gNSSKeyStoreLog, LogLevel::Debug, ("Error unlocking NSS key db"));
return NS_ERROR_FAILURE;
}
UniquePK11SymKey symKey(PK11_ListFixedKeysInSlot(
mSlot.get(), const_cast<char*>(PromiseFlatCString(aLabel).get()),

Просмотреть файл

@ -19,8 +19,6 @@ class NSSKeyStore final : public AbstractOSKeyStore {
virtual nsresult StoreSecret(const nsACString& secret,
const nsACString& label) override;
virtual nsresult DeleteSecret(const nsACString& label) override;
virtual nsresult Lock() override;
virtual nsresult Unlock() override;
virtual nsresult EncryptDecrypt(const nsACString& label,
const std::vector<uint8_t>& inBytes,
std::vector<uint8_t>& outBytes,

Просмотреть файл

@ -28,7 +28,7 @@ NS_IMPL_ISUPPORTS(OSKeyStore, nsIOSKeyStore)
using namespace mozilla;
using dom::Promise;
OSKeyStore::OSKeyStore() : mKs(nullptr), mKsIsNSSKeyStore(false) {
OSKeyStore::OSKeyStore() : mKs(nullptr) {
MOZ_ASSERT(NS_IsMainThread());
if (NS_WARN_IF(!NS_IsMainThread())) {
return;
@ -43,11 +43,9 @@ OSKeyStore::OSKeyStore() : mKs(nullptr), mKsIsNSSKeyStore(false) {
mKs.reset(new LibSecret());
} else {
mKs.reset(new NSSKeyStore());
mKsIsNSSKeyStore = true;
}
#else
mKs.reset(new NSSKeyStore());
mKsIsNSSKeyStore = true;
#endif
}
@ -185,23 +183,6 @@ nsresult OSKeyStore::DecryptBytes(const nsACString& aLabel,
return NS_OK;
}
nsresult OSKeyStore::Lock() {
NS_ENSURE_STATE(mKs);
return mKs->Lock();
}
nsresult OSKeyStore::Unlock() {
NS_ENSURE_STATE(mKs);
return mKs->Unlock();
}
NS_IMETHODIMP
OSKeyStore::GetIsNSSKeyStore(bool* aNSSKeyStore) {
NS_ENSURE_ARG_POINTER(aNSSKeyStore);
*aNSSKeyStore = mKsIsNSSKeyStore;
return NS_OK;
}
// Async interfaces that return promises because the key store implementation
// might block, e.g. asking for a password.
@ -218,85 +199,6 @@ nsresult GetPromise(JSContext* aCx, /* out */ RefPtr<Promise>& aPromise) {
return NS_OK;
}
void BackgroundUnlock(RefPtr<Promise>& aPromise, RefPtr<OSKeyStore> self) {
nsAutoCString recovery;
nsresult rv = self->Unlock();
nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
"BackgroundUnlockOSKSResolve", [rv, aPromise = std::move(aPromise)]() {
if (NS_FAILED(rv)) {
aPromise->MaybeReject(rv);
} else {
aPromise->MaybeResolveWithUndefined();
}
}));
NS_DispatchToMainThread(runnable.forget());
}
NS_IMETHODIMP
OSKeyStore::AsyncUnlock(JSContext* aCx, Promise** promiseOut) {
MOZ_ASSERT(NS_IsMainThread());
if (!NS_IsMainThread()) {
return NS_ERROR_NOT_SAME_THREAD;
}
NS_ENSURE_ARG_POINTER(aCx);
RefPtr<Promise> promiseHandle;
nsresult rv = GetPromise(aCx, promiseHandle);
if (NS_FAILED(rv)) {
return rv;
}
RefPtr<OSKeyStore> self = this;
nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
"BackgroundUnlock", [self, promiseHandle]() mutable {
BackgroundUnlock(promiseHandle, self);
}));
promiseHandle.forget(promiseOut);
return NS_DispatchBackgroundTask(runnable.forget(),
NS_DISPATCH_EVENT_MAY_BLOCK);
}
void BackgroundLock(RefPtr<Promise>& aPromise, RefPtr<OSKeyStore> self) {
nsresult rv = self->Lock();
nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
"BackgroundLockOSKSResolve", [rv, aPromise = std::move(aPromise)]() {
if (NS_FAILED(rv)) {
aPromise->MaybeReject(rv);
} else {
aPromise->MaybeResolveWithUndefined();
}
}));
NS_DispatchToMainThread(runnable.forget());
}
NS_IMETHODIMP
OSKeyStore::AsyncLock(JSContext* aCx, Promise** promiseOut) {
MOZ_ASSERT(NS_IsMainThread());
if (!NS_IsMainThread()) {
return NS_ERROR_NOT_SAME_THREAD;
}
NS_ENSURE_ARG_POINTER(aCx);
RefPtr<Promise> promiseHandle;
nsresult rv = GetPromise(aCx, promiseHandle);
if (NS_FAILED(rv)) {
return rv;
}
RefPtr<OSKeyStore> self = this;
nsCOMPtr<nsIRunnable> runnable(
NS_NewRunnableFunction("BackgroundLock", [self, promiseHandle]() mutable {
BackgroundLock(promiseHandle, self);
}));
promiseHandle.forget(promiseOut);
return NS_DispatchBackgroundTask(runnable.forget(),
NS_DISPATCH_EVENT_MAY_BLOCK);
}
void BackgroundGenerateSecret(const nsACString& aLabel,
RefPtr<Promise>& aPromise,
RefPtr<OSKeyStore> self) {

Просмотреть файл

@ -28,10 +28,6 @@ class AbstractOSKeyStore {
const nsACString& label) = 0;
// Delete the secret with the given label.
virtual nsresult DeleteSecret(const nsACString& label) = 0;
// Lock the key store.
virtual nsresult Lock() = 0;
// Unlock the key store.
virtual nsresult Unlock() = 0;
virtual ~AbstractOSKeyStore() = default;
// Returns true if the secret with the given label is available in the key
@ -92,14 +88,11 @@ class OSKeyStore final : public nsIOSKeyStore {
const nsACString& aEncryptedBase64Text,
/*out*/ uint32_t* outLen,
/*out*/ uint8_t** outBytes);
nsresult Lock();
nsresult Unlock();
private:
~OSKeyStore() = default;
std::unique_ptr<AbstractOSKeyStore> mKs;
bool mKsIsNSSKeyStore;
};
#endif // OSKeyStore_h

Просмотреть файл

@ -12,18 +12,15 @@ interface nsIOSKeyStore: nsISupports {
* rest. The key used to encrypt and decrypt the data is stored in the OS
* key store.
*
* NB: To first authenticate the user to the system, use
* nsIOSReauthenticator.
*
* Usage:
*
* // obtain the singleton OSKeyStore instance
* const oskeystore = Cc["@mozilla.org/security/oskeystore;1"].getService(Ci.nsIOSKeyStore);
*
* const PASSWORD_LABEL = "mylabel1";
* const COOKIE_LABEL = "mylabel2";
*
* // Unlock the key store.
* // Note that this is not necesssary. The key store will be unlocked
* // automatically when an operation is performed on it.
* await oskeystore.asyncUnlock();
*
* // Check if there's a secret for your label already.
* if (!await oskeystore.asyncSecretAvailable(PASSWORD_LABEL)) {
@ -42,9 +39,6 @@ interface nsIOSKeyStore: nsISupports {
*
* // Recover a secret from a recovery code.
* await oskeystore.asyncRecoverSecret(PASSWORD_LABEL, recoveryPhrase);
*
* // Lock the key store to prompt the user to log into her OS key store again.
* await oskeystore.asyncLock();
*/
/**
@ -115,30 +109,4 @@ interface nsIOSKeyStore: nsISupports {
*/
[implicit_jscontext, must_use]
Promise asyncDecryptBytes(in ACString label, in ACString encryptedBase64Text);
/**
* Lock the key store.
* The actual behaviour of this depends on the OS.
*
* @return Promise resolving to undefined or an error.
*/
[implicit_jscontext, must_use]
Promise asyncLock();
/**
* Unlock the key store.
* The actual behaviour of this depends on the OS.
*
* @return Promise resolving to undefined or an error.
*/
[implicit_jscontext, must_use]
Promise asyncUnlock();
/**
* Check if the implementation is using the NSS key store.
* This is a special case because Firefox has to handle the locking and
* unlocking.
*/
readonly attribute bool isNSSKeyStore;
};

Просмотреть файл

@ -25,46 +25,6 @@ async function delete_all_secrets() {
}
}
// Test that Firefox handles locking and unlocking of the OSKeyStore properly.
// Does so by mocking out the actual dialog and "filling in" the
// password. Also tests that providing an incorrect password will fail (well,
// technically the user will just get prompted again, but if they then cancel
// the dialog the overall operation will fail).
var gMockPrompter = {
passwordToTry: null,
numPrompts: 0,
// This intentionally does not use arrow function syntax to avoid an issue
// where in the context of the arrow function, |this != gMockPrompter| due to
// how objects get wrapped when going across xpcom boundaries.
promptPassword(dialogTitle, text, password, checkMsg, checkValue) {
this.numPrompts++;
equal(
text,
"Please enter your Primary Password.",
"password prompt text should be as expected"
);
equal(checkMsg, null, "checkMsg should be null");
ok(this.passwordToTry, "passwordToTry should be non-null");
if (this.passwordToTry == "DontTryThisPassword") {
// Cancel the prompt in this case.
return false;
}
password.value = this.passwordToTry;
return true;
},
QueryInterface: ChromeUtils.generateQI(["nsIPrompt"]),
};
// Mock nsIWindowWatcher. PSM calls getNewPrompter on this to get an nsIPrompt
// to call promptPassword. We return the mock one, above.
var gWindowWatcher = {
getNewPrompter: () => gMockPrompter,
QueryInterface: ChromeUtils.generateQI(["nsIWindowWatcher"]),
};
async function encrypt_decrypt_test() {
let keystore = Cc["@mozilla.org/security/oskeystore;1"].getService(
Ci.nsIOSKeyStore
@ -109,110 +69,9 @@ async function encrypt_decrypt_test() {
}
add_task(async function () {
let keystore = Cc["@mozilla.org/security/oskeystore;1"].getService(
Ci.nsIOSKeyStore
);
let windowWatcherCID;
if (keystore.isNSSKeyStore) {
windowWatcherCID = MockRegistrar.register(
"@mozilla.org/embedcomp/window-watcher;1",
gWindowWatcher
);
registerCleanupFunction(() => {
MockRegistrar.unregister(windowWatcherCID);
});
}
await delete_all_secrets();
await encrypt_decrypt_test();
await delete_all_secrets();
if (
AppConstants.platform == "macosx" ||
AppConstants.platform == "win" ||
AppConstants.platform == "linux"
) {
ok(
!keystore.isNSSKeyStore,
"OS X, Windows, and Linux should use the non-NSS implementation"
);
}
if (keystore.isNSSKeyStore) {
// If we use the NSS key store implementation test that everything works
// when a master password is set.
// Set an initial password.
let tokenDB = Cc["@mozilla.org/security/pk11tokendb;1"].getService(
Ci.nsIPK11TokenDB
);
let token = tokenDB.getInternalKeyToken();
token.initPassword("hunter2");
// Lock the key store. This should be equivalent to token.logoutSimple()
await keystore.asyncLock();
// Set the correct password so that the test operations should succeed.
gMockPrompter.passwordToTry = "hunter2";
await encrypt_decrypt_test();
ok(
gMockPrompter.numPrompts == 1,
"There should've been one password prompt."
);
await delete_all_secrets();
}
// Check lock/unlock behaviour.
// Unfortunately we can only test this automatically for the NSS key store.
// Uncomment the outer keystore.isNSSKeyStore to test other key stores manually.
if (keystore.isNSSKeyStore) {
await delete_all_secrets();
await encrypt_decrypt_test();
await keystore.asyncLock();
info("Keystore should be locked. Cancel the login request.");
try {
if (keystore.isNSSKeyStore) {
gMockPrompter.passwordToTry = "DontTryThisPassword";
}
await keystore.asyncUnlock();
ok(false, "Unlock should've rejected.");
} catch (e) {
ok(
e.result == Cr.NS_ERROR_FAILURE || e.result == Cr.NS_ERROR_ABORT,
"Rejected login prompt."
);
}
// clean up
if (keystore.isNSSKeyStore) {
gMockPrompter.passwordToTry = "hunter2";
}
await delete_all_secrets();
}
});
// Test that if we kick off a background operation and then call a synchronous function on the
// keystore, we don't deadlock.
add_task(async function () {
await delete_all_secrets();
let keystore = Cc["@mozilla.org/security/oskeystore;1"].getService(
Ci.nsIOSKeyStore
);
let recoveryPhrase = await keystore.asyncGenerateSecret(LABELS[0]);
ok(recoveryPhrase, "A recovery phrase should've been created.");
try {
let text = new Uint8Array(8192);
let promise = keystore.asyncEncryptBytes(LABELS[0], text);
/* eslint-disable no-unused-expressions */
keystore.isNSSKeyStore; // we don't care what this is - we just need to access it
/* eslint-enable no-unused-expressions */
let ciphertext = await promise;
ok(ciphertext, "We should have a ciphertext now.");
} catch (e) {
ok(false, "Error encrypting " + e);
}
await delete_all_secrets();
});
// Test that using a recovery phrase works.