Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mock for browser.secureStorage proposal #186

Merged
merged 9 commits into from
Jul 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions proposals/secure-storage-mock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
let global;

if (globalThis.browser?.runtime.id) {
global = browser;
} else if (globalThis.chrome?.runtime.id) {
global = chrome;
} else {
throw new Error(
"browser.secureStorage mock must be run in extension contexts"
);
}

if (!global.storage?.local) {
throw new Error("Using this mock requires the 'storage' permission");
}

// Existing browser APIs don't give us access to the system's secure storage,
// meaning all data in this mock is stored in less secure mechanisms.
console.warn(
"Warning: browser.secureStorage mock loaded. This proof of concept stores data insecurely and should not be used in production."
);

const RECOGNISED_AUTH_METHODS = [
"PIN",
"PASSWORD",
"BIOMETRY_FACE",
"BIOMETRY_FINGERPRINT",
];

const secureStorage = {
getInfo: async () => {
return {
type: "MACOS_KEYCHAIN",
availableAuthentication: RECOGNISED_AUTH_METHODS,
};
},
store: async (request) => {
if (typeof request !== "object")
throw new Error("secureStorage.store takes an object");

const { id, authentication, data } = request;

if (typeof id !== "string") throw new Error("id must be a string");

if (typeof authentication !== "undefined") {
if (!Array.isArray(authentication))
throw new Error("authentication must be an array");

if (authentication.length === 0)
throw new Error("authentication array must be non-empty if present");

for (const method of authentication) {
if (!RECOGNISED_AUTH_METHODS.includes(method)) {
throw new Error(`unrecognised auth method: ${method}`);
}
}
}

if (typeof data !== "string") throw new Error("data must be a string");

return new Promise((resolve) =>
global.storage.local.set({ [id]: data }, resolve)
);
},
retrieve: async (request) => {
if (typeof request !== "object")
throw new Error("secureStorage.retrieve takes an object");

const { id } = request;

if (typeof id !== "string") throw new Error("id must be a string");

return new Promise((resolve) => {
global.storage.local.get(id, (result) => resolve(result[id]));
});
},
remove: async (request) => {
if (typeof request !== "object")
throw new Error("secureStorage.remove takes an object");

const { id } = request;

if (typeof id !== "string") throw new Error("id must be a string");

return new Promise((resolve) => global.storage.local.remove(id, resolve));
},
};

// Attach to browser namespace in Firefox/Safari
if (globalThis.browser?.runtime?.id) {
browser.secureStorage = secureStorage;
}

// Attach to chrome namespace in all browsers
if (globalThis.chrome?.runtime?.id) {
chrome.secureStorage = secureStorage;
}
4 changes: 4 additions & 0 deletions proposals/secure-storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ We propose a new browser.secureStorage API that would use platform-dependent API
- Android: [Keystore](https://source.android.com/security/keystore)
- Linux: See FAQ

A mock for this proposal is available [here](secure-storage-mock.js).

### API

**browser.secureStorage.getInfo**
Expand Down Expand Up @@ -59,6 +61,8 @@ browser.secureStorage.store({
});
```

The authentication array is optional. If omitted, the secret is available without the need for any of the recognised auth methods but is still stored in the hardware backed location.

**browser.secureStorage.retrieve**

This retrieves the stored data. The browser will only provide it if the user authenticates with one of the allowed mechanisms for this secret, and will throw an error otherwise.
Expand Down