diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 846da4d8105..641215b845f 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -5537,5 +5537,24 @@ }, "verifyDomain": { "message": "Verify domain" + }, + "copyDnsTxtRecord": { + "message": "Copy DNS TXT record" + }, + "dnsTxtRecord": { + "message": "DNS TXT record" + }, + "dnsTxtRecordInputHint": { + "message": "Copy and paste the TXT record into your DNS Provider." + }, + "domainNameInputHint": { + "message": "Example: mydomain.com. Subdomains require separate entries to be verified." + }, + "automaticDomainVerification": { + "message": "Automatic Domain Verification" + }, + "automaticDomainVerificationProcess": { + "message": "Bitwarden will attempt to verify the domain 3 times during the first 72 hours. If the domain can’t be verified, check the DNS record in your host and manually verify." } + } diff --git a/bitwarden_license/bit-web/src/app/organizations/manage/domain-verification/domain-add-edit-dialog/domain-add-edit-dialog.component.html b/bitwarden_license/bit-web/src/app/organizations/manage/domain-verification/domain-add-edit-dialog/domain-add-edit-dialog.component.html index 34973505b03..6f35ecadeb4 100644 --- a/bitwarden_license/bit-web/src/app/organizations/manage/domain-verification/domain-add-edit-dialog/domain-add-edit-dialog.component.html +++ b/bitwarden_license/bit-web/src/app/organizations/manage/domain-verification/domain-add-edit-dialog/domain-add-edit-dialog.component.html @@ -3,19 +3,30 @@
- Domain name + {{ "domainName" | i18n }} - Example: mydomain.com. Subdomains require separate entries to be verified. + {{ "domainNameInputHint" | i18n }} - DNS TXT record + {{ "dnsTxtRecord" | i18n }} - Copy and paste the TXT record into your DNS Provider. + {{ "dnsTxtRecordInputHint" | i18n }} +
+ + + {{ "automaticDomainVerificationProcess" | i18n }} +
diff --git a/bitwarden_license/bit-web/src/app/organizations/manage/domain-verification/domain-add-edit-dialog/domain-add-edit-dialog.component.ts b/bitwarden_license/bit-web/src/app/organizations/manage/domain-verification/domain-add-edit-dialog/domain-add-edit-dialog.component.ts index e27b72763fc..bfa34b394fc 100644 --- a/bitwarden_license/bit-web/src/app/organizations/manage/domain-verification/domain-add-edit-dialog/domain-add-edit-dialog.component.ts +++ b/bitwarden_license/bit-web/src/app/organizations/manage/domain-verification/domain-add-edit-dialog/domain-add-edit-dialog.component.ts @@ -1,9 +1,12 @@ import { DialogRef, DIALOG_DATA } from "@angular/cdk/dialog"; import { Component, Inject, OnInit } from "@angular/core"; -import { FormBuilder, FormGroup, Validators } from "@angular/forms"; +import { FormBuilder, FormControl, FormGroup, Validators } from "@angular/forms"; +import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/abstractions/cryptoFunction.service"; +import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { OrganizationDomainResponse } from "@bitwarden/common/abstractions/organization-domain/responses/organization-domain.response"; - +import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; +import { Utils } from "@bitwarden/common/misc/utils"; export interface DomainAddEditDialogData { organizationId: string; orgDomain: OrganizationDomainResponse; @@ -17,18 +20,57 @@ export class DomainAddEditDialogComponent implements OnInit { dialogSize: "small" | "default" | "large" = "default"; disablePadding = false; + // TODO: custom validator for preventing https:// or www. on domainName domainForm: FormGroup = this.formBuilder.group({ domainName: ["", [Validators.required]], - txt: [""], + txt: [{ value: null, disabled: true }], }); + get domainNameCtrl(): FormControl { + return this.domainForm.controls.domainName as FormControl; + } + get txtCtrl(): FormControl { + return this.domainForm.controls.txt as FormControl; + } + constructor( public dialogRef: DialogRef, @Inject(DIALOG_DATA) public data: DomainAddEditDialogData, - private formBuilder: FormBuilder + private formBuilder: FormBuilder, + private cryptoFunctionService: CryptoFunctionServiceAbstraction, + private platformUtilsService: PlatformUtilsService, + private i18nService: I18nService ) {} - ngOnInit(): void { + async ngOnInit(): Promise { // If we have data.orgDomain, then editing, otherwise creating new domain + await this.populateForm(); + } + + async populateForm(): Promise { + if (this.data.orgDomain) { + // Edit + this.domainForm.patchValue(this.data.orgDomain); + } else { + // Add + + // Figuring out the proper length of our DNS TXT Record value was fun. + // DNS-Based Service Discovery RFC: https://www.ietf.org/rfc/rfc6763.txt; see section 6.1 + // Google uses 43 chars for their TXT record value: https://support.google.com/a/answer/2716802 + // So, chose a magic # of 33 bytes to achieve at least that once converted to base 64 (47 char length). + const generatedTxt = `bw=${Utils.fromBufferToB64( + await this.cryptoFunctionService.randomBytes(33) + )}`; + this.txtCtrl.setValue(generatedTxt); + } + } + + copyDnsTxt() { + this.platformUtilsService.copyToClipboard(this.txtCtrl.value); + this.platformUtilsService.showToast( + "info", + null, + this.i18nService.t("valueCopied", this.i18nService.t("dnsTxtRecord")) + ); } }