mirror of
https://github.com/bitwarden/browser
synced 2026-02-13 06:54:07 +00:00
Merge branch 'main' into fixing-imports
This commit is contained in:
12
.github/workflows/build-browser.yml
vendored
12
.github/workflows/build-browser.yml
vendored
@@ -168,10 +168,6 @@ jobs:
|
||||
run: npm run dist:chrome:beta
|
||||
working-directory: browser-source/apps/browser
|
||||
|
||||
- name: Gulp
|
||||
run: gulp ci
|
||||
working-directory: browser-source/apps/browser
|
||||
|
||||
- name: Upload Opera artifact
|
||||
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
|
||||
with:
|
||||
@@ -235,14 +231,6 @@ jobs:
|
||||
path: browser-source.zip
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload coverage artifact
|
||||
if: false
|
||||
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
|
||||
with:
|
||||
name: coverage-${{ env._BUILD_NUMBER }}.zip
|
||||
path: browser-source/apps/browser/coverage/coverage-${{ env._BUILD_NUMBER }}.zip
|
||||
if-no-files-found: error
|
||||
|
||||
build-safari:
|
||||
name: Build Safari
|
||||
runs-on: macos-13
|
||||
|
||||
34
.github/workflows/locales-lint.yml
vendored
Normal file
34
.github/workflows/locales-lint.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
name: Locales lint for Crowdin
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches-ignore:
|
||||
- 'l10n_master'
|
||||
- 'cf-pages'
|
||||
paths:
|
||||
- '**/messages.json'
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
- name: Checkout base branch repo
|
||||
uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.base.sha }}
|
||||
path: base
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Compare
|
||||
run: |
|
||||
npm run test:locales
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Lint check successful."
|
||||
else
|
||||
echo "Lint check failed."
|
||||
exit 1
|
||||
fi
|
||||
@@ -14,7 +14,6 @@ const betaBuild = process.env.BETA_BUILD === "1";
|
||||
const paths = {
|
||||
build: "./build/",
|
||||
dist: "./dist/",
|
||||
coverage: "./coverage/",
|
||||
node_modules: "./node_modules/",
|
||||
popupDir: "./src/popup/",
|
||||
cssDir: "./src/popup/css/",
|
||||
@@ -276,17 +275,6 @@ function stdOutProc(proc) {
|
||||
proc.stderr.on("data", (data) => console.error(data.toString()));
|
||||
}
|
||||
|
||||
async function ciCoverage(cb) {
|
||||
const { default: zip } = await import("gulp-zip");
|
||||
const { default: filter } = await import("gulp-filter");
|
||||
|
||||
return gulp
|
||||
.src(paths.coverage + "**/*")
|
||||
.pipe(filter(["**", "!coverage/coverage*.zip"]))
|
||||
.pipe(zip(`coverage${buildString()}.zip`))
|
||||
.pipe(gulp.dest(paths.coverage));
|
||||
}
|
||||
|
||||
function applyBetaLabels(manifest) {
|
||||
manifest.name = "Bitwarden Password Manager BETA";
|
||||
manifest.short_name = "Bitwarden BETA";
|
||||
@@ -320,5 +308,3 @@ exports["dist:safari:mas"] = distSafariMas;
|
||||
exports["dist:safari:masdev"] = distSafariMasDev;
|
||||
exports["dist:safari:dmg"] = distSafariDmg;
|
||||
exports.dist = gulp.parallel(distFirefox, distChrome, distOpera, distEdge);
|
||||
exports["ci:coverage"] = ciCoverage;
|
||||
exports.ci = ciCoverage;
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
"dist:safari:masdev": "npm run build:prod && gulp dist:safari:masdev",
|
||||
"dist:safari:dmg": "npm run build:prod && gulp dist:safari:dmg",
|
||||
"test": "jest",
|
||||
"test:coverage": "jest --coverage --coverageDirectory=coverage",
|
||||
"test:watch": "jest --watch",
|
||||
"test:watch:all": "jest --watchAll"
|
||||
}
|
||||
|
||||
@@ -381,7 +381,7 @@
|
||||
},
|
||||
"generator": {
|
||||
"message": "Generator",
|
||||
"description": "Short for 'Password Generator'."
|
||||
"description": "Short for 'credential generator'."
|
||||
},
|
||||
"passGenInfo": {
|
||||
"message": "Automatically generate strong, unique passwords for your logins."
|
||||
@@ -2498,7 +2498,25 @@
|
||||
"message": "Send created successfully!",
|
||||
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||
},
|
||||
"sendAvailability": {
|
||||
"sendExpiresInHoursSingle": {
|
||||
"message": "The Send will be available to anyone with the link for the next 1 hour.",
|
||||
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||
},
|
||||
"sendExpiresInHours": {
|
||||
"message": "The Send will be available to anyone with the link for the next $HOURS$ hours.",
|
||||
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.",
|
||||
"placeholders": {
|
||||
"hours": {
|
||||
"content": "$1",
|
||||
"example": "5"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sendExpiresInDaysSingle": {
|
||||
"message": "The Send will be available to anyone with the link for the next 1 day.",
|
||||
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||
},
|
||||
"sendExpiresInDays": {
|
||||
"message": "The Send will be available to anyone with the link for the next $DAYS$ days.",
|
||||
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.",
|
||||
"placeholders": {
|
||||
@@ -3662,6 +3680,9 @@
|
||||
"noMatchingLoginsForSite": {
|
||||
"message": "No matching logins for this site"
|
||||
},
|
||||
"searchSavePasskeyNewLogin": {
|
||||
"message": "Search or save passkey as new login"
|
||||
},
|
||||
"confirm": {
|
||||
"message": "Confirm"
|
||||
},
|
||||
|
||||
@@ -42,7 +42,7 @@ describe("AutoSubmitLoginBackground", () => {
|
||||
const validIpdUrl1 = "https://example.com";
|
||||
const validIpdUrl2 = "https://subdomain.example3.com";
|
||||
const validAutoSubmitHost = "some-valid-url.com";
|
||||
const validAutoSubmitUrl = `https://${validAutoSubmitHost}/?autofill=1`;
|
||||
const validAutoSubmitUrl = `https://${validAutoSubmitHost}/#autosubmit=1`;
|
||||
|
||||
beforeEach(() => {
|
||||
logService = mock<LogService>();
|
||||
@@ -122,7 +122,7 @@ describe("AutoSubmitLoginBackground", () => {
|
||||
await autoSubmitLoginBackground.init();
|
||||
});
|
||||
|
||||
it("sets up the auto-submit workflow when the web request occurs in the main frame and the destination URL contains a valid auto-fill param", () => {
|
||||
it("sets up the auto-submit workflow when the web request occurs in the main frame and the destination URL contains a valid auto-fill hash", () => {
|
||||
triggerWebRequestOnBeforeRequestEvent(webRequestDetails);
|
||||
|
||||
expect(autoSubmitLoginBackground["currentAutoSubmitHostData"]).toStrictEqual({
|
||||
@@ -226,7 +226,7 @@ describe("AutoSubmitLoginBackground", () => {
|
||||
|
||||
it("disables the auto-submit workflow if a web request is initiated after the auto-submit route has been visited", () => {
|
||||
webRequestDetails.url = `https://${validAutoSubmitHost}`;
|
||||
webRequestDetails.initiator = `https://${validAutoSubmitHost}?autofill=1`;
|
||||
webRequestDetails.initiator = `https://${validAutoSubmitHost}#autosubmit=1`;
|
||||
|
||||
triggerWebRequestOnBeforeRequestEvent(webRequestDetails);
|
||||
|
||||
|
||||
@@ -234,7 +234,7 @@ export class AutoSubmitLoginBackground implements AutoSubmitLoginBackgroundAbstr
|
||||
) => {
|
||||
if (
|
||||
details.tabId === this.currentAutoSubmitHostData.tabId &&
|
||||
this.urlContainsAutoFillParam(details.url)
|
||||
this.urlContainsAutoSubmitHash(details.url)
|
||||
) {
|
||||
this.injectAutoSubmitLoginScript(details.tabId).catch((error) =>
|
||||
this.logService.error(error),
|
||||
@@ -277,7 +277,7 @@ export class AutoSubmitLoginBackground implements AutoSubmitLoginBackgroundAbstr
|
||||
private handleWebRequestOnBeforeRedirect = (
|
||||
details: chrome.webRequest.WebRedirectionResponseDetails,
|
||||
) => {
|
||||
if (this.isRequestInMainFrame(details) && this.urlContainsAutoFillParam(details.redirectUrl)) {
|
||||
if (this.isRequestInMainFrame(details) && this.urlContainsAutoSubmitHash(details.redirectUrl)) {
|
||||
this.validAutoSubmitHosts.add(this.getUrlHost(details.redirectUrl));
|
||||
this.validAutoSubmitHosts.add(this.getUrlHost(details.url));
|
||||
}
|
||||
@@ -369,7 +369,7 @@ export class AutoSubmitLoginBackground implements AutoSubmitLoginBackgroundAbstr
|
||||
|
||||
/**
|
||||
* Determines if the provided URL is a valid auto-submit host. If the request is occurring
|
||||
* in the main frame, we will check for the presence of the `autofill=1` query parameter.
|
||||
* in the main frame, we will check for the presence of the `autosubmit=1` uri hash.
|
||||
* If the request is occurring in a sub frame, the main frame URL should be set as a
|
||||
* valid auto-submit host and can be used to validate the request.
|
||||
*
|
||||
@@ -382,7 +382,7 @@ export class AutoSubmitLoginBackground implements AutoSubmitLoginBackgroundAbstr
|
||||
) => {
|
||||
if (this.isRequestInMainFrame(details)) {
|
||||
return !!(
|
||||
this.urlContainsAutoFillParam(details.url) ||
|
||||
this.urlContainsAutoSubmitHash(details.url) ||
|
||||
this.triggerAutoSubmitAfterRedirectOnSafari(details.url)
|
||||
);
|
||||
}
|
||||
@@ -391,14 +391,14 @@ export class AutoSubmitLoginBackground implements AutoSubmitLoginBackgroundAbstr
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if the provided URL contains the `autofill=1` query parameter.
|
||||
* Determines if the provided URL contains the `autosubmit=1` uri hash.
|
||||
*
|
||||
* @param url - The URL to check for the `autofill=1` query parameter.
|
||||
* @param url - The URL to check for the `autosubmit=1` uri hash.
|
||||
*/
|
||||
private urlContainsAutoFillParam = (url: string) => {
|
||||
private urlContainsAutoSubmitHash = (url: string) => {
|
||||
try {
|
||||
const urlObj = new URL(url);
|
||||
return urlObj.search.indexOf("autofill=1") !== -1;
|
||||
return urlObj.hash.indexOf("autosubmit=1") !== -1;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
|
||||
import { CLEAR_NOTIFICATION_LOGIN_DATA_DURATION } from "@bitwarden/common/autofill/constants";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
@@ -24,6 +25,7 @@ import { OverlayNotificationsBackground } from "./overlay-notifications.backgrou
|
||||
|
||||
describe("OverlayNotificationsBackground", () => {
|
||||
let logService: MockProxy<LogService>;
|
||||
let getFeatureFlagMock$: BehaviorSubject<boolean>;
|
||||
let configService: MockProxy<ConfigService>;
|
||||
let notificationBackground: NotificationBackground;
|
||||
let getEnableChangedPasswordPromptSpy: jest.SpyInstance;
|
||||
@@ -33,7 +35,10 @@ describe("OverlayNotificationsBackground", () => {
|
||||
beforeEach(async () => {
|
||||
jest.useFakeTimers();
|
||||
logService = mock<LogService>();
|
||||
configService = mock<ConfigService>();
|
||||
getFeatureFlagMock$ = new BehaviorSubject(true);
|
||||
configService = mock<ConfigService>({
|
||||
getFeatureFlag$: jest.fn().mockReturnValue(getFeatureFlagMock$),
|
||||
});
|
||||
notificationBackground = mock<NotificationBackground>();
|
||||
getEnableChangedPasswordPromptSpy = jest
|
||||
.spyOn(notificationBackground, "getEnableChangedPasswordPrompt")
|
||||
@@ -164,8 +169,17 @@ describe("OverlayNotificationsBackground", () => {
|
||||
});
|
||||
|
||||
describe("storing the modified login form data", () => {
|
||||
const pageDetails = mock<AutofillPageDetails>({ fields: [mock<AutofillField>()] });
|
||||
const sender = mock<chrome.runtime.MessageSender>({ tab: { id: 1 } });
|
||||
|
||||
beforeEach(async () => {
|
||||
sendMockExtensionMessage(
|
||||
{ command: "collectPageDetailsResponse", details: pageDetails },
|
||||
sender,
|
||||
);
|
||||
await flushPromises();
|
||||
});
|
||||
|
||||
it("stores the modified login cipher form data", async () => {
|
||||
sendMockExtensionMessage(
|
||||
{
|
||||
@@ -349,8 +363,14 @@ describe("OverlayNotificationsBackground", () => {
|
||||
|
||||
describe("web requests that trigger notifications", () => {
|
||||
const requestId = "123345";
|
||||
const pageDetails = mock<AutofillPageDetails>({ fields: [mock<AutofillField>()] });
|
||||
|
||||
beforeEach(async () => {
|
||||
sendMockExtensionMessage(
|
||||
{ command: "collectPageDetailsResponse", details: pageDetails },
|
||||
sender,
|
||||
);
|
||||
await flushPromises();
|
||||
sendMockExtensionMessage(
|
||||
{
|
||||
command: "formFieldSubmitted",
|
||||
@@ -446,6 +466,11 @@ describe("OverlayNotificationsBackground", () => {
|
||||
|
||||
it("triggers the notification on the beforeRequest listener when a post-submission redirection is encountered", async () => {
|
||||
sender.tab = mock<chrome.tabs.Tab>({ id: 4 });
|
||||
sendMockExtensionMessage(
|
||||
{ command: "collectPageDetailsResponse", details: pageDetails },
|
||||
sender,
|
||||
);
|
||||
await flushPromises();
|
||||
sendMockExtensionMessage(
|
||||
{
|
||||
command: "formFieldSubmitted",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Subject, switchMap, timer } from "rxjs";
|
||||
import { startWith, Subject, Subscription, switchMap, timer } from "rxjs";
|
||||
import { pairwise } from "rxjs/operators";
|
||||
|
||||
import { CLEAR_NOTIFICATION_LOGIN_DATA_DURATION } from "@bitwarden/common/autofill/constants";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
@@ -23,7 +24,9 @@ export class OverlayNotificationsBackground implements OverlayNotificationsBackg
|
||||
private websiteOriginsWithFields: WebsiteOriginsWithFields = new Map();
|
||||
private activeFormSubmissionRequests: ActiveFormSubmissionRequests = new Set();
|
||||
private modifyLoginCipherFormData: ModifyLoginCipherFormDataForTab = new Map();
|
||||
private featureFlagState$: Subscription;
|
||||
private clearLoginCipherFormDataSubject: Subject<void> = new Subject();
|
||||
private notificationFallbackTimeout: number | NodeJS.Timeout | null;
|
||||
private readonly formSubmissionRequestMethods: Set<string> = new Set(["POST", "PUT", "PATCH"]);
|
||||
private readonly extensionMessageHandlers: OverlayNotificationsExtensionMessageHandlers = {
|
||||
formFieldSubmitted: ({ message, sender }) => this.storeModifiedLoginFormData(message, sender),
|
||||
@@ -41,19 +44,35 @@ export class OverlayNotificationsBackground implements OverlayNotificationsBackg
|
||||
* Initialize the overlay notifications background service.
|
||||
*/
|
||||
async init() {
|
||||
const featureFlagActive = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.NotificationBarAddLoginImprovements,
|
||||
);
|
||||
if (!featureFlagActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setupExtensionListeners();
|
||||
this.featureFlagState$ = this.configService
|
||||
.getFeatureFlag$(FeatureFlag.NotificationBarAddLoginImprovements)
|
||||
.pipe(startWith(undefined), pairwise())
|
||||
.subscribe(([prev, current]) => this.handleInitFeatureFlagChange(prev, current));
|
||||
this.clearLoginCipherFormDataSubject
|
||||
.pipe(switchMap(() => timer(CLEAR_NOTIFICATION_LOGIN_DATA_DURATION)))
|
||||
.subscribe(() => this.modifyLoginCipherFormData.clear());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles enabling/disabling the extension listeners that trigger the
|
||||
* overlay notifications based on the feature flag state.
|
||||
*
|
||||
* @param previousValue - The previous value of the feature flag
|
||||
* @param currentValue - The current value of the feature flag
|
||||
*/
|
||||
private handleInitFeatureFlagChange = (previousValue: boolean, currentValue: boolean) => {
|
||||
if (previousValue === currentValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentValue) {
|
||||
this.setupExtensionListeners();
|
||||
return;
|
||||
}
|
||||
|
||||
this.removeExtensionListeners();
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the response from the content script with the page details. Triggers an initialization
|
||||
* of the add login or change password notification if the conditions are met.
|
||||
@@ -126,6 +145,10 @@ export class OverlayNotificationsBackground implements OverlayNotificationsBackg
|
||||
message: OverlayNotificationsExtensionMessage,
|
||||
sender: chrome.runtime.MessageSender,
|
||||
) => {
|
||||
if (!this.websiteOriginsWithFields.has(sender.tab.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { uri, username, password, newPassword } = message;
|
||||
if (!username && !password && !newPassword) {
|
||||
return;
|
||||
@@ -142,8 +165,29 @@ export class OverlayNotificationsBackground implements OverlayNotificationsBackg
|
||||
}
|
||||
|
||||
this.modifyLoginCipherFormData.set(sender.tab.id, formData);
|
||||
|
||||
this.clearNotificationFallbackTimeout();
|
||||
this.notificationFallbackTimeout = setTimeout(
|
||||
() =>
|
||||
this.setupNotificationInitTrigger(
|
||||
sender.tab.id,
|
||||
"",
|
||||
this.modifyLoginCipherFormData.get(sender.tab.id),
|
||||
).catch((error) => this.logService.error(error)),
|
||||
1500,
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears the timeout used when triggering a notification on click of the submit button.
|
||||
*/
|
||||
private clearNotificationFallbackTimeout() {
|
||||
if (this.notificationFallbackTimeout) {
|
||||
clearTimeout(this.notificationFallbackTimeout);
|
||||
this.notificationFallbackTimeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the sender of the message is from an excluded domain. This is used to prevent the
|
||||
* add login or change password notification from being triggered on the user's vault domain or
|
||||
@@ -306,12 +350,16 @@ export class OverlayNotificationsBackground implements OverlayNotificationsBackg
|
||||
private handleOnCompletedRequestEvent = async (details: chrome.webRequest.WebResponseDetails) => {
|
||||
if (
|
||||
this.requestHostIsInvalid(details) ||
|
||||
isInvalidResponseStatusCode(details.statusCode) ||
|
||||
!this.activeFormSubmissionRequests.has(details.requestId)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isInvalidResponseStatusCode(details.statusCode)) {
|
||||
this.clearNotificationFallbackTimeout();
|
||||
return;
|
||||
}
|
||||
|
||||
const modifyLoginData = this.modifyLoginCipherFormData.get(details.tabId);
|
||||
if (!modifyLoginData) {
|
||||
return;
|
||||
@@ -335,6 +383,8 @@ export class OverlayNotificationsBackground implements OverlayNotificationsBackg
|
||||
requestId: string,
|
||||
modifyLoginData: ModifyLoginCipherFormData,
|
||||
) => {
|
||||
this.clearNotificationFallbackTimeout();
|
||||
|
||||
const tab = await BrowserApi.getTab(tabId);
|
||||
if (tab.status !== "complete") {
|
||||
await this.delayNotificationInitUntilTabIsComplete(tabId, requestId, modifyLoginData);
|
||||
@@ -463,11 +513,20 @@ export class OverlayNotificationsBackground implements OverlayNotificationsBackg
|
||||
* Sets up the listeners for the extension messages and the tab events.
|
||||
*/
|
||||
private setupExtensionListeners() {
|
||||
BrowserApi.messageListener("overlay-notifications", this.handleExtensionMessage);
|
||||
BrowserApi.addListener(chrome.runtime.onMessage, this.handleExtensionMessage);
|
||||
chrome.tabs.onRemoved.addListener(this.handleTabRemoved);
|
||||
chrome.tabs.onUpdated.addListener(this.handleTabUpdated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the listeners for the extension messages and the tab events.
|
||||
*/
|
||||
private removeExtensionListeners() {
|
||||
BrowserApi.removeListener(chrome.runtime.onMessage, this.handleExtensionMessage);
|
||||
chrome.tabs.onRemoved.removeListener(this.handleTabRemoved);
|
||||
chrome.tabs.onUpdated.removeListener(this.handleTabUpdated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles messages that are sent to the extension background.
|
||||
*
|
||||
|
||||
@@ -1484,9 +1484,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user's authentication status from the auth service. If the user's authentication
|
||||
* status has changed, the inline menu button's authentication status will be updated
|
||||
* and the inline menu list's ciphers will be updated.
|
||||
* Gets the user's authentication status from the auth service.
|
||||
*/
|
||||
private async getAuthStatus() {
|
||||
return await firstValueFrom(this.authService.activeAccountStatus$);
|
||||
|
||||
@@ -45,7 +45,6 @@ type Fido2BackgroundExtensionMessageHandlers = {
|
||||
|
||||
interface Fido2Background {
|
||||
init(): void;
|
||||
injectFido2ContentScriptsInAllTabs(): Promise<void>;
|
||||
}
|
||||
|
||||
export {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { Fido2ActiveRequestManager } from "@bitwarden/common/platform/abstractions/fido2/fido2-active-request-manager.abstraction";
|
||||
import {
|
||||
@@ -59,6 +61,8 @@ describe("Fido2Background", () => {
|
||||
let scriptInjectorServiceMock!: MockProxy<BrowserScriptInjectorService>;
|
||||
let configServiceMock!: MockProxy<ConfigService>;
|
||||
let enablePasskeysMock$!: BehaviorSubject<boolean>;
|
||||
let activeAccountStatusMock$: BehaviorSubject<AuthenticationStatus>;
|
||||
let authServiceMock!: MockProxy<AuthService>;
|
||||
let fido2Background!: Fido2Background;
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -81,6 +85,9 @@ describe("Fido2Background", () => {
|
||||
vaultSettingsService.enablePasskeys$ = enablePasskeysMock$;
|
||||
fido2ActiveRequestManager = mock<Fido2ActiveRequestManager>();
|
||||
fido2ClientService.isFido2FeatureEnabled.mockResolvedValue(true);
|
||||
activeAccountStatusMock$ = new BehaviorSubject(AuthenticationStatus.Unlocked);
|
||||
authServiceMock = mock<AuthService>();
|
||||
authServiceMock.activeAccountStatus$ = activeAccountStatusMock$;
|
||||
fido2Background = new Fido2Background(
|
||||
logService,
|
||||
fido2ActiveRequestManager,
|
||||
@@ -88,6 +95,7 @@ describe("Fido2Background", () => {
|
||||
vaultSettingsService,
|
||||
scriptInjectorServiceMock,
|
||||
configServiceMock,
|
||||
authServiceMock,
|
||||
);
|
||||
fido2Background["abortManager"] = abortManagerMock;
|
||||
abortManagerMock.runWithAbortController.mockImplementation((_requestId, runner) =>
|
||||
@@ -101,55 +109,31 @@ describe("Fido2Background", () => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe("injectFido2ContentScriptsInAllTabs", () => {
|
||||
it("does not inject any FIDO2 content scripts when no tabs have a secure url protocol", async () => {
|
||||
const insecureTab = mock<chrome.tabs.Tab>({ id: 789, url: "http://example.com" });
|
||||
tabsQuerySpy.mockResolvedValueOnce([insecureTab]);
|
||||
describe("handleAuthStatusUpdate", () => {
|
||||
let updateContentScriptRegistrationSpy: jest.SpyInstance;
|
||||
|
||||
await fido2Background.injectFido2ContentScriptsInAllTabs();
|
||||
|
||||
expect(scriptInjectorServiceMock.inject).not.toHaveBeenCalled();
|
||||
beforeEach(() => {
|
||||
updateContentScriptRegistrationSpy = jest
|
||||
.spyOn(fido2Background as any, "updateContentScriptRegistration")
|
||||
.mockImplementation();
|
||||
});
|
||||
|
||||
it("only injects the FIDO2 content script into tabs that contain a secure url protocol", async () => {
|
||||
const secondTabMock = mock<chrome.tabs.Tab>({ id: 456, url: "https://example.com" });
|
||||
const insecureTab = mock<chrome.tabs.Tab>({ id: 789, url: "http://example.com" });
|
||||
const noUrlTab = mock<chrome.tabs.Tab>({ id: 101, url: undefined });
|
||||
tabsQuerySpy.mockResolvedValueOnce([tabMock, secondTabMock, insecureTab, noUrlTab]);
|
||||
it("skips triggering the passkeys settings update if the user is logged out", async () => {
|
||||
activeAccountStatusMock$.next(AuthenticationStatus.LoggedOut);
|
||||
|
||||
await fido2Background.injectFido2ContentScriptsInAllTabs();
|
||||
fido2Background.init();
|
||||
await flushPromises();
|
||||
|
||||
expect(scriptInjectorServiceMock.inject).toHaveBeenCalledWith({
|
||||
tabId: tabMock.id,
|
||||
injectDetails: contentScriptDetails,
|
||||
});
|
||||
expect(scriptInjectorServiceMock.inject).toHaveBeenCalledWith({
|
||||
tabId: secondTabMock.id,
|
||||
injectDetails: contentScriptDetails,
|
||||
});
|
||||
expect(scriptInjectorServiceMock.inject).not.toHaveBeenCalledWith({
|
||||
tabId: insecureTab.id,
|
||||
injectDetails: contentScriptDetails,
|
||||
});
|
||||
expect(scriptInjectorServiceMock.inject).not.toHaveBeenCalledWith({
|
||||
tabId: noUrlTab.id,
|
||||
injectDetails: contentScriptDetails,
|
||||
});
|
||||
expect(updateContentScriptRegistrationSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("injects the `page-script.js` content script into the provided tab", async () => {
|
||||
tabsQuerySpy.mockResolvedValueOnce([tabMock]);
|
||||
it("triggers the passkeys setting update if the user is logged in", async () => {
|
||||
activeAccountStatusMock$.next(AuthenticationStatus.Unlocked);
|
||||
|
||||
await fido2Background.injectFido2ContentScriptsInAllTabs();
|
||||
fido2Background.init();
|
||||
await flushPromises();
|
||||
|
||||
expect(scriptInjectorServiceMock.inject).toHaveBeenCalledWith({
|
||||
tabId: tabMock.id,
|
||||
injectDetails: sharedScriptInjectionDetails,
|
||||
mv2Details: { file: Fido2ContentScript.PageScriptAppend },
|
||||
mv3Details: { file: Fido2ContentScript.PageScript, world: "MAIN" },
|
||||
});
|
||||
expect(updateContentScriptRegistrationSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -157,6 +141,7 @@ describe("Fido2Background", () => {
|
||||
let portMock!: MockProxy<chrome.runtime.Port>;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(fido2Background as any, "handleAuthStatusUpdate").mockImplementation();
|
||||
fido2Background.init();
|
||||
jest.spyOn(BrowserApi, "registerContentScriptsMv2");
|
||||
jest.spyOn(BrowserApi, "registerContentScriptsMv3");
|
||||
@@ -168,6 +153,15 @@ describe("Fido2Background", () => {
|
||||
tabsQuerySpy.mockResolvedValue([tabMock]);
|
||||
});
|
||||
|
||||
it("skips handling the passkey update if the user is logged out", async () => {
|
||||
activeAccountStatusMock$.next(AuthenticationStatus.LoggedOut);
|
||||
|
||||
enablePasskeysMock$.next(true);
|
||||
|
||||
expect(portMock.disconnect).not.toHaveBeenCalled();
|
||||
expect(scriptInjectorServiceMock.inject).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not destroy and re-inject the content scripts when triggering `handleEnablePasskeysUpdate` with an undefined currentEnablePasskeysSetting property", async () => {
|
||||
await flushPromises();
|
||||
|
||||
@@ -421,6 +415,7 @@ describe("Fido2Background", () => {
|
||||
let portMock!: MockProxy<chrome.runtime.Port>;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(fido2Background as any, "handleAuthStatusUpdate").mockImplementation();
|
||||
fido2Background.init();
|
||||
portMock = createPortSpyMock(Fido2PortName.InjectedScript);
|
||||
triggerRuntimeOnConnectEvent(portMock);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { firstValueFrom, startWith } from "rxjs";
|
||||
import { firstValueFrom, startWith, Subscription } from "rxjs";
|
||||
import { pairwise } from "rxjs/operators";
|
||||
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { Fido2ActiveRequestManager } from "@bitwarden/common/platform/abstractions/fido2/fido2-active-request-manager.abstraction";
|
||||
@@ -29,6 +31,7 @@ import {
|
||||
} from "./abstractions/fido2.background";
|
||||
|
||||
export class Fido2Background implements Fido2BackgroundInterface {
|
||||
private currentAuthStatus$: Subscription;
|
||||
private abortManager = new AbortManager();
|
||||
private fido2ContentScriptPortsSet = new Set<chrome.runtime.Port>();
|
||||
private registeredContentScripts: browser.contentScripts.RegisteredContentScript;
|
||||
@@ -55,6 +58,7 @@ export class Fido2Background implements Fido2BackgroundInterface {
|
||||
private vaultSettingsService: VaultSettingsService,
|
||||
private scriptInjectorService: ScriptInjectorService,
|
||||
private configService: ConfigService,
|
||||
private authService: AuthService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -68,12 +72,32 @@ export class Fido2Background implements Fido2BackgroundInterface {
|
||||
this.vaultSettingsService.enablePasskeys$
|
||||
.pipe(startWith(undefined), pairwise())
|
||||
.subscribe(([previous, current]) => this.handleEnablePasskeysUpdate(previous, current));
|
||||
this.currentAuthStatus$ = this.authService.activeAccountStatus$
|
||||
.pipe(startWith(undefined), pairwise())
|
||||
.subscribe(([_previous, current]) => this.handleAuthStatusUpdate(current));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles initializing the FIDO2 content scripts based on the current
|
||||
* authentication status. We only want to inject the FIDO2 content scripts
|
||||
* if the user is logged in.
|
||||
*
|
||||
* @param authStatus - The current authentication status.
|
||||
*/
|
||||
private async handleAuthStatusUpdate(authStatus: AuthenticationStatus) {
|
||||
if (authStatus === AuthenticationStatus.LoggedOut) {
|
||||
return;
|
||||
}
|
||||
|
||||
const enablePasskeys = await this.isPasskeySettingEnabled();
|
||||
await this.handleEnablePasskeysUpdate(enablePasskeys, enablePasskeys);
|
||||
this.currentAuthStatus$.unsubscribe();
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects the FIDO2 content and page script into all existing browser tabs.
|
||||
*/
|
||||
async injectFido2ContentScriptsInAllTabs() {
|
||||
private async injectFido2ContentScriptsInAllTabs() {
|
||||
const tabs = await BrowserApi.tabsQuery({});
|
||||
|
||||
for (let index = 0; index < tabs.length; index++) {
|
||||
@@ -85,6 +109,13 @@ export class Fido2Background implements Fido2BackgroundInterface {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user's authentication status from the auth service.
|
||||
*/
|
||||
private async getAuthStatus() {
|
||||
return await firstValueFrom(this.authService.activeAccountStatus$);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles reacting to the enablePasskeys setting being updated. If the setting
|
||||
* is enabled, the FIDO2 content scripts are injected into all tabs. If the setting
|
||||
@@ -98,13 +129,17 @@ export class Fido2Background implements Fido2BackgroundInterface {
|
||||
previousEnablePasskeysSetting: boolean,
|
||||
enablePasskeys: boolean,
|
||||
) {
|
||||
this.fido2ActiveRequestManager.removeAllActiveRequests();
|
||||
await this.updateContentScriptRegistration();
|
||||
if ((await this.getAuthStatus()) === AuthenticationStatus.LoggedOut) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (previousEnablePasskeysSetting === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.fido2ActiveRequestManager.removeAllActiveRequests();
|
||||
await this.updateContentScriptRegistration();
|
||||
|
||||
this.destroyLoadedFido2ContentScripts();
|
||||
if (enablePasskeys) {
|
||||
void this.injectFido2ContentScriptsInAllTabs();
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
const script = globalContext.document.createElement("script");
|
||||
script.src = chrome.runtime.getURL("content/fido2-page-script.js");
|
||||
script.async = false;
|
||||
|
||||
const scriptInsertionPoint =
|
||||
globalContext.document.head || globalContext.document.documentElement;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
const script = globalContext.document.createElement("script");
|
||||
script.src = chrome.runtime.getURL("content/fido2-page-script.js");
|
||||
script.async = false;
|
||||
|
||||
// We are ensuring that the script injection is delayed in the event that we are loading
|
||||
// within an iframe element. This prevents an issue with web mail clients that load content
|
||||
|
||||
@@ -4,6 +4,12 @@ import { MessageType } from "./messaging/message";
|
||||
import { Messenger } from "./messaging/messenger";
|
||||
|
||||
(function (globalContext) {
|
||||
if (globalContext.document.currentScript) {
|
||||
globalContext.document.currentScript.parentNode.removeChild(
|
||||
globalContext.document.currentScript,
|
||||
);
|
||||
}
|
||||
|
||||
const shouldExecuteContentScript =
|
||||
globalContext.document.contentType === "text/html" &&
|
||||
(globalContext.document.location.protocol === "https:" ||
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
<ng-container *ngIf="!displayedCiphers.length">
|
||||
<bit-no-items class="tw-text-main" [icon]="noResultsIcon">
|
||||
<ng-container slot="title">{{ "noMatchingLoginsForSite" | i18n }}</ng-container>
|
||||
<ng-container slot="description">Search or save passkey as new login</ng-container>
|
||||
<ng-container slot="description">{{ "searchSavePasskeyNewLogin" | i18n }}</ng-container>
|
||||
<button
|
||||
bitButton
|
||||
buttonType="primary"
|
||||
@@ -100,8 +100,8 @@
|
||||
<!-- Display when no matching ciphers exist -->
|
||||
<ng-container *ngIf="!displayedCiphers.length">
|
||||
<bit-no-items class="tw-text-main" [icon]="noResultsIcon">
|
||||
<ng-container slot="title">No matching logins for this site</ng-container>
|
||||
<ng-container slot="description">Search or save passkey as new login</ng-container>
|
||||
<ng-container slot="title">{{ "noItemsMatchSearch" | i18n }}</ng-container>
|
||||
<ng-container slot="description">{{ "clearFiltersOrTryAnother" | i18n }}</ng-container>
|
||||
<button
|
||||
bitButton
|
||||
buttonType="primary"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Subject, filter, firstValueFrom, map, merge, timeout } from "rxjs";
|
||||
|
||||
import { CollectionService, DefaultCollectionService } from "@bitwarden/admin-console/common";
|
||||
import {
|
||||
PinServiceAbstraction,
|
||||
PinService,
|
||||
@@ -170,7 +171,6 @@ import { InternalSendService as InternalSendServiceAbstraction } from "@bitwarde
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { VaultTimeoutStringType } from "@bitwarden/common/types/vault-timeout.type";
|
||||
import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService as CollectionServiceAbstraction } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { CipherFileUploadService as CipherFileUploadServiceAbstraction } from "@bitwarden/common/vault/abstractions/file-upload/cipher-file-upload.service";
|
||||
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
|
||||
import { InternalFolderService as InternalFolderServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
@@ -178,7 +178,6 @@ import { TotpService as TotpServiceAbstraction } from "@bitwarden/common/vault/a
|
||||
import { VaultSettingsService as VaultSettingsServiceAbstraction } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { CipherService } from "@bitwarden/common/vault/services/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/services/collection.service";
|
||||
import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-upload/cipher-file-upload.service";
|
||||
import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/services/folder/folder.service";
|
||||
@@ -288,7 +287,7 @@ export default class MainBackground {
|
||||
cipherService: CipherServiceAbstraction;
|
||||
folderService: InternalFolderServiceAbstraction;
|
||||
userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction;
|
||||
collectionService: CollectionServiceAbstraction;
|
||||
collectionService: CollectionService;
|
||||
vaultTimeoutService?: VaultTimeoutService;
|
||||
vaultTimeoutSettingsService: VaultTimeoutSettingsServiceAbstraction;
|
||||
passwordGenerationService: PasswordGenerationServiceAbstraction;
|
||||
@@ -699,7 +698,7 @@ export default class MainBackground {
|
||||
);
|
||||
this.searchService = new SearchService(this.logService, this.i18nService, this.stateProvider);
|
||||
|
||||
this.collectionService = new CollectionService(
|
||||
this.collectionService = new DefaultCollectionService(
|
||||
this.cryptoService,
|
||||
this.encryptService,
|
||||
this.i18nService,
|
||||
@@ -1104,6 +1103,7 @@ export default class MainBackground {
|
||||
this.vaultSettingsService,
|
||||
this.scriptInjectorService,
|
||||
this.configService,
|
||||
this.authService,
|
||||
);
|
||||
|
||||
const lockService = new DefaultLockService(this.accountService, this.vaultTimeoutService);
|
||||
@@ -1119,7 +1119,6 @@ export default class MainBackground {
|
||||
this.messagingService,
|
||||
this.logService,
|
||||
this.configService,
|
||||
this.fido2Background,
|
||||
messageListener,
|
||||
this.accountService,
|
||||
lockService,
|
||||
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
openTwoFactorAuthPopout,
|
||||
} from "../auth/popup/utils/auth-popout-window";
|
||||
import { LockedVaultPendingNotificationsData } from "../autofill/background/abstractions/notification.background";
|
||||
import { Fido2Background } from "../autofill/fido2/background/abstractions/fido2.background";
|
||||
import { AutofillService } from "../autofill/services/abstractions/autofill.service";
|
||||
import { BrowserApi } from "../platform/browser/browser-api";
|
||||
import { BrowserEnvironmentService } from "../platform/services/browser-environment.service";
|
||||
@@ -46,7 +45,6 @@ export default class RuntimeBackground {
|
||||
private messagingService: MessagingService,
|
||||
private logService: LogService,
|
||||
private configService: ConfigService,
|
||||
private fido2Background: Fido2Background,
|
||||
private messageListener: MessageListener,
|
||||
private accountService: AccountService,
|
||||
private readonly lockService: LockService,
|
||||
@@ -365,7 +363,6 @@ export default class RuntimeBackground {
|
||||
|
||||
private async checkOnInstalled() {
|
||||
setTimeout(async () => {
|
||||
void this.fido2Background.injectFido2ContentScriptsInAllTabs();
|
||||
void this.autofillService.loadAutofillScriptsOnInstall();
|
||||
|
||||
if (this.onInstalledReason != null) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { DeepJsonify } from "@bitwarden/common/types/deep-jsonify";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
||||
|
||||
import { BrowserComponentState } from "./browserComponentState";
|
||||
|
||||
@@ -43,23 +43,17 @@ function buildRegisterContentScriptsPolyfill() {
|
||||
function NestedProxy<T extends object>(target: T): T {
|
||||
return new Proxy(target, {
|
||||
get(target, prop) {
|
||||
const propertyValue = target[prop as keyof T];
|
||||
|
||||
if (!propertyValue) {
|
||||
if (!target[prop as keyof T]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof propertyValue === "object") {
|
||||
return NestedProxy<typeof propertyValue>(propertyValue);
|
||||
}
|
||||
|
||||
if (typeof propertyValue !== "function") {
|
||||
return propertyValue;
|
||||
if (typeof target[prop as keyof T] !== "function") {
|
||||
return NestedProxy(target[prop as keyof T] as object);
|
||||
}
|
||||
|
||||
return (...arguments_: any[]) =>
|
||||
new Promise((resolve, reject) => {
|
||||
propertyValue(...arguments_, (result: any) => {
|
||||
(target[prop as keyof T] as CallableFunction)(...arguments_, (result: any) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
reject(new Error(chrome.runtime.lastError.message));
|
||||
} else {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { mock } from "jest-mock-extended";
|
||||
import { Subject } from "rxjs";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
@@ -13,7 +14,6 @@ import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.s
|
||||
import { InternalSendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
|
||||
import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { filter, firstValueFrom, of, timeout } from "rxjs";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
@@ -16,7 +17,6 @@ import { CoreSyncService } from "@bitwarden/common/platform/sync/internal";
|
||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
||||
import { InternalSendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
|
||||
import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
unauthGuardFn,
|
||||
} from "@bitwarden/angular/auth/guards";
|
||||
import { canAccessFeature } from "@bitwarden/angular/platform/guard/feature-flag.guard";
|
||||
import { generatorSwap } from "@bitwarden/angular/tools/generator/generator-swap";
|
||||
import { extensionRefreshRedirect } from "@bitwarden/angular/utils/extension-refresh-redirect";
|
||||
import { extensionRefreshSwap } from "@bitwarden/angular/utils/extension-refresh-swap";
|
||||
import {
|
||||
@@ -555,7 +554,7 @@ const routes: Routes = [
|
||||
canDeactivate: [clearVaultStateGuard],
|
||||
data: { state: "tabs_vault" } satisfies RouteDataProperties,
|
||||
}),
|
||||
...generatorSwap(GeneratorComponent, CredentialGeneratorComponent, {
|
||||
...extensionRefreshSwap(GeneratorComponent, CredentialGeneratorComponent, {
|
||||
path: "generator",
|
||||
canActivate: [authGuard],
|
||||
data: { state: "tabs_generator" } satisfies RouteDataProperties,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { APP_INITIALIZER, NgModule, NgZone } from "@angular/core";
|
||||
import { Subject, merge, of } from "rxjs";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { ViewCacheService } from "@bitwarden/angular/platform/abstractions/view-cache.service";
|
||||
import { AngularThemingService } from "@bitwarden/angular/platform/services/theming/angular-theming.service";
|
||||
import { SafeProvider, safeProvider } from "@bitwarden/angular/platform/utils/safe-provider";
|
||||
@@ -86,7 +87,6 @@ import { WindowStorageService } from "@bitwarden/common/platform/storage/window-
|
||||
import { SyncService } from "@bitwarden/common/platform/sync";
|
||||
import { VaultTimeoutStringType } from "@bitwarden/common/types/vault-timeout.type";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { FolderService as FolderServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { TotpService as TotpServiceAbstraction } from "@bitwarden/common/vault/abstractions/totp.service";
|
||||
import { TotpService } from "@bitwarden/common/vault/services/totp.service";
|
||||
|
||||
@@ -1,2 +1,15 @@
|
||||
<!-- Note: this is all throwaway markup, so it won't follow best practices -->
|
||||
<tools-username-generator />
|
||||
<popup-page>
|
||||
<popup-header slot="header" [pageTitle]="'generator' | i18n">
|
||||
<ng-container slot="end">
|
||||
<app-pop-out />
|
||||
<app-current-account />
|
||||
</ng-container>
|
||||
</popup-header>
|
||||
<tools-credential-generator />
|
||||
<bit-item>
|
||||
<a type="button" bit-item-content routerLink="/generator-history">
|
||||
{{ "passwordHistory" | i18n }}
|
||||
<i slot="end" class="bwi bwi-angle-right" aria-hidden="true"></i>
|
||||
</a>
|
||||
</bit-item>
|
||||
</popup-page>
|
||||
|
||||
@@ -1,12 +1,28 @@
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
import { SectionComponent } from "@bitwarden/components";
|
||||
import { UsernameGeneratorComponent } from "@bitwarden/generator-components";
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { ItemModule } from "@bitwarden/components";
|
||||
import { GeneratorModule } from "@bitwarden/generator-components";
|
||||
|
||||
import { CurrentAccountComponent } from "../../../auth/popup/account-switching/current-account.component";
|
||||
import { PopOutComponent } from "../../../platform/popup/components/pop-out.component";
|
||||
import { PopupFooterComponent } from "../../../platform/popup/layout/popup-footer.component";
|
||||
import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-header.component";
|
||||
import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.component";
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: "credential-generator",
|
||||
templateUrl: "credential-generator.component.html",
|
||||
imports: [UsernameGeneratorComponent, SectionComponent],
|
||||
imports: [
|
||||
GeneratorModule,
|
||||
CurrentAccountComponent,
|
||||
JslibModule,
|
||||
PopOutComponent,
|
||||
PopupHeaderComponent,
|
||||
PopupPageComponent,
|
||||
PopupFooterComponent,
|
||||
ItemModule,
|
||||
],
|
||||
})
|
||||
export class CredentialGeneratorComponent {}
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
>
|
||||
<bit-icon [icon]="sendCreatedIcon"></bit-icon>
|
||||
<h3 class="tw-font-semibold">{{ "createdSendSuccessfully" | i18n }}</h3>
|
||||
<p class="tw-text-center">{{ "sendAvailability" | i18n: daysAvailable }}</p>
|
||||
<p class="tw-text-center">
|
||||
{{ formatExpirationDate() }}
|
||||
</p>
|
||||
<button bitButton type="button" buttonType="primary" (click)="copyLink()">
|
||||
<b>{{ "copyLink" | i18n }}</b>
|
||||
</button>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ComponentFixture, TestBed } from "@angular/core/testing";
|
||||
import { ActivatedRoute, Router, RouterLink } from "@angular/router";
|
||||
import { RouterTestingModule } from "@angular/router/testing";
|
||||
import { MockProxy, mock } from "jest-mock-extended";
|
||||
import { of } from "rxjs";
|
||||
import { BehaviorSubject, of } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
@@ -13,7 +13,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
||||
import { SelfHostedEnvironment } from "@bitwarden/common/platform/services/default-environment.service";
|
||||
import { SendView } from "@bitwarden/common/tools/send/models/view/send.view";
|
||||
import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
||||
import { ButtonModule, IconModule, ToastService } from "@bitwarden/components";
|
||||
import { ButtonModule, I18nMockService, IconModule, ToastService } from "@bitwarden/components";
|
||||
|
||||
import { PopOutComponent } from "../../../../platform/popup/components/pop-out.component";
|
||||
import { PopupFooterComponent } from "../../../../platform/popup/layout/popup-footer.component";
|
||||
@@ -26,7 +26,6 @@ import { SendCreatedComponent } from "./send-created.component";
|
||||
describe("SendCreatedComponent", () => {
|
||||
let component: SendCreatedComponent;
|
||||
let fixture: ComponentFixture<SendCreatedComponent>;
|
||||
let i18nService: MockProxy<I18nService>;
|
||||
let platformUtilsService: MockProxy<PlatformUtilsService>;
|
||||
let sendService: MockProxy<SendService>;
|
||||
let toastService: MockProxy<ToastService>;
|
||||
@@ -36,17 +35,10 @@ describe("SendCreatedComponent", () => {
|
||||
let router: MockProxy<Router>;
|
||||
|
||||
const sendId = "test-send-id";
|
||||
const deletionDate = new Date();
|
||||
deletionDate.setDate(deletionDate.getDate() + 7);
|
||||
const sendView: SendView = {
|
||||
id: sendId,
|
||||
deletionDate,
|
||||
accessId: "abc",
|
||||
urlB64Key: "123",
|
||||
} as SendView;
|
||||
let sendView: SendView;
|
||||
let sendViewsSubject: BehaviorSubject<SendView[]>;
|
||||
|
||||
beforeEach(async () => {
|
||||
i18nService = mock<I18nService>();
|
||||
platformUtilsService = mock<PlatformUtilsService>();
|
||||
sendService = mock<SendService>();
|
||||
toastService = mock<ToastService>();
|
||||
@@ -54,6 +46,17 @@ describe("SendCreatedComponent", () => {
|
||||
activatedRoute = mock<ActivatedRoute>();
|
||||
environmentService = mock<EnvironmentService>();
|
||||
router = mock<Router>();
|
||||
|
||||
sendView = {
|
||||
id: sendId,
|
||||
deletionDate: new Date(),
|
||||
accessId: "abc",
|
||||
urlB64Key: "123",
|
||||
} as SendView;
|
||||
|
||||
sendViewsSubject = new BehaviorSubject<SendView[]>([sendView]);
|
||||
sendService.sendViews$ = sendViewsSubject.asObservable();
|
||||
|
||||
Object.defineProperty(environmentService, "environment$", {
|
||||
configurable: true,
|
||||
get: () => of(new SelfHostedEnvironment({ webVault: "https://example.com" })),
|
||||
@@ -65,8 +68,6 @@ describe("SendCreatedComponent", () => {
|
||||
},
|
||||
} as any;
|
||||
|
||||
sendService.sendViews$ = of([sendView]);
|
||||
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
@@ -82,7 +83,25 @@ describe("SendCreatedComponent", () => {
|
||||
SendCreatedComponent,
|
||||
],
|
||||
providers: [
|
||||
{ provide: I18nService, useValue: i18nService },
|
||||
{
|
||||
provide: I18nService,
|
||||
useFactory: () => {
|
||||
return new I18nMockService({
|
||||
back: "back",
|
||||
loading: "loading",
|
||||
copyLink: "copyLink",
|
||||
close: "close",
|
||||
createdSend: "createdSend",
|
||||
createdSendSuccessfully: "createdSendSuccessfully",
|
||||
popOutNewWindow: "popOutNewWindow",
|
||||
sendExpiresInHours: (hours) => `sendExpiresInHours ${hours}`,
|
||||
sendExpiresInHoursSingle: "sendExpiresInHoursSingle",
|
||||
sendExpiresInDays: (days) => `sendExpiresInDays ${days}`,
|
||||
sendExpiresInDaysSingle: "sendExpiresInDaysSingle",
|
||||
sendLinkCopied: "sendLinkCopied",
|
||||
});
|
||||
},
|
||||
},
|
||||
{ provide: PlatformUtilsService, useValue: platformUtilsService },
|
||||
{ provide: SendService, useValue: sendService },
|
||||
{ provide: ToastService, useValue: toastService },
|
||||
@@ -94,40 +113,73 @@ describe("SendCreatedComponent", () => {
|
||||
{ provide: Router, useValue: router },
|
||||
],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SendCreatedComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it("should create", () => {
|
||||
fixture.detectChanges();
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should initialize send and daysAvailable", () => {
|
||||
fixture.detectChanges();
|
||||
it("should initialize send, daysAvailable, and hoursAvailable", () => {
|
||||
expect(component["send"]).toBe(sendView);
|
||||
expect(component["daysAvailable"]).toBe(7);
|
||||
expect(component["daysAvailable"]).toBe(0);
|
||||
expect(component["hoursAvailable"]).toBe(0);
|
||||
});
|
||||
|
||||
it("should navigate back to send list on close", async () => {
|
||||
fixture.detectChanges();
|
||||
await component.close();
|
||||
expect(router.navigate).toHaveBeenCalledWith(["/tabs/send"]);
|
||||
});
|
||||
|
||||
describe("getDaysAvailable", () => {
|
||||
it("returns the correct number of days", () => {
|
||||
describe("getHoursAvailable", () => {
|
||||
it("returns the correct number of hours", () => {
|
||||
sendView.deletionDate.setDate(sendView.deletionDate.getDate() + 7);
|
||||
sendViewsSubject.next([sendView]);
|
||||
fixture.detectChanges();
|
||||
expect(component.getDaysAvailable(sendView)).toBe(7);
|
||||
|
||||
expect(component.getHoursAvailable(sendView)).toBeCloseTo(168, 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("formatExpirationDate", () => {
|
||||
it("returns days plural if expiry is more than 24 hours", () => {
|
||||
sendView.deletionDate.setDate(sendView.deletionDate.getDate() + 7);
|
||||
sendViewsSubject.next([sendView]);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.formatExpirationDate()).toBe("sendExpiresInDays 7");
|
||||
});
|
||||
|
||||
it("returns days singular if expiry is 24 hours", () => {
|
||||
sendView.deletionDate.setDate(sendView.deletionDate.getDate() + 1);
|
||||
sendViewsSubject.next([sendView]);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.formatExpirationDate()).toBe("sendExpiresInDaysSingle");
|
||||
});
|
||||
|
||||
it("returns hours plural if expiry is more than 1 hour but less than 24", () => {
|
||||
sendView.deletionDate.setHours(sendView.deletionDate.getHours() + 2);
|
||||
sendViewsSubject.next([sendView]);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.formatExpirationDate()).toBe("sendExpiresInHours 2");
|
||||
});
|
||||
|
||||
it("returns hours singular if expiry is in 1 hour", () => {
|
||||
sendView.deletionDate.setHours(sendView.deletionDate.getHours() + 1);
|
||||
sendViewsSubject.next([sendView]);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.formatExpirationDate()).toBe("sendExpiresInHoursSingle");
|
||||
});
|
||||
});
|
||||
|
||||
describe("copyLink", () => {
|
||||
it("should copy link and show toast", async () => {
|
||||
fixture.detectChanges();
|
||||
const link = "https://example.com/#/send/abc/123";
|
||||
|
||||
await component.copyLink();
|
||||
@@ -136,7 +188,7 @@ describe("SendCreatedComponent", () => {
|
||||
expect(toastService.showToast).toHaveBeenCalledWith({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: i18nService.t("sendLinkCopied"),
|
||||
message: "sendLinkCopied",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -39,6 +39,7 @@ export class SendCreatedComponent {
|
||||
protected sendCreatedIcon = SendCreatedIcon;
|
||||
protected send: SendView;
|
||||
protected daysAvailable = 0;
|
||||
protected hoursAvailable = 0;
|
||||
|
||||
constructor(
|
||||
private i18nService: I18nService,
|
||||
@@ -54,14 +55,26 @@ export class SendCreatedComponent {
|
||||
this.sendService.sendViews$.pipe(takeUntilDestroyed()).subscribe((sendViews) => {
|
||||
this.send = sendViews.find((s) => s.id === sendId);
|
||||
if (this.send) {
|
||||
this.daysAvailable = this.getDaysAvailable(this.send);
|
||||
this.hoursAvailable = this.getHoursAvailable(this.send);
|
||||
this.daysAvailable = Math.ceil(this.hoursAvailable / 24);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getDaysAvailable(send: SendView): number {
|
||||
formatExpirationDate(): string {
|
||||
if (this.hoursAvailable < 24) {
|
||||
return this.hoursAvailable === 1
|
||||
? this.i18nService.t("sendExpiresInHoursSingle")
|
||||
: this.i18nService.t("sendExpiresInHours", this.hoursAvailable);
|
||||
}
|
||||
return this.daysAvailable === 1
|
||||
? this.i18nService.t("sendExpiresInDaysSingle")
|
||||
: this.i18nService.t("sendExpiresInDays", this.daysAvailable);
|
||||
}
|
||||
|
||||
getHoursAvailable(send: SendView): number {
|
||||
const now = new Date().getTime();
|
||||
return Math.max(0, Math.ceil((send.deletionDate.getTime() - now) / (1000 * 60 * 60 * 24)));
|
||||
return Math.max(0, Math.ceil((send.deletionDate.getTime() - now) / (1000 * 60 * 60)));
|
||||
}
|
||||
|
||||
async close() {
|
||||
|
||||
@@ -5,11 +5,11 @@ import { ReactiveFormsModule } from "@angular/forms";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { Observable, combineLatest, first, map, switchMap } from "rxjs";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { OrganizationId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import {
|
||||
ButtonModule,
|
||||
|
||||
@@ -5,6 +5,7 @@ import { FormsModule } from "@angular/forms";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { firstValueFrom, map, Observable, switchMap } from "rxjs";
|
||||
|
||||
import { CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
@@ -17,7 +18,6 @@ import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.servi
|
||||
import { ViewPasswordHistoryService } from "@bitwarden/common/vault/abstractions/view-password-history.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
||||
import {
|
||||
AsyncActionsModule,
|
||||
|
||||
@@ -5,6 +5,7 @@ import qrcodeParser from "qrcode-parser";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
import { first } from "rxjs/operators";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/vault/components/add-edit.component";
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
@@ -20,7 +21,6 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view";
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { first } from "rxjs/operators";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { CollectionsComponent as BaseCollectionsComponent } from "@bitwarden/angular/admin-console/components/collections.component";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
@@ -10,7 +11,6 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { ToastService } from "@bitwarden/components";
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { first } from "rxjs/operators";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { ShareComponent as BaseShareComponent } from "@bitwarden/angular/components/share.component";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
@@ -9,7 +10,6 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
|
||||
@Component({
|
||||
selector: "app-vault-share",
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { BehaviorSubject, Subject, firstValueFrom, from } from "rxjs";
|
||||
import { first, switchMap, takeUntil } from "rxjs/operators";
|
||||
|
||||
import { CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model";
|
||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
||||
@@ -14,7 +15,6 @@ import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.servi
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
||||
|
||||
import { BrowserGroupingsComponentState } from "../../../../models/browserGroupingsComponentState";
|
||||
|
||||
@@ -3,6 +3,7 @@ import { ChangeDetectorRef, Component, NgZone, OnDestroy, OnInit } from "@angula
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { first } from "rxjs/operators";
|
||||
|
||||
import { CollectionService, CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { VaultItemsComponent as BaseVaultItemsComponent } from "@bitwarden/angular/vault/components/vault-items.component";
|
||||
import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model";
|
||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||
@@ -11,11 +12,9 @@ import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broa
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
||||
|
||||
import { BrowserComponentState } from "../../../../models/browserComponentState";
|
||||
|
||||
@@ -2,6 +2,7 @@ import { TestBed } from "@angular/core/testing";
|
||||
import { mock } from "jest-mock-extended";
|
||||
import { BehaviorSubject, firstValueFrom, timeout } from "rxjs";
|
||||
|
||||
import { CollectionService, CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
@@ -10,11 +11,9 @@ import { SyncService } from "@bitwarden/common/platform/sync";
|
||||
import { ObservableTracker } from "@bitwarden/common/spec";
|
||||
import { CipherId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
|
||||
import { BrowserApi } from "../../../platform/browser/browser-api";
|
||||
|
||||
|
||||
@@ -20,13 +20,13 @@ import {
|
||||
withLatestFrom,
|
||||
} from "rxjs";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { SyncService } from "@bitwarden/common/platform/sync";
|
||||
import { CollectionId, OrganizationId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
|
||||
@@ -2,6 +2,7 @@ import { TestBed } from "@angular/core/testing";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { BehaviorSubject, skipWhile } from "rxjs";
|
||||
|
||||
import { CollectionService, Collection, CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||
@@ -9,12 +10,9 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/orga
|
||||
import { ProductTierType } from "@bitwarden/common/billing/enums";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { Collection } from "@bitwarden/common/vault/models/domain/collection";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
||||
|
||||
import { MY_VAULT_ID, VaultPopupListFiltersService } from "./vault-popup-list-filters.service";
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
tap,
|
||||
} from "rxjs";
|
||||
|
||||
import { CollectionService, Collection, CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { DynamicTreeNode } from "@bitwarden/angular/vault/vault-filter/models/dynamic-tree-node.model";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
@@ -20,13 +21,10 @@ import { ProductTierType } from "@bitwarden/common/billing/enums";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { Collection } from "@bitwarden/common/vault/models/domain/collection";
|
||||
import { ITreeNodeObject, TreeNode } from "@bitwarden/common/vault/models/domain/tree-node";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
||||
import { ServiceUtils } from "@bitwarden/common/vault/service-utils";
|
||||
import { ChipSelectOption } from "@bitwarden/components";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
|
||||
/**
|
||||
* Extended cipher view for the popup. Includes the associated collections and organization
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model";
|
||||
import { VaultFilterService as BaseVaultFilterService } from "@bitwarden/angular/vault/vault-filter/services/vault-filter.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
@@ -5,7 +6,6 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { StateProvider } from "@bitwarden/common/platform/state";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
import { CollectionView } from "@bitwarden/admin-console/common";
|
||||
|
||||
import { CollectionResponse } from "../../../vault/models/collection.response";
|
||||
import { SelectionReadOnly } from "../selection-read-only";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { CollectionRequest } from "@bitwarden/admin-console/common";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { SelectionReadOnlyRequest } from "@bitwarden/common/admin-console/models/request/selection-read-only.request";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
@@ -12,7 +13,6 @@ import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { CollectionRequest } from "@bitwarden/common/vault/models/request/collection.request";
|
||||
|
||||
import { OrganizationCollectionRequest } from "../admin-console/models/request/organization-collection.request";
|
||||
import { OrganizationCollectionResponse } from "../admin-console/models/response/organization-collection.response";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { CollectionService, CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
@@ -27,12 +28,10 @@ import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||
import { SendType } from "@bitwarden/common/tools/send/enums/send-type";
|
||||
import { OrganizationId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
||||
|
||||
import { OrganizationCollectionRequest } from "../admin-console/models/request/organization-collection.request";
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { OrganizationUserApiService } from "@bitwarden/admin-console/common";
|
||||
import {
|
||||
OrganizationUserApiService,
|
||||
CollectionService,
|
||||
CollectionData,
|
||||
Collection,
|
||||
CollectionDetailsResponse as ApiCollectionDetailsResponse,
|
||||
CollectionResponse as ApiCollectionResponse,
|
||||
} from "@bitwarden/admin-console/common";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||
@@ -9,14 +16,7 @@ import { EventType } from "@bitwarden/common/enums";
|
||||
import { ListResponse as ApiListResponse } from "@bitwarden/common/models/response/list.response";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { CollectionData } from "@bitwarden/common/vault/models/data/collection.data";
|
||||
import { Collection } from "@bitwarden/common/vault/models/domain/collection";
|
||||
import {
|
||||
CollectionDetailsResponse as ApiCollectionDetailsResponse,
|
||||
CollectionResponse as ApiCollectionResponse,
|
||||
} from "@bitwarden/common/vault/models/response/collection.response";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
|
||||
import { OrganizationUserResponse } from "../admin-console/models/response/organization-user.response";
|
||||
|
||||
@@ -7,6 +7,7 @@ import { firstValueFrom, map } from "rxjs";
|
||||
import {
|
||||
OrganizationUserApiService,
|
||||
DefaultOrganizationUserApiService,
|
||||
DefaultCollectionService,
|
||||
} from "@bitwarden/admin-console/common";
|
||||
import {
|
||||
InternalUserDecryptionOptionsServiceAbstraction,
|
||||
@@ -129,7 +130,6 @@ import { SendService } from "@bitwarden/common/tools/send/services/send.service"
|
||||
import { VaultTimeoutStringType } from "@bitwarden/common/types/vault-timeout.type";
|
||||
import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { CipherService } from "@bitwarden/common/vault/services/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/services/collection.service";
|
||||
import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-upload/cipher-file-upload.service";
|
||||
import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/services/folder/folder.service";
|
||||
@@ -191,7 +191,7 @@ export class ServiceContainer {
|
||||
cipherService: CipherService;
|
||||
folderService: InternalFolderService;
|
||||
organizationUserApiService: OrganizationUserApiService;
|
||||
collectionService: CollectionService;
|
||||
collectionService: DefaultCollectionService;
|
||||
vaultTimeoutService: VaultTimeoutService;
|
||||
masterPasswordService: InternalMasterPasswordServiceAbstraction;
|
||||
vaultTimeoutSettingsService: VaultTimeoutSettingsService;
|
||||
@@ -498,7 +498,7 @@ export class ServiceContainer {
|
||||
|
||||
this.searchService = new SearchService(this.logService, this.i18nService, this.stateProvider);
|
||||
|
||||
this.collectionService = new CollectionService(
|
||||
this.collectionService = new DefaultCollectionService(
|
||||
this.cryptoService,
|
||||
this.encryptService,
|
||||
this.i18nService,
|
||||
|
||||
@@ -4,10 +4,10 @@ import * as path from "path";
|
||||
import * as inquirer from "inquirer";
|
||||
import * as JSZip from "jszip";
|
||||
|
||||
import { CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
||||
import { NodeUtils } from "@bitwarden/node/node-utils";
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import * as path from "path";
|
||||
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { CollectionRequest } from "@bitwarden/admin-console/common";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { SelectionReadOnlyRequest } from "@bitwarden/common/admin-console/models/request/selection-read-only.request";
|
||||
@@ -17,7 +18,6 @@ import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { CollectionRequest } from "@bitwarden/common/vault/models/request/collection.request";
|
||||
|
||||
import { OrganizationCollectionRequest } from "../admin-console/models/request/organization-collection.request";
|
||||
import { OrganizationCollectionResponse } from "../admin-console/models/response/organization-collection.response";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { CollectionWithIdExport } from "@bitwarden/common/models/export/collection-with-id.export";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
|
||||
import { BaseResponse } from "../../models/response/base.response";
|
||||
|
||||
|
||||
65
apps/desktop/desktop_native/Cargo.lock
generated
65
apps/desktop/desktop_native/Cargo.lock
generated
@@ -304,9 +304,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.1.24"
|
||||
version = "1.1.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938"
|
||||
checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
@@ -725,9 +725,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
|
||||
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
@@ -735,15 +735,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
|
||||
checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
@@ -752,9 +752,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
|
||||
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
@@ -771,9 +771,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -782,21 +782,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
|
||||
checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@@ -936,9 +936,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
@@ -975,9 +975,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.5.0"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
|
||||
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
@@ -1378,21 +1378,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.4"
|
||||
version = "0.36.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a"
|
||||
checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.1"
|
||||
version = "1.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1"
|
||||
dependencies = [
|
||||
"portable-atomic",
|
||||
]
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "option-ext"
|
||||
@@ -1503,12 +1500,6 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
@@ -1535,9 +1526,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
version = "1.0.87"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||
checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
@@ -12,6 +12,7 @@ import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { Router } from "@angular/router";
|
||||
import { catchError, filter, firstValueFrom, map, of, Subject, takeUntil, timeout } from "rxjs";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { ModalRef } from "@bitwarden/angular/components/modal/modal.ref";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { FingerprintDialogComponent } from "@bitwarden/auth/angular";
|
||||
@@ -47,7 +48,6 @@ import { SyncService } from "@bitwarden/common/platform/sync";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { VaultTimeout, VaultTimeoutStringType } from "@bitwarden/common/types/vault-timeout.type";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { DialogService, ToastOptions, ToastService } from "@bitwarden/components";
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<bit-dialog #dialog dialogSize="large" background="alt">
|
||||
<span bitDialogTitle>{{ "generator" | i18n }}</span>
|
||||
<ng-container bitDialogContent>
|
||||
<!-- FIXME: Will get replaced with <tools-credential-generator /> once https://github.com/bitwarden/clients/pull/11398 has been merged -->
|
||||
<tools-password-generator />
|
||||
<tools-credential-generator />
|
||||
</ng-container>
|
||||
<ng-container bitDialogFooter>
|
||||
<button type="button" bitButton bitFormButton buttonType="secondary" bitDialogClose>
|
||||
|
||||
@@ -2,12 +2,12 @@ import { Component } from "@angular/core";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { ButtonModule, DialogModule } from "@bitwarden/components";
|
||||
import { PasswordGeneratorComponent } from "@bitwarden/generator-components";
|
||||
import { GeneratorModule } from "@bitwarden/generator-components";
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: "credential-generator",
|
||||
templateUrl: "credential-generator.component.html",
|
||||
imports: [DialogModule, ButtonModule, JslibModule, PasswordGeneratorComponent],
|
||||
imports: [DialogModule, ButtonModule, JslibModule, GeneratorModule],
|
||||
})
|
||||
export class CredentialGeneratorComponent {}
|
||||
|
||||
@@ -2319,7 +2319,8 @@
|
||||
"message": "Unlocked"
|
||||
},
|
||||
"generator": {
|
||||
"message": "Generator"
|
||||
"message": "Generator",
|
||||
"description": "Short for 'credential generator'."
|
||||
},
|
||||
"whatWouldYouLikeToGenerate": {
|
||||
"message": "What would you like to generate?"
|
||||
|
||||
1
apps/desktop/src/package-lock.json
generated
1
apps/desktop/src/package-lock.json
generated
@@ -14,6 +14,7 @@
|
||||
}
|
||||
},
|
||||
"../desktop_native/napi": {
|
||||
"name": "@bitwarden/desktop-napi",
|
||||
"version": "0.1.0",
|
||||
"license": "GPL-3.0",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { DatePipe } from "@angular/common";
|
||||
import { Component, NgZone, OnChanges, OnInit, OnDestroy, ViewChild } from "@angular/core";
|
||||
import { NgForm } from "@angular/forms";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/vault/components/add-edit.component";
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
@@ -16,7 +17,6 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { CollectionsComponent as BaseCollectionsComponent } from "@bitwarden/angular/admin-console/components/collections.component";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
@@ -7,7 +8,6 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { ToastService } from "@bitwarden/components";
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { ModalRef } from "@bitwarden/angular/components/modal/modal.ref";
|
||||
import { ShareComponent as BaseShareComponent } from "@bitwarden/angular/components/share.component";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
@@ -8,7 +9,6 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
|
||||
@Component({
|
||||
selector: "app-vault-share",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@bitwarden/web-vault",
|
||||
"version": "2024.10.1",
|
||||
"version": "2024.10.2",
|
||||
"scripts": {
|
||||
"build:oss": "webpack",
|
||||
"build:bit": "webpack -c ../../bitwarden_license/bit-web/webpack.config.js",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CollectionAccessSelectionView } from "@bitwarden/admin-console/common";
|
||||
import { View } from "@bitwarden/common/src/models/view/view";
|
||||
import { View } from "@bitwarden/common/models/view/view";
|
||||
|
||||
import { GroupDetailsResponse, GroupResponse } from "../services/group/responses/group.response";
|
||||
|
||||
|
||||
@@ -39,6 +39,11 @@
|
||||
*ngIf="organization.canAccessReports"
|
||||
></bit-nav-item>
|
||||
</bit-nav-group>
|
||||
<bit-nav-item
|
||||
*ngIf="isAccessIntelligenceFeatureEnabled"
|
||||
[text]="'accessIntelligence' | i18n"
|
||||
route="access-intelligence"
|
||||
></bit-nav-item>
|
||||
<bit-nav-group
|
||||
icon="bwi-billing"
|
||||
[text]="'billing' | i18n"
|
||||
|
||||
@@ -51,6 +51,7 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy {
|
||||
showPaymentAndHistory$: Observable<boolean>;
|
||||
hideNewOrgButton$: Observable<boolean>;
|
||||
organizationIsUnmanaged$: Observable<boolean>;
|
||||
isAccessIntelligenceFeatureEnabled = false;
|
||||
|
||||
private _destroy = new Subject<void>();
|
||||
|
||||
@@ -70,6 +71,10 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy {
|
||||
async ngOnInit() {
|
||||
document.body.classList.remove("layout_frontend");
|
||||
|
||||
this.isAccessIntelligenceFeatureEnabled = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.AccessIntelligence,
|
||||
);
|
||||
|
||||
this.organization$ = this.route.params
|
||||
.pipe(takeUntil(this._destroy))
|
||||
.pipe<string>(map((p) => p.organizationId))
|
||||
|
||||
@@ -14,18 +14,18 @@ import {
|
||||
} from "rxjs";
|
||||
import { debounceTime, first } from "rxjs/operators";
|
||||
|
||||
import {
|
||||
CollectionService,
|
||||
CollectionData,
|
||||
Collection,
|
||||
CollectionDetailsResponse,
|
||||
CollectionResponse,
|
||||
CollectionView,
|
||||
} from "@bitwarden/admin-console/common";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { ListResponse } from "@bitwarden/common/models/response/list.response";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { CollectionData } from "@bitwarden/common/vault/models/data/collection.data";
|
||||
import { Collection } from "@bitwarden/common/vault/models/domain/collection";
|
||||
import {
|
||||
CollectionDetailsResponse,
|
||||
CollectionResponse,
|
||||
} from "@bitwarden/common/vault/models/response/collection.response";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
import { DialogService, TableDataSource, ToastService } from "@bitwarden/components";
|
||||
|
||||
import { InternalGroupService as GroupService, GroupView } from "../core";
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
CollectionAdminService,
|
||||
CollectionAdminView,
|
||||
OrganizationUserApiService,
|
||||
CollectionView,
|
||||
} from "@bitwarden/admin-console/common";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
@@ -29,7 +30,6 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/orga
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { ProductTierType } from "@bitwarden/common/billing/enums";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
|
||||
import {
|
||||
|
||||
@@ -17,6 +17,10 @@ import {
|
||||
OrganizationUserApiService,
|
||||
OrganizationUserConfirmRequest,
|
||||
OrganizationUserUserDetailsResponse,
|
||||
CollectionService,
|
||||
CollectionData,
|
||||
Collection,
|
||||
CollectionDetailsResponse,
|
||||
} from "@bitwarden/admin-console/common";
|
||||
import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
@@ -43,11 +47,7 @@ import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { CollectionData } from "@bitwarden/common/vault/models/data/collection.data";
|
||||
import { Collection } from "@bitwarden/common/vault/models/domain/collection";
|
||||
import { CollectionDetailsResponse } from "@bitwarden/common/vault/models/response/collection.response";
|
||||
import { DialogService, SimpleDialogOptions, ToastService } from "@bitwarden/components";
|
||||
|
||||
import {
|
||||
|
||||
@@ -62,6 +62,13 @@ const routes: Routes = [
|
||||
(m) => m.OrganizationReportingModule,
|
||||
),
|
||||
},
|
||||
{
|
||||
path: "access-intelligence",
|
||||
loadChildren: () =>
|
||||
import("../../tools/access-intelligence/access-intelligence.module").then(
|
||||
(m) => m.AccessIntelligenceModule,
|
||||
),
|
||||
},
|
||||
{
|
||||
path: "billing",
|
||||
loadChildren: () =>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
|
||||
@@ -5,6 +5,7 @@ import { NavigationEnd, Router } from "@angular/router";
|
||||
import * as jq from "jquery";
|
||||
import { Subject, filter, firstValueFrom, map, takeUntil, timeout, catchError, of } from "rxjs";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { LogoutReason } from "@bitwarden/auth/common";
|
||||
import { EventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service";
|
||||
import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service";
|
||||
@@ -27,7 +28,6 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv
|
||||
import { StateEventRunnerService } from "@bitwarden/common/platform/state";
|
||||
import { SyncService } from "@bitwarden/common/platform/sync";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { DialogService, ToastOptions, ToastService } from "@bitwarden/components";
|
||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy";
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { DatePipe } from "@angular/common";
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
@@ -14,7 +15,6 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service";
|
||||
import { Cipher } from "@bitwarden/common/vault/models/domain/cipher";
|
||||
|
||||
@@ -11,8 +11,12 @@
|
||||
></i>
|
||||
<span class="tw-sr-only">{{ "loading" | i18n }}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="invoices || transactions">
|
||||
<app-billing-history [invoices]="invoices" [transactions]="transactions"></app-billing-history>
|
||||
<ng-container *ngIf="openInvoices || paidInvoices || transactions">
|
||||
<app-billing-history
|
||||
[openInvoices]="openInvoices"
|
||||
[paidInvoices]="paidInvoices"
|
||||
[transactions]="transactions"
|
||||
></app-billing-history>
|
||||
<button
|
||||
type="button"
|
||||
bitButton
|
||||
|
||||
@@ -14,7 +14,8 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
||||
export class BillingHistoryViewComponent implements OnInit {
|
||||
loading = false;
|
||||
firstLoaded = false;
|
||||
invoices: BillingInvoiceResponse[] = [];
|
||||
openInvoices: BillingInvoiceResponse[] = [];
|
||||
paidInvoices: BillingInvoiceResponse[] = [];
|
||||
transactions: BillingTransactionResponse[] = [];
|
||||
hasAdditionalHistory: boolean = false;
|
||||
|
||||
@@ -41,8 +42,14 @@ export class BillingHistoryViewComponent implements OnInit {
|
||||
}
|
||||
this.loading = true;
|
||||
|
||||
const invoicesPromise = this.accountBillingApiService.getBillingInvoices(
|
||||
this.invoices.length > 0 ? this.invoices[this.invoices.length - 1].id : null,
|
||||
const openInvoicesPromise = this.accountBillingApiService.getBillingInvoices(
|
||||
"open",
|
||||
this.openInvoices.length > 0 ? this.openInvoices[this.openInvoices.length - 1].id : null,
|
||||
);
|
||||
|
||||
const paidInvoicesPromise = this.accountBillingApiService.getBillingInvoices(
|
||||
"paid",
|
||||
this.paidInvoices.length > 0 ? this.paidInvoices[this.paidInvoices.length - 1].id : null,
|
||||
);
|
||||
|
||||
const transactionsPromise = this.accountBillingApiService.getBillingTransactions(
|
||||
@@ -51,15 +58,20 @@ export class BillingHistoryViewComponent implements OnInit {
|
||||
: null,
|
||||
);
|
||||
|
||||
const accountInvoices = await invoicesPromise;
|
||||
const accountTransactions = await transactionsPromise;
|
||||
const openInvoices = await openInvoicesPromise;
|
||||
const paidInvoices = await paidInvoicesPromise;
|
||||
const transactions = await transactionsPromise;
|
||||
|
||||
const pageSize = 5;
|
||||
|
||||
this.invoices = [...this.invoices, ...accountInvoices];
|
||||
this.transactions = [...this.transactions, ...accountTransactions];
|
||||
this.hasAdditionalHistory = !(
|
||||
accountInvoices.length < pageSize && accountTransactions.length < pageSize
|
||||
);
|
||||
this.openInvoices = [...this.openInvoices, ...openInvoices];
|
||||
this.paidInvoices = [...this.paidInvoices, ...paidInvoices];
|
||||
this.transactions = [...this.transactions, ...transactions];
|
||||
|
||||
this.hasAdditionalHistory =
|
||||
openInvoices.length >= pageSize ||
|
||||
paidInvoices.length >= pageSize ||
|
||||
transactions.length >= pageSize;
|
||||
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
@@ -9,8 +9,12 @@
|
||||
></i>
|
||||
<span class="tw-sr-only">{{ "loading" | i18n }}</span>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="invoices || transactions">
|
||||
<app-billing-history [invoices]="invoices" [transactions]="transactions"></app-billing-history>
|
||||
<ng-container *ngIf="openInvoices || paidInvoices || transactions">
|
||||
<app-billing-history
|
||||
[openInvoices]="openInvoices"
|
||||
[paidInvoices]="paidInvoices"
|
||||
[transactions]="transactions"
|
||||
></app-billing-history>
|
||||
<button
|
||||
type="button"
|
||||
bitButton
|
||||
|
||||
@@ -14,7 +14,8 @@ import {
|
||||
export class OrgBillingHistoryViewComponent implements OnInit, OnDestroy {
|
||||
loading = false;
|
||||
firstLoaded = false;
|
||||
invoices: BillingInvoiceResponse[] = [];
|
||||
openInvoices: BillingInvoiceResponse[] = [];
|
||||
paidInvoices: BillingInvoiceResponse[] = [];
|
||||
transactions: BillingTransactionResponse[] = [];
|
||||
organizationId: string;
|
||||
hasAdditionalHistory: boolean = false;
|
||||
@@ -51,9 +52,16 @@ export class OrgBillingHistoryViewComponent implements OnInit, OnDestroy {
|
||||
|
||||
this.loading = true;
|
||||
|
||||
const invoicesPromise = this.organizationBillingApiService.getBillingInvoices(
|
||||
const openInvoicesPromise = this.organizationBillingApiService.getBillingInvoices(
|
||||
this.organizationId,
|
||||
this.invoices.length > 0 ? this.invoices[this.invoices.length - 1].id : null,
|
||||
"open",
|
||||
this.openInvoices.length > 0 ? this.openInvoices[this.openInvoices.length - 1].id : null,
|
||||
);
|
||||
|
||||
const paidInvoicesPromise = this.organizationBillingApiService.getBillingInvoices(
|
||||
this.organizationId,
|
||||
"paid",
|
||||
this.paidInvoices.length > 0 ? this.paidInvoices[this.paidInvoices.length - 1].id : null,
|
||||
);
|
||||
|
||||
const transactionsPromise = this.organizationBillingApiService.getBillingTransactions(
|
||||
@@ -63,13 +71,21 @@ export class OrgBillingHistoryViewComponent implements OnInit, OnDestroy {
|
||||
: null,
|
||||
);
|
||||
|
||||
const invoices = await invoicesPromise;
|
||||
const openInvoices = await openInvoicesPromise;
|
||||
const paidInvoices = await paidInvoicesPromise;
|
||||
const transactions = await transactionsPromise;
|
||||
|
||||
const pageSize = 5;
|
||||
|
||||
this.invoices = [...this.invoices, ...invoices];
|
||||
this.openInvoices = [...this.openInvoices, ...openInvoices];
|
||||
this.paidInvoices = [...this.paidInvoices, ...paidInvoices];
|
||||
this.transactions = [...this.transactions, ...transactions];
|
||||
this.hasAdditionalHistory = !(invoices.length < pageSize && transactions.length < pageSize);
|
||||
|
||||
this.hasAdditionalHistory =
|
||||
openInvoices.length <= pageSize ||
|
||||
paidInvoices.length <= pageSize ||
|
||||
transactions.length <= pageSize;
|
||||
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<bit-section>
|
||||
<h3 bitTypography="h3">{{ "invoices" | i18n }}</h3>
|
||||
<p bitTypography="body1" *ngIf="!invoices || !invoices.length">{{ "noInvoices" | i18n }}</p>
|
||||
<h3 bitTypography="h3">{{ "unpaid" | i18n }} {{ "invoices" | i18n }}</h3>
|
||||
<p bitTypography="body1" *ngIf="!openInvoices || !openInvoices.length">
|
||||
{{ "noUnpaidInvoices" | i18n }}
|
||||
</p>
|
||||
<bit-table>
|
||||
<ng-template body>
|
||||
<tr bitRow *ngFor="let i of invoices">
|
||||
<tr bitRow *ngFor="let i of openInvoices">
|
||||
<td bitCell>{{ i.date | date: "mediumDate" }}</td>
|
||||
<td bitCell>
|
||||
<a
|
||||
@@ -26,7 +28,51 @@
|
||||
>
|
||||
</td>
|
||||
<td bitCell>{{ i.amount | currency: "$" }}</td>
|
||||
<td bitCell class="tw-w-28">
|
||||
<span *ngIf="i.paid">
|
||||
<i class="bwi bwi-check tw-text-success" aria-hidden="true"></i>
|
||||
{{ "paid" | i18n }}
|
||||
</span>
|
||||
<span *ngIf="!i.paid">
|
||||
<i class="bwi bwi-exclamation-circle tw-text-muted" aria-hidden="true"></i>
|
||||
{{ "unpaid" | i18n }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</ng-template>
|
||||
</bit-table>
|
||||
</bit-section>
|
||||
<bit-section>
|
||||
<h3 bitTypography="h3">{{ "paid" | i18n }} {{ "invoices" | i18n }}</h3>
|
||||
<p bitTypography="body1" *ngIf="!paidInvoices || !paidInvoices.length">
|
||||
{{ "noPaidInvoices" | i18n }}
|
||||
</p>
|
||||
<bit-table>
|
||||
<ng-template body>
|
||||
<tr bitRow *ngFor="let i of paidInvoices">
|
||||
<td bitCell>{{ i.date | date: "mediumDate" }}</td>
|
||||
<td bitCell>
|
||||
<a
|
||||
href="{{ i.pdfUrl }}"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
class="tw-mr-2"
|
||||
appA11yTitle="{{ 'downloadInvoice' | i18n }}"
|
||||
>
|
||||
<i class="bwi bwi-file-pdf" aria-hidden="true"></i
|
||||
></a>
|
||||
<a
|
||||
bitLink
|
||||
href="{{ i.url }}"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
title="{{ 'viewInvoice' | i18n }}"
|
||||
>
|
||||
{{ "invoiceNumber" | i18n: i.number }}</a
|
||||
>
|
||||
</td>
|
||||
<td bitCell>{{ i.amount | currency: "$" }}</td>
|
||||
<td bitCell class="tw-w-28">
|
||||
<span *ngIf="i.paid">
|
||||
<i class="bwi bwi-check tw-text-success" aria-hidden="true"></i>
|
||||
{{ "paid" | i18n }}
|
||||
|
||||
@@ -12,7 +12,10 @@ import {
|
||||
})
|
||||
export class BillingHistoryComponent {
|
||||
@Input()
|
||||
invoices: BillingInvoiceResponse[];
|
||||
openInvoices: BillingInvoiceResponse[];
|
||||
|
||||
@Input()
|
||||
paidInvoices: BillingInvoiceResponse[];
|
||||
|
||||
@Input()
|
||||
transactions: BillingTransactionResponse[];
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
CollectionAdminService,
|
||||
DefaultCollectionAdminService,
|
||||
OrganizationUserApiService,
|
||||
CollectionService,
|
||||
} from "@bitwarden/admin-console/common";
|
||||
import { SafeProvider, safeProvider } from "@bitwarden/angular/platform/utils/safe-provider";
|
||||
import {
|
||||
@@ -71,7 +72,6 @@ import {
|
||||
ThemeStateService,
|
||||
} from "@bitwarden/common/platform/theming/theme-state.service";
|
||||
import { VaultTimeout, VaultTimeoutStringType } from "@bitwarden/common/types/vault-timeout.type";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { BiometricsService } from "@bitwarden/key-management";
|
||||
|
||||
import { flagEnabled } from "../../utils/flags";
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
import { RouterModule, Routes } from "@angular/router";
|
||||
|
||||
import { unauthGuardFn } from "@bitwarden/angular/auth/guards";
|
||||
import { canAccessFeature } from "@bitwarden/angular/platform/guard/feature-flag.guard";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
|
||||
import { AccessIntelligenceComponent } from "./access-intelligence.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: "",
|
||||
component: AccessIntelligenceComponent,
|
||||
canActivate: [canAccessFeature(FeatureFlag.AccessIntelligence), unauthGuardFn()],
|
||||
data: {
|
||||
titleId: "accessIntelligence",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class AccessIntelligenceRoutingModule {}
|
||||
@@ -0,0 +1,23 @@
|
||||
<app-header></app-header>
|
||||
<bit-tab-group [(selectedIndex)]="tabIndex">
|
||||
<bit-tab label="{{ 'allApplicationsWithCount' | i18n: apps.length }}">
|
||||
<h2 bitTypography="h2">{{ "allApplications" | i18n }}</h2>
|
||||
<tools-application-table></tools-application-table>
|
||||
</bit-tab>
|
||||
<bit-tab>
|
||||
<ng-template bitTabLabel>
|
||||
<i class="bwi bwi-star"></i>
|
||||
{{ "priorityApplicationsWithCount" | i18n: priorityApps.length }}
|
||||
</ng-template>
|
||||
<h2 bitTypography>{{ "priorityApplications" | i18n }}</h2>
|
||||
<tools-application-table></tools-application-table>
|
||||
</bit-tab>
|
||||
<bit-tab>
|
||||
<ng-template bitTabLabel>
|
||||
<i class="bwi bwi-envelope"></i>
|
||||
{{ "notifiedMembersWithCount" | i18n: priorityApps.length }}
|
||||
</ng-template>
|
||||
<h2 bitTypography="h2">{{ "notifiedMembers" | i18n }}</h2>
|
||||
<tools-notified-members-table></tools-notified-members-table>
|
||||
</bit-tab>
|
||||
</bit-tab-group>
|
||||
@@ -0,0 +1,45 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component } from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { first } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { TabsModule } from "@bitwarden/components";
|
||||
|
||||
import { HeaderModule } from "../../layouts/header/header.module";
|
||||
|
||||
import { ApplicationTableComponent } from "./application-table.component";
|
||||
import { NotifiedMembersTableComponent } from "./notified-members-table.component";
|
||||
|
||||
export enum AccessIntelligenceTabType {
|
||||
AllApps = 0,
|
||||
PriorityApps = 1,
|
||||
NotifiedMembers = 2,
|
||||
}
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
templateUrl: "./access-intelligence.component.html",
|
||||
imports: [
|
||||
ApplicationTableComponent,
|
||||
CommonModule,
|
||||
JslibModule,
|
||||
HeaderModule,
|
||||
NotifiedMembersTableComponent,
|
||||
TabsModule,
|
||||
],
|
||||
})
|
||||
export class AccessIntelligenceComponent {
|
||||
tabIndex: AccessIntelligenceTabType;
|
||||
|
||||
apps: any[] = [];
|
||||
priorityApps: any[] = [];
|
||||
notifiedMembers: any[] = [];
|
||||
|
||||
constructor(route: ActivatedRoute) {
|
||||
route.queryParams.pipe(takeUntilDestroyed(), first()).subscribe(({ tabIndex }) => {
|
||||
this.tabIndex = !isNaN(tabIndex) ? tabIndex : AccessIntelligenceTabType.AllApps;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
|
||||
import { AccessIntelligenceRoutingModule } from "./access-intelligence-routing.module";
|
||||
import { AccessIntelligenceComponent } from "./access-intelligence.component";
|
||||
|
||||
@NgModule({
|
||||
imports: [AccessIntelligenceComponent, AccessIntelligenceRoutingModule],
|
||||
})
|
||||
export class AccessIntelligenceModule {}
|
||||
@@ -0,0 +1,11 @@
|
||||
<!-- <bit-table [dataSource]="dataSource"> -->
|
||||
<ng-container header>
|
||||
<tr>
|
||||
<th bitCell>{{ "application" | i18n }}</th>
|
||||
<th bitCell>{{ "atRiskPasswords" | i18n }}</th>
|
||||
<th bitCell>{{ "totalPasswords" | i18n }}</th>
|
||||
<th bitCell>{{ "atRiskMembers" | i18n }}</th>
|
||||
<th bitCell>{{ "totalMembers" | i18n }}</th>
|
||||
</tr>
|
||||
</ng-container>
|
||||
<!-- </bit-table> -->
|
||||
@@ -0,0 +1,19 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { TableDataSource, TableModule } from "@bitwarden/components";
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: "tools-application-table",
|
||||
templateUrl: "./application-table.component.html",
|
||||
imports: [CommonModule, JslibModule, TableModule],
|
||||
})
|
||||
export class ApplicationTableComponent {
|
||||
protected dataSource = new TableDataSource<any>();
|
||||
|
||||
constructor() {
|
||||
this.dataSource.data = [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<!-- <bit-table [dataSource]="dataSource"> -->
|
||||
<ng-container header>
|
||||
<tr>
|
||||
<th bitCell>{{ "member" | i18n }}</th>
|
||||
<th bitCell>{{ "atRiskPasswords" | i18n }}</th>
|
||||
<th bitCell>{{ "totalPasswords" | i18n }}</th>
|
||||
<th bitCell>{{ "atRiskApplications" | i18n }}</th>
|
||||
<th bitCell>{{ "totalApplications" | i18n }}</th>
|
||||
</tr>
|
||||
</ng-container>
|
||||
<!-- </bit-table> -->
|
||||
@@ -0,0 +1,19 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { TableDataSource, TableModule } from "@bitwarden/components";
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: "tools-notified-members-table",
|
||||
templateUrl: "./notified-members-table.component.html",
|
||||
imports: [CommonModule, JslibModule, TableModule],
|
||||
})
|
||||
export class NotifiedMembersTableComponent {
|
||||
dataSource = new TableDataSource<any>();
|
||||
|
||||
constructor() {
|
||||
this.dataSource.data = [];
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,12 @@ import { ComponentFixture, TestBed } from "@angular/core/testing";
|
||||
import { MockProxy, mock } from "jest-mock-extended";
|
||||
import { of } from "rxjs";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
|
||||
import { CollectionService, Collection } from "@bitwarden/admin-console/common";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { Collection } from "@bitwarden/common/vault/models/domain/collection";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
|
||||
|
||||
@@ -19,14 +19,14 @@ import {
|
||||
CollectionAdminView,
|
||||
OrganizationUserApiService,
|
||||
OrganizationUserUserMiniResponse,
|
||||
CollectionResponse,
|
||||
CollectionView,
|
||||
} from "@bitwarden/admin-console/common";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { CollectionResponse } from "@bitwarden/common/vault/models/response/collection.response";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
import { BitValidators, DialogService } from "@bitwarden/components";
|
||||
|
||||
import { GroupService, GroupView } from "../../../admin-console/organizations/core";
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Router } from "@angular/router";
|
||||
import { firstValueFrom, Subject } from "rxjs";
|
||||
import { map } from "rxjs/operators";
|
||||
|
||||
import { CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions";
|
||||
@@ -17,7 +18,6 @@ import { PremiumUpgradePromptService } from "@bitwarden/common/vault/abstraction
|
||||
import { ViewPasswordHistoryService } from "@bitwarden/common/vault/abstractions/view-password-history.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
import {
|
||||
AsyncActionsModule,
|
||||
ButtonModule,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
|
||||
import { VaultItemEvent } from "./vault-item-event";
|
||||
import { RowHeightClass } from "./vault-items.component";
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
||||
|
||||
import { CollectionAdminView, Unassigned } from "@bitwarden/admin-console/common";
|
||||
import { CollectionAdminView, Unassigned, CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
|
||||
import { GroupView } from "../../../admin-console/organizations/core";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CollectionView } from "@bitwarden/common/src/vault/models/view/collection.view";
|
||||
import { CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
|
||||
import { VaultItem } from "./vault-item";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
|
||||
export interface VaultItem {
|
||||
collection?: CollectionView;
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { SelectionModel } from "@angular/cdk/collections";
|
||||
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
||||
|
||||
import { Unassigned } from "@bitwarden/admin-console/common";
|
||||
import { Unassigned, CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
import { TableDataSource } from "@bitwarden/components";
|
||||
|
||||
import { GroupView } from "../../../admin-console/organizations/core";
|
||||
@@ -92,7 +91,12 @@ export class VaultItemsComponent {
|
||||
}
|
||||
|
||||
get disableMenu() {
|
||||
return !this.bulkMoveAllowed && !this.showAssignToCollections() && !this.showDelete();
|
||||
return (
|
||||
!this.bulkMoveAllowed &&
|
||||
!this.showAssignToCollections() &&
|
||||
!this.showDelete() &&
|
||||
!this.showBulkEditCollectionAccess
|
||||
);
|
||||
}
|
||||
|
||||
get bulkAssignToCollectionsAllowed() {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
import { of } from "rxjs";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||
@@ -13,7 +14,6 @@ import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.se
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy";
|
||||
|
||||
@@ -2,6 +2,7 @@ import { DatePipe } from "@angular/common";
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/vault/components/add-edit.component";
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
@@ -20,7 +21,6 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog";
|
||||
import { Component, Inject } from "@angular/core";
|
||||
|
||||
import { CollectionService, CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { CipherBulkDeleteRequest } from "@bitwarden/common/vault/models/request/cipher-bulk-delete.request";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
export interface BulkDeleteDialogParams {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { DialogConfig, DialogRef, DIALOG_DATA } from "@angular/cdk/dialog";
|
||||
import { Component, Inject, OnDestroy, OnInit } from "@angular/core";
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { CollectionService, CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
@@ -10,9 +11,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { Checkable, isChecked } from "@bitwarden/common/types/checkable";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
export interface BulkShareDialogParams {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog";
|
||||
import { Component, Inject, OnDestroy } from "@angular/core";
|
||||
|
||||
import { CollectionService, CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { CollectionsComponent as BaseCollectionsComponent } from "@bitwarden/angular/admin-console/components/collections.component";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
@@ -8,8 +9,6 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
|
||||
@Component({
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user