1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-11 22:13:32 +00:00

consistency updates

This commit is contained in:
✨ Audrey ✨
2024-12-27 11:53:13 -05:00
parent b8d5d3c0a6
commit baf38f6cbc
12 changed files with 106 additions and 108 deletions

View File

@@ -7,7 +7,7 @@ export const AddyIo = {
name: "Addy.io",
};
export const AddyIoIntegrations: ExtensionMetadata[] = [
export const AddyIoExtensions: ExtensionMetadata[] = [
{
site: Extension.forwarder,
product: {

View File

@@ -7,7 +7,7 @@ export const DuckDuckGo = {
name: "DuckDuckGo",
};
export const DuckDuckGoIntegrations: ExtensionMetadata[] = [
export const DuckDuckGoExtensions: ExtensionMetadata[] = [
{
site: Extension.forwarder,
product: {

View File

@@ -7,8 +7,7 @@ export const Fastmail = {
name: "Fastmail",
};
// integration-wide configuration
export const FastmailIntegrations: ExtensionMetadata[] = [
export const FastmailExtensions: ExtensionMetadata[] = [
{
site: Extension.forwarder,
product: {

View File

@@ -7,7 +7,7 @@ export const ForwardEmail = {
name: "Forward Email",
};
export const ForwardEmailIntegrations: ExtensionMetadata[] = [
export const ForwardEmailExtensions: ExtensionMetadata[] = [
{
site: Extension.forwarder,
product: {

View File

@@ -7,7 +7,7 @@ export const Mozilla = {
name: "Mozilla",
};
export const MozillaIntegrations: ExtensionMetadata[] = [
export const MozillaExtensions: ExtensionMetadata[] = [
{
site: Extension.forwarder,
product: {

View File

@@ -7,7 +7,7 @@ export const SimpleLogin: VendorMetadata = {
name: "SimpleLogin",
};
export const SimpleLoginIntegrations: ExtensionMetadata[] = [
export const SimpleLoginExtensions: ExtensionMetadata[] = [
{
site: Extension.forwarder,
product: {

View File

@@ -1,6 +1,5 @@
import { ExtensionSite } from "../extension-site";
import { ExtensionPermission, ExtensionRegistry } from "./extension-registry.abstraction";
import { ExtensionSite } from "./extension-site";
import {
SiteMetadata,
SiteId,
@@ -8,21 +7,20 @@ import {
ExtensionSet,
VendorId,
VendorMetadata,
} from "./type";
} from "./metadata/type";
/** Tracks extension points and the integrations that extend them. */
export class DefaultIntegrationRegistry implements ExtensionRegistry {
/** Tracks extension sites and the vendors that extend them. */
export class DefaultExtensionRegistry implements ExtensionRegistry {
private allRule: ExtensionPermission = "default";
private siteRegistrations = new Map<SiteId, SiteMetadata>();
private siteRules = new Map<SiteId, ExtensionPermission>();
private sitePermissions = new Map<SiteId, ExtensionPermission>();
private vendorRegistrations = new Map<VendorId, VendorMetadata>();
private vendorRules = new Map<VendorId, ExtensionPermission>();
private vendorPermissions = new Map<VendorId, ExtensionPermission>();
private integrations = new Array<ExtensionMetadata>();
private siteIntegrationsByVendor = new Map<VendorId, Map<SiteId, number>>();
private vendorIntegrationsBySite = new Map<SiteId, Map<VendorId, number>>();
private extensions = new Array<ExtensionMetadata>();
private vendorExtensionsBySite = new Map<SiteId, Map<VendorId, number>>();
registerSite(meta: SiteMetadata): this {
if (!this.siteRegistrations.has(meta.id)) {
@@ -37,7 +35,7 @@ export class DefaultIntegrationRegistry implements ExtensionRegistry {
for (const [k, site] of this.siteRegistrations.entries()) {
const s: (typeof sites)[number] = { site };
const permission = this.siteRules.get(k);
const permission = this.sitePermissions.get(k);
if (permission) {
s.permission = permission;
}
@@ -61,7 +59,7 @@ export class DefaultIntegrationRegistry implements ExtensionRegistry {
for (const [k, vendor] of this.vendorRegistrations.entries()) {
const s: (typeof vendors)[number] = { vendor };
const permission = this.vendorRules.get(k);
const permission = this.vendorPermissions.get(k);
if (permission) {
s.permission = permission;
}
@@ -76,11 +74,11 @@ export class DefaultIntegrationRegistry implements ExtensionRegistry {
if ("all" in set && set.all) {
this.allRule = permission;
} else if ("vendor" in set) {
this.vendorRules.set(set.vendor, permission);
this.vendorPermissions.set(set.vendor, permission);
} else if ("site" in set) {
this.siteRules.set(set.site, permission);
this.sitePermissions.set(set.site, permission);
} else {
throw new Error(`Unrecognized integration set received: ${JSON.stringify(set)}.`);
throw new Error(`Unrecognized extension set received: ${JSON.stringify(set)}.`);
}
return this;
@@ -90,9 +88,9 @@ export class DefaultIntegrationRegistry implements ExtensionRegistry {
if ("all" in set && set.all) {
return this.allRule;
} else if ("vendor" in set) {
return this.vendorRules.get(set.vendor);
return this.vendorPermissions.get(set.vendor);
} else if ("site" in set) {
return this.siteRules.get(set.site);
return this.sitePermissions.get(set.site);
} else {
return undefined;
}
@@ -102,11 +100,11 @@ export class DefaultIntegrationRegistry implements ExtensionRegistry {
const rules: { set: ExtensionSet; permission: ExtensionPermission }[] = [];
rules.push({ set: { all: true }, permission: this.allRule });
for (const [site, permission] of this.siteRules.entries()) {
for (const [site, permission] of this.sitePermissions.entries()) {
rules.push({ set: { site }, permission });
}
for (const [vendor, permission] of this.vendorRules.entries()) {
for (const [vendor, permission] of this.vendorPermissions.entries()) {
rules.push({ set: { vendor }, permission });
}
@@ -120,19 +118,15 @@ export class DefaultIntegrationRegistry implements ExtensionRegistry {
throw new Error(`Unrecognized vendor: ${meta.product.vendor.id}`);
}
// is the integration registered?
const vendorMap =
this.vendorIntegrationsBySite.get(meta.site.id) ?? new Map<VendorId, number>();
// is the extension registered?
const vendorMap = this.vendorExtensionsBySite.get(meta.site.id) ?? new Map<VendorId, number>();
if (vendorMap.has(meta.product.vendor.id)) {
return;
}
// if not, register it
const siteMap =
this.siteIntegrationsByVendor.get(meta.product.vendor.id) ?? new Map<SiteId, number>();
const index = this.integrations.push(meta) - 1;
const index = this.extensions.push(meta) - 1;
vendorMap.set(meta.product.vendor.id, index);
siteMap.set(meta.site.id, index);
return this;
}
@@ -148,22 +142,22 @@ export class DefaultIntegrationRegistry implements ExtensionRegistry {
}
const extensions = new Map<VendorId, ExtensionMetadata>();
const entries = this.vendorIntegrationsBySite.get(id)?.entries() ?? ([] as const);
const entries = this.vendorExtensionsBySite.get(id)?.entries() ?? ([] as const);
for (const [vendor, maybeIndex] of entries) {
// prepare rules
const vendorRule = this.vendorRules.get(vendor) ?? this.allRule;
const siteRule = this.siteRules.get(id) ?? this.allRule;
const vendorRule = this.vendorPermissions.get(vendor) ?? this.allRule;
const siteRule = this.sitePermissions.get(id) ?? this.allRule;
const rules = [vendorRule, siteRule, this.allRule];
// evaluate rules
const extension = rules.includes("deny")
? undefined
: rules.includes("allow")
? this.integrations[maybeIndex]
? this.extensions[maybeIndex]
: rules.includes("none")
? undefined
: rules.includes("default")
? this.integrations[maybeIndex]
? this.extensions[maybeIndex]
: undefined;
// the presence of an extension indicates it's accessible

View File

@@ -1,13 +1,18 @@
import { ExtensionSite } from "../extension-site";
import { SiteMetadata, ExtensionMetadata, ExtensionSet, VendorMetadata, SiteId } from "./type";
import { ExtensionSite } from "./extension-site";
import {
SiteMetadata,
ExtensionMetadata,
ExtensionSet,
VendorMetadata,
SiteId,
} from "./metadata/type";
/** Permission levels for metadata.
* * default - unless a rule denies access, allow it. This is the
* default permission.
* * none - unless a rule allows access, deny it.
* * allow - access is explicitly granted to use an integration.
* * deny - access is explicitly prohibited for this integration. This
* * allow - access is explicitly granted to use an extension.
* * deny - access is explicitly prohibited for this extension. This
* rule overrides allow rules.
*/
export type ExtensionPermission = "default" | "none" | "allow" | "deny";
@@ -20,49 +25,49 @@ export abstract class ExtensionRegistry {
*/
registerSite: (meta: SiteMetadata) => this;
/** List all registered extension sites with their integration rule, if any.
/** List all registered extension sites with their extension rule, if any.
* @returns a list of all extension sites. `rule` is defined when the site
* is associated with an integration rule.
* is associated with an extension rule.
*/
sites: () => { site: SiteMetadata; permission?: ExtensionPermission }[];
/** Registers a vendor providing an integration
/** Registers a vendor providing an extension
* @param site - identifies the site being extended
* @param meta - configures the extension site
* @return self for method chaining.
*/
registerVendor: (meta: VendorMetadata) => this;
/** List all registered vendors with their integration rule, if any.
/** List all registered vendors with their extension rule, if any.
* @returns a list of all extension sites. `rule` is defined when the site
* is associated with an integration rule.
* is associated with an extension rule.
*/
vendors: () => { vendor: VendorMetadata; permission?: ExtensionPermission }[];
/** Registers an integration provided by a vendor to an extension site.
* The vendor and site MUST be registered before the integration.
/** Registers an extension provided by a vendor to an extension site.
* The vendor and site MUST be registered before the extension.
* @param site - identifies the site being extended
* @param meta - configures the extension site
* @return self for method chaining.
*/
registerExtension: (meta: ExtensionMetadata) => this;
/** Registers a rule. Only 1 rule can be registered for each integration set.
/** Registers a rule. Only 1 rule can be registered for each extension set.
* The last-registered rule wins.
* @param set the collection of integrations affected by the rule
* @param set the collection of extensions affected by the rule
* @param permission the permission for the collection
* @return self for method chaining.
*/
setPermission: (set: ExtensionSet, permission: ExtensionPermission) => this;
/** Retrieves the current rule for the given integration set or undefined if a rule
/** Retrieves the current rule for the given extension set or undefined if a rule
* doesn't exist. */
permission: (set: ExtensionSet) => ExtensionPermission | undefined;
/** Returns all registered integration rules. */
/** Returns all registered extension rules. */
permissions: () => { set: ExtensionSet; permission: ExtensionPermission }[];
/** Creates a point-in-time snapshot of the registry's contents with integration
/** Creates a point-in-time snapshot of the registry's contents with extension
* permissions applied for the provided SiteId.
* @returns the extension site, or `undefined` if the site is not registered.
*/

View File

@@ -2,11 +2,11 @@ import { StateProvider } from "@bitwarden/common/platform/state";
import { LegacyEncryptorProvider } from "../cryptography/legacy-encryptor-provider";
import { DefaultIntegrationRegistry } from "./metadata/default-extension-registry";
import { DefaultExtensionRegistry } from "./default-extension-registry";
export class ExtensionService {
constructor(
private readonly registry: DefaultIntegrationRegistry,
private readonly registry: DefaultExtensionRegistry,
private readonly stateProvider: StateProvider,
private readonly encryptorProvider: LegacyEncryptorProvider,
) {}

View File

@@ -0,0 +1,36 @@
import { AddyIo, AddyIoExtensions } from "./data/addy-io";
import { DuckDuckGo, DuckDuckGoExtensions } from "./data/duck-duck-go";
import { Fastmail, FastmailExtensions } from "./data/fastmail";
import { ForwardEmail, ForwardEmailExtensions } from "./data/forward-email";
import { Mozilla, MozillaExtensions } from "./data/mozilla";
import { SimpleLogin, SimpleLoginExtensions } from "./data/simple-login";
import { DefaultExtensionRegistry } from "./default-extension-registry";
import { Extension } from "./metadata/extension";
import { ExtensionMetadata, VendorMetadata } from "./metadata/type";
// FIXME: find a better way to build the registry than a hard-coded factory function
/** Constructs the extension registry */
export function buildRegistry() {
function registerAll(vendor: VendorMetadata, extensions: ExtensionMetadata[]) {
registry.registerVendor(vendor);
for (const extension of extensions) {
registry.registerExtension(extension);
}
}
const registry = new DefaultExtensionRegistry();
for (const site of Reflect.ownKeys(Extension) as string[]) {
registry.registerSite(Extension[site]);
}
registerAll(AddyIo, AddyIoExtensions);
registerAll(DuckDuckGo, DuckDuckGoExtensions);
registerAll(Fastmail, FastmailExtensions);
registerAll(ForwardEmail, ForwardEmailExtensions);
registerAll(Mozilla, MozillaExtensions);
registerAll(SimpleLogin, SimpleLoginExtensions);
return registry;
}

View File

@@ -1,36 +0,0 @@
import { AddyIo, AddyIoIntegrations } from "../data/addy-io";
import { DuckDuckGo, DuckDuckGoIntegrations } from "../data/duck-duck-go";
import { Fastmail, FastmailIntegrations } from "../data/fastmail";
import { ForwardEmail, ForwardEmailIntegrations } from "../data/forward-email";
import { Mozilla, MozillaIntegrations } from "../data/mozilla";
import { SimpleLogin, SimpleLoginIntegrations } from "../data/simple-login";
import { DefaultIntegrationRegistry } from "./default-extension-registry";
import { Extension } from "./extension";
import { ExtensionMetadata, VendorMetadata } from "./type";
/** Constructs the integration registry */
export function buildRegistry() {
// FIXME: find a better way to build the registry than a hard-coded factory function
function registerAll(vendor: VendorMetadata, integrations: ExtensionMetadata[]) {
registry.registerVendor(vendor);
for (const integration of integrations) {
registry.registerExtension(integration);
}
}
const registry = new DefaultIntegrationRegistry();
for (const site of Reflect.ownKeys(Extension) as string[]) {
registry.registerSite(Extension[site]);
}
registerAll(AddyIo, AddyIoIntegrations);
registerAll(DuckDuckGo, DuckDuckGoIntegrations);
registerAll(Fastmail, FastmailIntegrations);
registerAll(ForwardEmail, ForwardEmailIntegrations);
registerAll(Mozilla, MozillaIntegrations);
registerAll(SimpleLogin, SimpleLoginIntegrations);
return registry;
}

View File

@@ -1,17 +1,17 @@
import { FieldsBySite, Site, VendorsByExtension } from "./data";
/** well-known name for a feature extensible through an integration. */
/** well-known name for a feature extensible through an extension. */
export type SiteId = keyof typeof Site;
/** well-known name for a field surfaced from an extension site to a vendor. */
export type DisclosedField = (typeof FieldsBySite)[SiteId][number];
/** Identifies a vendor integrated into bitwarden */
/** Identifies a vendor extending bitwarden */
export type VendorId = (typeof VendorsByExtension)[SiteId][number];
/** The capabilities and descriptive content for an integration */
/** The capabilities and descriptive content for an extension */
export type SiteMetadata = {
/** Uniquely identifies the integrator. */
/** Uniquely identifies the extension site. */
id: SiteId;
/** Lists the fields disclosed by the extension to the vendor */
@@ -33,7 +33,7 @@ type TokenHeader =
authorization: "bearer" | "token" | "basic-username";
};
/** Catalogues an integration's hosting status.
/** Catalogues an extension's hosting status.
* selfHost: "never" always uses the service's base URL
* selfHost: "maybe" allows the user to override the service's
* base URL with their own.
@@ -46,16 +46,16 @@ export type ApiHost = TokenHeader &
| { selfHost: "always" }
);
/** The capabilities and descriptive content for an integration */
/** The capabilities and descriptive content for an extension */
export type VendorMetadata = {
/** Uniquely identifies the integrator. */
/** Uniquely identifies the vendor. */
id: VendorId;
/** Brand name of the integrator. */
/** Brand name of the service providing the extension. */
name: string;
};
/** Describes an integration provided by a vendor */
/** Describes an extension provided by a vendor */
export type ExtensionMetadata = {
/** The part of Bitwarden extended by the vendor's services */
site: SiteMetadata;
@@ -69,7 +69,7 @@ export type ExtensionMetadata = {
name?: string;
};
/** Hosting provider capabilities required by the integration */
/** Hosting provider capabilities required by the extension */
host: ApiHost;
/** Lists the fields disclosed by the extension to the vendor.
@@ -79,20 +79,20 @@ export type ExtensionMetadata = {
requestedFields: DisclosedField[];
};
/** Identifies a collection of integrations.
/** Identifies a collection of extensions.
*/
export type ExtensionSet =
| {
/** A set of integrations sharing an extension point */
/** A set of extensions sharing an extension point */
site: SiteId;
}
| {
/** A set of integrations sharing a vendor */
/** A set of extensions sharing a vendor */
vendor: VendorId;
}
| {
/** The total set of integrations. This is used to set a categorical
* rule affecting all integrations.
/** The total set of extensions. This is used to set a categorical
* rule affecting all extensions.
*/
all: true;
};