mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 16:23:44 +00:00
Merge branch 'main' into autofill/pm-5189-fix-issues-present-with-inline-menu-rendering-in-iframes
This commit is contained in:
34
.github/workflows/test.yml
vendored
34
.github/workflows/test.yml
vendored
@@ -1,5 +1,4 @@
|
|||||||
---
|
name: Testing
|
||||||
name: Run tests
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
@@ -8,29 +7,20 @@ on:
|
|||||||
- "main"
|
- "main"
|
||||||
- "rc"
|
- "rc"
|
||||||
- "hotfix-rc-*"
|
- "hotfix-rc-*"
|
||||||
pull_request_target:
|
pull_request:
|
||||||
types: [opened, synchronize]
|
types: [opened, synchronize]
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check-run:
|
|
||||||
name: Check PR run
|
|
||||||
uses: bitwarden/gh-actions/.github/workflows/check-run.yml@main
|
|
||||||
|
|
||||||
test:
|
test:
|
||||||
name: Run tests
|
name: Run tests
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
needs: check-run
|
|
||||||
permissions:
|
permissions:
|
||||||
checks: write
|
checks: write
|
||||||
contents: read
|
contents: read
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Check out repo
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||||
|
|
||||||
- name: Get Node Version
|
- name: Get Node Version
|
||||||
@@ -75,14 +65,26 @@ jobs:
|
|||||||
reporter: jest-junit
|
reporter: jest-junit
|
||||||
fail-on-error: true
|
fail-on-error: true
|
||||||
|
|
||||||
|
- name: Check for Codecov secret
|
||||||
|
id: check-codecov-secret
|
||||||
|
run: |
|
||||||
|
if [ "${{ secrets.CODECOV_TOKEN }}" != '' ]; then
|
||||||
|
echo "available=true" >> $GITHUB_OUTPUT;
|
||||||
|
else
|
||||||
|
echo "available=false" >> $GITHUB_OUTPUT;
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Upload to codecov.io
|
- name: Upload to codecov.io
|
||||||
uses: codecov/codecov-action@54bcd8715eee62d40e33596ef5e8f0f48dbbccab # v4.1.0
|
uses: codecov/codecov-action@54bcd8715eee62d40e33596ef5e8f0f48dbbccab # v4.1.0
|
||||||
|
if: steps.check-codecov-secret.outputs.available == 'true'
|
||||||
env:
|
env:
|
||||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
|
||||||
rust:
|
rust:
|
||||||
name: rust - ${{ matrix.os }}
|
name: Run Rust tests on ${{ matrix.os }}
|
||||||
runs-on: ${{ matrix.os || 'ubuntu-latest' }}
|
runs-on: ${{ matrix.os || 'ubuntu-latest' }}
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
@@ -92,7 +94,7 @@ jobs:
|
|||||||
- windows-latest
|
- windows-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Rust version check
|
- name: Check Rust version
|
||||||
run: rustup --version
|
run: rustup --version
|
||||||
|
|
||||||
- name: Install gnome-keyring
|
- name: Install gnome-keyring
|
||||||
@@ -101,7 +103,7 @@ jobs:
|
|||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y gnome-keyring dbus-x11
|
sudo apt-get install -y gnome-keyring dbus-x11
|
||||||
|
|
||||||
- name: Checkout repo
|
- name: Check out repo
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|||||||
@@ -938,7 +938,6 @@ export default class MainBackground {
|
|||||||
logoutCallback,
|
logoutCallback,
|
||||||
this.stateService,
|
this.stateService,
|
||||||
this.authService,
|
this.authService,
|
||||||
this.authRequestService,
|
|
||||||
this.messagingService,
|
this.messagingService,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -166,20 +166,6 @@
|
|||||||
"recommendedForSecurity" | i18n
|
"recommendedForSecurity" | i18n
|
||||||
}}</small>
|
}}</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
|
||||||
<div class="checkbox">
|
|
||||||
<label for="approveLoginRequests">
|
|
||||||
<input
|
|
||||||
id="approveLoginRequests"
|
|
||||||
type="checkbox"
|
|
||||||
formControlName="approveLoginRequests"
|
|
||||||
(change)="updateApproveLoginRequests()"
|
|
||||||
/>
|
|
||||||
{{ "approveLoginRequests" | i18n }}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<small class="help-block">{{ "approveLoginRequestDesc" | i18n }}</small>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { FormBuilder } from "@angular/forms";
|
|||||||
import { BehaviorSubject, Observable, Subject, firstValueFrom } from "rxjs";
|
import { BehaviorSubject, Observable, Subject, firstValueFrom } from "rxjs";
|
||||||
import { concatMap, debounceTime, filter, map, switchMap, takeUntil, tap } from "rxjs/operators";
|
import { concatMap, debounceTime, filter, map, switchMap, takeUntil, tap } from "rxjs/operators";
|
||||||
|
|
||||||
import { AuthRequestServiceAbstraction, PinServiceAbstraction } from "@bitwarden/auth/common";
|
import { PinServiceAbstraction } from "@bitwarden/auth/common";
|
||||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
|
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
|
||||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||||
@@ -90,7 +90,6 @@ export class SettingsComponent implements OnInit {
|
|||||||
biometric: false,
|
biometric: false,
|
||||||
autoPromptBiometrics: false,
|
autoPromptBiometrics: false,
|
||||||
requirePasswordOnStart: false,
|
requirePasswordOnStart: false,
|
||||||
approveLoginRequests: false,
|
|
||||||
// Account Preferences
|
// Account Preferences
|
||||||
clearClipboard: [null],
|
clearClipboard: [null],
|
||||||
minimizeOnCopyToClipboard: false,
|
minimizeOnCopyToClipboard: false,
|
||||||
@@ -135,7 +134,6 @@ export class SettingsComponent implements OnInit {
|
|||||||
private biometricStateService: BiometricStateService,
|
private biometricStateService: BiometricStateService,
|
||||||
private desktopAutofillSettingsService: DesktopAutofillSettingsService,
|
private desktopAutofillSettingsService: DesktopAutofillSettingsService,
|
||||||
private pinService: PinServiceAbstraction,
|
private pinService: PinServiceAbstraction,
|
||||||
private authRequestService: AuthRequestServiceAbstraction,
|
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
private nativeMessagingManifestService: NativeMessagingManifestService,
|
private nativeMessagingManifestService: NativeMessagingManifestService,
|
||||||
) {
|
) {
|
||||||
@@ -275,8 +273,6 @@ export class SettingsComponent implements OnInit {
|
|||||||
requirePasswordOnStart: await firstValueFrom(
|
requirePasswordOnStart: await firstValueFrom(
|
||||||
this.biometricStateService.requirePasswordOnStart$,
|
this.biometricStateService.requirePasswordOnStart$,
|
||||||
),
|
),
|
||||||
approveLoginRequests:
|
|
||||||
(await this.authRequestService.getAcceptAuthRequests(this.currentUserId)) ?? false,
|
|
||||||
clearClipboard: await firstValueFrom(this.autofillSettingsService.clearClipboardDelay$),
|
clearClipboard: await firstValueFrom(this.autofillSettingsService.clearClipboardDelay$),
|
||||||
minimizeOnCopyToClipboard: await firstValueFrom(this.desktopSettingsService.minimizeOnCopy$),
|
minimizeOnCopyToClipboard: await firstValueFrom(this.desktopSettingsService.minimizeOnCopy$),
|
||||||
enableFavicons: await firstValueFrom(this.domainSettingsService.showFavicons$),
|
enableFavicons: await firstValueFrom(this.domainSettingsService.showFavicons$),
|
||||||
@@ -722,13 +718,6 @@ export class SettingsComponent implements OnInit {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateApproveLoginRequests() {
|
|
||||||
await this.authRequestService.setAcceptAuthRequests(
|
|
||||||
this.form.value.approveLoginRequests,
|
|
||||||
this.currentUserId,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.destroy$.next();
|
this.destroy$.next();
|
||||||
this.destroy$.complete();
|
this.destroy$.complete();
|
||||||
|
|||||||
@@ -2401,9 +2401,6 @@
|
|||||||
"denyLogIn": {
|
"denyLogIn": {
|
||||||
"message": "Deny login"
|
"message": "Deny login"
|
||||||
},
|
},
|
||||||
"approveLoginRequests": {
|
|
||||||
"message": "Approve login requests"
|
|
||||||
},
|
|
||||||
"logInConfirmedForEmailOnDevice": {
|
"logInConfirmedForEmailOnDevice": {
|
||||||
"message": "Login confirmed for $EMAIL$ on $DEVICE$",
|
"message": "Login confirmed for $EMAIL$ on $DEVICE$",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
@@ -2438,9 +2435,6 @@
|
|||||||
"thisRequestIsNoLongerValid": {
|
"thisRequestIsNoLongerValid": {
|
||||||
"message": "This request is no longer valid."
|
"message": "This request is no longer valid."
|
||||||
},
|
},
|
||||||
"approveLoginRequestDesc": {
|
|
||||||
"message": "Use this device to approve login requests made from other devices."
|
|
||||||
},
|
|
||||||
"confirmLoginAtemptForMail": {
|
"confirmLoginAtemptForMail": {
|
||||||
"message": "Confirm login attempt for $EMAIL$",
|
"message": "Confirm login attempt for $EMAIL$",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
ViewContainerRef,
|
ViewContainerRef,
|
||||||
} from "@angular/core";
|
} from "@angular/core";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
import { firstValueFrom, Subject, takeUntil } from "rxjs";
|
import { Subject, takeUntil } from "rxjs";
|
||||||
import { first } from "rxjs/operators";
|
import { first } from "rxjs/operators";
|
||||||
|
|
||||||
import { ModalRef } from "@bitwarden/angular/components/modal/modal.ref";
|
import { ModalRef } from "@bitwarden/angular/components/modal/modal.ref";
|
||||||
@@ -16,7 +16,6 @@ import { ModalService } from "@bitwarden/angular/services/modal.service";
|
|||||||
import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model";
|
import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||||
import { EventType } from "@bitwarden/common/enums";
|
import { EventType } from "@bitwarden/common/enums";
|
||||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
||||||
@@ -32,7 +31,6 @@ import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
|||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||||
|
|
||||||
import { AuthRequestServiceAbstraction } from "../../../../../../libs/auth/src/common/abstractions";
|
|
||||||
import { SearchBarService } from "../../../app/layout/search/search-bar.service";
|
import { SearchBarService } from "../../../app/layout/search/search-bar.service";
|
||||||
import { GeneratorComponent } from "../../../app/tools/generator.component";
|
import { GeneratorComponent } from "../../../app/tools/generator.component";
|
||||||
import { invokeMenu, RendererMenuItem } from "../../../utils";
|
import { invokeMenu, RendererMenuItem } from "../../../utils";
|
||||||
@@ -107,8 +105,6 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
private dialogService: DialogService,
|
private dialogService: DialogService,
|
||||||
private billingAccountProfileStateService: BillingAccountProfileStateService,
|
private billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||||
private authRequestService: AuthRequestServiceAbstraction,
|
|
||||||
private accountService: AccountService,
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
@@ -226,15 +222,11 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
this.searchBarService.setEnabled(true);
|
this.searchBarService.setEnabled(true);
|
||||||
this.searchBarService.setPlaceholderText(this.i18nService.t("searchVault"));
|
this.searchBarService.setPlaceholderText(this.i18nService.t("searchVault"));
|
||||||
|
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$)).id;
|
const authRequest = await this.apiService.getLastAuthRequest();
|
||||||
const approveLoginRequests = await this.authRequestService.getAcceptAuthRequests(userId);
|
if (authRequest != null) {
|
||||||
if (approveLoginRequests) {
|
this.messagingService.send("openLoginApproval", {
|
||||||
const authRequest = await this.apiService.getLastAuthRequest();
|
notificationId: authRequest.id,
|
||||||
if (authRequest != null) {
|
});
|
||||||
this.messagingService.send("openLoginApproval", {
|
|
||||||
notificationId: authRequest.id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -311,10 +311,6 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
this.editableCollections$ = this.allCollectionsWithoutUnassigned$.pipe(
|
this.editableCollections$ = this.allCollectionsWithoutUnassigned$.pipe(
|
||||||
map((collections) => {
|
map((collections) => {
|
||||||
// If restricted, providers can not add items to any collections or edit those items
|
|
||||||
if (this.organization.isProviderUser && this.restrictProviderAccessEnabled) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
// Users that can edit all ciphers can implicitly add to / edit within any collection
|
// Users that can edit all ciphers can implicitly add to / edit within any collection
|
||||||
if (
|
if (
|
||||||
this.organization.canEditAllCiphers(
|
this.organization.canEditAllCiphers(
|
||||||
@@ -356,10 +352,6 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
let ciphers;
|
let ciphers;
|
||||||
|
|
||||||
if (organization.isProviderUser && this.restrictProviderAccessEnabled) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.flexibleCollectionsV1Enabled) {
|
if (this.flexibleCollectionsV1Enabled) {
|
||||||
// Flexible collections V1 logic.
|
// Flexible collections V1 logic.
|
||||||
// If the user can edit all ciphers for the organization then fetch them ALL.
|
// If the user can edit all ciphers for the organization then fetch them ALL.
|
||||||
@@ -488,10 +480,6 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
organization$,
|
organization$,
|
||||||
]).pipe(
|
]).pipe(
|
||||||
map(([filter, collection, organization]) => {
|
map(([filter, collection, organization]) => {
|
||||||
if (organization.isProviderUser && this.restrictProviderAccessEnabled) {
|
|
||||||
return collection != undefined || filter.collectionId === Unassigned;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
(filter.collectionId === Unassigned &&
|
(filter.collectionId === Unassigned &&
|
||||||
!organization.canEditUnassignedCiphers(this.restrictProviderAccessEnabled)) ||
|
!organization.canEditUnassignedCiphers(this.restrictProviderAccessEnabled)) ||
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ export class DeviceApprovalProgram extends BaseProgram {
|
|||||||
|
|
||||||
private deviceApprovalCommand() {
|
private deviceApprovalCommand() {
|
||||||
return new Command("device-approval")
|
return new Command("device-approval")
|
||||||
.description("Manage device approvals")
|
.description(
|
||||||
|
"Manage device approval requests sent to organizations that use SSO with trusted devices.",
|
||||||
|
)
|
||||||
.addCommand(this.listCommand())
|
.addCommand(this.listCommand())
|
||||||
.addCommand(this.approveCommand())
|
.addCommand(this.approveCommand())
|
||||||
.addCommand(this.approveAllCommand())
|
.addCommand(this.approveAllCommand())
|
||||||
|
|||||||
@@ -802,7 +802,6 @@ const safeProviders: SafeProvider[] = [
|
|||||||
LOGOUT_CALLBACK,
|
LOGOUT_CALLBACK,
|
||||||
StateServiceAbstraction,
|
StateServiceAbstraction,
|
||||||
AuthServiceAbstraction,
|
AuthServiceAbstraction,
|
||||||
AuthRequestServiceAbstraction,
|
|
||||||
MessagingServiceAbstraction,
|
MessagingServiceAbstraction,
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -10,20 +10,6 @@ export abstract class AuthRequestServiceAbstraction {
|
|||||||
/** Emits an auth request id when an auth request has been approved. */
|
/** Emits an auth request id when an auth request has been approved. */
|
||||||
authRequestPushNotification$: Observable<string>;
|
authRequestPushNotification$: Observable<string>;
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the user has chosen to allow auth requests to show on this client.
|
|
||||||
* Intended to prevent spamming the user with auth requests.
|
|
||||||
* @param userId The user id.
|
|
||||||
* @throws If `userId` is not provided.
|
|
||||||
*/
|
|
||||||
abstract getAcceptAuthRequests: (userId: UserId) => Promise<boolean>;
|
|
||||||
/**
|
|
||||||
* Sets whether to allow auth requests to show on this client for this user.
|
|
||||||
* @param accept Whether to allow auth requests to show on this client.
|
|
||||||
* @param userId The user id.
|
|
||||||
* @throws If `userId` is not provided.
|
|
||||||
*/
|
|
||||||
abstract setAcceptAuthRequests: (accept: boolean, userId: UserId) => Promise<void>;
|
|
||||||
/**
|
/**
|
||||||
* Returns an admin auth request for the given user if it exists.
|
* Returns an admin auth request for the given user if it exists.
|
||||||
* @param userId The user id.
|
* @param userId The user id.
|
||||||
|
|||||||
@@ -62,15 +62,6 @@ describe("AuthRequestService", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("AcceptAuthRequests", () => {
|
|
||||||
it("returns an error when userId isn't provided", async () => {
|
|
||||||
await expect(sut.getAcceptAuthRequests(undefined)).rejects.toThrow("User ID is required");
|
|
||||||
await expect(sut.setAcceptAuthRequests(true, undefined)).rejects.toThrow(
|
|
||||||
"User ID is required",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("AdminAuthRequest", () => {
|
describe("AdminAuthRequest", () => {
|
||||||
it("returns an error when userId isn't provided", async () => {
|
it("returns an error when userId isn't provided", async () => {
|
||||||
await expect(sut.getAdminAuthRequest(undefined)).rejects.toThrow("User ID is required");
|
await expect(sut.getAdminAuthRequest(undefined)).rejects.toThrow("User ID is required");
|
||||||
|
|||||||
@@ -22,20 +22,6 @@ import { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
|||||||
|
|
||||||
import { AuthRequestServiceAbstraction } from "../../abstractions/auth-request.service.abstraction";
|
import { AuthRequestServiceAbstraction } from "../../abstractions/auth-request.service.abstraction";
|
||||||
|
|
||||||
/**
|
|
||||||
* Disk-local to maintain consistency between tabs (even though
|
|
||||||
* approvals are currently only available on desktop). We don't
|
|
||||||
* want to clear this on logout as it's a user preference.
|
|
||||||
*/
|
|
||||||
export const ACCEPT_AUTH_REQUESTS_KEY = new UserKeyDefinition<boolean>(
|
|
||||||
AUTH_REQUEST_DISK_LOCAL,
|
|
||||||
"acceptAuthRequests",
|
|
||||||
{
|
|
||||||
deserializer: (value) => value ?? false,
|
|
||||||
clearOn: [],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disk-local to maintain consistency between tabs. We don't want to
|
* Disk-local to maintain consistency between tabs. We don't want to
|
||||||
* clear this on logout since admin auth requests are long-lived.
|
* clear this on logout since admin auth requests are long-lived.
|
||||||
@@ -64,25 +50,6 @@ export class AuthRequestService implements AuthRequestServiceAbstraction {
|
|||||||
this.authRequestPushNotification$ = this.authRequestPushNotificationSubject.asObservable();
|
this.authRequestPushNotification$ = this.authRequestPushNotificationSubject.asObservable();
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAcceptAuthRequests(userId: UserId): Promise<boolean> {
|
|
||||||
if (userId == null) {
|
|
||||||
throw new Error("User ID is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
const value = await firstValueFrom(
|
|
||||||
this.stateProvider.getUser(userId, ACCEPT_AUTH_REQUESTS_KEY).state$,
|
|
||||||
);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
async setAcceptAuthRequests(accept: boolean, userId: UserId): Promise<void> {
|
|
||||||
if (userId == null) {
|
|
||||||
throw new Error("User ID is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.stateProvider.setUserState(ACCEPT_AUTH_REQUESTS_KEY, accept, userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAdminAuthRequest(userId: UserId): Promise<AdminAuthRequestStorable | null> {
|
async getAdminAuthRequest(userId: UserId): Promise<AdminAuthRequestStorable | null> {
|
||||||
if (userId == null) {
|
if (userId == null) {
|
||||||
throw new Error("User ID is required");
|
throw new Error("User ID is required");
|
||||||
|
|||||||
@@ -195,10 +195,18 @@ export class Organization {
|
|||||||
}
|
}
|
||||||
|
|
||||||
canEditUnassignedCiphers(restrictProviderAccessFlagEnabled: boolean) {
|
canEditUnassignedCiphers(restrictProviderAccessFlagEnabled: boolean) {
|
||||||
if (this.isProviderUser) {
|
// Providers can access items until the restrictProviderAccess flag is enabled
|
||||||
return !restrictProviderAccessFlagEnabled;
|
// After the flag is enabled and removed, this block will be deleted
|
||||||
|
// so that they permanently lose access to items
|
||||||
|
if (this.isProviderUser && !restrictProviderAccessFlagEnabled) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return this.isAdmin || this.permissions.editAnyCollection;
|
|
||||||
|
return (
|
||||||
|
this.type === OrganizationUserType.Admin ||
|
||||||
|
this.type === OrganizationUserType.Owner ||
|
||||||
|
this.permissions.editAnyCollection
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
canEditAllCiphers(
|
canEditAllCiphers(
|
||||||
@@ -210,8 +218,11 @@ export class Organization {
|
|||||||
return this.isAdmin || this.permissions.editAnyCollection;
|
return this.isAdmin || this.permissions.editAnyCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isProviderUser) {
|
// Providers can access items until the restrictProviderAccess flag is enabled
|
||||||
return !restrictProviderAccessFlagEnabled;
|
// After the flag is enabled and removed, this block will be deleted
|
||||||
|
// so that they permanently lose access to items
|
||||||
|
if (this.isProviderUser && !restrictProviderAccessFlagEnabled) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Post Flexible Collections V1, the allowAdminAccessToAllCollectionItems flag can restrict admins
|
// Post Flexible Collections V1, the allowAdminAccessToAllCollectionItems flag can restrict admins
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { firstValueFrom } from "rxjs";
|
|||||||
|
|
||||||
import { LogoutReason } from "@bitwarden/auth/common";
|
import { LogoutReason } from "@bitwarden/auth/common";
|
||||||
|
|
||||||
import { AuthRequestServiceAbstraction } from "../../../auth/src/common/abstractions";
|
|
||||||
import { ApiService } from "../abstractions/api.service";
|
import { ApiService } from "../abstractions/api.service";
|
||||||
import { NotificationsService as NotificationsServiceAbstraction } from "../abstractions/notifications.service";
|
import { NotificationsService as NotificationsServiceAbstraction } from "../abstractions/notifications.service";
|
||||||
import { AuthService } from "../auth/abstractions/auth.service";
|
import { AuthService } from "../auth/abstractions/auth.service";
|
||||||
@@ -21,8 +20,7 @@ import { EnvironmentService } from "../platform/abstractions/environment.service
|
|||||||
import { LogService } from "../platform/abstractions/log.service";
|
import { LogService } from "../platform/abstractions/log.service";
|
||||||
import { MessagingService } from "../platform/abstractions/messaging.service";
|
import { MessagingService } from "../platform/abstractions/messaging.service";
|
||||||
import { StateService } from "../platform/abstractions/state.service";
|
import { StateService } from "../platform/abstractions/state.service";
|
||||||
import { SyncService } from "../platform/sync/sync.service";
|
import { SyncService } from "../vault/abstractions/sync/sync.service.abstraction";
|
||||||
import { UserId } from "../types/guid";
|
|
||||||
|
|
||||||
export class NotificationsService implements NotificationsServiceAbstraction {
|
export class NotificationsService implements NotificationsServiceAbstraction {
|
||||||
private signalrConnection: signalR.HubConnection;
|
private signalrConnection: signalR.HubConnection;
|
||||||
@@ -41,7 +39,6 @@ export class NotificationsService implements NotificationsServiceAbstraction {
|
|||||||
private logoutCallback: (logoutReason: LogoutReason) => Promise<void>,
|
private logoutCallback: (logoutReason: LogoutReason) => Promise<void>,
|
||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
private authRequestService: AuthRequestServiceAbstraction,
|
|
||||||
private messagingService: MessagingService,
|
private messagingService: MessagingService,
|
||||||
) {
|
) {
|
||||||
this.environmentService.environment$.subscribe(() => {
|
this.environmentService.environment$.subscribe(() => {
|
||||||
@@ -205,12 +202,9 @@ export class NotificationsService implements NotificationsServiceAbstraction {
|
|||||||
break;
|
break;
|
||||||
case NotificationType.AuthRequest:
|
case NotificationType.AuthRequest:
|
||||||
{
|
{
|
||||||
const userId = await this.stateService.getUserId();
|
this.messagingService.send("openLoginApproval", {
|
||||||
if (await this.authRequestService.getAcceptAuthRequests(userId as UserId)) {
|
notificationId: notification.payload.id,
|
||||||
this.messagingService.send("openLoginApproval", {
|
});
|
||||||
notificationId: notification.payload.id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
Reference in New Issue
Block a user