mirror of
https://github.com/bitwarden/browser
synced 2025-12-13 23:03:32 +00:00
SG-680 - Domain Add Edit Dialog - (1) Random generation of DNS TXT Record now working (2) DNS TXT Record Copyable (3) Additional translations added (4) Info callout added
This commit is contained in:
@@ -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."
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,19 +3,30 @@
|
||||
<div bitDialogContent>
|
||||
<form [formGroup]="domainForm">
|
||||
<bit-form-field>
|
||||
<bit-label>Domain name</bit-label>
|
||||
<bit-label>{{ "domainName" | i18n }}</bit-label>
|
||||
<input bitInput formControlName="domainName" />
|
||||
<bit-hint
|
||||
>Example: mydomain.com. Subdomains require separate entries to be verified.</bit-hint
|
||||
>
|
||||
<bit-hint>{{ "domainNameInputHint" | i18n }}</bit-hint>
|
||||
</bit-form-field>
|
||||
|
||||
<bit-form-field>
|
||||
<bit-label>DNS TXT record</bit-label>
|
||||
<bit-label>{{ "dnsTxtRecord" | i18n }}</bit-label>
|
||||
<input bitInput formControlName="txt" />
|
||||
<bit-hint>Copy and paste the TXT record into your DNS Provider.</bit-hint>
|
||||
<bit-hint>{{ "dnsTxtRecordInputHint" | i18n }}</bit-hint>
|
||||
<button
|
||||
type="button"
|
||||
bitSuffix
|
||||
bitButton
|
||||
appA11yTitle="{{ 'copyDnsTxtRecord' | i18n }}"
|
||||
(click)="copyDnsTxt()"
|
||||
>
|
||||
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
||||
</button>
|
||||
</bit-form-field>
|
||||
</form>
|
||||
|
||||
<bit-callout type="info" title="{{ 'automaticDomainVerification' | i18n }}">
|
||||
{{ "automaticDomainVerificationProcess" | i18n }}
|
||||
</bit-callout>
|
||||
</div>
|
||||
<div bitDialogFooter class="tw-flex tw-flex-row tw-items-center tw-gap-2">
|
||||
<button bitButton buttonType="primary">{{ "verifyDomain" | i18n }}</button>
|
||||
|
||||
@@ -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<void> {
|
||||
// If we have data.orgDomain, then editing, otherwise creating new domain
|
||||
await this.populateForm();
|
||||
}
|
||||
|
||||
async populateForm(): Promise<void> {
|
||||
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"))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user