diff --git a/docs/admin_console/models.dsl b/docs/admin_console/models.dsl index e13c4547528..bde6fc1e72c 100644 --- a/docs/admin_console/models.dsl +++ b/docs/admin_console/models.dsl @@ -5,10 +5,3 @@ provider = person "MSP" "And employee of a managed service provider" { tags "MSP" } -!element server { - scim = container "SCIM" { - tags "SCIM" - } -} - -directory_connector -> server.api "Syncs users and groups to Bitwarden" diff --git a/docs/admin_console/relationships.dsl b/docs/admin_console/relationships.dsl index daca986bb9b..e69de29bb2d 100644 --- a/docs/admin_console/relationships.dsl +++ b/docs/admin_console/relationships.dsl @@ -1 +0,0 @@ -server.scim -> server.database "Queries" diff --git a/docs/auth/models.dsl b/docs/auth/models.dsl index eddb79138ec..d6ae8960d07 100644 --- a/docs/auth/models.dsl +++ b/docs/auth/models.dsl @@ -2,7 +2,4 @@ identity = container "Identity" { tags "Auth" } - sso = container "SSO" { - tags "Auth" - } } diff --git a/docs/auth/relationships.dsl b/docs/auth/relationships.dsl index f39bf8261d3..e69de29bb2d 100644 --- a/docs/auth/relationships.dsl +++ b/docs/auth/relationships.dsl @@ -1,2 +0,0 @@ -server.identity -> server.database "Queries" -server.sso -> server.database "Queries" diff --git a/docs/billing/relationships.dsl b/docs/billing/relationships.dsl index 45a5ce355b1..e69de29bb2d 100644 --- a/docs/billing/relationships.dsl +++ b/docs/billing/relationships.dsl @@ -1,4 +0,0 @@ -# High-level provider relationships -server.api.billing -> stripe "Requests payments for customers" -server.api.billing -> braintree "Requests payments for customers" -stripe -> server.api.billing "Sends subscription events to" diff --git a/docs/bitwarden_system.dsl b/docs/bitwarden_system.dsl index 6728864dfb1..78ce6782ff4 100644 --- a/docs/bitwarden_system.dsl +++ b/docs/bitwarden_system.dsl @@ -46,7 +46,7 @@ workspace "Bitwarden Server System" { include * } - container server "Bitwarden_Server" { + container clients "bitwarden_js_clients" { include * } diff --git a/docs/bitwarden_system.json b/docs/bitwarden_system.json index 1b51cbc46f4..fd6d149c20d 100644 --- a/docs/bitwarden_system.json +++ b/docs/bitwarden_system.json @@ -11,14 +11,14 @@ "title": "" }, { - "content": "## Perspectives\n\n### Security\nHighlights models and relationships identified as a part of [threat modeling](https://www.threatmodelingmanifesto.org/).\n\nIdentified threats are expected to be itemized in the perspective description, tagged with an appropriate `Security: threat` tag, and include a `!docs` property that describes the threat and mitigations. [`-> (relationships)`](https://docs.structurizr.com/dsl/language#relationship) do not allow for a `!docs` property, so a `url` property is used instead, linking to the appropriate section of the published docs.\n\n#### Example Model or Relationship\n\n##### Example Threat\n\n- **Type**: type\n- **Priority**: TBD/Low/Medium/High/Critical\n- **Likelihood**: TBD/Low/Medium/High/Critical\n- **Impact**: TBD/Low/Medium/High/Critical\n\ndescription of the threat.\n\n###### Example Threat Mitigations\ndescribe the mitigations for the threat and whether or not they are complete\n\n\n### SRE\n\nHighlights concerns and requirements for cloud deployments.\n", + "content": "## Perspectives\n\n### Security\n\nHighlights models and relationships identified as a part of [threat modeling](https://www.threatmodelingmanifesto.org/).\n\nIdentified threats are expected to be itemized in the perspective description, tagged with an appropriate `Security: threat` tag, and include a `!docs` property that describes the threat and mitigations. [`-> (relationships)`](https://docs.structurizr.com/dsl/language#relationship) do not allow for a `!docs` property, so a `url` property is used instead, linking to the appropriate section of the published docs.\n\n#### Example Model or Relationship\n\n##### Example Threat\n\n- **Type**: type\n- **Priority**: TBD/Low/Medium/High/Critical\n- **Likelihood**: TBD/Low/Medium/High/Critical\n- **Impact**: TBD/Low/Medium/High/Critical\n\ndescription of the threat.\n\n###### Example Threat Mitigations\n\ndescribe the mitigations for the threat and whether or not they are complete\n\n### SRE\n\nHighlights concerns and requirements for cloud deployments.\n", "filename": "perspectives.md", "format": "Markdown", "order": 2, "title": "" }, { - "content": "## Tags\n\n### Admin\n### API\n### Auth\n### Azure\n### Billing\n### Bitwarden Employee\n### Browser\n### CLI\n### Cloud Host Requirement\n### Database\n### Desktop\n### Directory\n### Events\n### External\n### HealthCheck\n### Icons\n### LDAP\n### MSP\n### Mobile\n### Queue\n### SCIM\n### Security:Privacy\n### Self-Hosted\n### Web\n", + "content": "## Tags\n\n### Admin\n\n### API\n\n### Auth\n\n### Azure\n\n### Billing\n\n### Bitwarden Employee\n\n### Browser\n\n### CLI\n\n### Cloud Host Requirement\n\n### Database\n\n### Desktop\n\n### Directory\n\n### Events\n\n### External\n\n### HealthCheck\n\n### Icons\n\n### LDAP\n\n### MSP\n\n### Mobile\n\n### Queue\n\n### SCIM\n\n### Security:Privacy\n\n### Self-Hosted\n\n### Web\n", "filename": "tags.md", "format": "Markdown", "order": 3, @@ -27,7 +27,8 @@ ] }, "id": 1, - "lastModifiedDate": "2025-07-01T14:14:59Z", + "lastModifiedAgent": "structurizr-ui", + "lastModifiedDate": "2025-07-28T21:38:09Z", "model": { "people": [ { @@ -41,50 +42,36 @@ "relationships": [ { "description": "Uses", - "destinationId": "16", - "id": "52", + "destinationId": "10", + "id": "42", "sourceId": "1", "tags": "Relationship" }, { "description": "Uses", - "destinationId": "15", - "id": "53", - "linkedRelationshipId": "52", + "destinationId": "9", + "id": "43", + "linkedRelationshipId": "42", "sourceId": "1" }, { "description": "Uses", - "destinationId": "17", - "id": "54", + "destinationId": "11", + "id": "44", "sourceId": "1", "tags": "Relationship" }, { "description": "Uses", - "destinationId": "18", - "id": "55", + "destinationId": "12", + "id": "45", "sourceId": "1", "tags": "Relationship" }, { "description": "Uses", - "destinationId": "19", - "id": "56", - "sourceId": "1", - "tags": "Relationship" - }, - { - "description": "Uses", - "destinationId": "20", - "id": "57", - "sourceId": "1", - "tags": "Relationship" - }, - { - "description": "Uses", - "destinationId": "21", - "id": "58", + "destinationId": "13", + "id": "46", "sourceId": "1", "tags": "Relationship" } @@ -99,22 +86,6 @@ "properties": { "structurizr.dsl.identifier": "system_admin" }, - "relationships": [ - { - "description": "Administers System", - "destinationId": "9", - "id": "67", - "sourceId": "2", - "tags": "Relationship" - }, - { - "description": "Administers System", - "destinationId": "4", - "id": "68", - "linkedRelationshipId": "67", - "sourceId": "2" - } - ], "tags": "Element,Person,Bitwarden Employee,Self-Host Admin" }, { @@ -126,27 +97,11 @@ "properties": { "structurizr.dsl.identifier": "customer_success" }, - "relationships": [ - { - "description": "Inspects and supports", - "destinationId": "9", - "id": "65", - "sourceId": "3", - "tags": "Relationship" - }, - { - "description": "Inspects and supports", - "destinationId": "4", - "id": "66", - "linkedRelationshipId": "65", - "sourceId": "3" - } - ], "tags": "Element,Person,Bitwarden Employee" }, { "description": "An administrator of an organization", - "id": "25", + "id": "17", "location": "Unspecified", "name": "Organization Admin", "properties": { @@ -155,24 +110,24 @@ "relationships": [ { "description": "Administers Organizations", - "destinationId": "16", - "id": "59", - "sourceId": "25", + "destinationId": "10", + "id": "47", + "sourceId": "17", "tags": "Relationship" }, { "description": "Administers Organizations", - "destinationId": "15", - "id": "60", - "linkedRelationshipId": "59", - "sourceId": "25" + "destinationId": "9", + "id": "48", + "linkedRelationshipId": "47", + "sourceId": "17" } ], "tags": "Element,Person,Admin" }, { "description": "And employee of a managed service provider", - "id": "26", + "id": "18", "location": "Unspecified", "name": "MSP", "properties": { @@ -180,32 +135,18 @@ }, "relationships": [ { - "description": "Completes Provider registration with", + "description": "Administers Providers and Organizations", + "destinationId": "10", + "id": "49", + "sourceId": "18", + "tags": "Relationship" + }, + { + "description": "Administers Providers and Organizations", "destinationId": "9", - "id": "61", - "sourceId": "26", - "tags": "Relationship" - }, - { - "description": "Completes Provider registration with", - "destinationId": "4", - "id": "62", - "linkedRelationshipId": "61", - "sourceId": "26" - }, - { - "description": "Administers Providers and Organizations", - "destinationId": "16", - "id": "63", - "sourceId": "26", - "tags": "Relationship" - }, - { - "description": "Administers Providers and Organizations", - "destinationId": "15", - "id": "64", - "linkedRelationshipId": "63", - "sourceId": "26" + "id": "50", + "linkedRelationshipId": "49", + "sourceId": "18" } ], "tags": "Element,Person,MSP" @@ -226,22 +167,6 @@ "properties": { "structurizr.dsl.identifier": "server.api.billing" }, - "relationships": [ - { - "description": "Requests payments for customers", - "destinationId": "32", - "id": "105", - "sourceId": "6", - "tags": "Relationship" - }, - { - "description": "Requests payments for customers", - "destinationId": "33", - "id": "108", - "sourceId": "6", - "tags": "Relationship" - } - ], "tags": "Element,Component,Billing" } ], @@ -254,53 +179,11 @@ "relationships": [ { "description": "Validates JWTs with", - "destinationId": "30", - "id": "89", + "destinationId": "19", + "id": "65", "sourceId": "5", "tags": "Relationship", "url": "https://bitwarden.com" - }, - { - "description": "Queries", - "destinationId": "11", - "id": "91", - "sourceId": "5", - "tags": "Relationship" - }, - { - "description": "Sends events to", - "destinationId": "12", - "id": "93", - "sourceId": "5", - "tags": "Relationship" - }, - { - "description": "Sends emails to", - "destinationId": "13", - "id": "95", - "sourceId": "5", - "tags": "Relationship" - }, - { - "description": "Sends notifications to", - "destinationId": "14", - "id": "96", - "sourceId": "5", - "tags": "Relationship" - }, - { - "description": "Requests payments for customers", - "destinationId": "32", - "id": "106", - "linkedRelationshipId": "105", - "sourceId": "5" - }, - { - "description": "Requests payments for customers", - "destinationId": "33", - "id": "109", - "linkedRelationshipId": "108", - "sourceId": "5" } ], "tags": "Element,Container,API" @@ -312,15 +195,6 @@ "properties": { "structurizr.dsl.identifier": "server.events" }, - "relationships": [ - { - "description": "Sends events to", - "destinationId": "12", - "id": "94", - "sourceId": "7", - "tags": "Relationship" - } - ], "tags": "Element,Container,Events" }, { @@ -330,267 +204,25 @@ "properties": { "structurizr.dsl.identifier": "server.notifications" }, - "relationships": [ - { - "description": "Sends notifications to", - "destinationId": "14", - "id": "97", - "sourceId": "8", - "tags": "Relationship" - } - ], "tags": "Element,Container" }, { "documentation": {}, - "id": "9", - "name": "Bitwarden Portal", - "properties": { - "structurizr.dsl.identifier": "server.portal" - }, - "relationships": [ - { - "description": "Queries", - "destinationId": "11", - "id": "92", - "sourceId": "9", - "tags": "Relationship" - } - ], - "tags": "Element,Container,Web" - }, - { - "documentation": {}, - "id": "10", - "name": "Events Processor", - "properties": { - "structurizr.dsl.identifier": "server.events_processor" - }, - "tags": "Element,Container,Events" - }, - { - "documentation": {}, - "id": "11", - "name": "Database", - "properties": { - "structurizr.dsl.identifier": "server.database" - }, - "tags": "Element,Container,Database" - }, - { - "documentation": {}, - "id": "12", - "name": "Events Queue", - "properties": { - "structurizr.dsl.identifier": "server.events_queue" - }, - "relationships": [ - { - "description": "Processes events from", - "destinationId": "10", - "id": "98", - "sourceId": "12", - "tags": "Relationship" - } - ], - "tags": "Element,Container,Queue,Azure" - }, - { - "documentation": {}, - "id": "13", - "name": "Mail Queue", - "properties": { - "structurizr.dsl.identifier": "server.mail_queue" - }, - "relationships": [ - { - "description": "Processes emails from", - "destinationId": "9", - "id": "99", - "sourceId": "13", - "tags": "Relationship" - } - ], - "tags": "Element,Container,Queue,Azure" - }, - { - "documentation": {}, - "id": "14", - "name": "Notifications Queue", - "properties": { - "structurizr.dsl.identifier": "server.notifications_queue" - }, - "tags": "Element,Container,Queue,Azure" - }, - { - "documentation": {}, - "id": "27", - "name": "SCIM", - "properties": { - "structurizr.dsl.identifier": "server.scim" - }, - "relationships": [ - { - "description": "Queries", - "destinationId": "11", - "id": "102", - "sourceId": "27", - "tags": "Relationship" - } - ], - "tags": "Element,Container,SCIM" - }, - { - "documentation": {}, - "id": "30", + "id": "19", "name": "Identity", "properties": { "structurizr.dsl.identifier": "server.identity" }, - "relationships": [ - { - "description": "Queries", - "destinationId": "11", - "id": "103", - "sourceId": "30", - "tags": "Relationship" - } - ], "tags": "Element,Container,Auth" }, { + "description": "The Icons service provides favicons for websites.", "documentation": {}, - "id": "31", - "name": "SSO", - "properties": { - "structurizr.dsl.identifier": "server.sso" - }, - "relationships": [ - { - "description": "Queries", - "destinationId": "11", - "id": "104", - "sourceId": "31", - "tags": "Relationship" - } - ], - "tags": "Element,Container,Auth" - }, - { - "components": [ - { - "description": "IconsController", - "documentation": {}, - "id": "35", - "name": "IconsController", - "properties": { - "structurizr.dsl.identifier": "server.icons.icons_controller" - }, - "relationships": [ - { - "description": "Requests icons from", - "destinationId": "37", - "id": "42", - "sourceId": "35", - "tags": "Relationship" - }, - { - "description": "Caches icons in", - "destinationId": "38", - "id": "43", - "perspectives": [ - { - "description": "Icons 1.3.1 Aggregate vault content leak through timing attack on cache \n\n Icons 1.3.2 Possible injection attack through cache key \n\n Icons 1.3.3 & Icons 1.3.4 Cache bloat leading to DoS \n\n Icons 1.3.5 Cache poisoning leading to incorrect icon storage", - "name": "Security" - } - ], - "sourceId": "35", - "tags": "Relationship" - } - ], - "tags": "Element,Component", - "technology": "C# ASP.NET Core" - }, - { - "description": "Provides information about the deployed icon service. Allow for health checks.", - "documentation": {}, - "id": "36", - "name": "InfoController", - "properties": { - "structurizr.dsl.identifier": "server.icons.info_controller" - }, - "tags": "Element,Component,Info,HealthCheck", - "technology": "C# ASP.NET Core" - }, - { - "description": "Resolves a single source for a website icon and downloads it.", - "documentation": {}, - "id": "37", - "name": "IconDetermination", - "properties": { - "structurizr.dsl.identifier": "server.icons.icon_determination" - }, - "relationships": [ - { - "description": "Resolves IP addresses for domain names from", - "destinationId": "44", - "id": "45", - "sourceId": "37", - "tags": "Relationship" - }, - { - "description": "Retrieves icons from", - "destinationId": "48", - "id": "49", - "sourceId": "37", - "tags": "Relationship" - } - ], - "tags": "Element,Component" - }, - { - "description": "Caches icons for a given domain", - "documentation": {}, - "id": "38", - "name": "IconCache", - "properties": { - "structurizr.dsl.identifier": "server.icons.icon_cache" - }, - "tags": "Element,Component,Cache", - "technology": "C# MemoryCache" - } - ], - "documentation": { - "sections": [ - { - "content": "## Threat Model\n\n### Example Model or Relationship\n\n#### Example Threat\n\n- **Type**: type\n- **Priority**: TBD/Low/Medium/High/Critical\n- **Likelihood**: TBD/Low/Medium/High/Critical\n- **Impact**: TBD/Low/Medium/High/Critical\n\ndescription of the threat.\n\n##### Example Threat Mitigations\ndescribe the mitigations for the threat.\n\n### Clients -> IconsController\nCommunication from clients to the icons component. This is an unauthenticated endpoint with minimal input validation.\n\n#### SSL termination exposes vault contents to network administrators\n\n- **Type**: Information Disclosure\n- **Priority**: TBD\n- **Likelihood**: TBD\n- **Impact**: TBD\n\nA machine with SSL terminating proxies cannot rely on encrypted query parameters hiding vault contents from network administrators.\n\n##### Mitigations\n- Not Implemented: Establish encrypted pipe communication with Icons service prior to requesting icon resolution\n\n#### Cleartext transmission of vault contents to Server\n\n- **Type**: Information Disclosure\n- **Priority**: TBD\n- **Likelihood**: TBD\n- **Impact**: TBD\n\nServer-side after TLS by necessity to lookup a favicon. However, to maintain our promises as a no-log proxy, we need to be sure not to maintain ip records for icon service requests\n\n##### Mitigations\n- Unconfirmed: Configure network edge and datadog to drop this identifying data.\n\n#### No SLA offered on Icons service\n\n- **Type**: Denial of Service\n- **Priority**: TBD\n- **Likelihood**: TBD\n- **Impact**: TBD\n\nWe do not offer SLA on up time of icons service. Clients may be unable to resolve icons, and we need to determine a graceful degradation strategy.\n\n##### Mitigations\n- Done: Default icon fallback (globe)\n- Not Implemented, Not Prioritized: Local cache of retrieved icons\n\n#### SSRF by proxied requests\n\n- **Type**: Elevation of Privilege / Information Disclosure\n- **Priority**: TBD\n- **Likelihood**: TBD\n- **Impact**: TBD\n\nThe service is designed to proxy requests to arbitrary URLs. This can be used to access internal network resources.\n\nIf a site redirects to an internal network address, the internal network topography may be exposed to the client.\n\n##### Mitigations\n- Done: Isolation of the icons component from the rest of the system intranet.\n- Done: Avoid fetching by domain name. All requests must be first resolved to an IP address and filtered against internal network ranges, defined as:\n - `::1`, `::`, `::ffff:`\n - IPv6 and starting with `fc`, `fd`, `fe`, or `ff`\n - IPv4 and starting with `0.`, `10.`, `100.`, `127.`, `169.254`, `172.16-31`, or `192.168`\n\n This is done in the `IconDetermination` component\n\n### IconsController -> IconCache\nCommunication from the icons controller to a mem cache of previously retrieved icons, keyed by original domain requested.\n\n#### Cache determination through timing measurements\n\n- **Type**: Information Disclosure\n- **Priority**: Low\n- **Likelihood**: Low\n- **Impact**: Low\n\nBy measuring the time it takes to retrieve an icon, an attacker may be able to determine if a domain has been previously requested by another user, revealing that some user on the service has that domain in their vault.\n\n##### Mitigations\nNone identified\n\n#### Unescaped storage of user-input data in cache\n\n- **Type**: Tampering\n- **Priority**: Low\n- **Likelihood**: Low\n- **Impact**: Low\n\nUnescaped user input data may be stored as keys in the cache. This input data is not executed, but if the storage method is changed in the future, this may lead to some injection attack.\n\n##### Mitigations\nNone identified\n\n#### Cache bloat through intentionally large icons\n\n- **Type**: Denial of Service\n- **Priority**: TBD\n- **Likelihood**: TBD\n- **Impact**: TBD\n\nUser request may intentionally resolve to very large icons, bloating the cache and increasing memory requirements.\n\nOpen question: Should we also limit the size of icons fetched?\n\n##### Mitigations\nDone: Limit size of icons stored in cache\n\n#### Cache bloat through many unique domain requests\n\n- **Type**: Denial of Service\n- **Priority**: TBD\n- **Likelihood**: TBD\n- **Impact**: TBD\n\nUser request may intentionally resolve many unique domains to resolve that may or may not exist, bloating the cache and increasing memory requirements.\n\n##### Mitigations\nUnconfirmed: Rate limit requests to the icons service\n\n#### Storage of potentially sensitive data as keys or values in cache\n\n- **Type**: Information Disclosure\n- **Priority**: TBD\n- **Likelihood**: TBD\n- **Impact**: TBD\n\nUpload of urls is automatic to our icon service. If our filters for upload are incorrect, we may store sensitive data in our cache. For example, onion addresses.\n\n##### Mitigations\nDone: Avoid filter known sensitive urls\nNot implemented, Not prioritized: Add client-side setting to disable icon request for a given url or pattern\n\n#### Cache poisoning via dns poisoning\n\n- **Type**: Tampering\n- **Priority**: Low\n- **Likelihood**: Low\n- **Impact**: Low\n\nDNS poisoning would lead to incorrect icons being cached for a given domain.\n\n##### Mitigations\nNone Identified\n", - "format": "Markdown", - "order": 1, - "title": "" - } - ] - }, - "id": "34", + "id": "38", "name": "Icons", "properties": { "structurizr.dsl.identifier": "server.icons" }, - "relationships": [ - { - "description": "Resolves IP addresses for domain names from", - "destinationId": "44", - "id": "46", - "linkedRelationshipId": "45", - "sourceId": "34" - }, - { - "description": "Retrieves icons from", - "destinationId": "48", - "id": "50", - "linkedRelationshipId": "49", - "sourceId": "34" - } - ], "tags": "Element,Container" } ], @@ -602,43 +234,13 @@ "properties": { "structurizr.dsl.identifier": "server" }, - "relationships": [ - { - "description": "Resolves IP addresses for domain names from", - "destinationId": "44", - "id": "47", - "linkedRelationshipId": "45", - "sourceId": "4" - }, - { - "description": "Retrieves icons from", - "destinationId": "48", - "id": "51", - "linkedRelationshipId": "49", - "sourceId": "4" - }, - { - "description": "Requests payments for customers", - "destinationId": "32", - "id": "107", - "linkedRelationshipId": "105", - "sourceId": "4" - }, - { - "description": "Requests payments for customers", - "destinationId": "33", - "id": "110", - "linkedRelationshipId": "108", - "sourceId": "4" - } - ], "tags": "Element,Software System" }, { "containers": [ { "documentation": {}, - "id": "16", + "id": "10", "name": "Web Application", "properties": { "structurizr.dsl.identifier": "clients.web" @@ -647,22 +249,22 @@ { "description": "Makes requests to", "destinationId": "5", - "id": "69", - "sourceId": "16", + "id": "51", + "sourceId": "10", "tags": "Relationship" }, { "description": "Makes requests to", "destinationId": "4", - "id": "70", - "linkedRelationshipId": "69", - "sourceId": "16" + "id": "52", + "linkedRelationshipId": "51", + "sourceId": "10" }, { "description": "Authenticates with", - "destinationId": "30", - "id": "82", - "sourceId": "16", + "destinationId": "19", + "id": "60", + "sourceId": "10", "tags": "Relationship" } ], @@ -670,95 +272,45 @@ }, { "documentation": {}, - "id": "17", - "name": "iOS Application", - "properties": { - "structurizr.dsl.identifier": "clients.ios" - }, - "relationships": [ - { - "description": "Makes requests to", - "destinationId": "5", - "id": "72", - "sourceId": "17", - "tags": "Relationship" - }, - { - "description": "Makes requests to", - "destinationId": "4", - "id": "73", - "linkedRelationshipId": "72", - "sourceId": "17" - }, - { - "description": "Authenticates With", - "destinationId": "30", - "id": "84", - "sourceId": "17", - "tags": "Relationship" - } - ], - "tags": "Element,Container,Mobile" - }, - { - "documentation": {}, - "id": "18", - "name": "Android Application", - "properties": { - "structurizr.dsl.identifier": "clients.android" - }, - "relationships": [ - { - "description": "Makes requests to", - "destinationId": "5", - "id": "74", - "sourceId": "18", - "tags": "Relationship" - }, - { - "description": "Makes requests to", - "destinationId": "4", - "id": "75", - "linkedRelationshipId": "74", - "sourceId": "18" - }, - { - "description": "Authenticates With", - "destinationId": "30", - "id": "85", - "sourceId": "18", - "tags": "Relationship" - } - ], - "tags": "Element,Container,Mobile" - }, - { - "documentation": {}, - "id": "19", + "id": "11", "name": "Browser Extension", "properties": { "structurizr.dsl.identifier": "clients.browser_extension" }, "relationships": [ + { + "description": "Connects to IPC to request biometric authentication", + "destinationId": "24", + "id": "28", + "sourceId": "11", + "tags": "Relationship" + }, + { + "description": "Connects to IPC to request biometric authentication", + "destinationId": "13", + "id": "29", + "linkedRelationshipId": "28", + "sourceId": "11" + }, { "description": "Makes requests to", "destinationId": "5", - "id": "76", - "sourceId": "19", + "id": "54", + "sourceId": "11", "tags": "Relationship" }, { "description": "Makes requests to", "destinationId": "4", - "id": "77", - "linkedRelationshipId": "76", - "sourceId": "19" + "id": "55", + "linkedRelationshipId": "54", + "sourceId": "11" }, { "description": "Authenticates With", - "destinationId": "30", - "id": "86", - "sourceId": "19", + "destinationId": "19", + "id": "62", + "sourceId": "11", "tags": "Relationship" } ], @@ -766,7 +318,7 @@ }, { "documentation": {}, - "id": "20", + "id": "12", "name": "CLI", "properties": { "structurizr.dsl.identifier": "clients.cli" @@ -775,54 +327,137 @@ { "description": "Makes requests to", "destinationId": "5", - "id": "78", - "sourceId": "20", + "id": "56", + "sourceId": "12", "tags": "Relationship" }, { "description": "Makes requests to", "destinationId": "4", - "id": "79", - "linkedRelationshipId": "78", - "sourceId": "20" + "id": "57", + "linkedRelationshipId": "56", + "sourceId": "12" }, { "description": "Authenticates With", - "destinationId": "30", - "id": "87", - "sourceId": "20", + "destinationId": "19", + "id": "63", + "sourceId": "12", "tags": "Relationship" } ], "tags": "Element,Container,CLI" }, { + "components": [ + { + "description": "Handles biometric authentication for the Bitwarden desktop application.", + "documentation": {}, + "id": "22", + "name": "Biometric Authentication", + "properties": { + "structurizr.dsl.identifier": "clients.desktop.biometric" + }, + "relationships": [ + { + "description": "Read/Write user keys", + "destinationId": "23", + "id": "31", + "sourceId": "22", + "tags": "Relationship", + "technology": "Napi Rust FFI" + }, + { + "description": "Requests user verification for biometric authentication", + "destinationId": "26", + "id": "35", + "sourceId": "22", + "tags": "Relationship" + } + ], + "tags": "Element,Component" + }, + { + "description": "CRUD operations on keys-values stored by the OS.", + "documentation": {}, + "id": "23", + "name": "OS Password Management Native Module", + "properties": { + "structurizr.dsl.identifier": "clients.desktop.password" + }, + "relationships": [ + { + "description": "CRUD operations on keys stored in the OS secure storage", + "destinationId": "25", + "id": "32", + "sourceId": "23", + "tags": "Relationship" + } + ], + "tags": "Element,Component", + "technology": "rust module" + }, + { + "description": "Inter-process communication between the desktop application and the browser extension.", + "documentation": {}, + "id": "24", + "name": "IPC", + "properties": { + "structurizr.dsl.identifier": "clients.desktop.ipc" + }, + "relationships": [ + { + "description": "Relays biometric authentication requests to", + "destinationId": "22", + "id": "30", + "sourceId": "24", + "tags": "Relationship" + } + ], + "tags": "Element,Component", + "technology": "Sockets" + } + ], "documentation": {}, - "id": "21", + "id": "13", "name": "Desktop Application", "properties": { "structurizr.dsl.identifier": "clients.desktop" }, "relationships": [ + { + "description": "CRUD operations on keys stored in the OS secure storage", + "destinationId": "25", + "id": "33", + "linkedRelationshipId": "32", + "sourceId": "13" + }, + { + "description": "Requests user verification for biometric authentication", + "destinationId": "26", + "id": "36", + "linkedRelationshipId": "35", + "sourceId": "13" + }, { "description": "Makes requests to", "destinationId": "5", - "id": "80", - "sourceId": "21", + "id": "58", + "sourceId": "13", "tags": "Relationship" }, { "description": "Makes requests to", "destinationId": "4", - "id": "81", - "linkedRelationshipId": "80", - "sourceId": "21" + "id": "59", + "linkedRelationshipId": "58", + "sourceId": "13" }, { "description": "Authenticates With", - "destinationId": "30", - "id": "88", - "sourceId": "21", + "destinationId": "19", + "id": "64", + "sourceId": "13", "tags": "Relationship" } ], @@ -831,59 +466,60 @@ ], "documentation": {}, "group": "Bitwarden Controlled", - "id": "15", + "id": "9", "location": "Unspecified", "name": "Clients", "properties": { "structurizr.dsl.identifier": "clients" }, "relationships": [ + { + "description": "CRUD operations on keys stored in the OS secure storage", + "destinationId": "25", + "id": "34", + "linkedRelationshipId": "32", + "sourceId": "9" + }, + { + "description": "Requests user verification for biometric authentication", + "destinationId": "26", + "id": "37", + "linkedRelationshipId": "35", + "sourceId": "9" + }, { "description": "Requests icons for cleartext urls from", - "destinationId": "35", + "destinationId": "38", "id": "39", - "perspectives": [ - { - "description": "Icons 1.2.1 Broken SSL communication exposes vault contents to network administrators \n\n Icons 1.2.2 Tracking of user vault contents by ip correlation between identity and icons services \n\n Icons 1.2.3 No SLA offered on Icons service, graceful degradation of features needed if it goes down \n\n Icons 1.2.4 SSRF through crafted input resolving to a location the server has elevated privileges in", - "name": "Security" - } - ], - "sourceId": "15", + "sourceId": "9", "tags": "Relationship" }, { "description": "Requests icons for cleartext urls from", - "destinationId": "34", + "destinationId": "4", "id": "40", "linkedRelationshipId": "39", - "sourceId": "15" - }, - { - "description": "Requests icons for cleartext urls from", - "destinationId": "4", - "id": "41", - "linkedRelationshipId": "39", - "sourceId": "15" + "sourceId": "9" }, { "description": "Makes requests to", "destinationId": "5", - "id": "71", - "linkedRelationshipId": "69", - "sourceId": "15" + "id": "53", + "linkedRelationshipId": "51", + "sourceId": "9" }, { "description": "Authenticates with", - "destinationId": "30", - "id": "83", - "linkedRelationshipId": "82", - "sourceId": "15" + "destinationId": "19", + "id": "61", + "linkedRelationshipId": "60", + "sourceId": "9" }, { "description": "Posts local usage events to", "destinationId": "7", - "id": "90", - "sourceId": "15", + "id": "66", + "sourceId": "9", "tags": "Relationship" } ], @@ -892,34 +528,7 @@ { "documentation": {}, "group": "Bitwarden Controlled", - "id": "22", - "location": "Unspecified", - "name": "Directory Connector", - "properties": { - "structurizr.dsl.identifier": "directory_connector" - }, - "relationships": [ - { - "description": "Syncs users and groups to Bitwarden", - "destinationId": "5", - "id": "28", - "sourceId": "22", - "tags": "Relationship" - }, - { - "description": "Syncs users and groups to Bitwarden", - "destinationId": "4", - "id": "29", - "linkedRelationshipId": "28", - "sourceId": "22" - } - ], - "tags": "Element,Software System,Directory,LDAP,Self-Hosted" - }, - { - "documentation": {}, - "group": "Bitwarden Controlled", - "id": "23", + "id": "14", "location": "Unspecified", "name": "Key Connector", "properties": { @@ -928,17 +537,17 @@ "relationships": [ { "description": "Validates JWTs with", - "destinationId": "30", - "id": "114", - "sourceId": "23", + "destinationId": "19", + "id": "69", + "sourceId": "14", "tags": "Relationship" }, { "description": "Validates JWTs with", "destinationId": "4", - "id": "115", - "linkedRelationshipId": "114", - "sourceId": "23" + "id": "70", + "linkedRelationshipId": "69", + "sourceId": "14" } ], "tags": "Element,Software System" @@ -946,7 +555,7 @@ { "description": "Self-hosted instances of Bitwarden servers", "documentation": {}, - "id": "24", + "id": "15", "location": "Unspecified", "name": "Self-Hosted Instances", "properties": { @@ -956,60 +565,47 @@ { "description": "Sends push notification proxy requests to", "destinationId": "8", - "id": "100", - "sourceId": "24", + "id": "67", + "sourceId": "15", "tags": "Relationship" }, { "description": "Sends push notification proxy requests to", "destinationId": "4", - "id": "101", - "linkedRelationshipId": "100", - "sourceId": "24" + "id": "68", + "linkedRelationshipId": "67", + "sourceId": "15" } ], "tags": "Element,Software System,Self-Hosted,External" }, + { + "documentation": {}, + "id": "16", + "location": "Unspecified", + "name": "External Websites", + "properties": { + "structurizr.dsl.identifier": "external_websites" + }, + "tags": "Element,Software System,External,Icons" + }, { "description": "Handles credit cards and subscriptions.", "documentation": {}, "group": "Payment Systems", - "id": "32", + "id": "20", "location": "Unspecified", "name": "Stripe", "properties": { "structurizr.dsl.identifier": "stripe" }, - "relationships": [ - { - "description": "Sends subscription events to", - "destinationId": "6", - "id": "111", - "sourceId": "32", - "tags": "Relationship" - }, - { - "description": "Sends subscription events to", - "destinationId": "5", - "id": "112", - "linkedRelationshipId": "111", - "sourceId": "32" - }, - { - "description": "Sends subscription events to", - "destinationId": "4", - "id": "113", - "linkedRelationshipId": "111", - "sourceId": "32" - } - ], "tags": "Element,Software System,External,Billing" }, { "description": "Handles PayPal and cryptocurrency.", "documentation": {}, "group": "Payment Systems", - "id": "33", + "id": "21", "location": "Unspecified", "name": "Braintree", "properties": { @@ -1018,101 +614,129 @@ "tags": "Element,Software System,External,Billing" }, { + "description": "The operating system's secure storage for sensitive data, such as Windows Credential Locker or macOS Keychain.", "documentation": {}, - "id": "44", + "id": "25", + "location": "Unspecified", + "name": "OS Secure Storage", + "properties": { + "structurizr.dsl.identifier": "os_secure_storage" + }, + "tags": "Element,Software System,External" + }, + { + "description": "The operating system's user verification system, such as Windows Hello or macOS Touch ID.", + "documentation": {}, + "id": "26", + "location": "Unspecified", + "name": "OS User Verification", + "properties": { + "structurizr.dsl.identifier": "os_user_verification" + }, + "tags": "Element,Software System,External" + }, + { + "description": "A Windows Hello signer that can be used to sign requests for the Bitwarden desktop application.", + "documentation": {}, + "id": "27", + "location": "Unspecified", + "name": "Windows Hello Signer", + "properties": { + "structurizr.dsl.identifier": "windows_hello_signer" + }, + "tags": "Element,Software System,External,Windows-Biometric" + }, + { + "documentation": {}, + "id": "41", "location": "Unspecified", "name": "DNS", "properties": { "structurizr.dsl.identifier": "dns" }, "tags": "Element,Software System,External,Icons" - }, - { - "documentation": {}, - "id": "48", - "location": "Unspecified", - "name": "External Websites", - "properties": { - "structurizr.dsl.identifier": "external_websites" - }, - "tags": "Element,Software System,External,Icons" } ] }, "name": "Bitwarden Server System", "properties": { - "structurizr.dsl": "d29ya3NwYWNlICJCaXR3YXJkZW4gU2VydmVyIFN5c3RlbSIgewoKICAhaWRlbnRpZmllcnMgaGllcmFyY2hpY2FsCgogICFkb2NzICJ1c2FnZV9kb2NzIgogIG1vZGVsIHsKICAgIHByb3BlcnRpZXMgewogICAgICAic3RydWN0dXJpenIuZ3JvdXBTZXBhcmF0b3IiICIvIgogICAgfQoKICAgICMgSW5jbHVkZSBzaGFyZWQgbGV2ZWwgbW9kZWxzCiAgICAjIFBlcnNvbiB0eXBlcwogICAgdXNlciA9IHBlcnNvbiAiQml0d2FyZGVuIFVzZXIiICJBbiBlbmQgdXNlciBvZiB0aGUgQml0d2FyZGVuIFN5c3RlbSIKICAgIHN5c3RlbV9hZG1pbiA9IHBlcnNvbiAiU3lzdGVtIEFkbWluIiAiRWl0aGVyIGEgQml0d2FyZGVuIHNpdGUtcmVsaWFiaWxpdHkgZW5naW5lZXIgb3IgYWRtaW5pc3RyYXRvciBvZiBhIHNlbGYtaG9zdGVkIGluc3RhbmNlIiB7CiAgICAgIHRhZ3MgIkJpdHdhcmRlbiBFbXBsb3llZSIgIlNlbGYtSG9zdCBBZG1pbiIKICAgIH0KICAgIAogICAgCiAgICBid19jb250cm9sbGVkID0gZ3JvdXAgIkJpdHdhcmRlbiBDb250cm9sbGVkIiB7CiAgICAgICMgQml0d2FyZGVuIHN0YWZmCiAgICAgIGN1c3RvbWVyX3N1Y2Nlc3MgPSBwZXJzb24gIkN1c3RvbWVyIFN1Y2Nlc3MiICJBIGN1c3RvbWVyIHN1Y2Nlc3MgZW5naW5lZXIuIEluc3BlY3RzIGJpdHdhcmRlbiBzdGF0ZSB0aHJvdWdoIHRoZSBhZG1pbiBwb3J0YWwgYW5kIGludGVybmFsIHRvb2xzIiB7CiAgICAgICAgdGFncyAiQml0d2FyZGVuIEVtcGxveWVlIgogICAgICB9CiAgICAgIAogICAgICAjIFJvb3Qgc3lzdGVtcwogICAgICBzZXJ2ZXIgPSBzb2Z0d2FyZVN5c3RlbSAiQml0d2FyZGVuIFNlcnZlciIgewogICAgICAgIGFwaSA9IGNvbnRhaW5lciAiQVBJIiB7CiAgICAgICAgICBiaWxsaW5nID0gY29tcG9uZW50ICJCaWxsaW5nIiB7CiAgICAgICAgICAgIHRhZ3MgIkJpbGxpbmciCiAgICAgICAgICB9CiAgICAgICAgICB0YWdzICJBUEkiCiAgICAgICAgfQogICAgICAgIGV2ZW50cyA9IGNvbnRhaW5lciAiRXZlbnRzIiB7CiAgICAgICAgICB0YWdzICJFdmVudHMiCiAgICAgICAgfQogICAgICAgIG5vdGlmaWNhdGlvbnMgPSBjb250YWluZXIgIk5vdGlmaWNhdGlvbnMiCiAgICAgICAgcG9ydGFsID0gY29udGFpbmVyICJCaXR3YXJkZW4gUG9ydGFsIiB7CiAgICAgICAgICB0YWdzICJXZWIiCiAgICAgICAgfQogICAgICAgIGV2ZW50c19wcm9jZXNzb3IgPSBjb250YWluZXIgIkV2ZW50cyBQcm9jZXNzb3IiIHsKICAgICAgICAgIHRhZ3MgIkV2ZW50cyIKICAgICAgICB9CiAgICAKICAgICAgICAjIERhdGEgc3RvcmVzCiAgICAgICAgZGF0YWJhc2UgPSBjb250YWluZXIgIkRhdGFiYXNlIiB7CiAgICAgICAgICB0YWdzICJEYXRhYmFzZSIKICAgICAgICB9CiAgICAgICAgZXZlbnRzX3F1ZXVlID0gY29udGFpbmVyICJFdmVudHMgUXVldWUiIHsKICAgICAgICAgIHRhZ3MgIlF1ZXVlIgogICAgICAgICAgdGFncyAiQXp1cmUiCiAgICAgICAgfQogICAgICAgIG1haWxfcXVldWUgPSBjb250YWluZXIgIk1haWwgUXVldWUiIHsKICAgICAgICAgIHRhZ3MgIlF1ZXVlIgogICAgICAgICAgdGFncyAiQXp1cmUiCiAgICAgICAgfQogICAgICAgIG5vdGlmaWNhdGlvbnNfcXVldWUgPSBjb250YWluZXIgIk5vdGlmaWNhdGlvbnMgUXVldWUiIHsKICAgICAgICAgIHRhZ3MgIlF1ZXVlIgogICAgICAgICAgdGFncyAiQXp1cmUiCiAgICAgICAgfQogICAgICB9CiAgICAgIGNsaWVudHMgPSBzb2Z0d2FyZVN5c3RlbSAiQ2xpZW50cyIgewogICAgICAgIHdlYiA9IGNvbnRhaW5lciAiV2ViIEFwcGxpY2F0aW9uIiB7CiAgICAgICAgICB0YWdzICJXZWIiCiAgICAgICAgfQogICAgICAgIGlvcyA9IGNvbnRhaW5lciAiaU9TIEFwcGxpY2F0aW9uIiB7CiAgICAgICAgICB0YWdzICJNb2JpbGUiCiAgICAgICAgfQogICAgICAgIGFuZHJvaWQgPSBjb250YWluZXIgIkFuZHJvaWQgQXBwbGljYXRpb24iIHsKICAgICAgICAgIHRhZ3MgIk1vYmlsZSIKICAgICAgICB9CiAgICAgICAgYnJvd3Nlcl9leHRlbnNpb24gPSBjb250YWluZXIgIkJyb3dzZXIgRXh0ZW5zaW9uIiB7CiAgICAgICAgICB0YWdzICJCcm93c2VyIgogICAgICAgIH0KICAgICAgICBjbGkgPSBjb250YWluZXIgIkNMSSIgewogICAgICAgICAgdGFncyAiQ0xJIgogICAgICAgIH0KICAgICAgICBkZXNrdG9wID0gY29udGFpbmVyICJEZXNrdG9wIEFwcGxpY2F0aW9uIiB7CiAgICAgICAgICB0YWdzICJEZXNrdG9wIgogICAgICAgIH0KICAgICAgfQogICAgICBkaXJlY3RvcnlfY29ubmVjdG9yID0gc29mdHdhcmVTeXN0ZW0gIkRpcmVjdG9yeSBDb25uZWN0b3IiIHsKICAgICAgICB0YWdzICJEaXJlY3RvcnkiCiAgICAgICAgdGFncyAiTERBUCIKICAgICAgICB0YWdzICJTZWxmLUhvc3RlZCIKICAgICAgfQogICAgICBrZXlfY29ubmVjdG9yID0gc29mdHdhcmVTeXN0ZW0gIktleSBDb25uZWN0b3IiIAogICAgfQogICAgCiAgICBzZWxmX2hvc3RlZF9pbnN0YW5jZXMgPSBzb2Z0d2FyZVN5c3RlbSAiU2VsZi1Ib3N0ZWQgSW5zdGFuY2VzIiB7CiAgICAgIHRhZ3MgIlNlbGYtSG9zdGVkIgogICAgICB0YWdzICJFeHRlcm5hbCIKICAgICAgZGVzY3JpcHRpb24gIlNlbGYtaG9zdGVkIGluc3RhbmNlcyBvZiBCaXR3YXJkZW4gc2VydmVycyIKICAgIH0KCiAgICAjIEluY2x1ZGUgdGVhbSBsZXZlbCBtb2RlbHMKICAgIGFkbWluID0gcGVyc29uICJPcmdhbml6YXRpb24gQWRtaW4iICJBbiBhZG1pbmlzdHJhdG9yIG9mIGFuIG9yZ2FuaXphdGlvbiIgewogICAgICB0YWdzICJBZG1pbiIKICAgIH0KICAgIHByb3ZpZGVyID0gcGVyc29uICJNU1AiICJBbmQgZW1wbG95ZWUgb2YgYSBtYW5hZ2VkIHNlcnZpY2UgcHJvdmlkZXIiIHsKICAgICAgdGFncyAiTVNQIgogICAgfQogICAgCiAgICAhZWxlbWVudCBzZXJ2ZXIgewogICAgICBzY2ltID0gY29udGFpbmVyICJTQ0lNIiB7CiAgICAgICAgdGFncyAiU0NJTSIKICAgICAgfQogICAgfQogICAgCiAgICBkaXJlY3RvcnlfY29ubmVjdG9yIC0+IHNlcnZlci5hcGkgIlN5bmNzIHVzZXJzIGFuZCBncm91cHMgdG8gQml0d2FyZGVuIgogICAgIWVsZW1lbnQgc2VydmVyIHsKICAgICAgaWRlbnRpdHkgPSBjb250YWluZXIgIklkZW50aXR5IiB7CiAgICAgICAgdGFncyAiQXV0aCIKICAgICAgfQogICAgICBzc28gPSBjb250YWluZXIgIlNTTyIgewogICAgICAgIHRhZ3MgIkF1dGgiCiAgICAgIH0KICAgIH0KICAgICMgRXh0ZXJuYWwgdmVuZG9ycwogICAgZ3JvdXAgIlBheW1lbnQgU3lzdGVtcyIgewogICAgICBzdHJpcGUgPSBzb2Z0d2FyZVN5c3RlbSAiU3RyaXBlIiB7CiAgICAgICAgdGFncyAiRXh0ZXJuYWwiCiAgICAgICAgdGFncyAiQmlsbGluZyIKICAgICAgICBkZXNjcmlwdGlvbiAiSGFuZGxlcyBjcmVkaXQgY2FyZHMgYW5kIHN1YnNjcmlwdGlvbnMuIgogICAgICB9CiAgICAgIGJyYWludHJlZSA9IHNvZnR3YXJlU3lzdGVtICJCcmFpbnRyZWUiIHsKICAgICAgICB0YWdzICJFeHRlcm5hbCIKICAgICAgICB0YWdzICJCaWxsaW5nIgogICAgICAgIGRlc2NyaXB0aW9uICJIYW5kbGVzIFBheVBhbCBhbmQgY3J5cHRvY3VycmVuY3kuIgogICAgICB9CiAgICB9CiAgICAKICAgICFlbGVtZW50IHNlcnZlciB7CiAgICAgIGljb25zID0gY29udGFpbmVyICJJY29ucyIgewogICAgICAgICFkb2NzICJ0aHJlYXRfbW9kZWwubWQiCiAgICAgICAgaWNvbnNfY29udHJvbGxlciA9IGNvbXBvbmVudCAiSWNvbnNDb250cm9sbGVyIiB7CiAgICAgICAgICBkZXNjcmlwdGlvbiAiSWNvbnNDb250cm9sbGVyIgogICAgICAgICAgdGVjaG5vbG9neSAiQyMgQVNQLk5FVCBDb3JlIgogICAgICAgICAgCiAgICAgICAgfQogICAgICAgIGluZm9fY29udHJvbGxlciA9IGNvbXBvbmVudCAiSW5mb0NvbnRyb2xsZXIiIHsKICAgICAgICAgIGRlc2NyaXB0aW9uICJQcm92aWRlcyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgZGVwbG95ZWQgaWNvbiBzZXJ2aWNlLiBBbGxvdyBmb3IgaGVhbHRoIGNoZWNrcy4iCiAgICAgICAgICB0ZWNobm9sb2d5ICJDIyBBU1AuTkVUIENvcmUiCiAgICAgICAgICB0YWdzICJJbmZvIiAiSGVhbHRoQ2hlY2siCiAgICAgICAgfQogICAgICAgIGljb25fZGV0ZXJtaW5hdGlvbiA9IGNvbXBvbmVudCAiSWNvbkRldGVybWluYXRpb24iIHsKICAgICAgICAgIGRlc2NyaXB0aW9uICJSZXNvbHZlcyBhIHNpbmdsZSBzb3VyY2UgZm9yIGEgd2Vic2l0ZSBpY29uIGFuZCBkb3dubG9hZHMgaXQuIgogICAgICAgIH0KICAgICAgICBpY29uX2NhY2hlID0gY29tcG9uZW50ICJJY29uQ2FjaGUiIHsKICAgICAgICAgIGRlc2NyaXB0aW9uICJDYWNoZXMgaWNvbnMgZm9yIGEgZ2l2ZW4gZG9tYWluIgogICAgICAgICAgdGFncyAiQ2FjaGUiCiAgICAgICAgICB0ZWNobm9sb2d5ICJDIyBNZW1vcnlDYWNoZSIKICAgICAgICB9CiAgICAKICAgICAgICBjbGllbnRzIC0+IGljb25zX2NvbnRyb2xsZXIgIlJlcXVlc3RzIGljb25zIGZvciBjbGVhcnRleHQgdXJscyBmcm9tIiB7CiAgICAgICAgICBwZXJzcGVjdGl2ZXMgewogICAgICAgICAgICAiU2VjdXJpdHkiICIgICAgICAgICAgICBJY29ucyAxLjIuMSBCcm9rZW4gU1NMIGNvbW11bmljYXRpb24gZXhwb3NlcyB2YXVsdCBjb250ZW50cyB0byBuZXR3b3JrIGFkbWluaXN0cmF0b3JzIFxuXG4gICAgICAgICAgICBJY29ucyAxLjIuMiBUcmFja2luZyBvZiB1c2VyIHZhdWx0IGNvbnRlbnRzIGJ5IGlwIGNvcnJlbGF0aW9uIGJldHdlZW4gaWRlbnRpdHkgYW5kIGljb25zIHNlcnZpY2VzIFxuXG4gICAgICAgICAgICBJY29ucyAxLjIuMyBObyBTTEEgb2ZmZXJlZCBvbiBJY29ucyBzZXJ2aWNlLCBncmFjZWZ1bCBkZWdyYWRhdGlvbiBvZiBmZWF0dXJlcyBuZWVkZWQgaWYgaXQgZ29lcyBkb3duIFxuXG4gICAgICAgICAgICBJY29ucyAxLjIuNCBTU1JGIHRocm91Z2ggY3JhZnRlZCBpbnB1dCByZXNvbHZpbmcgdG8gYSBsb2NhdGlvbiB0aGUgc2VydmVyIGhhcyBlbGV2YXRlZCBwcml2aWxlZ2VzIGluIgogICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpY29uc19jb250cm9sbGVyIC0+IGljb25fZGV0ZXJtaW5hdGlvbiAiUmVxdWVzdHMgaWNvbnMgZnJvbSIKICAgICAgICBpY29uc19jb250cm9sbGVyIC0+IGljb25fY2FjaGUgIkNhY2hlcyBpY29ucyBpbiIgewogICAgICAgICAgcGVyc3BlY3RpdmVzIHsKICAgICAgICAgICAgIlNlY3VyaXR5IiAiICAgICAgICAgICAgSWNvbnMgMS4zLjEgQWdncmVnYXRlIHZhdWx0IGNvbnRlbnQgbGVhayB0aHJvdWdoIHRpbWluZyBhdHRhY2sgb24gY2FjaGUgXG5cbiAgICAgICAgICAgIEljb25zIDEuMy4yIFBvc3NpYmxlIGluamVjdGlvbiBhdHRhY2sgdGhyb3VnaCBjYWNoZSBrZXkgXG5cbiAgICAgICAgICAgIEljb25zIDEuMy4zICYgSWNvbnMgMS4zLjQgQ2FjaGUgYmxvYXQgbGVhZGluZyB0byBEb1MgXG5cbiAgICAgICAgICAgIEljb25zIDEuMy41IENhY2hlIHBvaXNvbmluZyBsZWFkaW5nIHRvIGluY29ycmVjdCBpY29uIHN0b3JhZ2UgIgogICAgICAgICAgfQogICAgICAgIH0KICAgICAgfQogICAgfQogICAgCiAgICBkbnMgPSBzb2Z0d2FyZVN5c3RlbSAiRE5TIiB7CiAgICAgIHRhZ3MgIkV4dGVybmFsIgogICAgICB0YWdzICJJY29ucyIKICAgIH0KICAgIAogICAgc2VydmVyLmljb25zLmljb25fZGV0ZXJtaW5hdGlvbiAtPiBkbnMgIlJlc29sdmVzIElQIGFkZHJlc3NlcyBmb3IgZG9tYWluIG5hbWVzIGZyb20iCiAgICAKICAgIGV4dGVybmFsX3dlYnNpdGVzID0gc29mdHdhcmVTeXN0ZW0gIkV4dGVybmFsIFdlYnNpdGVzIiB7CiAgICAgIHRhZ3MgIkV4dGVybmFsIgogICAgICB0YWdzICJJY29ucyIKICAgIH0KICAgIAogICAgc2VydmVyLmljb25zLmljb25fZGV0ZXJtaW5hdGlvbiAtPiBleHRlcm5hbF93ZWJzaXRlcyAiUmV0cmlldmVzIGljb25zIGZyb20iCgogICAgIyBJbmNsdWRlIHNoYXJlZCBsZXZlbCByZWxhdGlvbnNoaXBzCiAgICAjIFVzZXIgUmVsYXRpb25zaGlwcwogICAgdXNlciAtPiBjbGllbnRzLndlYiAiVXNlcyIKICAgIHVzZXIgLT4gY2xpZW50cy5pb3MgIlVzZXMiCiAgICB1c2VyIC0+IGNsaWVudHMuYW5kcm9pZCAiVXNlcyIKICAgIHVzZXIgLT4gY2xpZW50cy5icm93c2VyX2V4dGVuc2lvbiAiVXNlcyIKICAgIHVzZXIgLT4gY2xpZW50cy5jbGkgIlVzZXMiCiAgICB1c2VyIC0+IGNsaWVudHMuZGVza3RvcCAiVXNlcyIKICAgIGFkbWluIC0+IGNsaWVudHMud2ViICJBZG1pbmlzdGVycyBPcmdhbml6YXRpb25zIgogICAgcHJvdmlkZXIgLT4gc2VydmVyLnBvcnRhbCAiQ29tcGxldGVzIFByb3ZpZGVyIHJlZ2lzdHJhdGlvbiB3aXRoIgogICAgcHJvdmlkZXIgLT4gY2xpZW50cy53ZWIgIkFkbWluaXN0ZXJzIFByb3ZpZGVycyBhbmQgT3JnYW5pemF0aW9ucyIKICAgIGN1c3RvbWVyX3N1Y2Nlc3MgLT4gc2VydmVyLnBvcnRhbCAiSW5zcGVjdHMgYW5kIHN1cHBvcnRzIgogICAgc3lzdGVtX2FkbWluIC0+IHNlcnZlci5wb3J0YWwgIkFkbWluaXN0ZXJzIFN5c3RlbSIKICAgIAogICAgIyBIaWdoLWxldmVsIENsaWVudCBSZWxhdGlvbnNoaXBzCiAgICBjbGllbnRzLndlYiAtPiBzZXJ2ZXIuYXBpICJNYWtlcyByZXF1ZXN0cyB0byIKICAgIGNsaWVudHMuaW9zIC0+IHNlcnZlci5hcGkgIk1ha2VzIHJlcXVlc3RzIHRvIgogICAgY2xpZW50cy5hbmRyb2lkIC0+IHNlcnZlci5hcGkgIk1ha2VzIHJlcXVlc3RzIHRvIgogICAgY2xpZW50cy5icm93c2VyX2V4dGVuc2lvbiAtPiBzZXJ2ZXIuYXBpICJNYWtlcyByZXF1ZXN0cyB0byIKICAgIGNsaWVudHMuY2xpIC0+IHNlcnZlci5hcGkgIk1ha2VzIHJlcXVlc3RzIHRvIgogICAgY2xpZW50cy5kZXNrdG9wIC0+IHNlcnZlci5hcGkgIk1ha2VzIHJlcXVlc3RzIHRvIgogICAgY2xpZW50cy53ZWIgLT4gc2VydmVyLmlkZW50aXR5ICJBdXRoZW50aWNhdGVzIHdpdGgiCiAgICBjbGllbnRzLmlvcyAtPiBzZXJ2ZXIuaWRlbnRpdHkgIkF1dGhlbnRpY2F0ZXMgV2l0aCIKICAgIGNsaWVudHMuYW5kcm9pZCAtPiBzZXJ2ZXIuaWRlbnRpdHkgIkF1dGhlbnRpY2F0ZXMgV2l0aCIKICAgIGNsaWVudHMuYnJvd3Nlcl9leHRlbnNpb24gLT4gc2VydmVyLmlkZW50aXR5ICJBdXRoZW50aWNhdGVzIFdpdGgiCiAgICBjbGllbnRzLmNsaSAtPiBzZXJ2ZXIuaWRlbnRpdHkgIkF1dGhlbnRpY2F0ZXMgV2l0aCIKICAgIGNsaWVudHMuZGVza3RvcCAtPiBzZXJ2ZXIuaWRlbnRpdHkgIkF1dGhlbnRpY2F0ZXMgV2l0aCIKICAgIHNlcnZlci5hcGkgLT4gc2VydmVyLmlkZW50aXR5ICJWYWxpZGF0ZXMgSldUcyB3aXRoIiB7CiAgICAgIHVybCAiaHR0cHM6Ly9iaXR3YXJkZW4uY29tIgogICAgfQogICAgY2xpZW50cyAtPiBzZXJ2ZXIuZXZlbnRzICJQb3N0cyBsb2NhbCB1c2FnZSBldmVudHMgdG8iCiAgICAKICAgICMgRGF0YWJhc2UgUmVsYXRpb25zaGlwcwogICAgCiAgICBzZXJ2ZXIuYXBpIC0+IHNlcnZlci5kYXRhYmFzZSAiUXVlcmllcyIKICAgIHNlcnZlci5wb3J0YWwgLT4gc2VydmVyLmRhdGFiYXNlICJRdWVyaWVzIgogICAgCiAgICAjIHF1ZXVlIFJlbGF0aW9uc2hpcHMKICAgIHNlcnZlci5hcGkgLT4gc2VydmVyLmV2ZW50c19xdWV1ZSAiU2VuZHMgZXZlbnRzIHRvIgogICAgc2VydmVyLmV2ZW50cyAtPiBzZXJ2ZXIuZXZlbnRzX3F1ZXVlICJTZW5kcyBldmVudHMgdG8iCiAgICBzZXJ2ZXIuYXBpIC0+IHNlcnZlci5tYWlsX3F1ZXVlICJTZW5kcyBlbWFpbHMgdG8iCiAgICBzZXJ2ZXIuYXBpIC0+IHNlcnZlci5ub3RpZmljYXRpb25zX3F1ZXVlICJTZW5kcyBub3RpZmljYXRpb25zIHRvIgogICAgc2VydmVyLm5vdGlmaWNhdGlvbnMgLT4gc2VydmVyLm5vdGlmaWNhdGlvbnNfcXVldWUgIlNlbmRzIG5vdGlmaWNhdGlvbnMgdG8iCiAgICBzZXJ2ZXIuZXZlbnRzX3F1ZXVlIC0+IHNlcnZlci5ldmVudHNfcHJvY2Vzc29yICJQcm9jZXNzZXMgZXZlbnRzIGZyb20iCiAgICBzZXJ2ZXIubWFpbF9xdWV1ZSAtPiBzZXJ2ZXIucG9ydGFsICJQcm9jZXNzZXMgZW1haWxzIGZyb20iCiAgICAKICAgICMgc2VsZiBob3N0IHBob25lIGhvbWUKICAgIHNlbGZfaG9zdGVkX2luc3RhbmNlcyAtPiBzZXJ2ZXIubm90aWZpY2F0aW9ucyAiU2VuZHMgcHVzaCBub3RpZmljYXRpb24gcHJveHkgcmVxdWVzdHMgdG8iCgoKICAgIHNlcnZlci5zY2ltIC0+IHNlcnZlci5kYXRhYmFzZSAiUXVlcmllcyIKICAgIHNlcnZlci5pZGVudGl0eSAtPiBzZXJ2ZXIuZGF0YWJhc2UgIlF1ZXJpZXMiCiAgICBzZXJ2ZXIuc3NvIC0+IHNlcnZlci5kYXRhYmFzZSAiUXVlcmllcyIKICAgICMgSGlnaC1sZXZlbCBwcm92aWRlciByZWxhdGlvbnNoaXBzCiAgICBzZXJ2ZXIuYXBpLmJpbGxpbmcgLT4gc3RyaXBlICJSZXF1ZXN0cyBwYXltZW50cyBmb3IgY3VzdG9tZXJzIgogICAgc2VydmVyLmFwaS5iaWxsaW5nIC0+IGJyYWludHJlZSAiUmVxdWVzdHMgcGF5bWVudHMgZm9yIGN1c3RvbWVycyIKICAgIHN0cmlwZSAtPiBzZXJ2ZXIuYXBpLmJpbGxpbmcgIlNlbmRzIHN1YnNjcmlwdGlvbiBldmVudHMgdG8iCiAgICBrZXlfY29ubmVjdG9yIC0+IHNlcnZlci5pZGVudGl0eSAiVmFsaWRhdGVzIEpXVHMgd2l0aCIKICB9CgogIHZpZXdzIHsKICAgIHN0eWxlcyB7CiAgICAgIGVsZW1lbnQgIlBlcnNvbiIgewogICAgICAgIGJhY2tncm91bmQgIzMxMDdkMwogICAgICAgIHNoYXBlIHBlcnNvbgogICAgICB9CiAgICAgIGVsZW1lbnQgIk1TUCIgewogICAgICAgIGJhY2tncm91bmQgIzMxMDdkMwogICAgICAgIHNoYXBlIHBlcnNvbgogICAgICB9CiAgICB9CiAgICBjb21wb25lbnQgc2VydmVyLmljb25zICJpY29uc19zZXJ2aWNlIiB7CiAgICAgIGluY2x1ZGUgKgogICAgfQoKICAgIHN5c3RlbUxhbmRzY2FwZSAiQml0d2FyZGVuIiB7CiAgICAgIGluY2x1ZGUgKgogICAgfQoKICAgIGNvbnRhaW5lciBzZXJ2ZXIgIkJpdHdhcmRlbl9TZXJ2ZXIiIHsKICAgICAgaW5jbHVkZSAqCiAgICB9CgogICAgLy8gVGhpcyBpcyBsYXN0IHRvIG92ZXJyaWRlIHRlYW0gc3R5bGVzIHdpdGggY29tbW9uIHN0eWxlcwogICAgc3R5bGVzIHsKICAgICAgdGhlbWUgZGVmYXVsdAogICAgICBlbGVtZW50ICJFbGVtZW50IiB7CiAgICAgICAgY29sb3IgIzNjM2IzYgogICAgICB9CiAgICAgIGVsZW1lbnQgIlBlcnNvbiIgewogICAgICAgIGJhY2tncm91bmQgI2QzNDQwNwogICAgICAgIHNoYXBlIHBlcnNvbgogICAgICB9CiAgICAgIGVsZW1lbnQgIkNvbnRhaW5lciIgewogICAgICAgIGJhY2tncm91bmQgI2Y4ODcyOAogICAgICB9CiAgICAgIGVsZW1lbnQgIk1TUCIgewogICAgICAgIGJhY2tncm91bmQgIzMxMDdkMwogICAgICB9CiAgICAgIGVsZW1lbnQgIlF1ZXVlIiB7CiAgICAgICAgc2hhcGUgcGlwZQogICAgICB9CiAgICAgIGVsZW1lbnQgIk1vYmlsZSIgewogICAgICAgIHNoYXBlIG1vYmlsZURldmljZVBvcnRyYWl0CiAgICAgIH0KICAgICAgZWxlbWVudCAiV2ViIiB7CiAgICAgICAgc2hhcGUgd2ViQnJvd3NlcgogICAgICB9CiAgICAgIGVsZW1lbnQgIkRhdGFiYXNlIiB7CiAgICAgICAgc2hhcGUgY3lsaW5kZXIKICAgICAgfQogICAgICBlbGVtZW50ICJFeHRlcm5hbCIgewogICAgICAgIGNvbG9yICMwMDAwMDAKICAgICAgICBiYWNrZ3JvdW5kICNiNWI1YjUKICAgICAgfQogICAgfQogIH0KfQ==" + "structurizr.dsl": "d29ya3NwYWNlICJCaXR3YXJkZW4gU2VydmVyIFN5c3RlbSIgewoKICAhaWRlbnRpZmllcnMgaGllcmFyY2hpY2FsCgogICFkb2NzICJ1c2FnZV9kb2NzIgogIG1vZGVsIHsKICAgIHByb3BlcnRpZXMgewogICAgICAic3RydWN0dXJpenIuZ3JvdXBTZXBhcmF0b3IiICIvIgogICAgfQoKICAgICMgSW5jbHVkZSBzaGFyZWQgbGV2ZWwgbW9kZWxzCiAgICAjIFBlcnNvbiB0eXBlcwogICAgdXNlciA9IHBlcnNvbiAiQml0d2FyZGVuIFVzZXIiICJBbiBlbmQgdXNlciBvZiB0aGUgQml0d2FyZGVuIFN5c3RlbSIKICAgIHN5c3RlbV9hZG1pbiA9IHBlcnNvbiAiU3lzdGVtIEFkbWluIiAiRWl0aGVyIGEgQml0d2FyZGVuIHNpdGUtcmVsaWFiaWxpdHkgZW5naW5lZXIgb3IgYWRtaW5pc3RyYXRvciBvZiBhIHNlbGYtaG9zdGVkIGluc3RhbmNlIiB7CiAgICAgIHRhZ3MgIkJpdHdhcmRlbiBFbXBsb3llZSIgIlNlbGYtSG9zdCBBZG1pbiIKICAgIH0KICAgIAogICAgCiAgICBid19jb250cm9sbGVkID0gZ3JvdXAgIkJpdHdhcmRlbiBDb250cm9sbGVkIiB7CiAgICAgICMgQml0d2FyZGVuIHN0YWZmCiAgICAgIGN1c3RvbWVyX3N1Y2Nlc3MgPSBwZXJzb24gIkN1c3RvbWVyIFN1Y2Nlc3MiICJBIGN1c3RvbWVyIHN1Y2Nlc3MgZW5naW5lZXIuIEluc3BlY3RzIGJpdHdhcmRlbiBzdGF0ZSB0aHJvdWdoIHRoZSBhZG1pbiBwb3J0YWwgYW5kIGludGVybmFsIHRvb2xzIiB7CiAgICAgICAgdGFncyAiQml0d2FyZGVuIEVtcGxveWVlIgogICAgICB9CiAgICAgIAogICAgICAjIFJvb3Qgc3lzdGVtcwogICAgICBzZXJ2ZXIgPSBzb2Z0d2FyZVN5c3RlbSAiQml0d2FyZGVuIFNlcnZlciIgewogICAgICAgIGFwaSA9IGNvbnRhaW5lciAiQVBJIiB7CiAgICAgICAgICBiaWxsaW5nID0gY29tcG9uZW50ICJCaWxsaW5nIiB7CiAgICAgICAgICAgIHRhZ3MgIkJpbGxpbmciCiAgICAgICAgICB9CiAgICAgICAgICB0YWdzICJBUEkiCiAgICAgICAgfQogICAgICAgIGV2ZW50cyA9IGNvbnRhaW5lciAiRXZlbnRzIiB7CiAgICAgICAgICB0YWdzICJFdmVudHMiCiAgICAgICAgfQogICAgICAgIG5vdGlmaWNhdGlvbnMgPSBjb250YWluZXIgIk5vdGlmaWNhdGlvbnMiCiAgICAgIH0KICAgICAgY2xpZW50cyA9IHNvZnR3YXJlU3lzdGVtICJDbGllbnRzIiB7CiAgICAgICAgd2ViID0gY29udGFpbmVyICJXZWIgQXBwbGljYXRpb24iIHsKICAgICAgICAgIHRhZ3MgIldlYiIKICAgICAgICB9CiAgICAgICAgYnJvd3Nlcl9leHRlbnNpb24gPSBjb250YWluZXIgIkJyb3dzZXIgRXh0ZW5zaW9uIiB7CiAgICAgICAgICB0YWdzICJCcm93c2VyIgogICAgICAgIH0KICAgICAgICBjbGkgPSBjb250YWluZXIgIkNMSSIgewogICAgICAgICAgdGFncyAiQ0xJIgogICAgICAgIH0KICAgICAgICBkZXNrdG9wID0gY29udGFpbmVyICJEZXNrdG9wIEFwcGxpY2F0aW9uIiB7CiAgICAgICAgICB0YWdzICJEZXNrdG9wIgogICAgICAgIH0KICAgICAgfQogICAgICBrZXlfY29ubmVjdG9yID0gc29mdHdhcmVTeXN0ZW0gIktleSBDb25uZWN0b3IiIAogICAgfQogICAgCiAgICBzZWxmX2hvc3RlZF9pbnN0YW5jZXMgPSBzb2Z0d2FyZVN5c3RlbSAiU2VsZi1Ib3N0ZWQgSW5zdGFuY2VzIiB7CiAgICAgIHRhZ3MgIlNlbGYtSG9zdGVkIgogICAgICB0YWdzICJFeHRlcm5hbCIKICAgICAgZGVzY3JpcHRpb24gIlNlbGYtaG9zdGVkIGluc3RhbmNlcyBvZiBCaXR3YXJkZW4gc2VydmVycyIKICAgIH0KICAgIAogICAgZXh0ZXJuYWxfd2Vic2l0ZXMgPSBzb2Z0d2FyZVN5c3RlbSAiRXh0ZXJuYWwgV2Vic2l0ZXMiIHsKICAgICAgdGFncyAiRXh0ZXJuYWwiCiAgICAgIHRhZ3MgIkljb25zIgogICAgfQoKICAgICMgSW5jbHVkZSB0ZWFtIGxldmVsIG1vZGVscwogICAgYWRtaW4gPSBwZXJzb24gIk9yZ2FuaXphdGlvbiBBZG1pbiIgIkFuIGFkbWluaXN0cmF0b3Igb2YgYW4gb3JnYW5pemF0aW9uIiB7CiAgICAgIHRhZ3MgIkFkbWluIgogICAgfQogICAgcHJvdmlkZXIgPSBwZXJzb24gIk1TUCIgIkFuZCBlbXBsb3llZSBvZiBhIG1hbmFnZWQgc2VydmljZSBwcm92aWRlciIgewogICAgICB0YWdzICJNU1AiCiAgICB9CiAgICAKICAgICFlbGVtZW50IHNlcnZlciB7CiAgICAgIGlkZW50aXR5ID0gY29udGFpbmVyICJJZGVudGl0eSIgewogICAgICAgIHRhZ3MgIkF1dGgiCiAgICAgIH0KICAgIH0KICAgICMgRXh0ZXJuYWwgdmVuZG9ycwogICAgZ3JvdXAgIlBheW1lbnQgU3lzdGVtcyIgewogICAgICBzdHJpcGUgPSBzb2Z0d2FyZVN5c3RlbSAiU3RyaXBlIiB7CiAgICAgICAgdGFncyAiRXh0ZXJuYWwiCiAgICAgICAgdGFncyAiQmlsbGluZyIKICAgICAgICBkZXNjcmlwdGlvbiAiSGFuZGxlcyBjcmVkaXQgY2FyZHMgYW5kIHN1YnNjcmlwdGlvbnMuIgogICAgICB9CiAgICAgIGJyYWludHJlZSA9IHNvZnR3YXJlU3lzdGVtICJCcmFpbnRyZWUiIHsKICAgICAgICB0YWdzICJFeHRlcm5hbCIKICAgICAgICB0YWdzICJCaWxsaW5nIgogICAgICAgIGRlc2NyaXB0aW9uICJIYW5kbGVzIFBheVBhbCBhbmQgY3J5cHRvY3VycmVuY3kuIgogICAgICB9CiAgICB9CiAgICAKICAgICFlbGVtZW50IGNsaWVudHMuZGVza3RvcCB7CiAgICAgIGJpb21ldHJpYyA9IGNvbXBvbmVudCAiQmlvbWV0cmljIEF1dGhlbnRpY2F0aW9uIiB7CiAgICAgICAgZGVzY3JpcHRpb24gIkhhbmRsZXMgYmlvbWV0cmljIGF1dGhlbnRpY2F0aW9uIGZvciB0aGUgQml0d2FyZGVuIGRlc2t0b3AgYXBwbGljYXRpb24uIgogICAgICB9CiAgICAKICAgICAgcGFzc3dvcmQgPSBjb21wb25lbnQgIk9TIFBhc3N3b3JkIE1hbmFnZW1lbnQgTmF0aXZlIE1vZHVsZSIgewogICAgICAgIGRlc2NyaXB0aW9uICJDUlVEIG9wZXJhdGlvbnMgb24ga2V5cy12YWx1ZXMgc3RvcmVkIGJ5IHRoZSBPUy4iCiAgICAgICAgdGVjaG5vbG9neSAicnVzdCBtb2R1bGUiCiAgICAgIH0KICAgIAogICAgICBpcGMgPSBjb21wb25lbnQgIklQQyIgewogICAgICAgIGRlc2NyaXB0aW9uICJJbnRlci1wcm9jZXNzIGNvbW11bmljYXRpb24gYmV0d2VlbiB0aGUgZGVza3RvcCBhcHBsaWNhdGlvbiBhbmQgdGhlIGJyb3dzZXIgZXh0ZW5zaW9uLiIKICAgICAgICB0ZWNobm9sb2d5ICJTb2NrZXRzIgogICAgICB9CiAgICB9CiAgICAKICAgIG9zX3NlY3VyZV9zdG9yYWdlID0gc29mdHdhcmVTeXN0ZW0gIk9TIFNlY3VyZSBTdG9yYWdlIiB7CiAgICAgIHRhZ3MgIkV4dGVybmFsIgogICAgICBkZXNjcmlwdGlvbiAiVGhlIG9wZXJhdGluZyBzeXN0ZW0ncyBzZWN1cmUgc3RvcmFnZSBmb3Igc2Vuc2l0aXZlIGRhdGEsIHN1Y2ggYXMgV2luZG93cyBDcmVkZW50aWFsIExvY2tlciBvciBtYWNPUyBLZXljaGFpbi4iCiAgICB9CiAgICAKICAgIG9zX3VzZXJfdmVyaWZpY2F0aW9uID0gc29mdHdhcmVTeXN0ZW0gIk9TIFVzZXIgVmVyaWZpY2F0aW9uIiB7CiAgICAgIHRhZ3MgIkV4dGVybmFsIgogICAgICBkZXNjcmlwdGlvbiAiVGhlIG9wZXJhdGluZyBzeXN0ZW0ncyB1c2VyIHZlcmlmaWNhdGlvbiBzeXN0ZW0sIHN1Y2ggYXMgV2luZG93cyBIZWxsbyBvciBtYWNPUyBUb3VjaCBJRC4iCiAgICB9CiAgICAKICAgIHdpbmRvd3NfaGVsbG9fc2lnbmVyID0gc29mdHdhcmVTeXN0ZW0gIldpbmRvd3MgSGVsbG8gU2lnbmVyIiB7CiAgICAgIHRhZ3MgIkV4dGVybmFsIiAiV2luZG93cy1CaW9tZXRyaWMiCiAgICAgIGRlc2NyaXB0aW9uICJBIFdpbmRvd3MgSGVsbG8gc2lnbmVyIHRoYXQgY2FuIGJlIHVzZWQgdG8gc2lnbiByZXF1ZXN0cyBmb3IgdGhlIEJpdHdhcmRlbiBkZXNrdG9wIGFwcGxpY2F0aW9uLiIKICAgIH0KICAgIAogICAgY2xpZW50cy5icm93c2VyX2V4dGVuc2lvbiAtPiBjbGllbnRzLmRlc2t0b3AuaXBjICJDb25uZWN0cyB0byBJUEMgdG8gcmVxdWVzdCBiaW9tZXRyaWMgYXV0aGVudGljYXRpb24iCiAgICBjbGllbnRzLmRlc2t0b3AuaXBjIC0+IGNsaWVudHMuZGVza3RvcC5iaW9tZXRyaWMgIlJlbGF5cyBiaW9tZXRyaWMgYXV0aGVudGljYXRpb24gcmVxdWVzdHMgdG8iCiAgICAKICAgIGNsaWVudHMuZGVza3RvcC5iaW9tZXRyaWMgLT4gY2xpZW50cy5kZXNrdG9wLnBhc3N3b3JkICJSZWFkL1dyaXRlIHVzZXIga2V5cyIgIk5hcGkgUnVzdCBGRkkiCiAgICBjbGllbnRzLmRlc2t0b3AucGFzc3dvcmQgLT4gb3Nfc2VjdXJlX3N0b3JhZ2UgIkNSVUQgb3BlcmF0aW9ucyBvbiBrZXlzIHN0b3JlZCBpbiB0aGUgT1Mgc2VjdXJlIHN0b3JhZ2UiCiAgICBjbGllbnRzLmRlc2t0b3AuYmlvbWV0cmljIC0+IG9zX3VzZXJfdmVyaWZpY2F0aW9uICJSZXF1ZXN0cyB1c2VyIHZlcmlmaWNhdGlvbiBmb3IgYmlvbWV0cmljIGF1dGhlbnRpY2F0aW9uIgogICAgIWVsZW1lbnQgc2VydmVyIHsKICAgICAgaWNvbnMgPSBjb250YWluZXIgIkljb25zIiB7CiAgICAgICAgZGVzY3JpcHRpb24gIlRoZSBJY29ucyBzZXJ2aWNlIHByb3ZpZGVzIGZhdmljb25zIGZvciB3ZWJzaXRlcy4iCiAgICAgICAgY2xpZW50cyAtPiBzZXJ2ZXIuaWNvbnMgIlJlcXVlc3RzIGljb25zIGZvciBjbGVhcnRleHQgdXJscyBmcm9tIiAKICAgICAgfQogICAgfQogICAgCiAgICBkbnMgPSBzb2Z0d2FyZVN5c3RlbSAiRE5TIiB7CiAgICAgIHRhZ3MgIkV4dGVybmFsIgogICAgICB0YWdzICJJY29ucyIKICAgIH0KCiAgICAjIEluY2x1ZGUgc2hhcmVkIGxldmVsIHJlbGF0aW9uc2hpcHMKICAgICMgVXNlciBSZWxhdGlvbnNoaXBzCiAgICB1c2VyIC0+IGNsaWVudHMud2ViICJVc2VzIgogICAgdXNlciAtPiBjbGllbnRzLmJyb3dzZXJfZXh0ZW5zaW9uICJVc2VzIgogICAgdXNlciAtPiBjbGllbnRzLmNsaSAiVXNlcyIKICAgIHVzZXIgLT4gY2xpZW50cy5kZXNrdG9wICJVc2VzIgogICAgYWRtaW4gLT4gY2xpZW50cy53ZWIgIkFkbWluaXN0ZXJzIE9yZ2FuaXphdGlvbnMiCiAgICBwcm92aWRlciAtPiBjbGllbnRzLndlYiAiQWRtaW5pc3RlcnMgUHJvdmlkZXJzIGFuZCBPcmdhbml6YXRpb25zIgogICAgCiAgICAjIEhpZ2gtbGV2ZWwgQ2xpZW50IFJlbGF0aW9uc2hpcHMKICAgIGNsaWVudHMud2ViIC0+IHNlcnZlci5hcGkgIk1ha2VzIHJlcXVlc3RzIHRvIgogICAgY2xpZW50cy5icm93c2VyX2V4dGVuc2lvbiAtPiBzZXJ2ZXIuYXBpICJNYWtlcyByZXF1ZXN0cyB0byIKICAgIGNsaWVudHMuY2xpIC0+IHNlcnZlci5hcGkgIk1ha2VzIHJlcXVlc3RzIHRvIgogICAgY2xpZW50cy5kZXNrdG9wIC0+IHNlcnZlci5hcGkgIk1ha2VzIHJlcXVlc3RzIHRvIgogICAgY2xpZW50cy53ZWIgLT4gc2VydmVyLmlkZW50aXR5ICJBdXRoZW50aWNhdGVzIHdpdGgiCiAgICBjbGllbnRzLmJyb3dzZXJfZXh0ZW5zaW9uIC0+IHNlcnZlci5pZGVudGl0eSAiQXV0aGVudGljYXRlcyBXaXRoIgogICAgY2xpZW50cy5jbGkgLT4gc2VydmVyLmlkZW50aXR5ICJBdXRoZW50aWNhdGVzIFdpdGgiCiAgICBjbGllbnRzLmRlc2t0b3AgLT4gc2VydmVyLmlkZW50aXR5ICJBdXRoZW50aWNhdGVzIFdpdGgiCiAgICBzZXJ2ZXIuYXBpIC0+IHNlcnZlci5pZGVudGl0eSAiVmFsaWRhdGVzIEpXVHMgd2l0aCIgewogICAgICB1cmwgImh0dHBzOi8vYml0d2FyZGVuLmNvbSIKICAgIH0KICAgIGNsaWVudHMgLT4gc2VydmVyLmV2ZW50cyAiUG9zdHMgbG9jYWwgdXNhZ2UgZXZlbnRzIHRvIgogICAgCiAgICAjIHNlbGYgaG9zdCBwaG9uZSBob21lCiAgICBzZWxmX2hvc3RlZF9pbnN0YW5jZXMgLT4gc2VydmVyLm5vdGlmaWNhdGlvbnMgIlNlbmRzIHB1c2ggbm90aWZpY2F0aW9uIHByb3h5IHJlcXVlc3RzIHRvIgoKCiAgICBrZXlfY29ubmVjdG9yIC0+IHNlcnZlci5pZGVudGl0eSAiVmFsaWRhdGVzIEpXVHMgd2l0aCIKICB9CgogIHZpZXdzIHsKICAgIHN0eWxlcyB7CiAgICAgIGVsZW1lbnQgIlBlcnNvbiIgewogICAgICAgIGJhY2tncm91bmQgIzMxMDdkMwogICAgICAgIHNoYXBlIHBlcnNvbgogICAgICB9CiAgICAgIGVsZW1lbnQgIk1TUCIgewogICAgICAgIGJhY2tncm91bmQgIzMxMDdkMwogICAgICAgIHNoYXBlIHBlcnNvbgogICAgICB9CiAgICB9CiAgICBjb21wb25lbnQgY2xpZW50cy5kZXNrdG9wICJkZXNrdG9wX2Jpb21ldHJpY3NfbWFjb3MiIHsKICAgICAgaW5jbHVkZSAqCiAgICAgIGluY2x1ZGUgb3NfdXNlcl92ZXJpZmljYXRpb24KICAgICAgYXV0b0xheW91dCB0YgogICAgfQogICAgLy8gVE9ETzogQWRkIFdpbmRvd3MgYW5kIExpbnV4LCBleGNsdWRpbmcgcmVsZXZhbnQgVGFncwoKICAgIHN5c3RlbUxhbmRzY2FwZSAiQml0d2FyZGVuIiB7CiAgICAgIGluY2x1ZGUgKgogICAgfQoKICAgIGNvbnRhaW5lciBjbGllbnRzICJiaXR3YXJkZW5fanNfY2xpZW50cyIgewogICAgICBpbmNsdWRlICoKICAgIH0KCiAgICAvLyBUaGlzIGlzIGxhc3QgdG8gb3ZlcnJpZGUgdGVhbSBzdHlsZXMgd2l0aCBjb21tb24gc3R5bGVzCiAgICBzdHlsZXMgewogICAgICB0aGVtZSBkZWZhdWx0CiAgICAgIGVsZW1lbnQgIkVsZW1lbnQiIHsKICAgICAgICBjb2xvciAjM2MzYjNiCiAgICAgIH0KICAgICAgZWxlbWVudCAiUGVyc29uIiB7CiAgICAgICAgYmFja2dyb3VuZCAjZDM0NDA3CiAgICAgICAgc2hhcGUgcGVyc29uCiAgICAgIH0KICAgICAgZWxlbWVudCAiQ29udGFpbmVyIiB7CiAgICAgICAgYmFja2dyb3VuZCAjZjg4NzI4CiAgICAgIH0KICAgICAgZWxlbWVudCAiTVNQIiB7CiAgICAgICAgYmFja2dyb3VuZCAjMzEwN2QzCiAgICAgIH0KICAgICAgZWxlbWVudCAiUXVldWUiIHsKICAgICAgICBzaGFwZSBwaXBlCiAgICAgIH0KICAgICAgZWxlbWVudCAiTW9iaWxlIiB7CiAgICAgICAgc2hhcGUgbW9iaWxlRGV2aWNlUG9ydHJhaXQKICAgICAgfQogICAgICBlbGVtZW50ICJXZWIiIHsKICAgICAgICBzaGFwZSB3ZWJCcm93c2VyCiAgICAgIH0KICAgICAgZWxlbWVudCAiRGF0YWJhc2UiIHsKICAgICAgICBzaGFwZSBjeWxpbmRlcgogICAgICB9CiAgICAgIGVsZW1lbnQgIkV4dGVybmFsIiB7CiAgICAgICAgY29sb3IgIzAwMDAwMAogICAgICAgIGJhY2tncm91bmQgI2I1YjViNQogICAgICB9CiAgICB9CiAgfQp9" }, "views": { "componentViews": [ { - "containerId": "34", + "automaticLayout": { + "applied": true, + "edgeSeparation": 0, + "implementation": "Graphviz", + "nodeSeparation": 300, + "rankDirection": "TopBottom", + "rankSeparation": 300, + "vertices": false + }, + "containerId": "13", "dimensions": { - "height": 2510, - "width": 1713 + "height": 3100, + "width": 1620 }, "elements": [ { - "id": "15", - "x": 1042, + "id": "11", + "x": 220, "y": 165 }, { - "id": "35", - "x": 1042, - "y": 765 - }, - { - "id": "36", - "x": 292, - "y": 765 - }, - { - "id": "37", - "x": 292, + "id": "22", + "x": 220, "y": 1365 }, { - "id": "38", - "x": 1042, - "y": 1365 + "id": "23", + "x": 220, + "y": 1965 }, { - "id": "44", - "x": 199, - "y": 1975 + "id": "24", + "x": 220, + "y": 765 }, { - "id": "48", - "x": 789, - "y": 1975 + "id": "25", + "x": 220, + "y": 2565 + }, + { + "id": "26", + "x": 970, + "y": 1965 } ], "externalContainerBoundariesVisible": false, - "key": "icons_service", + "key": "desktop_biometrics_macos", "order": 1, "relationships": [ { - "id": "39" + "id": "28" }, { - "id": "42" + "id": "30" }, { - "id": "43" + "id": "31" }, { - "id": "45" + "id": "32" }, { - "id": "49" + "id": "35" } ] } ], "configuration": { "branding": {}, - "lastSavedView": "Bitwarden", + "lastSavedView": "desktop_biometrics_macos", + "metadataSymbols": "SquareBrackets", "styles": { "elements": [ { @@ -1162,480 +786,100 @@ "containerViews": [ { "dimensions": { - "height": 4020, - "width": 7258 + "height": 2616, + "width": 3304 }, "elements": [ { - "id": "2", - "x": 317, - "y": 2108 - }, - { - "id": "3", - "x": 6650, - "y": 2108 - }, - { - "id": "5", - "x": 2383, - "y": 1508 - }, - { - "id": "7", - "x": 1633, - "y": 1508 - }, - { - "id": "8", - "x": 3883, - "y": 1508 - }, - { - "id": "9", - "x": 3883, - "y": 2808 - }, - { - "id": "10", - "x": 1325, - "y": 2808 - }, - { - "id": "11", - "x": 2825, - "y": 3408 - }, - { - "id": "12", - "x": 1767, - "y": 2158 - }, - { - "id": "13", - "x": 3042, - "y": 2158 - }, - { - "id": "14", - "x": 3792, - "y": 2158 - }, - { - "id": "15", - "x": 1633, - "y": 908 - }, - { - "id": "22", - "x": 2383, - "y": 908 - }, - { - "id": "23", - "x": 358, - "y": 1508 - }, - { - "id": "24", - "x": 3883, - "y": 908 - }, - { - "id": "26", - "x": 3825, + "id": "1", + "x": 1658, "y": 208 }, { - "id": "27", - "x": 2825, - "y": 2808 + "id": "4", + "x": 1012, + "y": 2108 }, { - "id": "30", - "x": 1017, - "y": 2158 - }, - { - "id": "31", - "x": 2075, - "y": 2808 - }, - { - "id": "32", - "x": 3133, + "id": "10", + "x": 533, "y": 908 }, { - "id": "33", - "x": 4542, - "y": 2158 + "id": "11", + "x": 2033, + "y": 908 }, { - "id": "34", - "x": 3133, + "id": "12", + "x": 1283, + "y": 908 + }, + { + "id": "13", + "x": 2033, "y": 1508 }, { - "id": "44", - "x": 5292, - "y": 2158 + "id": "17", + "x": 908, + "y": 208 }, { - "id": "48", - "x": 5292, - "y": 2158 + "id": "18", + "x": 208, + "y": 208 + }, + { + "id": "25", + "x": 1896, + "y": 2108 + }, + { + "id": "26", + "x": 2646, + "y": 2108 } ], "externalSoftwareSystemBoundariesVisible": false, - "key": "Bitwarden_Server", + "key": "bitwarden_js_clients", "order": 3, - "paperSize": "A1_Landscape", + "paperSize": "A3_Landscape", "relationships": [ { - "id": "100" + "id": "29" }, { - "id": "102" + "id": "33" }, { - "id": "103", + "id": "36" + }, + { + "id": "42", "vertices": [ { - "x": 1175, - "y": 2808 - }, - { - "x": 1175, - "y": 3108 + "x": 1133, + "y": 804 } ] }, { - "id": "104" + "id": "44" }, { - "id": "106", - "vertices": [ - { - "x": 3076, - "y": 1475 - } - ] - }, - { - "id": "109", - "vertices": [ - { - "x": 2983, - "y": 1808 - }, - { - "x": 4512, - "y": 2108 - } - ] - }, - { - "id": "112", - "vertices": [ - { - "x": 2889, - "y": 1240 - } - ] - }, - { - "id": "114" - }, - { - "id": "28" - }, - { - "id": "40", - "vertices": [ - { - "x": 2233, - "y": 1208 - }, - { - "x": 2983, - "y": 1404 - } - ] + "id": "45" }, { "id": "46", "vertices": [ { - "x": 3733, - "y": 1808 + "x": 2633, + "y": 804 }, { - "x": 5142, - "y": 2108 - } - ] - }, - { - "id": "50", - "vertices": [ - { - "x": 3733, - "y": 1808 - }, - { - "x": 5142, - "y": 2108 - } - ] - }, - { - "id": "61", - "vertices": [ - { - "x": 5892, - "y": 2108 - }, - { - "x": 5892, - "y": 2508 - } - ] - }, - { - "id": "64", - "vertices": [ - { - "x": 2233, - "y": 908 - } - ] - }, - { - "id": "65", - "vertices": [ - { - "x": 6425, - "y": 2508 - } - ] - }, - { - "id": "67", - "vertices": [ - { - "x": 837, - "y": 2508 - }, - { - "x": 3425, - "y": 2808 - } - ] - }, - { - "id": "71" - }, - { - "id": "83", - "vertices": [ - { - "x": 208, - "y": 1404 - }, - { - "x": 208, - "y": 1808 - }, - { - "x": 867, - "y": 2108 - } - ] - }, - { - "id": "89", - "vertices": [ - { - "x": 1617, - "y": 2108 - } - ] - }, - { - "id": "90" - }, - { - "id": "91", - "vertices": [ - { - "x": 2892, - "y": 2508 - }, - { - "x": 3425, - "y": 2808 - }, - { - "x": 3425, - "y": 3108 - } - ] - }, - { - "id": "92" - }, - { - "id": "93" - }, - { - "id": "94" - }, - { - "id": "95" - }, - { - "id": "96", - "vertices": [ - { - "x": 3642, - "y": 2108 - } - ] - }, - { - "id": "97" - }, - { - "id": "98" - }, - { - "id": "99" - } - ], - "softwareSystemId": "4" - } - ], - "systemLandscapeViews": [ - { - "dimensions": { - "height": 2820, - "width": 4433 - }, - "elements": [ - { - "id": "1", - "x": 2425, - "y": 208 - }, - { - "id": "2", - "x": 208, - "y": 908 - }, - { - "id": "3", - "x": 908, - "y": 908 - }, - { - "id": "4", - "x": 1633, - "y": 1608 - }, - { - "id": "15", - "x": 3108, - "y": 958 - }, - { - "id": "22", - "x": 2358, - "y": 958 - }, - { - "id": "23", - "x": 1608, - "y": 958 - }, - { - "id": "24", - "x": 3195, - "y": 2210 - }, - { - "id": "25", - "x": 3125, - "y": 208 - }, - { - "id": "26", - "x": 3825, - "y": 208 - }, - { - "id": "32", - "x": 1633, - "y": 2210 - }, - { - "id": "33", - "x": 883, - "y": 2210 - }, - { - "id": "44", - "x": 2383, - "y": 2210 - }, - { - "id": "48", - "x": 2383, - "y": 2210 - } - ], - "enterpriseBoundaryVisible": true, - "key": "Bitwarden", - "order": 2, - "paperSize": "A3_Landscape", - "relationships": [ - { - "id": "101" - }, - { - "id": "107", - "vertices": [ - { - "x": 1708, - "y": 2058 - } - ] - }, - { - "id": "110" - }, - { - "id": "113", - "vertices": [ - { - "x": 2008, - "y": 2058 - } - ] - }, - { - "id": "115" - }, - { - "id": "29" - }, - { - "id": "41", - "vertices": [ - { - "x": 2958, - "y": 1308 + "x": 2633, + "y": 1208 } ] }, @@ -1643,37 +887,152 @@ "id": "47" }, { - "id": "51" + "id": "49" }, { - "id": "53" + "id": "52" }, { - "id": "60" + "id": "55" }, { - "id": "62", + "id": "57", "vertices": [ { - "x": 3708, - "y": 1308 + "x": 1350, + "y": 1508 } ] }, { - "id": "64" + "id": "59" + } + ], + "softwareSystemId": "9" + } + ], + "systemLandscapeViews": [ + { + "dimensions": { + "height": 2308, + "width": 8191 + }, + "elements": [ + { + "id": "1", + "x": 1733, + "y": 279 }, { - "id": "66" + "id": "2", + "x": 6083, + "y": 279 }, { - "id": "68", + "id": "3", + "x": 1708, + "y": 979 + }, + { + "id": "4", + "x": 958, + "y": 1679 + }, + { + "id": "9", + "x": 2408, + "y": 1029 + }, + { + "id": "14", + "x": 958, + "y": 1029 + }, + { + "id": "15", + "x": 208, + "y": 1029 + }, + { + "id": "16", + "x": 5333, + "y": 329 + }, + { + "id": "17", + "x": 2433, + "y": 279 + }, + { + "id": "18", + "x": 3133, + "y": 279 + }, + { + "id": "20", + "x": 4583, + "y": 329 + }, + { + "id": "21", + "x": 3833, + "y": 329 + }, + { + "id": "25", + "x": 3067, + "y": 1679 + }, + { + "id": "26", + "x": 3817, + "y": 1679 + }, + { + "id": "27", + "x": 6783, + "y": 329 + }, + { + "id": "41", + "x": 7533, + "y": 329 + } + ], + "enterpriseBoundaryVisible": true, + "key": "Bitwarden", + "order": 2, + "paperSize": "A1_Landscape", + "relationships": [ + { + "id": "34" + }, + { + "id": "37" + }, + { + "id": "40", "vertices": [ { - "x": 729, - "y": 1308 + "x": 2258, + "y": 1379 } ] + }, + { + "id": "43" + }, + { + "id": "48" + }, + { + "id": "50" + }, + { + "id": "68" + }, + { + "id": "70" } ] } diff --git a/docs/key_management/desktop_biometric/models.dsl b/docs/key_management/desktop_biometric/models.dsl new file mode 100644 index 00000000000..efe7d6e71f6 --- /dev/null +++ b/docs/key_management/desktop_biometric/models.dsl @@ -0,0 +1,37 @@ +!element clients.desktop { + biometric = component "Biometric Authentication" { + description "Handles biometric authentication for the Bitwarden desktop application." + } + + password = component "OS Password Management Native Module" { + description "CRUD operations on keys-values stored by the OS." + technology "rust module" + } + + ipc = component "IPC" { + description "Inter-process communication between the desktop application and the browser extension." + technology "Sockets" + } +} + +os_secure_storage = softwareSystem "OS Secure Storage" { + tags "External" + description "The operating system's secure storage for sensitive data, such as Windows Credential Locker or macOS Keychain." +} + +os_user_verification = softwareSystem "OS User Verification" { + tags "External" + description "The operating system's user verification system, such as Windows Hello or macOS Touch ID." +} + +windows_hello_signer = softwareSystem "Windows Hello Signer" { + tags "External" "Windows-Biometric" + description "A Windows Hello signer that can be used to sign requests for the Bitwarden desktop application." +} + +clients.browser_extension -> clients.desktop.ipc "Connects to IPC to request biometric authentication" +clients.desktop.ipc -> clients.desktop.biometric "Relays biometric authentication requests to" + +clients.desktop.biometric -> clients.desktop.password "Read/Write user keys" "Napi Rust FFI" +clients.desktop.password -> os_secure_storage "CRUD operations on keys stored in the OS secure storage" +clients.desktop.biometric -> os_user_verification "Requests user verification for biometric authentication" diff --git a/docs/key_management/desktop_biometric/views.dsl b/docs/key_management/desktop_biometric/views.dsl new file mode 100644 index 00000000000..3d72e777c4c --- /dev/null +++ b/docs/key_management/desktop_biometric/views.dsl @@ -0,0 +1,6 @@ +component clients.desktop "desktop_biometrics_macos" { + include * + include os_user_verification + autoLayout tb +} +// TODO: Add Windows and Linux, excluding relevant Tags diff --git a/docs/key_management/models.dsl b/docs/key_management/models.dsl index e69de29bb2d..97341754cd4 100644 --- a/docs/key_management/models.dsl +++ b/docs/key_management/models.dsl @@ -0,0 +1 @@ +!include "desktop_biometric/models.dsl" diff --git a/docs/key_management/views.dsl b/docs/key_management/views.dsl index e69de29bb2d..fb44495a66f 100644 --- a/docs/key_management/views.dsl +++ b/docs/key_management/views.dsl @@ -0,0 +1 @@ +!include "desktop_biometric/views.dsl" diff --git a/docs/platform/icons/models.dsl b/docs/platform/icons/models.dsl index 091cda88c51..0cbc2051f48 100644 --- a/docs/platform/icons/models.dsl +++ b/docs/platform/icons/models.dsl @@ -1,46 +1,7 @@ !element server { icons = container "Icons" { - !docs "threat_model.md" - icons_controller = component "IconsController" { - description "IconsController" - technology "C# ASP.NET Core" - - } - info_controller = component "InfoController" { - description "Provides information about the deployed icon service. Allow for health checks." - technology "C# ASP.NET Core" - tags "Info" "HealthCheck" - } - icon_determination = component "IconDetermination" { - description "Resolves a single source for a website icon and downloads it." - } - icon_cache = component "IconCache" { - description "Caches icons for a given domain" - tags "Cache" - technology "C# MemoryCache" - } - - clients -> icons_controller "Requests icons for cleartext urls from" { - perspectives { - "Security" "\ - Icons 1.2.1 Broken SSL communication exposes vault contents to network administrators \n\n\ - Icons 1.2.2 Tracking of user vault contents by ip correlation between identity and icons services \n\n\ - Icons 1.2.3 No SLA offered on Icons service, graceful degradation of features needed if it goes down \n\n\ - Icons 1.2.4 SSRF through crafted input resolving to a location the server has elevated privileges in\ - " - } - } - icons_controller -> icon_determination "Requests icons from" - icons_controller -> icon_cache "Caches icons in" { - perspectives { - "Security" "\ - Icons 1.3.1 Aggregate vault content leak through timing attack on cache \n\n\ - Icons 1.3.2 Possible injection attack through cache key \n\n\ - Icons 1.3.3 & Icons 1.3.4 Cache bloat leading to DoS \n\n\ - Icons 1.3.5 Cache poisoning leading to incorrect icon storage \ - " - } - } + description "The Icons service provides favicons for websites." + clients -> server.icons "Requests icons for cleartext urls from" } } @@ -48,12 +9,3 @@ dns = softwareSystem "DNS" { tags "External" tags "Icons" } - -server.icons.icon_determination -> dns "Resolves IP addresses for domain names from" - -external_websites = softwareSystem "External Websites" { - tags "External" - tags "Icons" -} - -server.icons.icon_determination -> external_websites "Retrieves icons from" diff --git a/docs/platform/icons/threat_model.md b/docs/platform/icons/threat_model.md deleted file mode 100644 index 26c5d886c6c..00000000000 --- a/docs/platform/icons/threat_model.md +++ /dev/null @@ -1,167 +0,0 @@ -## Threat Model - -### Example Model or Relationship - -#### Example Threat - -- **Type**: type -- **Priority**: TBD/Low/Medium/High/Critical -- **Likelihood**: TBD/Low/Medium/High/Critical -- **Impact**: TBD/Low/Medium/High/Critical - -description of the threat. - -##### Example Threat Mitigations - -describe the mitigations for the threat. - -### Clients -> IconsController - -Communication from clients to the icons component. This is an unauthenticated endpoint with minimal input validation. - -#### SSL termination exposes vault contents to network administrators - -- **Type**: Information Disclosure -- **Priority**: TBD -- **Likelihood**: TBD -- **Impact**: TBD - -A machine with SSL terminating proxies cannot rely on encrypted query parameters hiding vault contents from network administrators. - -##### Mitigations - -- Not Implemented: Establish encrypted pipe communication with Icons service prior to requesting icon resolution - -#### Cleartext transmission of vault contents to Server - -- **Type**: Information Disclosure -- **Priority**: TBD -- **Likelihood**: TBD -- **Impact**: TBD - -Server-side after TLS by necessity to lookup a favicon. However, to maintain our promises as a no-log proxy, we need to be sure not to maintain ip records for icon service requests - -##### Mitigations - -- Unconfirmed: Configure network edge and datadog to drop this identifying data. - -#### No SLA offered on Icons service - -- **Type**: Denial of Service -- **Priority**: TBD -- **Likelihood**: TBD -- **Impact**: TBD - -We do not offer SLA on up time of icons service. Clients may be unable to resolve icons, and we need to determine a graceful degradation strategy. - -##### Mitigations - -- Done: Default icon fallback (globe) -- Not Implemented, Not Prioritized: Local cache of retrieved icons - -#### SSRF by proxied requests - -- **Type**: Elevation of Privilege / Information Disclosure -- **Priority**: TBD -- **Likelihood**: TBD -- **Impact**: TBD - -The service is designed to proxy requests to arbitrary URLs. This can be used to access internal network resources. - -If a site redirects to an internal network address, the internal network topography may be exposed to the client. - -##### Mitigations - -- Done: Isolation of the icons component from the rest of the system intranet. -- Done: Avoid fetching by domain name. All requests must be first resolved to an IP address and filtered against internal network ranges, defined as: - - - `::1`, `::`, `::ffff:` - - IPv6 and starting with `fc`, `fd`, `fe`, or `ff` - - IPv4 and starting with `0.`, `10.`, `100.`, `127.`, `169.254`, `172.16-31`, or `192.168` - - This is done in the `IconDetermination` component - -### IconsController -> IconCache - -Communication from the icons controller to a mem cache of previously retrieved icons, keyed by original domain requested. - -#### Cache determination through timing measurements - -- **Type**: Information Disclosure -- **Priority**: Low -- **Likelihood**: Low -- **Impact**: Low - -By measuring the time it takes to retrieve an icon, an attacker may be able to determine if a domain has been previously requested by another user, revealing that some user on the service has that domain in their vault. - -##### Mitigations - -None identified - -#### Unescaped storage of user-input data in cache - -- **Type**: Tampering -- **Priority**: Low -- **Likelihood**: Low -- **Impact**: Low - -Unescaped user input data may be stored as keys in the cache. This input data is not executed, but if the storage method is changed in the future, this may lead to some injection attack. - -##### Mitigations - -None identified - -#### Cache bloat through intentionally large icons - -- **Type**: Denial of Service -- **Priority**: TBD -- **Likelihood**: TBD -- **Impact**: TBD - -User request may intentionally resolve to very large icons, bloating the cache and increasing memory requirements. - -Open question: Should we also limit the size of icons fetched? - -##### Mitigations - -Done: Limit size of icons stored in cache - -#### Cache bloat through many unique domain requests - -- **Type**: Denial of Service -- **Priority**: TBD -- **Likelihood**: TBD -- **Impact**: TBD - -User request may intentionally resolve many unique domains to resolve that may or may not exist, bloating the cache and increasing memory requirements. - -##### Mitigations - -Unconfirmed: Rate limit requests to the icons service - -#### Storage of potentially sensitive data as keys or values in cache - -- **Type**: Information Disclosure -- **Priority**: TBD -- **Likelihood**: TBD -- **Impact**: TBD - -Upload of urls is automatic to our icon service. If our filters for upload are incorrect, we may store sensitive data in our cache. For example, onion addresses. - -##### Mitigations - -Done: Avoid filter known sensitive urls -Not implemented, Not prioritized: Add client-side setting to disable icon request for a given url or pattern - -#### Cache poisoning via dns poisoning - -- **Type**: Tampering -- **Priority**: Low -- **Likelihood**: Low -- **Impact**: Low - -DNS poisoning would lead to incorrect icons being cached for a given domain. - -##### Mitigations - -None Identified diff --git a/docs/platform/views.dsl b/docs/platform/views.dsl index a9f45b20a76..e69de29bb2d 100644 --- a/docs/platform/views.dsl +++ b/docs/platform/views.dsl @@ -1,3 +0,0 @@ -component server.icons "icons_service" { - include * -} diff --git a/docs/shared.models.dsl b/docs/shared.models.dsl index 7fc29359199..9cf66d32b78 100644 --- a/docs/shared.models.dsl +++ b/docs/shared.models.dsl @@ -23,40 +23,11 @@ bw_controlled = group "Bitwarden Controlled" { tags "Events" } notifications = container "Notifications" - portal = container "Bitwarden Portal" { - tags "Web" - } - events_processor = container "Events Processor" { - tags "Events" - } - - # Data stores - database = container "Database" { - tags "Database" - } - events_queue = container "Events Queue" { - tags "Queue" - tags "Azure" - } - mail_queue = container "Mail Queue" { - tags "Queue" - tags "Azure" - } - notifications_queue = container "Notifications Queue" { - tags "Queue" - tags "Azure" - } } clients = softwareSystem "Clients" { web = container "Web Application" { tags "Web" } - ios = container "iOS Application" { - tags "Mobile" - } - android = container "Android Application" { - tags "Mobile" - } browser_extension = container "Browser Extension" { tags "Browser" } @@ -67,11 +38,6 @@ bw_controlled = group "Bitwarden Controlled" { tags "Desktop" } } - directory_connector = softwareSystem "Directory Connector" { - tags "Directory" - tags "LDAP" - tags "Self-Hosted" - } key_connector = softwareSystem "Key Connector" } @@ -80,3 +46,8 @@ self_hosted_instances = softwareSystem "Self-Hosted Instances" { tags "External" description "Self-hosted instances of Bitwarden servers" } + +external_websites = softwareSystem "External Websites" { + tags "External" + tags "Icons" +} diff --git a/docs/shared.relationships.dsl b/docs/shared.relationships.dsl index 0d3eb7c4a2e..a4d483a8fe4 100644 --- a/docs/shared.relationships.dsl +++ b/docs/shared.relationships.dsl @@ -1,26 +1,17 @@ # User Relationships user -> clients.web "Uses" -user -> clients.ios "Uses" -user -> clients.android "Uses" user -> clients.browser_extension "Uses" user -> clients.cli "Uses" user -> clients.desktop "Uses" admin -> clients.web "Administers Organizations" -provider -> server.portal "Completes Provider registration with" provider -> clients.web "Administers Providers and Organizations" -customer_success -> server.portal "Inspects and supports" -system_admin -> server.portal "Administers System" # High-level Client Relationships clients.web -> server.api "Makes requests to" -clients.ios -> server.api "Makes requests to" -clients.android -> server.api "Makes requests to" clients.browser_extension -> server.api "Makes requests to" clients.cli -> server.api "Makes requests to" clients.desktop -> server.api "Makes requests to" clients.web -> server.identity "Authenticates with" -clients.ios -> server.identity "Authenticates With" -clients.android -> server.identity "Authenticates With" clients.browser_extension -> server.identity "Authenticates With" clients.cli -> server.identity "Authenticates With" clients.desktop -> server.identity "Authenticates With" @@ -29,19 +20,5 @@ server.api -> server.identity "Validates JWTs with" { } clients -> server.events "Posts local usage events to" -# Database Relationships - -server.api -> server.database "Queries" -server.portal -> server.database "Queries" - -# queue Relationships -server.api -> server.events_queue "Sends events to" -server.events -> server.events_queue "Sends events to" -server.api -> server.mail_queue "Sends emails to" -server.api -> server.notifications_queue "Sends notifications to" -server.notifications -> server.notifications_queue "Sends notifications to" -server.events_queue -> server.events_processor "Processes events from" -server.mail_queue -> server.portal "Processes emails from" - # self host phone home self_hosted_instances -> server.notifications "Sends push notification proxy requests to"