Skip to content

Commit

Permalink
Merge branch 'main' into km/fix-bio
Browse files Browse the repository at this point in the history
  • Loading branch information
quexten authored Jan 13, 2025
2 parents b230395 + a54508a commit 0f44783
Show file tree
Hide file tree
Showing 20 changed files with 114 additions and 57 deletions.
2 changes: 1 addition & 1 deletion apps/browser/src/background/nativeMessaging.background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ export class NativeMessagingBackground {
message.command == BiometricsCommands.Unlock ||
message.command == BiometricsCommands.IsAvailable
) {
// TODO remove after 2025.01
// TODO remove after 2025.3
// wait until there is no other callbacks, or timeout
const call = await firstValueFrom(
race(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,15 @@ export class ExtensionLockComponentService implements LockComponentService {
if (!(await firstValueFrom(this.biometricStateService.biometricUnlockEnabled$))) {
return BiometricsStatus.NotEnabledLocally;
} else {
return await this.biometricsService.getBiometricsStatusForUser(userId);
// TODO remove after 2025.3
// remove after backward compatibility code for old biometrics ipc protocol is removed
const result: BiometricsStatus = (await Promise.race([
this.biometricsService.getBiometricsStatusForUser(userId),
new Promise((resolve) =>
setTimeout(() => resolve(BiometricsStatus.DesktopDisconnected), 1000),
),
])) as BiometricsStatus;
return result;
}
}),
this.userDecryptionOptionsService.userDecryptionOptionsById$(userId),
Expand Down
4 changes: 1 addition & 3 deletions apps/desktop/resources/com.bitwarden.desktop.devel.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ command: bitwarden.sh
finish-args:
- --share=ipc
- --share=network
- --socket=wayland
- --socket=x11
- --device=dri
- --env=XDG_CURRENT_DESKTOP=Unity
Expand Down Expand Up @@ -43,5 +42,4 @@ modules:
commands:
- ulimit -c 0
- export TMPDIR="$XDG_RUNTIME_DIR/app/$FLATPAK_ID"
- exec zypak-wrapper /app/bin/bitwarden-app --ozone-platform-hint=auto
--enable-features=WaylandWindowDecorations "$@"
- exec zypak-wrapper /app/bin/bitwarden-app "$@"
14 changes: 14 additions & 0 deletions apps/desktop/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,20 @@ export class AppComponent implements OnInit, OnDestroy {
}
break;
}
case "upgradeOrganization": {
const upgradeConfirmed = await this.dialogService.openSimpleDialog({
title: { key: "upgradeOrganization" },
content: { key: "upgradeOrganizationDesc" },
acceptButtonText: { key: "learnMore" },
type: "info",
});
if (upgradeConfirmed) {
this.platformUtilsService.launchUri(
"https://bitwarden.com/help/upgrade-from-individual-to-org/",
);
}
break;
}
case "emailVerificationRequired": {
const emailVerificationConfirmed = await this.dialogService.openSimpleDialog({
title: { key: "emailVerificationRequired" },
Expand Down
9 changes: 9 additions & 0 deletions apps/desktop/src/locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -3474,5 +3474,14 @@
},
"changeAcctEmail": {
"message": "Change account email"
},
"organizationUpgradeRequired": {
"message": "Organization upgrade required"
},
"upgradeOrganization": {
"message": "Upgrade organization"
},
"upgradeOrganizationDesc": {
"message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features."
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ export class BiometricMessageHandlerService {
appId,
);
}
// TODO: legacy, remove after 2025.01
// TODO: legacy, remove after 2025.3
case BiometricsCommands.IsAvailable: {
const available =
(await this.biometricsService.getBiometricsStatus()) == BiometricsStatus.Available;
Expand All @@ -200,7 +200,7 @@ export class BiometricMessageHandlerService {
appId,
);
}
// TODO: legacy, remove after 2025.01
// TODO: legacy, remove after 2025.3
case BiometricsCommands.Unlock: {
const isTemporarilyDisabled =
(await this.biometricStateService.getBiometricUnlockEnabled(message.userId as UserId)) &&
Expand Down
10 changes: 10 additions & 0 deletions apps/desktop/src/vault/app/vault/view.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,16 @@ <h2 class="box-header">
</span>
</div>
</div>
<div class="box-content-row box-content-row-flex totp" *ngIf="showUpgradeRequiredTotp">
<div class="row-main">
<span class="row-label">{{ "verificationCodeTotp" | i18n }}</span>
<span class="row-label">
<a [routerLink]="" (click)="upgradeOrganization()"
>{{ "organizationUpgradeRequired" | i18n }}
</a>
</span>
</div>
</div>
</div>
<!-- Card -->
<div *ngIf="cipher.card">
Expand Down
6 changes: 6 additions & 0 deletions apps/desktop/src/vault/app/vault/view.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,10 @@ export class ViewComponent extends BaseViewComponent implements OnInit, OnDestro
this.messagingService.send("premiumRequired");
}
}

upgradeOrganization() {
this.messagingService.send("upgradeOrganization", {
organizationId: this.cipher.organizationId,
});
}
}
5 changes: 3 additions & 2 deletions apps/web/src/app/vault/individual-vault/add-edit.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit, On
protected messagingService: MessagingService,
eventCollectionService: EventCollectionService,
protected policyService: PolicyService,
organizationService: OrganizationService,
protected organizationService: OrganizationService,
logService: LogService,
passwordRepromptService: PasswordRepromptService,
dialogService: DialogService,
Expand Down Expand Up @@ -307,7 +307,8 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit, On
this.cipher.type === CipherType.Login &&
this.cipher.login.totp &&
this.organization?.productTierType != ProductTierType.Free &&
(this.cipher.organizationUseTotp || this.canAccessPremium)
((this.canAccessPremium && this.cipher.organizationId == null) ||
this.cipher.organizationUseTotp)
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ import { KeyService } from "@bitwarden/key-management";
templateUrl: "setup.component.html",
})
export class SetupComponent implements OnInit, OnDestroy {
@ViewChild(ManageTaxInformationComponent)
manageTaxInformationComponent: ManageTaxInformationComponent;
@ViewChild(ManageTaxInformationComponent) taxInformationComponent: ManageTaxInformationComponent;

loading = true;
providerId: string;
Expand Down Expand Up @@ -111,7 +110,7 @@ export class SetupComponent implements OnInit, OnDestroy {
try {
this.formGroup.markAllAsTouched();

if (!this.manageTaxInformationComponent.validate() || !this.formGroup.valid) {
if (!this.taxInformationComponent.validate() || !this.formGroup.valid) {
return;
}

Expand All @@ -125,7 +124,7 @@ export class SetupComponent implements OnInit, OnDestroy {
request.key = key;

request.taxInfo = new ExpandedTaxInfoUpdateRequest();
const taxInformation = this.manageTaxInformationComponent.getTaxInformation();
const taxInformation = this.taxInformationComponent.getTaxInformation();

request.taxInfo.country = taxInformation.country;
request.taxInfo.postalCode = taxInformation.postalCode;
Expand All @@ -147,6 +146,7 @@ export class SetupComponent implements OnInit, OnDestroy {

await this.router.navigate(["/providers", provider.id]);
} catch (e) {
e.message = this.i18nService.translate(e.message) || e.message;
this.validationService.showError(e);
}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { NgModule } from "@angular/core";

import { BannerModule } from "@bitwarden/components";
import { OnboardingModule } from "@bitwarden/web-vault/app/shared/components/onboarding/onboarding.module";

// FIXME: remove `src` and fix import
// eslint-disable-next-line no-restricted-imports
import { OnboardingModule } from "../../../../../../apps/web/src/app/shared/components/onboarding/onboarding.module";
import { SecretsManagerSharedModule } from "../shared/sm-shared.module";

import { OverviewRoutingModule } from "./overview-routing.module";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { ToastService } from "@bitwarden/components";
import { RouterService } from "@bitwarden/web-vault/app/core";

// FIXME: remove `src` and fix import
// eslint-disable-next-line no-restricted-imports
import { RouterService } from "../../../../../../../apps/web/src/app/core/router.service";
import { ProjectView } from "../../models/view/project.view";
import { ProjectService } from "../project.service";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { ToastService } from "@bitwarden/components";
import { RouterService } from "@bitwarden/web-vault/app/core";

// FIXME: remove `src` and fix import
// eslint-disable-next-line no-restricted-imports
import { RouterService } from "../../../../../../../../clients/apps/web/src/app/core/router.service";
import { ServiceAccountView } from "../../models/view/service-account.view";
import { ServiceAccountService } from "../service-account.service";

Expand Down
2 changes: 1 addition & 1 deletion libs/angular/src/vault/components/add-edit.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export class AddEditComponent implements OnInit, OnDestroy {
protected policyService: PolicyService,
protected logService: LogService,
protected passwordRepromptService: PasswordRepromptService,
private organizationService: OrganizationService,
protected organizationService: OrganizationService,
protected dialogService: DialogService,
protected win: Window,
protected datePipe: DatePipe,
Expand Down
16 changes: 10 additions & 6 deletions libs/angular/src/vault/components/view.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export class ViewComponent implements OnDestroy, OnInit {
showPrivateKey: boolean;
canAccessPremium: boolean;
showPremiumRequiredTotp: boolean;
showUpgradeRequiredTotp: boolean;
totpCode: string;
totpCodeFormatted: string;
totpDash: number;
Expand Down Expand Up @@ -151,22 +152,25 @@ export class ViewComponent implements OnDestroy, OnInit {
this.billingAccountProfileStateService.hasPremiumFromAnySource$(activeUserId),
);
this.showPremiumRequiredTotp =
this.cipher.login.totp && !this.canAccessPremium && !this.cipher.organizationUseTotp;
this.cipher.login.totp && !this.canAccessPremium && !this.cipher.organizationId;
this.canDeleteCipher$ = this.cipherAuthorizationService.canDeleteCipher$(this.cipher, [
this.collectionId as CollectionId,
]);

this.showUpgradeRequiredTotp =
this.cipher.login.totp && this.cipher.organizationId && !this.cipher.organizationUseTotp;

if (this.cipher.folderId) {
this.folder = await (
await firstValueFrom(this.folderService.folderViews$(activeUserId))
).find((f) => f.id == this.cipher.folderId);
}

if (
this.cipher.type === CipherType.Login &&
this.cipher.login.totp &&
(cipher.organizationUseTotp || this.canAccessPremium)
) {
const canGenerateTotp = this.cipher.organizationId
? this.cipher.organizationUseTotp
: this.canAccessPremium;

if (this.cipher.type === CipherType.Login && this.cipher.login.totp && canGenerateTotp) {
await this.totpUpdateCode();
const interval = this.totpService.getTimeInterval(this.cipher.login.totp);
await this.totpTick(interval);
Expand Down
5 changes: 5 additions & 0 deletions libs/importer/src/components/import.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,11 @@ <h2 class="tw-font-bold" bitTypography="h6">{{ "data" | i18n }}</h2>
Open the FullClient, go to the Main Menu and select Export. Start the export passwords
wizard and follow the instructions to export a CSV file.
</ng-container>
<ng-container *ngIf="format === 'nordpasscsv'">
Log in to NordPass and open Settings &rarr; Scroll down to the Import and Export section
and select Export items &rarr; Enter your Master Password and select Continue. &rarr; Save
the CSV file on your device.
</ng-container>
</bit-callout>
<import-lastpass
*ngIf="showLastPassOptions"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ <h2 bitTypography="h6">{{ "loginCredentials" | i18n }}</h2>
<bit-label [appTextDrag]="totpCodeCopyObj?.totpCode"
>{{ "verificationCodeTotp" | i18n }}
<span
*ngIf="!(isPremium$ | async)"
*ngIf="!(allowTotpGeneration$ | async)"
bitBadge
variant="success"
class="tw-ml-2 tw-cursor-pointer"
Expand All @@ -130,14 +130,14 @@ <h2 bitTypography="h6">{{ "loginCredentials" | i18n }}</h2>
id="totp"
readonly
bitInput
[type]="!(isPremium$ | async) ? 'password' : 'text'"
[type]="!(allowTotpGeneration$ | async) ? 'password' : 'text'"
[value]="totpCodeCopyObj?.totpCodeFormatted || '*** ***'"
aria-readonly="true"
data-testid="login-totp"
class="tw-font-mono"
/>
<div
*ngIf="isPremium$ | async"
*ngIf="allowTotpGeneration$ | async"
bitTotpCountdown
[cipher]="cipher"
bitSuffix
Expand All @@ -152,7 +152,7 @@ <h2 bitTypography="h6">{{ "loginCredentials" | i18n }}</h2>
showToast
[appA11yTitle]="'copyVerificationCode' | i18n"
data-testid="copy-totp"
[disabled]="!(isPremium$ | async)"
[disabled]="!(allowTotpGeneration$ | async)"
class="disabled:tw-cursor-default"
></button>
</bit-form-field>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@
// @ts-strict-ignore
import { CommonModule, DatePipe } from "@angular/common";
import { Component, inject, Input } from "@angular/core";
import { Observable, switchMap } from "rxjs";
import {
BehaviorSubject,
combineLatest,
filter,
map,
Observable,
shareReplay,
switchMap,
} from "rxjs";

import { JslibModule } from "@bitwarden/angular/jslib.module";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
Expand All @@ -12,13 +20,13 @@ import { EventType } from "@bitwarden/common/enums";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import {
BadgeModule,
ColorPasswordModule,
FormFieldModule,
IconButtonModule,
SectionComponent,
SectionHeaderComponent,
TypographyModule,
IconButtonModule,
BadgeModule,
ColorPasswordModule,
} from "@bitwarden/components";

// FIXME: remove `src` and fix import
Expand Down Expand Up @@ -51,13 +59,31 @@ type TotpCodeValues = {
],
})
export class LoginCredentialsViewComponent {
@Input() cipher: CipherView;
@Input()
get cipher(): CipherView {
return this._cipher$.value;
}
set cipher(value: CipherView) {
this._cipher$.next(value);
}
private _cipher$ = new BehaviorSubject<CipherView>(null);

isPremium$: Observable<boolean> = this.accountService.activeAccount$.pipe(
private _userHasPremium$: Observable<boolean> = this.accountService.activeAccount$.pipe(
switchMap((account) =>
this.billingAccountProfileStateService.hasPremiumFromAnySource$(account.id),
),
);

allowTotpGeneration$: Observable<boolean> = combineLatest([
this._userHasPremium$,
this._cipher$.pipe(filter((c) => c != null)),
]).pipe(
map(([userHasPremium, cipher]) => {
// User premium status only applies to personal ciphers, organizationUseTotp applies to organization ciphers
return (userHasPremium && cipher.organizationId == null) || cipher.organizationUseTotp;
}),
shareReplay({ refCount: true, bufferSize: 1 }),
);
showPasswordCount: boolean = false;
passwordRevealed: boolean = false;
totpCodeCopyObj: TotpCodeValues;
Expand Down
Loading

0 comments on commit 0f44783

Please sign in to comment.