mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 16:23:44 +00:00
Merge branch 'master' into feature/org-admin-refresh
This commit is contained in:
6
.github/workflows/release-cli.yml
vendored
6
.github/workflows/release-cli.yml
vendored
@@ -287,7 +287,9 @@ jobs:
|
|||||||
artifacts: bitwarden-cli-${{ env._PKG_VERSION }}-npm-build.zip
|
artifacts: bitwarden-cli-${{ env._PKG_VERSION }}-npm-build.zip
|
||||||
|
|
||||||
- name: Setup NPM
|
- name: Setup NPM
|
||||||
run: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > .npmrc
|
run: |
|
||||||
|
echo 'registry="https://registry.npmjs.org/"' > ./.npmrc
|
||||||
|
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ./.npmrc
|
||||||
env:
|
env:
|
||||||
NPM_TOKEN: ${{ steps.retrieve-secrets.outputs.cli-npm-api-key }}
|
NPM_TOKEN: ${{ steps.retrieve-secrets.outputs.cli-npm-api-key }}
|
||||||
|
|
||||||
@@ -296,5 +298,5 @@ jobs:
|
|||||||
|
|
||||||
- name: Publish NPM
|
- name: Publish NPM
|
||||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||||
run: npm publish --access public
|
run: npm publish --access public --regsitry=https://registry.npmjs.org/ --userconfig=./.npmrc
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"extends": "../tsconfig",
|
"extends": "../tsconfig",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"types": ["node", "jest"],
|
"types": ["node", "jest", "chrome"],
|
||||||
"allowSyntheticDefaultImports": true
|
"allowSyntheticDefaultImports": true
|
||||||
},
|
},
|
||||||
"exclude": ["../src/test.setup.ts", "../apps/src/**/*.spec.ts", "../libs/**/*.spec.ts"],
|
"exclude": ["../src/test.setup.ts", "../apps/src/**/*.spec.ts", "../libs/**/*.spec.ts"],
|
||||||
|
|||||||
@@ -1968,6 +1968,9 @@
|
|||||||
"ssoKeyConnectorError": {
|
"ssoKeyConnectorError": {
|
||||||
"message": "Key Connector error: make sure Key Connector is available and working correctly."
|
"message": "Key Connector error: make sure Key Connector is available and working correctly."
|
||||||
},
|
},
|
||||||
|
"premiumSubcriptionRequired": {
|
||||||
|
"message": "Premium subscription required"
|
||||||
|
},
|
||||||
"organizationIsDisabled": {
|
"organizationIsDisabled": {
|
||||||
"message": "Organization is disabled."
|
"message": "Organization is disabled."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
import MainBackground from "./background/main.background";
|
import MainBackground from "./background/main.background";
|
||||||
|
import { onCommandListener } from "./listeners/onCommandListener";
|
||||||
|
|
||||||
const bitwardenMain = ((window as any).bitwardenMain = new MainBackground());
|
const manifest = chrome.runtime.getManifest();
|
||||||
bitwardenMain.bootstrap().then(() => {
|
|
||||||
|
if (manifest.manifest_version === 3) {
|
||||||
|
chrome.commands.onCommand.addListener(onCommandListener);
|
||||||
|
} else {
|
||||||
|
const bitwardenMain = ((window as any).bitwardenMain = new MainBackground());
|
||||||
|
bitwardenMain.bootstrap().then(() => {
|
||||||
// Finished bootstrapping
|
// Finished bootstrapping
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -81,6 +81,10 @@ export default class ContextMenusBackground {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async cipherAction(tab: chrome.tabs.Tab, info: chrome.contextMenus.OnClickData) {
|
private async cipherAction(tab: chrome.tabs.Tab, info: chrome.contextMenus.OnClickData) {
|
||||||
|
if (typeof info.menuItemId !== "string") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const id = info.menuItemId.split("_")[1];
|
const id = info.menuItemId.split("_")[1];
|
||||||
|
|
||||||
if ((await this.authService.getAuthStatus()) < AuthenticationStatus.Unlocked) {
|
if ((await this.authService.getAuthStatus()) < AuthenticationStatus.Unlocked) {
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ import { SystemService as SystemServiceAbstraction } from "@bitwarden/common/abs
|
|||||||
import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/abstractions/token.service";
|
import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/abstractions/token.service";
|
||||||
import { TotpService as TotpServiceAbstraction } from "@bitwarden/common/abstractions/totp.service";
|
import { TotpService as TotpServiceAbstraction } from "@bitwarden/common/abstractions/totp.service";
|
||||||
import { TwoFactorService as TwoFactorServiceAbstraction } from "@bitwarden/common/abstractions/twoFactor.service";
|
import { TwoFactorService as TwoFactorServiceAbstraction } from "@bitwarden/common/abstractions/twoFactor.service";
|
||||||
import { UserVerificationService as UserVerificationServiceAbstraction } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationApiServiceAbstraction } from "@bitwarden/common/abstractions/userVerification/userVerification-api.service.abstraction";
|
||||||
|
import { UserVerificationService as UserVerificationServiceAbstraction } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
import { UsernameGenerationService as UsernameGenerationServiceAbstraction } from "@bitwarden/common/abstractions/usernameGeneration.service";
|
import { UsernameGenerationService as UsernameGenerationServiceAbstraction } from "@bitwarden/common/abstractions/usernameGeneration.service";
|
||||||
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "@bitwarden/common/abstractions/vaultTimeout.service";
|
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "@bitwarden/common/abstractions/vaultTimeout.service";
|
||||||
import { AuthenticationStatus } from "@bitwarden/common/enums/authenticationStatus";
|
import { AuthenticationStatus } from "@bitwarden/common/enums/authenticationStatus";
|
||||||
@@ -71,7 +72,8 @@ import { SystemService } from "@bitwarden/common/services/system.service";
|
|||||||
import { TokenService } from "@bitwarden/common/services/token.service";
|
import { TokenService } from "@bitwarden/common/services/token.service";
|
||||||
import { TotpService } from "@bitwarden/common/services/totp.service";
|
import { TotpService } from "@bitwarden/common/services/totp.service";
|
||||||
import { TwoFactorService } from "@bitwarden/common/services/twoFactor.service";
|
import { TwoFactorService } from "@bitwarden/common/services/twoFactor.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/services/userVerification.service";
|
import { UserVerificationApiService } from "@bitwarden/common/services/userVerification/userVerification-api.service";
|
||||||
|
import { UserVerificationService } from "@bitwarden/common/services/userVerification/userVerification.service";
|
||||||
import { UsernameGenerationService } from "@bitwarden/common/services/usernameGeneration.service";
|
import { UsernameGenerationService } from "@bitwarden/common/services/usernameGeneration.service";
|
||||||
import { WebCryptoFunctionService } from "@bitwarden/common/services/webCryptoFunction.service";
|
import { WebCryptoFunctionService } from "@bitwarden/common/services/webCryptoFunction.service";
|
||||||
|
|
||||||
@@ -152,6 +154,7 @@ export default class MainBackground {
|
|||||||
encryptService: EncryptService;
|
encryptService: EncryptService;
|
||||||
folderApiService: FolderApiServiceAbstraction;
|
folderApiService: FolderApiServiceAbstraction;
|
||||||
policyApiService: PolicyApiServiceAbstraction;
|
policyApiService: PolicyApiServiceAbstraction;
|
||||||
|
userVerificationApiService: UserVerificationApiServiceAbstraction;
|
||||||
|
|
||||||
// Passed to the popup for Safari to workaround issues with theming, downloading, etc.
|
// Passed to the popup for Safari to workaround issues with theming, downloading, etc.
|
||||||
backgroundWindow = window;
|
backgroundWindow = window;
|
||||||
@@ -422,10 +425,12 @@ export default class MainBackground {
|
|||||||
);
|
);
|
||||||
this.popupUtilsService = new PopupUtilsService(isPrivateMode);
|
this.popupUtilsService = new PopupUtilsService(isPrivateMode);
|
||||||
|
|
||||||
|
this.userVerificationApiService = new UserVerificationApiService(this.apiService);
|
||||||
|
|
||||||
this.userVerificationService = new UserVerificationService(
|
this.userVerificationService = new UserVerificationService(
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.i18nService,
|
this.i18nService,
|
||||||
this.apiService
|
this.userVerificationApiService
|
||||||
);
|
);
|
||||||
|
|
||||||
const systemUtilsServiceReloadCallback = () => {
|
const systemUtilsServiceReloadCallback = () => {
|
||||||
|
|||||||
@@ -14,7 +14,10 @@ export default class WebRequestBackground {
|
|||||||
private cipherService: CipherService,
|
private cipherService: CipherService,
|
||||||
private authService: AuthService
|
private authService: AuthService
|
||||||
) {
|
) {
|
||||||
|
const manifest = chrome.runtime.getManifest();
|
||||||
|
if (manifest.manifest_version === 2) {
|
||||||
this.webRequest = (window as any).chrome.webRequest;
|
this.webRequest = (window as any).chrome.webRequest;
|
||||||
|
}
|
||||||
this.isFirefox = platformUtilsService.isFirefox();
|
this.isFirefox = platformUtilsService.isFirefox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
44
apps/browser/src/commands/autoFillActiveTabCommand.ts
Normal file
44
apps/browser/src/commands/autoFillActiveTabCommand.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import AutofillPageDetails from "../models/autofillPageDetails";
|
||||||
|
import { AutofillService } from "../services/abstractions/autofill.service";
|
||||||
|
|
||||||
|
export class AutoFillActiveTabCommand {
|
||||||
|
constructor(private autofillService: AutofillService) {}
|
||||||
|
|
||||||
|
async doAutoFillActiveTabCommand(tab: chrome.tabs.Tab) {
|
||||||
|
if (!tab.id) {
|
||||||
|
throw new Error("Tab does not have an id, cannot complete autofill.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const details = await this.collectPageDetails(tab.id);
|
||||||
|
await this.autofillService.doAutoFillOnTab(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
frameId: 0,
|
||||||
|
tab: tab,
|
||||||
|
details: details,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tab,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async collectPageDetails(tabId: number): Promise<AutofillPageDetails> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
chrome.tabs.sendMessage(
|
||||||
|
tabId,
|
||||||
|
{
|
||||||
|
command: "collectPageDetailsImmediately",
|
||||||
|
},
|
||||||
|
(response: AutofillPageDetails) => {
|
||||||
|
if (chrome.runtime.lastError) {
|
||||||
|
reject(chrome.runtime.lastError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(response);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,6 +39,7 @@
|
|||||||
6. Rename com.agilebits.* stuff to com.bitwarden.*
|
6. Rename com.agilebits.* stuff to com.bitwarden.*
|
||||||
7. Remove "some useful globals" on window
|
7. Remove "some useful globals" on window
|
||||||
8. Add ability to autofill span[data-bwautofill] elements
|
8. Add ability to autofill span[data-bwautofill] elements
|
||||||
|
9. Add new handler, for new command that responds with page details in response callback
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function collect(document, undefined) {
|
function collect(document, undefined) {
|
||||||
@@ -1037,6 +1038,11 @@
|
|||||||
fill(document, msg.fillScript);
|
fill(document, msg.fillScript);
|
||||||
sendResponse();
|
sendResponse();
|
||||||
return true;
|
return true;
|
||||||
|
} else if (msg.command === 'collectPageDetailsImmediately') {
|
||||||
|
var pageDetails = collect(document);
|
||||||
|
var pageDetailsObj = JSON.parse(pageDetails);
|
||||||
|
sendResponse(pageDetailsObj);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|||||||
140
apps/browser/src/listeners/onCommandListener.ts
Normal file
140
apps/browser/src/listeners/onCommandListener.ts
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
import { AuthenticationStatus } from "@bitwarden/common/enums/authenticationStatus";
|
||||||
|
import { StateFactory } from "@bitwarden/common/factories/stateFactory";
|
||||||
|
import { GlobalState } from "@bitwarden/common/models/domain/globalState";
|
||||||
|
import { AuthService } from "@bitwarden/common/services/auth.service";
|
||||||
|
import { CipherService } from "@bitwarden/common/services/cipher.service";
|
||||||
|
import { ConsoleLogService } from "@bitwarden/common/services/consoleLog.service";
|
||||||
|
import { EncryptService } from "@bitwarden/common/services/encrypt.service";
|
||||||
|
import NoOpEventService from "@bitwarden/common/services/noOpEvent.service";
|
||||||
|
import { SearchService } from "@bitwarden/common/services/search.service";
|
||||||
|
import { SettingsService } from "@bitwarden/common/services/settings.service";
|
||||||
|
import { StateMigrationService } from "@bitwarden/common/services/stateMigration.service";
|
||||||
|
import { WebCryptoFunctionService } from "@bitwarden/common/services/webCryptoFunction.service";
|
||||||
|
|
||||||
|
import { AutoFillActiveTabCommand } from "../commands/autoFillActiveTabCommand";
|
||||||
|
import { Account } from "../models/account";
|
||||||
|
import { StateService as AbstractStateService } from "../services/abstractions/state.service";
|
||||||
|
import AutofillService from "../services/autofill.service";
|
||||||
|
import { BrowserCryptoService } from "../services/browserCrypto.service";
|
||||||
|
import BrowserLocalStorageService from "../services/browserLocalStorage.service";
|
||||||
|
import BrowserPlatformUtilsService from "../services/browserPlatformUtils.service";
|
||||||
|
import I18nService from "../services/i18n.service";
|
||||||
|
import { KeyGenerationService } from "../services/keyGeneration.service";
|
||||||
|
import { LocalBackedSessionStorageService } from "../services/localBackedSessionStorage.service";
|
||||||
|
import { StateService } from "../services/state.service";
|
||||||
|
|
||||||
|
export const onCommandListener = async (command: string, tab: chrome.tabs.Tab) => {
|
||||||
|
switch (command) {
|
||||||
|
case "autofill_login":
|
||||||
|
await doAutoFillLogin(tab);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const doAutoFillLogin = async (tab: chrome.tabs.Tab): Promise<void> => {
|
||||||
|
const logService = new ConsoleLogService(false);
|
||||||
|
|
||||||
|
const cryptoFunctionService = new WebCryptoFunctionService(self);
|
||||||
|
|
||||||
|
const storageService = new BrowserLocalStorageService();
|
||||||
|
|
||||||
|
const secureStorageService = new BrowserLocalStorageService();
|
||||||
|
|
||||||
|
const memoryStorageService = new LocalBackedSessionStorageService(
|
||||||
|
new EncryptService(cryptoFunctionService, logService, false),
|
||||||
|
new KeyGenerationService(cryptoFunctionService)
|
||||||
|
);
|
||||||
|
|
||||||
|
const stateFactory = new StateFactory(GlobalState, Account);
|
||||||
|
|
||||||
|
const stateMigrationService = new StateMigrationService(
|
||||||
|
storageService,
|
||||||
|
secureStorageService,
|
||||||
|
stateFactory
|
||||||
|
);
|
||||||
|
|
||||||
|
const stateService: AbstractStateService = new StateService(
|
||||||
|
storageService,
|
||||||
|
secureStorageService,
|
||||||
|
memoryStorageService, // AbstractStorageService
|
||||||
|
logService,
|
||||||
|
stateMigrationService,
|
||||||
|
stateFactory
|
||||||
|
);
|
||||||
|
|
||||||
|
await stateService.init();
|
||||||
|
|
||||||
|
const platformUtils = new BrowserPlatformUtilsService(
|
||||||
|
null, // MessagingService
|
||||||
|
stateService,
|
||||||
|
null, // clipboardWriteCallback
|
||||||
|
null // biometricCallback
|
||||||
|
);
|
||||||
|
|
||||||
|
const cryptoService = new BrowserCryptoService(
|
||||||
|
cryptoFunctionService,
|
||||||
|
null, // AbstractEncryptService
|
||||||
|
platformUtils,
|
||||||
|
logService,
|
||||||
|
stateService
|
||||||
|
);
|
||||||
|
|
||||||
|
const settingsService = new SettingsService(stateService);
|
||||||
|
|
||||||
|
const i18nService = new I18nService(chrome.i18n.getUILanguage());
|
||||||
|
|
||||||
|
await i18nService.init();
|
||||||
|
|
||||||
|
// Don't love this pt.1
|
||||||
|
let searchService: SearchService = null;
|
||||||
|
|
||||||
|
const cipherService = new CipherService(
|
||||||
|
cryptoService,
|
||||||
|
settingsService,
|
||||||
|
null, // ApiService
|
||||||
|
null, // FileUploadService,
|
||||||
|
i18nService,
|
||||||
|
() => searchService, // Don't love this pt.2
|
||||||
|
logService,
|
||||||
|
stateService
|
||||||
|
);
|
||||||
|
|
||||||
|
// Don't love this pt.3
|
||||||
|
searchService = new SearchService(cipherService, logService, i18nService);
|
||||||
|
|
||||||
|
// TODO: Remove this before we encourage anyone to start using this
|
||||||
|
const eventService = new NoOpEventService();
|
||||||
|
|
||||||
|
const autofillService = new AutofillService(
|
||||||
|
cipherService,
|
||||||
|
stateService,
|
||||||
|
null, // TotpService
|
||||||
|
eventService,
|
||||||
|
logService
|
||||||
|
);
|
||||||
|
|
||||||
|
const authService = new AuthService(
|
||||||
|
cryptoService, // CryptoService
|
||||||
|
null, // ApiService
|
||||||
|
null, // TokenService
|
||||||
|
null, // AppIdService
|
||||||
|
platformUtils,
|
||||||
|
null, // MessagingService
|
||||||
|
logService,
|
||||||
|
null, // KeyConnectorService
|
||||||
|
null, // EnvironmentService
|
||||||
|
stateService,
|
||||||
|
null, // TwoFactorService
|
||||||
|
i18nService
|
||||||
|
);
|
||||||
|
|
||||||
|
const authStatus = await authService.getAuthStatus();
|
||||||
|
if (authStatus < AuthenticationStatus.Unlocked) {
|
||||||
|
// TODO: Add back in unlock on autofill
|
||||||
|
logService.info("Currently not unlocked, MV3 does not support unlock on autofill currently.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const command = new AutoFillActiveTabCommand(autofillService);
|
||||||
|
await command.doAutoFillActiveTabCommand(tab);
|
||||||
|
};
|
||||||
@@ -47,7 +47,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"background": {
|
"background": {
|
||||||
"service_worker": "background.js"
|
"service_worker": "background.js",
|
||||||
|
"type": "module"
|
||||||
},
|
},
|
||||||
"action": {
|
"action": {
|
||||||
"default_icon": {
|
"default_icon": {
|
||||||
|
|||||||
@@ -22,4 +22,5 @@ export default class AutofillField {
|
|||||||
selectInfo: any;
|
selectInfo: any;
|
||||||
maxLength: number;
|
maxLength: number;
|
||||||
tagName: string;
|
tagName: string;
|
||||||
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
// Clear them aggressively to make sure this doesn't occur
|
// Clear them aggressively to make sure this doesn't occur
|
||||||
await this.clearComponentStates();
|
await this.clearComponentStates();
|
||||||
|
|
||||||
this.stateService.activeAccount.pipe(takeUntil(this.destroy$)).subscribe((userId) => {
|
this.stateService.activeAccount$.pipe(takeUntil(this.destroy$)).subscribe((userId) => {
|
||||||
this.activeUserId = userId;
|
this.activeUserId = userId;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.stateService.activeAccount.getValue() == null) {
|
if (this.activeUserId === null) {
|
||||||
this.router.navigate(["home"]);
|
this.router.navigate(["home"]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ import { SyncService } from "@bitwarden/common/abstractions/sync.service";
|
|||||||
import { TokenService } from "@bitwarden/common/abstractions/token.service";
|
import { TokenService } from "@bitwarden/common/abstractions/token.service";
|
||||||
import { TotpService } from "@bitwarden/common/abstractions/totp.service";
|
import { TotpService } from "@bitwarden/common/abstractions/totp.service";
|
||||||
import { TwoFactorService } from "@bitwarden/common/abstractions/twoFactor.service";
|
import { TwoFactorService } from "@bitwarden/common/abstractions/twoFactor.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
import { UsernameGenerationService } from "@bitwarden/common/abstractions/usernameGeneration.service";
|
import { UsernameGenerationService } from "@bitwarden/common/abstractions/usernameGeneration.service";
|
||||||
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout.service";
|
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout.service";
|
||||||
import { AuthService } from "@bitwarden/common/services/auth.service";
|
import { AuthService } from "@bitwarden/common/services/auth.service";
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
|||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-export",
|
selector: "app-export",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<header>
|
<header>
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<button type="button" routerLink="/tabs/settings">
|
<button type="button" (click)="goBack()">
|
||||||
<span class="header-icon"><i class="bwi bwi-angle-left" aria-hidden="true"></i></span>
|
<span class="header-icon"><i class="bwi bwi-angle-left" aria-hidden="true"></i></span>
|
||||||
<span>{{ "back" | i18n }}</span>
|
<span>{{ "back" | i18n }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { CurrencyPipe } from "@angular/common";
|
import { CurrencyPipe, Location } from "@angular/common";
|
||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
|
|
||||||
import { PremiumComponent as BasePremiumComponent } from "@bitwarden/angular/components/premium.component";
|
import { PremiumComponent as BasePremiumComponent } from "@bitwarden/angular/components/premium.component";
|
||||||
@@ -21,6 +21,7 @@ export class PremiumComponent extends BasePremiumComponent {
|
|||||||
apiService: ApiService,
|
apiService: ApiService,
|
||||||
stateService: StateService,
|
stateService: StateService,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
|
private location: Location,
|
||||||
private currencyPipe: CurrencyPipe
|
private currencyPipe: CurrencyPipe
|
||||||
) {
|
) {
|
||||||
super(i18nService, platformUtilsService, apiService, logService, stateService);
|
super(i18nService, platformUtilsService, apiService, logService, stateService);
|
||||||
@@ -32,4 +33,8 @@ export class PremiumComponent extends BasePremiumComponent {
|
|||||||
this.priceString = this.priceString.replace("%price%", thePrice);
|
this.priceString = this.priceString.replace("%price%", thePrice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.location.back();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,6 +84,7 @@
|
|||||||
<div class="no-items">
|
<div class="no-items">
|
||||||
<i class="bwi bwi-spinner bwi-spin bwi-3x" *ngIf="!loaded" aria-hidden="true"></i>
|
<i class="bwi bwi-spinner bwi-spin bwi-3x" *ngIf="!loaded" aria-hidden="true"></i>
|
||||||
<ng-container *ngIf="loaded">
|
<ng-container *ngIf="loaded">
|
||||||
|
<img class="no-items-image" aria-hidden="true" />
|
||||||
<p>{{ "noItemsInList" | i18n }}</p>
|
<p>{{ "noItemsInList" | i18n }}</p>
|
||||||
<button type="button" (click)="addCipher()" class="btn block primary link">
|
<button type="button" (click)="addCipher()" class="btn block primary link">
|
||||||
{{ "addItem" | i18n }}
|
{{ "addItem" | i18n }}
|
||||||
|
|||||||
@@ -139,7 +139,7 @@
|
|||||||
<div
|
<div
|
||||||
class="box-content-row box-content-row-flex totp"
|
class="box-content-row box-content-row-flex totp"
|
||||||
[ngClass]="{ low: totpLow }"
|
[ngClass]="{ low: totpLow }"
|
||||||
*ngIf="cipher.login.totp && totpCode"
|
*ngIf="cipher.login.totp && totpCode && canAccessPremium"
|
||||||
>
|
>
|
||||||
<div class="row-main">
|
<div class="row-main">
|
||||||
<span
|
<span
|
||||||
@@ -177,6 +177,20 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="box-content-row box-content-row-flex totp"
|
||||||
|
*ngIf="cipher.login.totp && !canAccessPremium"
|
||||||
|
>
|
||||||
|
<div class="row-main">
|
||||||
|
<span class="row-label">{{ "verificationCodeTotp" | i18n }}</span>
|
||||||
|
<span class="row-label">
|
||||||
|
<a routerLink="/premium">
|
||||||
|
{{ "premiumSubcriptionRequired" | i18n }}
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Card -->
|
<!-- Card -->
|
||||||
<div *ngIf="cipher.card">
|
<div *ngIf="cipher.card">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { AbstractStorageService } from "@bitwarden/common/abstractions/storage.service";
|
import { AbstractStorageService } from "@bitwarden/common/abstractions/storage.service";
|
||||||
|
|
||||||
export default abstract class AbstractChromeStorageService implements AbstractStorageService {
|
export default abstract class AbstractChromeStorageService implements AbstractStorageService {
|
||||||
protected abstract chromeStorageApi: any;
|
protected abstract chromeStorageApi: chrome.storage.StorageArea;
|
||||||
|
|
||||||
async get<T>(key: string): Promise<T> {
|
async get<T>(key: string): Promise<T> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
|
|||||||
@@ -1,7 +1,41 @@
|
|||||||
|
import { CipherView } from "@bitwarden/common/models/view/cipherView";
|
||||||
|
|
||||||
|
import AutofillField from "../../models/autofillField";
|
||||||
|
import AutofillForm from "../../models/autofillForm";
|
||||||
import AutofillPageDetails from "../../models/autofillPageDetails";
|
import AutofillPageDetails from "../../models/autofillPageDetails";
|
||||||
|
|
||||||
export abstract class AutofillService {
|
export interface PageDetail {
|
||||||
getFormsWithPasswordFields: (pageDetails: AutofillPageDetails) => any[];
|
frameId: number;
|
||||||
doAutoFill: (options: any) => Promise<string>;
|
tab: chrome.tabs.Tab;
|
||||||
doAutoFillActiveTab: (pageDetails: any, fromCommand: boolean) => Promise<string>;
|
details: AutofillPageDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AutoFillOptions {
|
||||||
|
cipher: CipherView;
|
||||||
|
pageDetails: PageDetail[];
|
||||||
|
doc?: typeof window.document;
|
||||||
|
tab: chrome.tabs.Tab;
|
||||||
|
skipUsernameOnlyFill?: boolean;
|
||||||
|
onlyEmptyFields?: boolean;
|
||||||
|
onlyVisibleFields?: boolean;
|
||||||
|
fillNewPassword?: boolean;
|
||||||
|
skipLastUsed?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FormData {
|
||||||
|
form: AutofillForm;
|
||||||
|
password: AutofillField;
|
||||||
|
username: AutofillField;
|
||||||
|
passwords: AutofillField[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class AutofillService {
|
||||||
|
getFormsWithPasswordFields: (pageDetails: AutofillPageDetails) => FormData[];
|
||||||
|
doAutoFill: (options: AutoFillOptions) => Promise<string>;
|
||||||
|
doAutoFillOnTab: (
|
||||||
|
pageDetails: PageDetail[],
|
||||||
|
tab: chrome.tabs.Tab,
|
||||||
|
fromCommand: boolean
|
||||||
|
) => Promise<string>;
|
||||||
|
doAutoFillActiveTab: (pageDetails: PageDetail[], fromCommand: boolean) => Promise<string>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,13 +15,26 @@ import AutofillPageDetails from "../models/autofillPageDetails";
|
|||||||
import AutofillScript from "../models/autofillScript";
|
import AutofillScript from "../models/autofillScript";
|
||||||
import { StateService } from "../services/abstractions/state.service";
|
import { StateService } from "../services/abstractions/state.service";
|
||||||
|
|
||||||
import { AutofillService as AutofillServiceInterface } from "./abstractions/autofill.service";
|
import {
|
||||||
|
AutoFillOptions,
|
||||||
|
AutofillService as AutofillServiceInterface,
|
||||||
|
PageDetail,
|
||||||
|
FormData,
|
||||||
|
} from "./abstractions/autofill.service";
|
||||||
import {
|
import {
|
||||||
AutoFillConstants,
|
AutoFillConstants,
|
||||||
CreditCardAutoFillConstants,
|
CreditCardAutoFillConstants,
|
||||||
IdentityAutoFillConstants,
|
IdentityAutoFillConstants,
|
||||||
} from "./autofillConstants";
|
} from "./autofillConstants";
|
||||||
|
|
||||||
|
export interface GenerateFillScriptOptions {
|
||||||
|
skipUsernameOnlyFill: boolean;
|
||||||
|
onlyEmptyFields: boolean;
|
||||||
|
onlyVisibleFields: boolean;
|
||||||
|
fillNewPassword: boolean;
|
||||||
|
cipher: CipherView;
|
||||||
|
}
|
||||||
|
|
||||||
export default class AutofillService implements AutofillServiceInterface {
|
export default class AutofillService implements AutofillServiceInterface {
|
||||||
constructor(
|
constructor(
|
||||||
private cipherService: CipherService,
|
private cipherService: CipherService,
|
||||||
@@ -31,10 +44,16 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
private logService: LogService
|
private logService: LogService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
getFormsWithPasswordFields(pageDetails: AutofillPageDetails): any[] {
|
getFormsWithPasswordFields(pageDetails: AutofillPageDetails): FormData[] {
|
||||||
const formData: any[] = [];
|
const formData: FormData[] = [];
|
||||||
|
|
||||||
const passwordFields = this.loadPasswordFields(pageDetails, true, true, false, false);
|
const passwordFields = AutofillService.loadPasswordFields(
|
||||||
|
pageDetails,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
);
|
||||||
if (passwordFields.length === 0) {
|
if (passwordFields.length === 0) {
|
||||||
return formData;
|
return formData;
|
||||||
}
|
}
|
||||||
@@ -64,16 +83,17 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
return formData;
|
return formData;
|
||||||
}
|
}
|
||||||
|
|
||||||
async doAutoFill(options: any) {
|
async doAutoFill(options: AutoFillOptions) {
|
||||||
let totpPromise: Promise<string> = null;
|
|
||||||
const tab = options.tab;
|
const tab = options.tab;
|
||||||
if (!tab || !options.cipher || !options.pageDetails || !options.pageDetails.length) {
|
if (!tab || !options.cipher || !options.pageDetails || !options.pageDetails.length) {
|
||||||
throw new Error("Nothing to auto-fill.");
|
throw new Error("Nothing to auto-fill.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let totpPromise: Promise<string> = null;
|
||||||
|
|
||||||
const canAccessPremium = await this.stateService.getCanAccessPremium();
|
const canAccessPremium = await this.stateService.getCanAccessPremium();
|
||||||
let didAutofill = false;
|
let didAutofill = false;
|
||||||
options.pageDetails.forEach((pd: any) => {
|
options.pageDetails.forEach((pd) => {
|
||||||
// make sure we're still on correct tab
|
// make sure we're still on correct tab
|
||||||
if (pd.tab.id !== tab.id || pd.tab.url !== tab.url) {
|
if (pd.tab.id !== tab.id || pd.tab.url !== tab.url) {
|
||||||
return;
|
return;
|
||||||
@@ -138,12 +158,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async doAutoFillActiveTab(pageDetails: any, fromCommand: boolean) {
|
async doAutoFillOnTab(pageDetails: PageDetail[], tab: chrome.tabs.Tab, fromCommand: boolean) {
|
||||||
const tab = await this.getActiveTab();
|
|
||||||
if (!tab || !tab.url) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let cipher: CipherView;
|
let cipher: CipherView;
|
||||||
if (fromCommand) {
|
if (fromCommand) {
|
||||||
cipher = await this.cipherService.getNextCipherForUrl(tab.url);
|
cipher = await this.cipherService.getNextCipherForUrl(tab.url);
|
||||||
@@ -186,9 +201,18 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
return totpCode;
|
return totpCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async doAutoFillActiveTab(pageDetails: PageDetail[], fromCommand: boolean) {
|
||||||
|
const tab = await this.getActiveTab();
|
||||||
|
if (!tab || !tab.url) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await this.doAutoFillOnTab(pageDetails, tab, fromCommand);
|
||||||
|
}
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
|
|
||||||
private async getActiveTab(): Promise<any> {
|
private async getActiveTab(): Promise<chrome.tabs.Tab> {
|
||||||
const tab = await BrowserApi.getTabFromCurrentWindow();
|
const tab = await BrowserApi.getTabFromCurrentWindow();
|
||||||
if (!tab) {
|
if (!tab) {
|
||||||
throw new Error("No tab found.");
|
throw new Error("No tab found.");
|
||||||
@@ -197,7 +221,10 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
return tab;
|
return tab;
|
||||||
}
|
}
|
||||||
|
|
||||||
private generateFillScript(pageDetails: AutofillPageDetails, options: any): AutofillScript {
|
private generateFillScript(
|
||||||
|
pageDetails: AutofillPageDetails,
|
||||||
|
options: GenerateFillScriptOptions
|
||||||
|
): AutofillScript {
|
||||||
if (!pageDetails || !options.cipher) {
|
if (!pageDetails || !options.cipher) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -209,13 +236,13 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
if (fields && fields.length) {
|
if (fields && fields.length) {
|
||||||
const fieldNames: string[] = [];
|
const fieldNames: string[] = [];
|
||||||
|
|
||||||
fields.forEach((f: any) => {
|
fields.forEach((f) => {
|
||||||
if (this.hasValue(f.name)) {
|
if (AutofillService.hasValue(f.name)) {
|
||||||
fieldNames.push(f.name.toLowerCase());
|
fieldNames.push(f.name.toLowerCase());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
pageDetails.fields.forEach((field: any) => {
|
pageDetails.fields.forEach((field) => {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
if (filledFields.hasOwnProperty(field.opid)) {
|
if (filledFields.hasOwnProperty(field.opid)) {
|
||||||
return;
|
return;
|
||||||
@@ -228,10 +255,10 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
const matchingIndex = this.findMatchingFieldIndex(field, fieldNames);
|
const matchingIndex = this.findMatchingFieldIndex(field, fieldNames);
|
||||||
if (matchingIndex > -1) {
|
if (matchingIndex > -1) {
|
||||||
const matchingField: FieldView = fields[matchingIndex];
|
const matchingField: FieldView = fields[matchingIndex];
|
||||||
let val;
|
let val: string;
|
||||||
if (matchingField.type === FieldType.Linked) {
|
if (matchingField.type === FieldType.Linked) {
|
||||||
// Assumption: Linked Field is not being used to autofill a boolean value
|
// Assumption: Linked Field is not being used to autofill a boolean value
|
||||||
val = options.cipher.linkedFieldValue(matchingField.linkedId);
|
val = options.cipher.linkedFieldValue(matchingField.linkedId) as string;
|
||||||
} else {
|
} else {
|
||||||
val = matchingField.value;
|
val = matchingField.value;
|
||||||
if (val == null && matchingField.type === FieldType.Boolean) {
|
if (val == null && matchingField.type === FieldType.Boolean) {
|
||||||
@@ -240,7 +267,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
filledFields[field.opid] = field;
|
filledFields[field.opid] = field;
|
||||||
this.fillByOpid(fillScript, field, val);
|
AutofillService.fillByOpid(fillScript, field, val);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -269,9 +296,9 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
|
|
||||||
private generateLoginFillScript(
|
private generateLoginFillScript(
|
||||||
fillScript: AutofillScript,
|
fillScript: AutofillScript,
|
||||||
pageDetails: any,
|
pageDetails: AutofillPageDetails,
|
||||||
filledFields: { [id: string]: AutofillField },
|
filledFields: { [id: string]: AutofillField },
|
||||||
options: any
|
options: GenerateFillScriptOptions
|
||||||
): AutofillScript {
|
): AutofillScript {
|
||||||
if (!options.cipher.login) {
|
if (!options.cipher.login) {
|
||||||
return null;
|
return null;
|
||||||
@@ -285,11 +312,11 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
|
|
||||||
if (!login.password || login.password === "") {
|
if (!login.password || login.password === "") {
|
||||||
// No password for this login. Maybe they just wanted to auto-fill some custom fields?
|
// No password for this login. Maybe they just wanted to auto-fill some custom fields?
|
||||||
fillScript = this.setFillScriptForFocus(filledFields, fillScript);
|
fillScript = AutofillService.setFillScriptForFocus(filledFields, fillScript);
|
||||||
return fillScript;
|
return fillScript;
|
||||||
}
|
}
|
||||||
|
|
||||||
let passwordFields = this.loadPasswordFields(
|
let passwordFields = AutofillService.loadPasswordFields(
|
||||||
pageDetails,
|
pageDetails,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
@@ -298,7 +325,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
);
|
);
|
||||||
if (!passwordFields.length && !options.onlyVisibleFields) {
|
if (!passwordFields.length && !options.onlyVisibleFields) {
|
||||||
// not able to find any viewable password fields. maybe there are some "hidden" ones?
|
// not able to find any viewable password fields. maybe there are some "hidden" ones?
|
||||||
passwordFields = this.loadPasswordFields(
|
passwordFields = AutofillService.loadPasswordFields(
|
||||||
pageDetails,
|
pageDetails,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
@@ -362,11 +389,11 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
|
|
||||||
if (!passwordFields.length && !options.skipUsernameOnlyFill) {
|
if (!passwordFields.length && !options.skipUsernameOnlyFill) {
|
||||||
// No password fields on this page. Let's try to just fuzzy fill the username.
|
// No password fields on this page. Let's try to just fuzzy fill the username.
|
||||||
pageDetails.fields.forEach((f: any) => {
|
pageDetails.fields.forEach((f) => {
|
||||||
if (
|
if (
|
||||||
f.viewable &&
|
f.viewable &&
|
||||||
(f.type === "text" || f.type === "email" || f.type === "tel") &&
|
(f.type === "text" || f.type === "email" || f.type === "tel") &&
|
||||||
this.fieldIsFuzzyMatch(f, AutoFillConstants.UsernameFieldNames)
|
AutofillService.fieldIsFuzzyMatch(f, AutoFillConstants.UsernameFieldNames)
|
||||||
) {
|
) {
|
||||||
usernames.push(f);
|
usernames.push(f);
|
||||||
}
|
}
|
||||||
@@ -380,7 +407,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
filledFields[u.opid] = u;
|
filledFields[u.opid] = u;
|
||||||
this.fillByOpid(fillScript, u, login.username);
|
AutofillService.fillByOpid(fillScript, u, login.username);
|
||||||
});
|
});
|
||||||
|
|
||||||
passwords.forEach((p) => {
|
passwords.forEach((p) => {
|
||||||
@@ -390,18 +417,18 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
filledFields[p.opid] = p;
|
filledFields[p.opid] = p;
|
||||||
this.fillByOpid(fillScript, p, login.password);
|
AutofillService.fillByOpid(fillScript, p, login.password);
|
||||||
});
|
});
|
||||||
|
|
||||||
fillScript = this.setFillScriptForFocus(filledFields, fillScript);
|
fillScript = AutofillService.setFillScriptForFocus(filledFields, fillScript);
|
||||||
return fillScript;
|
return fillScript;
|
||||||
}
|
}
|
||||||
|
|
||||||
private generateCardFillScript(
|
private generateCardFillScript(
|
||||||
fillScript: AutofillScript,
|
fillScript: AutofillScript,
|
||||||
pageDetails: any,
|
pageDetails: AutofillPageDetails,
|
||||||
filledFields: { [id: string]: AutofillField },
|
filledFields: { [id: string]: AutofillField },
|
||||||
options: any
|
options: GenerateFillScriptOptions
|
||||||
): AutofillScript {
|
): AutofillScript {
|
||||||
if (!options.cipher.card) {
|
if (!options.cipher.card) {
|
||||||
return null;
|
return null;
|
||||||
@@ -409,8 +436,8 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
|
|
||||||
const fillFields: { [id: string]: AutofillField } = {};
|
const fillFields: { [id: string]: AutofillField } = {};
|
||||||
|
|
||||||
pageDetails.fields.forEach((f: any) => {
|
pageDetails.fields.forEach((f) => {
|
||||||
if (this.forCustomFieldsOnly(f)) {
|
if (AutofillService.forCustomFieldsOnly(f)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,7 +456,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
// ref https://developers.google.com/web/fundamentals/design-and-ux/input/forms/
|
// ref https://developers.google.com/web/fundamentals/design-and-ux/input/forms/
|
||||||
if (
|
if (
|
||||||
!fillFields.cardholderName &&
|
!fillFields.cardholderName &&
|
||||||
this.isFieldMatch(
|
AutofillService.isFieldMatch(
|
||||||
f[attr],
|
f[attr],
|
||||||
CreditCardAutoFillConstants.CardHolderFieldNames,
|
CreditCardAutoFillConstants.CardHolderFieldNames,
|
||||||
CreditCardAutoFillConstants.CardHolderFieldNameValues
|
CreditCardAutoFillConstants.CardHolderFieldNameValues
|
||||||
@@ -439,7 +466,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!fillFields.number &&
|
!fillFields.number &&
|
||||||
this.isFieldMatch(
|
AutofillService.isFieldMatch(
|
||||||
f[attr],
|
f[attr],
|
||||||
CreditCardAutoFillConstants.CardNumberFieldNames,
|
CreditCardAutoFillConstants.CardNumberFieldNames,
|
||||||
CreditCardAutoFillConstants.CardNumberFieldNameValues
|
CreditCardAutoFillConstants.CardNumberFieldNameValues
|
||||||
@@ -449,7 +476,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!fillFields.exp &&
|
!fillFields.exp &&
|
||||||
this.isFieldMatch(
|
AutofillService.isFieldMatch(
|
||||||
f[attr],
|
f[attr],
|
||||||
CreditCardAutoFillConstants.CardExpiryFieldNames,
|
CreditCardAutoFillConstants.CardExpiryFieldNames,
|
||||||
CreditCardAutoFillConstants.CardExpiryFieldNameValues
|
CreditCardAutoFillConstants.CardExpiryFieldNameValues
|
||||||
@@ -459,25 +486,25 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!fillFields.expMonth &&
|
!fillFields.expMonth &&
|
||||||
this.isFieldMatch(f[attr], CreditCardAutoFillConstants.ExpiryMonthFieldNames)
|
AutofillService.isFieldMatch(f[attr], CreditCardAutoFillConstants.ExpiryMonthFieldNames)
|
||||||
) {
|
) {
|
||||||
fillFields.expMonth = f;
|
fillFields.expMonth = f;
|
||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!fillFields.expYear &&
|
!fillFields.expYear &&
|
||||||
this.isFieldMatch(f[attr], CreditCardAutoFillConstants.ExpiryYearFieldNames)
|
AutofillService.isFieldMatch(f[attr], CreditCardAutoFillConstants.ExpiryYearFieldNames)
|
||||||
) {
|
) {
|
||||||
fillFields.expYear = f;
|
fillFields.expYear = f;
|
||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!fillFields.code &&
|
!fillFields.code &&
|
||||||
this.isFieldMatch(f[attr], CreditCardAutoFillConstants.CVVFieldNames)
|
AutofillService.isFieldMatch(f[attr], CreditCardAutoFillConstants.CVVFieldNames)
|
||||||
) {
|
) {
|
||||||
fillFields.code = f;
|
fillFields.code = f;
|
||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!fillFields.brand &&
|
!fillFields.brand &&
|
||||||
this.isFieldMatch(f[attr], CreditCardAutoFillConstants.CardBrandFieldNames)
|
AutofillService.isFieldMatch(f[attr], CreditCardAutoFillConstants.CardBrandFieldNames)
|
||||||
) {
|
) {
|
||||||
fillFields.brand = f;
|
fillFields.brand = f;
|
||||||
break;
|
break;
|
||||||
@@ -491,7 +518,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
this.makeScriptAction(fillScript, card, fillFields, filledFields, "code");
|
this.makeScriptAction(fillScript, card, fillFields, filledFields, "code");
|
||||||
this.makeScriptAction(fillScript, card, fillFields, filledFields, "brand");
|
this.makeScriptAction(fillScript, card, fillFields, filledFields, "brand");
|
||||||
|
|
||||||
if (fillFields.expMonth && this.hasValue(card.expMonth)) {
|
if (fillFields.expMonth && AutofillService.hasValue(card.expMonth)) {
|
||||||
let expMonth: string = card.expMonth;
|
let expMonth: string = card.expMonth;
|
||||||
|
|
||||||
if (fillFields.expMonth.selectInfo && fillFields.expMonth.selectInfo.options) {
|
if (fillFields.expMonth.selectInfo && fillFields.expMonth.selectInfo.options) {
|
||||||
@@ -526,10 +553,10 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
filledFields[fillFields.expMonth.opid] = fillFields.expMonth;
|
filledFields[fillFields.expMonth.opid] = fillFields.expMonth;
|
||||||
this.fillByOpid(fillScript, fillFields.expMonth, expMonth);
|
AutofillService.fillByOpid(fillScript, fillFields.expMonth, expMonth);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fillFields.expYear && this.hasValue(card.expYear)) {
|
if (fillFields.expYear && AutofillService.hasValue(card.expYear)) {
|
||||||
let expYear: string = card.expYear;
|
let expYear: string = card.expYear;
|
||||||
if (fillFields.expYear.selectInfo && fillFields.expYear.selectInfo.options) {
|
if (fillFields.expYear.selectInfo && fillFields.expYear.selectInfo.options) {
|
||||||
for (let i = 0; i < fillFields.expYear.selectInfo.options.length; i++) {
|
for (let i = 0; i < fillFields.expYear.selectInfo.options.length; i++) {
|
||||||
@@ -572,10 +599,14 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
filledFields[fillFields.expYear.opid] = fillFields.expYear;
|
filledFields[fillFields.expYear.opid] = fillFields.expYear;
|
||||||
this.fillByOpid(fillScript, fillFields.expYear, expYear);
|
AutofillService.fillByOpid(fillScript, fillFields.expYear, expYear);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fillFields.exp && this.hasValue(card.expMonth) && this.hasValue(card.expYear)) {
|
if (
|
||||||
|
fillFields.exp &&
|
||||||
|
AutofillService.hasValue(card.expMonth) &&
|
||||||
|
AutofillService.hasValue(card.expYear)
|
||||||
|
) {
|
||||||
const fullMonth = ("0" + card.expMonth).slice(-2);
|
const fullMonth = ("0" + card.expMonth).slice(-2);
|
||||||
|
|
||||||
let fullYear: string = card.expYear;
|
let fullYear: string = card.expYear;
|
||||||
@@ -712,7 +743,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
return fillScript;
|
return fillScript;
|
||||||
}
|
}
|
||||||
|
|
||||||
private fieldAttrsContain(field: any, containsVal: string) {
|
private fieldAttrsContain(field: AutofillField, containsVal: string) {
|
||||||
if (!field) {
|
if (!field) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -734,9 +765,9 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
|
|
||||||
private generateIdentityFillScript(
|
private generateIdentityFillScript(
|
||||||
fillScript: AutofillScript,
|
fillScript: AutofillScript,
|
||||||
pageDetails: any,
|
pageDetails: AutofillPageDetails,
|
||||||
filledFields: { [id: string]: AutofillField },
|
filledFields: { [id: string]: AutofillField },
|
||||||
options: any
|
options: GenerateFillScriptOptions
|
||||||
): AutofillScript {
|
): AutofillScript {
|
||||||
if (!options.cipher.identity) {
|
if (!options.cipher.identity) {
|
||||||
return null;
|
return null;
|
||||||
@@ -744,8 +775,8 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
|
|
||||||
const fillFields: { [id: string]: AutofillField } = {};
|
const fillFields: { [id: string]: AutofillField } = {};
|
||||||
|
|
||||||
pageDetails.fields.forEach((f: any) => {
|
pageDetails.fields.forEach((f) => {
|
||||||
if (this.forCustomFieldsOnly(f)) {
|
if (AutofillService.forCustomFieldsOnly(f)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -764,7 +795,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
// ref https://developers.google.com/web/fundamentals/design-and-ux/input/forms/
|
// ref https://developers.google.com/web/fundamentals/design-and-ux/input/forms/
|
||||||
if (
|
if (
|
||||||
!fillFields.name &&
|
!fillFields.name &&
|
||||||
this.isFieldMatch(
|
AutofillService.isFieldMatch(
|
||||||
f[attr],
|
f[attr],
|
||||||
IdentityAutoFillConstants.FullNameFieldNames,
|
IdentityAutoFillConstants.FullNameFieldNames,
|
||||||
IdentityAutoFillConstants.FullNameFieldNameValues
|
IdentityAutoFillConstants.FullNameFieldNameValues
|
||||||
@@ -774,37 +805,37 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!fillFields.firstName &&
|
!fillFields.firstName &&
|
||||||
this.isFieldMatch(f[attr], IdentityAutoFillConstants.FirstnameFieldNames)
|
AutofillService.isFieldMatch(f[attr], IdentityAutoFillConstants.FirstnameFieldNames)
|
||||||
) {
|
) {
|
||||||
fillFields.firstName = f;
|
fillFields.firstName = f;
|
||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!fillFields.middleName &&
|
!fillFields.middleName &&
|
||||||
this.isFieldMatch(f[attr], IdentityAutoFillConstants.MiddlenameFieldNames)
|
AutofillService.isFieldMatch(f[attr], IdentityAutoFillConstants.MiddlenameFieldNames)
|
||||||
) {
|
) {
|
||||||
fillFields.middleName = f;
|
fillFields.middleName = f;
|
||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!fillFields.lastName &&
|
!fillFields.lastName &&
|
||||||
this.isFieldMatch(f[attr], IdentityAutoFillConstants.LastnameFieldNames)
|
AutofillService.isFieldMatch(f[attr], IdentityAutoFillConstants.LastnameFieldNames)
|
||||||
) {
|
) {
|
||||||
fillFields.lastName = f;
|
fillFields.lastName = f;
|
||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!fillFields.title &&
|
!fillFields.title &&
|
||||||
this.isFieldMatch(f[attr], IdentityAutoFillConstants.TitleFieldNames)
|
AutofillService.isFieldMatch(f[attr], IdentityAutoFillConstants.TitleFieldNames)
|
||||||
) {
|
) {
|
||||||
fillFields.title = f;
|
fillFields.title = f;
|
||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!fillFields.email &&
|
!fillFields.email &&
|
||||||
this.isFieldMatch(f[attr], IdentityAutoFillConstants.EmailFieldNames)
|
AutofillService.isFieldMatch(f[attr], IdentityAutoFillConstants.EmailFieldNames)
|
||||||
) {
|
) {
|
||||||
fillFields.email = f;
|
fillFields.email = f;
|
||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!fillFields.address &&
|
!fillFields.address &&
|
||||||
this.isFieldMatch(
|
AutofillService.isFieldMatch(
|
||||||
f[attr],
|
f[attr],
|
||||||
IdentityAutoFillConstants.AddressFieldNames,
|
IdentityAutoFillConstants.AddressFieldNames,
|
||||||
IdentityAutoFillConstants.AddressFieldNameValues
|
IdentityAutoFillConstants.AddressFieldNameValues
|
||||||
@@ -814,61 +845,61 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!fillFields.address1 &&
|
!fillFields.address1 &&
|
||||||
this.isFieldMatch(f[attr], IdentityAutoFillConstants.Address1FieldNames)
|
AutofillService.isFieldMatch(f[attr], IdentityAutoFillConstants.Address1FieldNames)
|
||||||
) {
|
) {
|
||||||
fillFields.address1 = f;
|
fillFields.address1 = f;
|
||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!fillFields.address2 &&
|
!fillFields.address2 &&
|
||||||
this.isFieldMatch(f[attr], IdentityAutoFillConstants.Address2FieldNames)
|
AutofillService.isFieldMatch(f[attr], IdentityAutoFillConstants.Address2FieldNames)
|
||||||
) {
|
) {
|
||||||
fillFields.address2 = f;
|
fillFields.address2 = f;
|
||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!fillFields.address3 &&
|
!fillFields.address3 &&
|
||||||
this.isFieldMatch(f[attr], IdentityAutoFillConstants.Address3FieldNames)
|
AutofillService.isFieldMatch(f[attr], IdentityAutoFillConstants.Address3FieldNames)
|
||||||
) {
|
) {
|
||||||
fillFields.address3 = f;
|
fillFields.address3 = f;
|
||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!fillFields.postalCode &&
|
!fillFields.postalCode &&
|
||||||
this.isFieldMatch(f[attr], IdentityAutoFillConstants.PostalCodeFieldNames)
|
AutofillService.isFieldMatch(f[attr], IdentityAutoFillConstants.PostalCodeFieldNames)
|
||||||
) {
|
) {
|
||||||
fillFields.postalCode = f;
|
fillFields.postalCode = f;
|
||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!fillFields.city &&
|
!fillFields.city &&
|
||||||
this.isFieldMatch(f[attr], IdentityAutoFillConstants.CityFieldNames)
|
AutofillService.isFieldMatch(f[attr], IdentityAutoFillConstants.CityFieldNames)
|
||||||
) {
|
) {
|
||||||
fillFields.city = f;
|
fillFields.city = f;
|
||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!fillFields.state &&
|
!fillFields.state &&
|
||||||
this.isFieldMatch(f[attr], IdentityAutoFillConstants.StateFieldNames)
|
AutofillService.isFieldMatch(f[attr], IdentityAutoFillConstants.StateFieldNames)
|
||||||
) {
|
) {
|
||||||
fillFields.state = f;
|
fillFields.state = f;
|
||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!fillFields.country &&
|
!fillFields.country &&
|
||||||
this.isFieldMatch(f[attr], IdentityAutoFillConstants.CountryFieldNames)
|
AutofillService.isFieldMatch(f[attr], IdentityAutoFillConstants.CountryFieldNames)
|
||||||
) {
|
) {
|
||||||
fillFields.country = f;
|
fillFields.country = f;
|
||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!fillFields.phone &&
|
!fillFields.phone &&
|
||||||
this.isFieldMatch(f[attr], IdentityAutoFillConstants.PhoneFieldNames)
|
AutofillService.isFieldMatch(f[attr], IdentityAutoFillConstants.PhoneFieldNames)
|
||||||
) {
|
) {
|
||||||
fillFields.phone = f;
|
fillFields.phone = f;
|
||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!fillFields.username &&
|
!fillFields.username &&
|
||||||
this.isFieldMatch(f[attr], IdentityAutoFillConstants.UserNameFieldNames)
|
AutofillService.isFieldMatch(f[attr], IdentityAutoFillConstants.UserNameFieldNames)
|
||||||
) {
|
) {
|
||||||
fillFields.username = f;
|
fillFields.username = f;
|
||||||
break;
|
break;
|
||||||
} else if (
|
} else if (
|
||||||
!fillFields.company &&
|
!fillFields.company &&
|
||||||
this.isFieldMatch(f[attr], IdentityAutoFillConstants.CompanyFieldNames)
|
AutofillService.isFieldMatch(f[attr], IdentityAutoFillConstants.CompanyFieldNames)
|
||||||
) {
|
) {
|
||||||
fillFields.company = f;
|
fillFields.company = f;
|
||||||
break;
|
break;
|
||||||
@@ -923,16 +954,16 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
|
|
||||||
if (fillFields.name && (identity.firstName || identity.lastName)) {
|
if (fillFields.name && (identity.firstName || identity.lastName)) {
|
||||||
let fullName = "";
|
let fullName = "";
|
||||||
if (this.hasValue(identity.firstName)) {
|
if (AutofillService.hasValue(identity.firstName)) {
|
||||||
fullName = identity.firstName;
|
fullName = identity.firstName;
|
||||||
}
|
}
|
||||||
if (this.hasValue(identity.middleName)) {
|
if (AutofillService.hasValue(identity.middleName)) {
|
||||||
if (fullName !== "") {
|
if (fullName !== "") {
|
||||||
fullName += " ";
|
fullName += " ";
|
||||||
}
|
}
|
||||||
fullName += identity.middleName;
|
fullName += identity.middleName;
|
||||||
}
|
}
|
||||||
if (this.hasValue(identity.lastName)) {
|
if (AutofillService.hasValue(identity.lastName)) {
|
||||||
if (fullName !== "") {
|
if (fullName !== "") {
|
||||||
fullName += " ";
|
fullName += " ";
|
||||||
}
|
}
|
||||||
@@ -942,18 +973,18 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
this.makeScriptActionWithValue(fillScript, fullName, fillFields.name, filledFields);
|
this.makeScriptActionWithValue(fillScript, fullName, fillFields.name, filledFields);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fillFields.address && this.hasValue(identity.address1)) {
|
if (fillFields.address && AutofillService.hasValue(identity.address1)) {
|
||||||
let address = "";
|
let address = "";
|
||||||
if (this.hasValue(identity.address1)) {
|
if (AutofillService.hasValue(identity.address1)) {
|
||||||
address = identity.address1;
|
address = identity.address1;
|
||||||
}
|
}
|
||||||
if (this.hasValue(identity.address2)) {
|
if (AutofillService.hasValue(identity.address2)) {
|
||||||
if (address !== "") {
|
if (address !== "") {
|
||||||
address += ", ";
|
address += ", ";
|
||||||
}
|
}
|
||||||
address += identity.address2;
|
address += identity.address2;
|
||||||
}
|
}
|
||||||
if (this.hasValue(identity.address3)) {
|
if (AutofillService.hasValue(identity.address3)) {
|
||||||
if (address !== "") {
|
if (address !== "") {
|
||||||
address += ", ";
|
address += ", ";
|
||||||
}
|
}
|
||||||
@@ -970,7 +1001,11 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
return excludedTypes.indexOf(type) > -1;
|
return excludedTypes.indexOf(type) > -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private isFieldMatch(value: string, options: string[], containsOptions?: string[]): boolean {
|
private static isFieldMatch(
|
||||||
|
value: string,
|
||||||
|
options: string[],
|
||||||
|
containsOptions?: string[]
|
||||||
|
): boolean {
|
||||||
value = value
|
value = value
|
||||||
.trim()
|
.trim()
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
@@ -1011,12 +1046,15 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
filledFields: { [id: string]: AutofillField }
|
filledFields: { [id: string]: AutofillField }
|
||||||
) {
|
) {
|
||||||
let doFill = false;
|
let doFill = false;
|
||||||
if (this.hasValue(dataValue) && field) {
|
if (AutofillService.hasValue(dataValue) && field) {
|
||||||
if (field.type === "select-one" && field.selectInfo && field.selectInfo.options) {
|
if (field.type === "select-one" && field.selectInfo && field.selectInfo.options) {
|
||||||
for (let i = 0; i < field.selectInfo.options.length; i++) {
|
for (let i = 0; i < field.selectInfo.options.length; i++) {
|
||||||
const option = field.selectInfo.options[i];
|
const option = field.selectInfo.options[i];
|
||||||
for (let j = 0; j < option.length; j++) {
|
for (let j = 0; j < option.length; j++) {
|
||||||
if (this.hasValue(option[j]) && option[j].toLowerCase() === dataValue.toLowerCase()) {
|
if (
|
||||||
|
AutofillService.hasValue(option[j]) &&
|
||||||
|
option[j].toLowerCase() === dataValue.toLowerCase()
|
||||||
|
) {
|
||||||
doFill = true;
|
doFill = true;
|
||||||
if (option.length > 1) {
|
if (option.length > 1) {
|
||||||
dataValue = option[1];
|
dataValue = option[1];
|
||||||
@@ -1036,11 +1074,11 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
|
|
||||||
if (doFill) {
|
if (doFill) {
|
||||||
filledFields[field.opid] = field;
|
filledFields[field.opid] = field;
|
||||||
this.fillByOpid(fillScript, field, dataValue);
|
AutofillService.fillByOpid(fillScript, field, dataValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadPasswordFields(
|
static loadPasswordFields(
|
||||||
pageDetails: AutofillPageDetails,
|
pageDetails: AutofillPageDetails,
|
||||||
canBeHidden: boolean,
|
canBeHidden: boolean,
|
||||||
canBeReadOnly: boolean,
|
canBeReadOnly: boolean,
|
||||||
@@ -1049,7 +1087,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
) {
|
) {
|
||||||
const arr: AutofillField[] = [];
|
const arr: AutofillField[] = [];
|
||||||
pageDetails.fields.forEach((f) => {
|
pageDetails.fields.forEach((f) => {
|
||||||
if (this.forCustomFieldsOnly(f)) {
|
if (AutofillService.forCustomFieldsOnly(f)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1111,7 +1149,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
let usernameField: AutofillField = null;
|
let usernameField: AutofillField = null;
|
||||||
for (let i = 0; i < pageDetails.fields.length; i++) {
|
for (let i = 0; i < pageDetails.fields.length; i++) {
|
||||||
const f = pageDetails.fields[i];
|
const f = pageDetails.fields[i];
|
||||||
if (this.forCustomFieldsOnly(f)) {
|
if (AutofillService.forCustomFieldsOnly(f)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1195,7 +1233,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
|
|
||||||
private fieldPropertyIsMatch(field: any, property: string, name: string): boolean {
|
private fieldPropertyIsMatch(field: any, property: string, name: string): boolean {
|
||||||
let fieldVal = field[property] as string;
|
let fieldVal = field[property] as string;
|
||||||
if (!this.hasValue(fieldVal)) {
|
if (!AutofillService.hasValue(fieldVal)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1227,33 +1265,45 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
return fieldVal.toLowerCase() === name;
|
return fieldVal.toLowerCase() === name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private fieldIsFuzzyMatch(field: AutofillField, names: string[]): boolean {
|
static fieldIsFuzzyMatch(field: AutofillField, names: string[]): boolean {
|
||||||
if (this.hasValue(field.htmlID) && this.fuzzyMatch(names, field.htmlID)) {
|
if (AutofillService.hasValue(field.htmlID) && this.fuzzyMatch(names, field.htmlID)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (this.hasValue(field.htmlName) && this.fuzzyMatch(names, field.htmlName)) {
|
if (AutofillService.hasValue(field.htmlName) && this.fuzzyMatch(names, field.htmlName)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (this.hasValue(field["label-tag"]) && this.fuzzyMatch(names, field["label-tag"])) {
|
if (
|
||||||
|
AutofillService.hasValue(field["label-tag"]) &&
|
||||||
|
this.fuzzyMatch(names, field["label-tag"])
|
||||||
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (this.hasValue(field.placeholder) && this.fuzzyMatch(names, field.placeholder)) {
|
if (AutofillService.hasValue(field.placeholder) && this.fuzzyMatch(names, field.placeholder)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (this.hasValue(field["label-left"]) && this.fuzzyMatch(names, field["label-left"])) {
|
if (
|
||||||
|
AutofillService.hasValue(field["label-left"]) &&
|
||||||
|
this.fuzzyMatch(names, field["label-left"])
|
||||||
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (this.hasValue(field["label-top"]) && this.fuzzyMatch(names, field["label-top"])) {
|
if (
|
||||||
|
AutofillService.hasValue(field["label-top"]) &&
|
||||||
|
this.fuzzyMatch(names, field["label-top"])
|
||||||
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (this.hasValue(field["label-aria"]) && this.fuzzyMatch(names, field["label-aria"])) {
|
if (
|
||||||
|
AutofillService.hasValue(field["label-aria"]) &&
|
||||||
|
this.fuzzyMatch(names, field["label-aria"])
|
||||||
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private fuzzyMatch(options: string[], value: string): boolean {
|
private static fuzzyMatch(options: string[], value: string): boolean {
|
||||||
if (options == null || options.length === 0 || value == null || value === "") {
|
if (options == null || options.length === 0 || value == null || value === "") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1272,11 +1322,11 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private hasValue(str: string): boolean {
|
static hasValue(str: string): boolean {
|
||||||
return str && str !== "";
|
return str && str !== "";
|
||||||
}
|
}
|
||||||
|
|
||||||
private setFillScriptForFocus(
|
static setFillScriptForFocus(
|
||||||
filledFields: { [id: string]: AutofillField },
|
filledFields: { [id: string]: AutofillField },
|
||||||
fillScript: AutofillScript
|
fillScript: AutofillScript
|
||||||
): AutofillScript {
|
): AutofillScript {
|
||||||
@@ -1304,7 +1354,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
return fillScript;
|
return fillScript;
|
||||||
}
|
}
|
||||||
|
|
||||||
private fillByOpid(fillScript: AutofillScript, field: AutofillField, value: string): void {
|
static fillByOpid(fillScript: AutofillScript, field: AutofillField, value: string): void {
|
||||||
if (field.maxLength && value && value.length > field.maxLength) {
|
if (field.maxLength && value && value.length > field.maxLength) {
|
||||||
value = value.substr(0, value.length);
|
value = value.substr(0, value.length);
|
||||||
}
|
}
|
||||||
@@ -1315,7 +1365,7 @@ export default class AutofillService implements AutofillServiceInterface {
|
|||||||
fillScript.script.push(["fill_by_opid", field.opid, value]);
|
fillScript.script.push(["fill_by_opid", field.opid, value]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private forCustomFieldsOnly(field: AutofillField): boolean {
|
static forCustomFieldsOnly(field: AutofillField): boolean {
|
||||||
return field.tagName === "span";
|
return field.tagName === "span";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import AbstractChromeStorageService from "./abstractChromeStorageApi.service";
|
import AbstractChromeStorageService from "./abstractChromeStorageApi.service";
|
||||||
|
|
||||||
export default class BrowserLocalStorageService extends AbstractChromeStorageService {
|
export default class BrowserLocalStorageService extends AbstractChromeStorageService {
|
||||||
protected chromeStorageApi: any = chrome.storage.local;
|
protected chromeStorageApi = chrome.storage.local;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import AbstractChromeStorageService from "./abstractChromeStorageApi.service";
|
import AbstractChromeStorageService from "./abstractChromeStorageApi.service";
|
||||||
|
|
||||||
export default class BrowserMemoryStorageService extends AbstractChromeStorageService {
|
export default class BrowserMemoryStorageService extends AbstractChromeStorageService {
|
||||||
protected chromeStorageApi: any = (chrome.storage as any).session;
|
protected chromeStorageApi = chrome.storage.session;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,13 +176,6 @@ const config = {
|
|||||||
return chunk.name === "popup/main";
|
return chunk.name === "popup/main";
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
commons2: {
|
|
||||||
test: /[\\/]node_modules[\\/]/,
|
|
||||||
name: "vendor",
|
|
||||||
chunks: (chunk) => {
|
|
||||||
return chunk.name === "background";
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -209,4 +202,16 @@ const config = {
|
|||||||
plugins: plugins,
|
plugins: plugins,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (manifestVersion == 2) {
|
||||||
|
// We can't use this in manifest v3
|
||||||
|
// Ideally we understand why this breaks it and we don't have to do this
|
||||||
|
config.optimization.splitChunks.cacheGroups.commons2 = {
|
||||||
|
test: /[\\/]node_modules[\\/]/,
|
||||||
|
name: "vendor",
|
||||||
|
chunks: (chunk) => {
|
||||||
|
return chunk.name === "background";
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = config;
|
module.exports = config;
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ import { SyncService } from "@bitwarden/common/services/sync.service";
|
|||||||
import { TokenService } from "@bitwarden/common/services/token.service";
|
import { TokenService } from "@bitwarden/common/services/token.service";
|
||||||
import { TotpService } from "@bitwarden/common/services/totp.service";
|
import { TotpService } from "@bitwarden/common/services/totp.service";
|
||||||
import { TwoFactorService } from "@bitwarden/common/services/twoFactor.service";
|
import { TwoFactorService } from "@bitwarden/common/services/twoFactor.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/services/userVerification.service";
|
import { UserVerificationApiService } from "@bitwarden/common/services/userVerification/userVerification-api.service";
|
||||||
|
import { UserVerificationService } from "@bitwarden/common/services/userVerification/userVerification.service";
|
||||||
import { VaultTimeoutService } from "@bitwarden/common/services/vaultTimeout.service";
|
import { VaultTimeoutService } from "@bitwarden/common/services/vaultTimeout.service";
|
||||||
import { CliPlatformUtilsService } from "@bitwarden/node/cli/services/cliPlatformUtils.service";
|
import { CliPlatformUtilsService } from "@bitwarden/node/cli/services/cliPlatformUtils.service";
|
||||||
import { ConsoleLogService } from "@bitwarden/node/cli/services/consoleLog.service";
|
import { ConsoleLogService } from "@bitwarden/node/cli/services/consoleLog.service";
|
||||||
@@ -106,6 +107,7 @@ export class Main {
|
|||||||
twoFactorService: TwoFactorService;
|
twoFactorService: TwoFactorService;
|
||||||
broadcasterService: BroadcasterService;
|
broadcasterService: BroadcasterService;
|
||||||
folderApiService: FolderApiService;
|
folderApiService: FolderApiService;
|
||||||
|
userVerificationApiService: UserVerificationApiService;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
let p = null;
|
let p = null;
|
||||||
@@ -330,10 +332,13 @@ export class Main {
|
|||||||
this.program = new Program(this);
|
this.program = new Program(this);
|
||||||
this.vaultProgram = new VaultProgram(this);
|
this.vaultProgram = new VaultProgram(this);
|
||||||
this.sendProgram = new SendProgram(this);
|
this.sendProgram = new SendProgram(this);
|
||||||
|
|
||||||
|
this.userVerificationApiService = new UserVerificationApiService(this.apiService);
|
||||||
|
|
||||||
this.userVerificationService = new UserVerificationService(
|
this.userVerificationService = new UserVerificationService(
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.i18nService,
|
this.i18nService,
|
||||||
this.apiService
|
this.userVerificationApiService
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Component, NgZone, OnDestroy } from "@angular/core";
|
import { Component, NgZone } from "@angular/core";
|
||||||
import { ActivatedRoute, Router } from "@angular/router";
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
import { ipcRenderer } from "electron";
|
import { ipcRenderer } from "electron";
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ const BroadcasterSubscriptionId = "LockComponent";
|
|||||||
selector: "app-lock",
|
selector: "app-lock",
|
||||||
templateUrl: "lock.component.html",
|
templateUrl: "lock.component.html",
|
||||||
})
|
})
|
||||||
export class LockComponent extends BaseLockComponent implements OnDestroy {
|
export class LockComponent extends BaseLockComponent {
|
||||||
private deferFocus: boolean = null;
|
private deferFocus: boolean = null;
|
||||||
authenicatedUrl = "vault";
|
authenicatedUrl = "vault";
|
||||||
unAuthenicatedUrl = "update-temp-password";
|
unAuthenicatedUrl = "update-temp-password";
|
||||||
@@ -103,6 +103,7 @@ export class LockComponent extends BaseLockComponent implements OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
super.ngOnDestroy();
|
||||||
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
|
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
NgZone,
|
NgZone,
|
||||||
|
OnDestroy,
|
||||||
OnInit,
|
OnInit,
|
||||||
SecurityContext,
|
SecurityContext,
|
||||||
Type,
|
Type,
|
||||||
@@ -77,7 +78,7 @@ const systemTimeoutOptions = {
|
|||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
})
|
})
|
||||||
export class AppComponent implements OnInit {
|
export class AppComponent implements OnInit, OnDestroy {
|
||||||
@ViewChild("settings", { read: ViewContainerRef, static: true }) settingsRef: ViewContainerRef;
|
@ViewChild("settings", { read: ViewContainerRef, static: true }) settingsRef: ViewContainerRef;
|
||||||
@ViewChild("premium", { read: ViewContainerRef, static: true }) premiumRef: ViewContainerRef;
|
@ViewChild("premium", { read: ViewContainerRef, static: true }) premiumRef: ViewContainerRef;
|
||||||
@ViewChild("passwordHistory", { read: ViewContainerRef, static: true })
|
@ViewChild("passwordHistory", { read: ViewContainerRef, static: true })
|
||||||
@@ -129,7 +130,7 @@ export class AppComponent implements OnInit {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.stateService.activeAccount.pipe(takeUntil(this.destroy$)).subscribe((userId) => {
|
this.stateService.activeAccount$.pipe(takeUntil(this.destroy$)).subscribe((userId) => {
|
||||||
this.activeUserId = userId;
|
this.activeUserId = userId;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -8,15 +8,16 @@ export type SearchBarState = {
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SearchBarService {
|
export class SearchBarService {
|
||||||
searchText = new BehaviorSubject<string>(null);
|
private searchTextSubject = new BehaviorSubject<string>(null);
|
||||||
|
searchText$ = this.searchTextSubject.asObservable();
|
||||||
|
|
||||||
private _state = {
|
private _state = {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
placeholderText: "",
|
placeholderText: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
// tslint:disable-next-line:member-ordering
|
private stateSubject = new BehaviorSubject<SearchBarState>(this._state);
|
||||||
state = new BehaviorSubject<SearchBarState>(this._state);
|
state$ = this.stateSubject.asObservable();
|
||||||
|
|
||||||
setEnabled(enabled: boolean) {
|
setEnabled(enabled: boolean) {
|
||||||
this._state.enabled = enabled;
|
this._state.enabled = enabled;
|
||||||
@@ -29,10 +30,10 @@ export class SearchBarService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setSearchText(value: string) {
|
setSearchText(value: string) {
|
||||||
this.searchText.next(value);
|
this.searchTextSubject.next(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateState() {
|
private updateState() {
|
||||||
this.state.next(this._state);
|
this.stateSubject.next(this._state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||||
import { UntypedFormControl } from "@angular/forms";
|
import { UntypedFormControl } from "@angular/forms";
|
||||||
|
import { Subscription } from "rxjs";
|
||||||
|
|
||||||
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
||||||
|
|
||||||
@@ -13,8 +14,10 @@ export class SearchComponent implements OnInit, OnDestroy {
|
|||||||
state: SearchBarState;
|
state: SearchBarState;
|
||||||
searchText: UntypedFormControl = new UntypedFormControl(null);
|
searchText: UntypedFormControl = new UntypedFormControl(null);
|
||||||
|
|
||||||
|
private activeAccountSubscription: Subscription;
|
||||||
|
|
||||||
constructor(private searchBarService: SearchBarService, private stateService: StateService) {
|
constructor(private searchBarService: SearchBarService, private stateService: StateService) {
|
||||||
this.searchBarService.state.subscribe((state) => {
|
this.searchBarService.state$.subscribe((state) => {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -24,13 +27,13 @@ export class SearchComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.stateService.activeAccount.subscribe((value) => {
|
this.activeAccountSubscription = this.stateService.activeAccount$.subscribe((value) => {
|
||||||
this.searchBarService.setSearchText("");
|
this.searchBarService.setSearchText("");
|
||||||
this.searchText.patchValue("");
|
this.searchText.patchValue("");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.stateService.activeAccount.unsubscribe();
|
this.activeAccountSubscription.unsubscribe();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export class SendComponent extends BaseSendComponent implements OnInit, OnDestro
|
|||||||
policyService,
|
policyService,
|
||||||
logService
|
logService
|
||||||
);
|
);
|
||||||
this.searchBarService.searchText.subscribe((searchText) => {
|
this.searchBarService.searchText$.subscribe((searchText) => {
|
||||||
this.searchText = searchText;
|
this.searchText = searchText;
|
||||||
this.searchTextChanged();
|
this.searchTextChanged();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export class CiphersComponent extends BaseCiphersComponent {
|
|||||||
constructor(searchService: SearchService, searchBarService: SearchBarService) {
|
constructor(searchService: SearchService, searchBarService: SearchBarService) {
|
||||||
super(searchService);
|
super(searchService);
|
||||||
|
|
||||||
searchBarService.searchText.subscribe((searchText) => {
|
searchBarService.searchText$.subscribe((searchText) => {
|
||||||
this.searchText = searchText;
|
this.searchText = searchText;
|
||||||
this.search(200);
|
this.search(200);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
|||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
|
|
||||||
const BroadcasterSubscriptionId = "ExportComponent";
|
const BroadcasterSubscriptionId = "ExportComponent";
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,7 @@
|
|||||||
<div
|
<div
|
||||||
class="box-content-row box-content-row-flex totp"
|
class="box-content-row box-content-row-flex totp"
|
||||||
[ngClass]="{ low: totpLow }"
|
[ngClass]="{ low: totpLow }"
|
||||||
*ngIf="cipher.login.totp && totpCode"
|
*ngIf="cipher.login.totp && totpCode && canAccessPremium"
|
||||||
>
|
>
|
||||||
<div class="row-main">
|
<div class="row-main">
|
||||||
<span
|
<span
|
||||||
@@ -138,6 +138,19 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
class="box-content-row box-content-row-flex totp"
|
||||||
|
*ngIf="cipher.login.totp && !canAccessPremium"
|
||||||
|
>
|
||||||
|
<div class="row-main">
|
||||||
|
<span class="row-label">{{ "verificationCodeTotp" | i18n }}</span>
|
||||||
|
<span class="row-label">
|
||||||
|
<a [routerLink]="" (click)="showGetPremium()"
|
||||||
|
>{{ "premiumSubcriptionRequired" | i18n }}
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Card -->
|
<!-- Card -->
|
||||||
<div *ngIf="cipher.card">
|
<div *ngIf="cipher.card">
|
||||||
|
|||||||
@@ -115,4 +115,10 @@ export class ViewComponent extends BaseViewComponent implements OnChanges {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showGetPremium() {
|
||||||
|
if (!this.canAccessPremium) {
|
||||||
|
this.messagingService.send("premiumRequired");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1979,6 +1979,9 @@
|
|||||||
"apiKey": {
|
"apiKey": {
|
||||||
"message": "API Key"
|
"message": "API Key"
|
||||||
},
|
},
|
||||||
|
"premiumSubcriptionRequired": {
|
||||||
|
"message": "Premium subscription required"
|
||||||
|
},
|
||||||
"organizationIsDisabled": {
|
"organizationIsDisabled": {
|
||||||
"message": "Organization is disabled."
|
"message": "Organization is disabled."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwo
|
|||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
|
||||||
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-update-password",
|
selector: "app-update-password",
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
[password]="masterPassword"
|
[password]="masterPassword"
|
||||||
[email]="email"
|
[email]="email"
|
||||||
[showText]="true"
|
[showText]="true"
|
||||||
|
(passwordStrengthResult)="getStrengthResult($event)"
|
||||||
>
|
>
|
||||||
</app-password-strength>
|
</app-password-strength>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ export class AppComponent implements OnDestroy, OnInit {
|
|||||||
const premiumConfirmed = await this.platformUtilsService.showDialog(
|
const premiumConfirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t("premiumRequiredDesc"),
|
this.i18nService.t("premiumRequiredDesc"),
|
||||||
this.i18nService.t("premiumRequired"),
|
this.i18nService.t("premiumRequired"),
|
||||||
this.i18nService.t("learnMore"),
|
this.i18nService.t("upgrade"),
|
||||||
this.i18nService.t("cancel")
|
this.i18nService.t("cancel")
|
||||||
);
|
);
|
||||||
if (premiumConfirmed) {
|
if (premiumConfirmed) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Component } from "@angular/core";
|
|||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
import { OrganizationApiKeyType } from "@bitwarden/common/enums/organizationApiKeyType";
|
import { OrganizationApiKeyType } from "@bitwarden/common/enums/organizationApiKeyType";
|
||||||
import { OrganizationApiKeyRequest } from "@bitwarden/common/models/request/organizationApiKeyRequest";
|
import { OrganizationApiKeyRequest } from "@bitwarden/common/models/request/organizationApiKeyRequest";
|
||||||
import { ApiKeyResponse } from "@bitwarden/common/models/response/apiKeyResponse";
|
import { ApiKeyResponse } from "@bitwarden/common/models/response/apiKeyResponse";
|
||||||
|
|||||||
@@ -77,7 +77,12 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<app-password-strength [password]="newPassword" [email]="email" [showText]="true">
|
<app-password-strength
|
||||||
|
[password]="newPassword"
|
||||||
|
[email]="email"
|
||||||
|
[showText]="true"
|
||||||
|
(passwordStrengthResult)="getStrengthResult($event)"
|
||||||
|
>
|
||||||
</app-password-strength>
|
</app-password-strength>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from "@angular/core";
|
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from "@angular/core";
|
||||||
|
import zxcvbn from "zxcvbn";
|
||||||
|
|
||||||
import { PasswordStrengthComponent } from "@bitwarden/angular/shared/components/password-strength/password-strength.component";
|
import { PasswordStrengthComponent } from "@bitwarden/angular/shared/components/password-strength/password-strength.component";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
@@ -28,7 +29,7 @@ export class ResetPasswordComponent implements OnInit {
|
|||||||
enforcedPolicyOptions: MasterPasswordPolicyOptions;
|
enforcedPolicyOptions: MasterPasswordPolicyOptions;
|
||||||
newPassword: string = null;
|
newPassword: string = null;
|
||||||
showPassword = false;
|
showPassword = false;
|
||||||
masterPasswordScore: number;
|
passwordStrengthResult: zxcvbn.ZXCVBNResult;
|
||||||
formPromise: Promise<any>;
|
formPromise: Promise<any>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -97,7 +98,7 @@ export class ResetPasswordComponent implements OnInit {
|
|||||||
if (
|
if (
|
||||||
this.enforcedPolicyOptions != null &&
|
this.enforcedPolicyOptions != null &&
|
||||||
!this.policyService.evaluateMasterPassword(
|
!this.policyService.evaluateMasterPassword(
|
||||||
this.masterPasswordScore,
|
this.passwordStrengthResult.score,
|
||||||
this.newPassword,
|
this.newPassword,
|
||||||
this.enforcedPolicyOptions
|
this.enforcedPolicyOptions
|
||||||
)
|
)
|
||||||
@@ -110,7 +111,7 @@ export class ResetPasswordComponent implements OnInit {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.masterPasswordScore < 3) {
|
if (this.passwordStrengthResult.score < 3) {
|
||||||
const result = await this.platformUtilsService.showDialog(
|
const result = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t("weakMasterPasswordDesc"),
|
this.i18nService.t("weakMasterPasswordDesc"),
|
||||||
this.i18nService.t("weakMasterPassword"),
|
this.i18nService.t("weakMasterPassword"),
|
||||||
@@ -184,4 +185,8 @@ export class ResetPasswordComponent implements OnInit {
|
|||||||
this.logService.error(e);
|
this.logService.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getStrengthResult(result: zxcvbn.ZXCVBNResult) {
|
||||||
|
this.passwordStrengthResult = result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
|||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { OrganizationService } from "@bitwarden/common/abstractions/organization.service";
|
import { OrganizationService } from "@bitwarden/common/abstractions/organization.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
import { CipherType } from "@bitwarden/common/enums/cipherType";
|
import { CipherType } from "@bitwarden/common/enums/cipherType";
|
||||||
import { Utils } from "@bitwarden/common/misc/utils";
|
import { Utils } from "@bitwarden/common/misc/utils";
|
||||||
import { CipherView } from "@bitwarden/common/models/view/cipherView";
|
import { CipherView } from "@bitwarden/common/models/view/cipherView";
|
||||||
@@ -53,10 +53,10 @@ export class DeleteOrganizationComponent implements OnInit {
|
|||||||
deleteOrganizationRequestType: "InvalidFamiliesForEnterprise" | "RegularDelete" = "RegularDelete";
|
deleteOrganizationRequestType: "InvalidFamiliesForEnterprise" | "RegularDelete" = "RegularDelete";
|
||||||
organizationName: string;
|
organizationName: string;
|
||||||
organizationContentSummary: OrganizationContentSummary = new OrganizationContentSummary();
|
organizationContentSummary: OrganizationContentSummary = new OrganizationContentSummary();
|
||||||
@Output() onSuccess: EventEmitter<any> = new EventEmitter();
|
@Output() onSuccess: EventEmitter<unknown> = new EventEmitter();
|
||||||
|
|
||||||
masterPassword: Verification;
|
masterPassword: Verification;
|
||||||
formPromise: Promise<any>;
|
formPromise: Promise<unknown>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
|||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
import { EventType } from "@bitwarden/common/enums/eventType";
|
import { EventType } from "@bitwarden/common/enums/eventType";
|
||||||
|
|
||||||
import { ExportComponent } from "../../../tools/import-export/export.component";
|
import { ExportComponent } from "../../../tools/import-export/export.component";
|
||||||
@@ -66,7 +66,7 @@ export class OrganizationExportComponent extends ExportComponent {
|
|||||||
return super.getFileName("org");
|
return super.getFileName("org");
|
||||||
}
|
}
|
||||||
|
|
||||||
async collectEvent(): Promise<any> {
|
async collectEvent(): Promise<void> {
|
||||||
await this.eventService.collect(
|
await this.eventService.collect(
|
||||||
EventType.Organization_ClientExportedVault,
|
EventType.Organization_ClientExportedVault,
|
||||||
null,
|
null,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
|||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { SyncService } from "@bitwarden/common/abstractions/sync.service";
|
import { SyncService } from "@bitwarden/common/abstractions/sync.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
import { Utils } from "@bitwarden/common/misc/utils";
|
import { Utils } from "@bitwarden/common/misc/utils";
|
||||||
import { Organization } from "@bitwarden/common/models/domain/organization";
|
import { Organization } from "@bitwarden/common/models/domain/organization";
|
||||||
import { OrganizationUserResetPasswordEnrollmentRequest } from "@bitwarden/common/models/request/organizationUserResetPasswordEnrollmentRequest";
|
import { OrganizationUserResetPasswordEnrollmentRequest } from "@bitwarden/common/models/request/organizationUserResetPasswordEnrollmentRequest";
|
||||||
@@ -22,7 +22,7 @@ export class EnrollMasterPasswordReset {
|
|||||||
organization: Organization;
|
organization: Organization;
|
||||||
|
|
||||||
verification: Verification;
|
verification: Verification;
|
||||||
formPromise: Promise<any>;
|
formPromise: Promise<void>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private userVerificationService: UserVerificationService,
|
private userVerificationService: UserVerificationService,
|
||||||
|
|||||||
@@ -189,6 +189,7 @@
|
|||||||
<span class="sr-only">{{ "loading" | i18n }}</span>
|
<span class="sr-only">{{ "loading" | i18n }}</span>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container *ngIf="loaded">
|
<ng-container *ngIf="loaded">
|
||||||
|
<img class="no-items-image" aria-hidden="true" />
|
||||||
<p>{{ "noSendsInList" | i18n }}</p>
|
<p>{{ "noSendsInList" | i18n }}</p>
|
||||||
<button (click)="addSend()" class="btn btn-outline-primary" [disabled]="disableSend">
|
<button (click)="addSend()" class="btn btn-outline-primary" [disabled]="disableSend">
|
||||||
<i class="bwi bwi-plus bwi-fw"></i>{{ "createSend" | i18n }}
|
<i class="bwi bwi-plus bwi-fw"></i>{{ "createSend" | i18n }}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
|
|
||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
import { SecretVerificationRequest } from "@bitwarden/common/models/request/secretVerificationRequest";
|
import { SecretVerificationRequest } from "@bitwarden/common/models/request/secretVerificationRequest";
|
||||||
import { ApiKeyResponse } from "@bitwarden/common/models/response/apiKeyResponse";
|
import { ApiKeyResponse } from "@bitwarden/common/models/response/apiKeyResponse";
|
||||||
import { Verification } from "@bitwarden/common/types/verification";
|
import { Verification } from "@bitwarden/common/types/verification";
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
|||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
|
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
import { Verification } from "@bitwarden/common/types/verification";
|
import { Verification } from "@bitwarden/common/types/verification";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -14,7 +14,7 @@ import { Verification } from "@bitwarden/common/types/verification";
|
|||||||
})
|
})
|
||||||
export class DeauthorizeSessionsComponent {
|
export class DeauthorizeSessionsComponent {
|
||||||
masterPassword: Verification;
|
masterPassword: Verification;
|
||||||
formPromise: Promise<any>;
|
formPromise: Promise<unknown>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
|||||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
import { Verification } from "@bitwarden/common/types/verification";
|
import { Verification } from "@bitwarden/common/types/verification";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -16,7 +16,7 @@ export class PurgeVaultComponent {
|
|||||||
@Input() organizationId?: string = null;
|
@Input() organizationId?: string = null;
|
||||||
|
|
||||||
masterPassword: Verification;
|
masterPassword: Verification;
|
||||||
formPromise: Promise<any>;
|
formPromise: Promise<unknown>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
|
|||||||
@@ -5,13 +5,28 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
|||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
import { TwoFactorProviderType } from "@bitwarden/common/enums/twoFactorProviderType";
|
import { TwoFactorProviderType } from "@bitwarden/common/enums/twoFactorProviderType";
|
||||||
import { UpdateTwoFactorAuthenticatorRequest } from "@bitwarden/common/models/request/updateTwoFactorAuthenticatorRequest";
|
import { UpdateTwoFactorAuthenticatorRequest } from "@bitwarden/common/models/request/updateTwoFactorAuthenticatorRequest";
|
||||||
import { TwoFactorAuthenticatorResponse } from "@bitwarden/common/models/response/twoFactorAuthenticatorResponse";
|
import { TwoFactorAuthenticatorResponse } from "@bitwarden/common/models/response/twoFactorAuthenticatorResponse";
|
||||||
|
import { AuthResponse } from "@bitwarden/common/types/authResponse";
|
||||||
|
|
||||||
import { TwoFactorBaseComponent } from "./two-factor-base.component";
|
import { TwoFactorBaseComponent } from "./two-factor-base.component";
|
||||||
|
|
||||||
|
// NOTE: There are additional options available but these are just the ones we are current using.
|
||||||
|
// See: https://github.com/neocotic/qrious#examples
|
||||||
|
interface QRiousOptions {
|
||||||
|
element: HTMLElement;
|
||||||
|
value: string;
|
||||||
|
size: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
QRious: new (options: QRiousOptions) => unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-two-factor-authenticator",
|
selector: "app-two-factor-authenticator",
|
||||||
templateUrl: "two-factor-authenticator.component.html",
|
templateUrl: "two-factor-authenticator.component.html",
|
||||||
@@ -23,7 +38,7 @@ export class TwoFactorAuthenticatorComponent
|
|||||||
type = TwoFactorProviderType.Authenticator;
|
type = TwoFactorProviderType.Authenticator;
|
||||||
key: string;
|
key: string;
|
||||||
token: string;
|
token: string;
|
||||||
formPromise: Promise<any>;
|
formPromise: Promise<TwoFactorAuthenticatorResponse>;
|
||||||
|
|
||||||
private qrScript: HTMLScriptElement;
|
private qrScript: HTMLScriptElement;
|
||||||
|
|
||||||
@@ -49,7 +64,7 @@ export class TwoFactorAuthenticatorComponent
|
|||||||
window.document.body.removeChild(this.qrScript);
|
window.document.body.removeChild(this.qrScript);
|
||||||
}
|
}
|
||||||
|
|
||||||
auth(authResponse: any) {
|
auth(authResponse: AuthResponse<TwoFactorAuthenticatorResponse>) {
|
||||||
super.auth(authResponse);
|
super.auth(authResponse);
|
||||||
return this.processResponse(authResponse.response);
|
return this.processResponse(authResponse.response);
|
||||||
}
|
}
|
||||||
@@ -80,7 +95,7 @@ export class TwoFactorAuthenticatorComponent
|
|||||||
this.key = response.key;
|
this.key = response.key;
|
||||||
const email = await this.stateService.getEmail();
|
const email = await this.stateService.getEmail();
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
new (window as any).QRious({
|
new window.QRious({
|
||||||
element: document.getElementById("qr"),
|
element: document.getElementById("qr"),
|
||||||
value:
|
value:
|
||||||
"otpauth://totp/Bitwarden:" +
|
"otpauth://totp/Bitwarden:" +
|
||||||
|
|||||||
@@ -4,11 +4,12 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
|||||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
import { TwoFactorProviderType } from "@bitwarden/common/enums/twoFactorProviderType";
|
import { TwoFactorProviderType } from "@bitwarden/common/enums/twoFactorProviderType";
|
||||||
import { VerificationType } from "@bitwarden/common/enums/verificationType";
|
import { VerificationType } from "@bitwarden/common/enums/verificationType";
|
||||||
import { SecretVerificationRequest } from "@bitwarden/common/models/request/secretVerificationRequest";
|
import { SecretVerificationRequest } from "@bitwarden/common/models/request/secretVerificationRequest";
|
||||||
import { TwoFactorProviderRequest } from "@bitwarden/common/models/request/twoFactorProviderRequest";
|
import { TwoFactorProviderRequest } from "@bitwarden/common/models/request/twoFactorProviderRequest";
|
||||||
|
import { AuthResponseBase } from "@bitwarden/common/types/authResponse";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export abstract class TwoFactorBaseComponent {
|
export abstract class TwoFactorBaseComponent {
|
||||||
@@ -31,7 +32,7 @@ export abstract class TwoFactorBaseComponent {
|
|||||||
protected userVerificationService: UserVerificationService
|
protected userVerificationService: UserVerificationService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
protected auth(authResponse: any) {
|
protected auth(authResponse: AuthResponseBase) {
|
||||||
this.hashedSecret = authResponse.secret;
|
this.hashedSecret = authResponse.secret;
|
||||||
this.verificationType = authResponse.verificationType;
|
this.verificationType = authResponse.verificationType;
|
||||||
this.authed = true;
|
this.authed = true;
|
||||||
@@ -46,7 +47,7 @@ export abstract class TwoFactorBaseComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async disable(promise: Promise<any>) {
|
protected async disable(promise: Promise<unknown>) {
|
||||||
const confirmed = await this.platformUtilsService.showDialog(
|
const confirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t("twoStepDisableDesc"),
|
this.i18nService.t("twoStepDisableDesc"),
|
||||||
this.i18nService.t("disable"),
|
this.i18nService.t("disable"),
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
|||||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
import { TwoFactorProviderType } from "@bitwarden/common/enums/twoFactorProviderType";
|
import { TwoFactorProviderType } from "@bitwarden/common/enums/twoFactorProviderType";
|
||||||
import { UpdateTwoFactorDuoRequest } from "@bitwarden/common/models/request/updateTwoFactorDuoRequest";
|
import { UpdateTwoFactorDuoRequest } from "@bitwarden/common/models/request/updateTwoFactorDuoRequest";
|
||||||
import { TwoFactorDuoResponse } from "@bitwarden/common/models/response/twoFactorDuoResponse";
|
import { TwoFactorDuoResponse } from "@bitwarden/common/models/response/twoFactorDuoResponse";
|
||||||
|
import { AuthResponse } from "@bitwarden/common/types/authResponse";
|
||||||
|
|
||||||
import { TwoFactorBaseComponent } from "./two-factor-base.component";
|
import { TwoFactorBaseComponent } from "./two-factor-base.component";
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ export class TwoFactorDuoComponent extends TwoFactorBaseComponent {
|
|||||||
ikey: string;
|
ikey: string;
|
||||||
skey: string;
|
skey: string;
|
||||||
host: string;
|
host: string;
|
||||||
formPromise: Promise<any>;
|
formPromise: Promise<TwoFactorDuoResponse>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
apiService: ApiService,
|
apiService: ApiService,
|
||||||
@@ -32,7 +33,7 @@ export class TwoFactorDuoComponent extends TwoFactorBaseComponent {
|
|||||||
super(apiService, i18nService, platformUtilsService, logService, userVerificationService);
|
super(apiService, i18nService, platformUtilsService, logService, userVerificationService);
|
||||||
}
|
}
|
||||||
|
|
||||||
auth(authResponse: any) {
|
auth(authResponse: AuthResponse<TwoFactorDuoResponse>) {
|
||||||
super.auth(authResponse);
|
super.auth(authResponse);
|
||||||
this.processResponse(authResponse.response);
|
this.processResponse(authResponse.response);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,12 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
|||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
import { TwoFactorProviderType } from "@bitwarden/common/enums/twoFactorProviderType";
|
import { TwoFactorProviderType } from "@bitwarden/common/enums/twoFactorProviderType";
|
||||||
import { TwoFactorEmailRequest } from "@bitwarden/common/models/request/twoFactorEmailRequest";
|
import { TwoFactorEmailRequest } from "@bitwarden/common/models/request/twoFactorEmailRequest";
|
||||||
import { UpdateTwoFactorEmailRequest } from "@bitwarden/common/models/request/updateTwoFactorEmailRequest";
|
import { UpdateTwoFactorEmailRequest } from "@bitwarden/common/models/request/updateTwoFactorEmailRequest";
|
||||||
import { TwoFactorEmailResponse } from "@bitwarden/common/models/response/twoFactorEmailResponse";
|
import { TwoFactorEmailResponse } from "@bitwarden/common/models/response/twoFactorEmailResponse";
|
||||||
|
import { AuthResponse } from "@bitwarden/common/types/authResponse";
|
||||||
|
|
||||||
import { TwoFactorBaseComponent } from "./two-factor-base.component";
|
import { TwoFactorBaseComponent } from "./two-factor-base.component";
|
||||||
|
|
||||||
@@ -22,8 +23,8 @@ export class TwoFactorEmailComponent extends TwoFactorBaseComponent {
|
|||||||
email: string;
|
email: string;
|
||||||
token: string;
|
token: string;
|
||||||
sentEmail: string;
|
sentEmail: string;
|
||||||
formPromise: Promise<any>;
|
formPromise: Promise<TwoFactorEmailResponse>;
|
||||||
emailPromise: Promise<any>;
|
emailPromise: Promise<unknown>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
apiService: ApiService,
|
apiService: ApiService,
|
||||||
@@ -36,7 +37,7 @@ export class TwoFactorEmailComponent extends TwoFactorBaseComponent {
|
|||||||
super(apiService, i18nService, platformUtilsService, logService, userVerificationService);
|
super(apiService, i18nService, platformUtilsService, logService, userVerificationService);
|
||||||
}
|
}
|
||||||
|
|
||||||
auth(authResponse: any) {
|
auth(authResponse: AuthResponse<TwoFactorEmailResponse>) {
|
||||||
super.auth(authResponse);
|
super.auth(authResponse);
|
||||||
return this.processResponse(authResponse.response);
|
return this.processResponse(authResponse.response);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,26 +2,14 @@ import { Component, EventEmitter, Input, Output } from "@angular/core";
|
|||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
import { TwoFactorProviderType } from "@bitwarden/common/enums/twoFactorProviderType";
|
import { TwoFactorProviderType } from "@bitwarden/common/enums/twoFactorProviderType";
|
||||||
import { VerificationType } from "@bitwarden/common/enums/verificationType";
|
import { VerificationType } from "@bitwarden/common/enums/verificationType";
|
||||||
import { SecretVerificationRequest } from "@bitwarden/common/models/request/secretVerificationRequest";
|
import { SecretVerificationRequest } from "@bitwarden/common/models/request/secretVerificationRequest";
|
||||||
import { TwoFactorAuthenticatorResponse } from "@bitwarden/common/models/response/twoFactorAuthenticatorResponse";
|
import { AuthResponse } from "@bitwarden/common/types/authResponse";
|
||||||
import { TwoFactorDuoResponse } from "@bitwarden/common/models/response/twoFactorDuoResponse";
|
import { TwoFactorResponse } from "@bitwarden/common/types/twoFactorResponse";
|
||||||
import { TwoFactorEmailResponse } from "@bitwarden/common/models/response/twoFactorEmailResponse";
|
|
||||||
import { TwoFactorRecoverResponse } from "@bitwarden/common/models/response/twoFactorRescoverResponse";
|
|
||||||
import { TwoFactorWebAuthnResponse } from "@bitwarden/common/models/response/twoFactorWebAuthnResponse";
|
|
||||||
import { TwoFactorYubiKeyResponse } from "@bitwarden/common/models/response/twoFactorYubiKeyResponse";
|
|
||||||
import { Verification } from "@bitwarden/common/types/verification";
|
import { Verification } from "@bitwarden/common/types/verification";
|
||||||
|
|
||||||
type TwoFactorResponse =
|
|
||||||
| TwoFactorRecoverResponse
|
|
||||||
| TwoFactorDuoResponse
|
|
||||||
| TwoFactorEmailResponse
|
|
||||||
| TwoFactorWebAuthnResponse
|
|
||||||
| TwoFactorAuthenticatorResponse
|
|
||||||
| TwoFactorYubiKeyResponse;
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-two-factor-verify",
|
selector: "app-two-factor-verify",
|
||||||
templateUrl: "two-factor-verify.component.html",
|
templateUrl: "two-factor-verify.component.html",
|
||||||
@@ -29,7 +17,7 @@ type TwoFactorResponse =
|
|||||||
export class TwoFactorVerifyComponent {
|
export class TwoFactorVerifyComponent {
|
||||||
@Input() type: TwoFactorProviderType;
|
@Input() type: TwoFactorProviderType;
|
||||||
@Input() organizationId: string;
|
@Input() organizationId: string;
|
||||||
@Output() onAuthed = new EventEmitter<any>();
|
@Output() onAuthed = new EventEmitter<AuthResponse<TwoFactorResponse>>();
|
||||||
|
|
||||||
secret: Verification;
|
secret: Verification;
|
||||||
formPromise: Promise<TwoFactorResponse>;
|
formPromise: Promise<TwoFactorResponse>;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
|||||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
import { TwoFactorProviderType } from "@bitwarden/common/enums/twoFactorProviderType";
|
import { TwoFactorProviderType } from "@bitwarden/common/enums/twoFactorProviderType";
|
||||||
import { SecretVerificationRequest } from "@bitwarden/common/models/request/secretVerificationRequest";
|
import { SecretVerificationRequest } from "@bitwarden/common/models/request/secretVerificationRequest";
|
||||||
import { UpdateTwoFactorWebAuthnDeleteRequest } from "@bitwarden/common/models/request/updateTwoFactorWebAuthnDeleteRequest";
|
import { UpdateTwoFactorWebAuthnDeleteRequest } from "@bitwarden/common/models/request/updateTwoFactorWebAuthnDeleteRequest";
|
||||||
@@ -13,9 +13,18 @@ import {
|
|||||||
ChallengeResponse,
|
ChallengeResponse,
|
||||||
TwoFactorWebAuthnResponse,
|
TwoFactorWebAuthnResponse,
|
||||||
} from "@bitwarden/common/models/response/twoFactorWebAuthnResponse";
|
} from "@bitwarden/common/models/response/twoFactorWebAuthnResponse";
|
||||||
|
import { AuthResponse } from "@bitwarden/common/types/authResponse";
|
||||||
|
|
||||||
import { TwoFactorBaseComponent } from "./two-factor-base.component";
|
import { TwoFactorBaseComponent } from "./two-factor-base.component";
|
||||||
|
|
||||||
|
interface Key {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
configured: boolean;
|
||||||
|
migrated?: boolean;
|
||||||
|
removePromise: Promise<TwoFactorWebAuthnResponse> | null;
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-two-factor-webauthn",
|
selector: "app-two-factor-webauthn",
|
||||||
templateUrl: "two-factor-webauthn.component.html",
|
templateUrl: "two-factor-webauthn.component.html",
|
||||||
@@ -23,14 +32,14 @@ import { TwoFactorBaseComponent } from "./two-factor-base.component";
|
|||||||
export class TwoFactorWebAuthnComponent extends TwoFactorBaseComponent {
|
export class TwoFactorWebAuthnComponent extends TwoFactorBaseComponent {
|
||||||
type = TwoFactorProviderType.WebAuthn;
|
type = TwoFactorProviderType.WebAuthn;
|
||||||
name: string;
|
name: string;
|
||||||
keys: any[];
|
keys: Key[];
|
||||||
keyIdAvailable: number = null;
|
keyIdAvailable: number = null;
|
||||||
keysConfiguredCount = 0;
|
keysConfiguredCount = 0;
|
||||||
webAuthnError: boolean;
|
webAuthnError: boolean;
|
||||||
webAuthnListening: boolean;
|
webAuthnListening: boolean;
|
||||||
webAuthnResponse: PublicKeyCredential;
|
webAuthnResponse: PublicKeyCredential;
|
||||||
challengePromise: Promise<ChallengeResponse>;
|
challengePromise: Promise<ChallengeResponse>;
|
||||||
formPromise: Promise<any>;
|
formPromise: Promise<TwoFactorWebAuthnResponse>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
apiService: ApiService,
|
apiService: ApiService,
|
||||||
@@ -43,7 +52,7 @@ export class TwoFactorWebAuthnComponent extends TwoFactorBaseComponent {
|
|||||||
super(apiService, i18nService, platformUtilsService, logService, userVerificationService);
|
super(apiService, i18nService, platformUtilsService, logService, userVerificationService);
|
||||||
}
|
}
|
||||||
|
|
||||||
auth(authResponse: any) {
|
auth(authResponse: AuthResponse<TwoFactorWebAuthnResponse>) {
|
||||||
super.auth(authResponse);
|
super.auth(authResponse);
|
||||||
this.processResponse(authResponse.response);
|
this.processResponse(authResponse.response);
|
||||||
}
|
}
|
||||||
@@ -69,11 +78,11 @@ export class TwoFactorWebAuthnComponent extends TwoFactorBaseComponent {
|
|||||||
return super.disable(this.formPromise);
|
return super.disable(this.formPromise);
|
||||||
}
|
}
|
||||||
|
|
||||||
async remove(key: any) {
|
async remove(key: Key) {
|
||||||
if (this.keysConfiguredCount <= 1 || key.removePromise != null) {
|
if (this.keysConfiguredCount <= 1 || key.removePromise != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const name = key.name != null ? key.name : this.i18nService.t("webAuthnkeyX", key.id);
|
const name = key.name != null ? key.name : this.i18nService.t("webAuthnkeyX", key.id as any);
|
||||||
const confirmed = await this.platformUtilsService.showDialog(
|
const confirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t("removeU2fConfirmation"),
|
this.i18nService.t("removeU2fConfirmation"),
|
||||||
name,
|
name,
|
||||||
|
|||||||
@@ -4,24 +4,30 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
|||||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
import { TwoFactorProviderType } from "@bitwarden/common/enums/twoFactorProviderType";
|
import { TwoFactorProviderType } from "@bitwarden/common/enums/twoFactorProviderType";
|
||||||
import { UpdateTwoFactorYubioOtpRequest } from "@bitwarden/common/models/request/updateTwoFactorYubioOtpRequest";
|
import { UpdateTwoFactorYubioOtpRequest } from "@bitwarden/common/models/request/updateTwoFactorYubioOtpRequest";
|
||||||
import { TwoFactorYubiKeyResponse } from "@bitwarden/common/models/response/twoFactorYubiKeyResponse";
|
import { TwoFactorYubiKeyResponse } from "@bitwarden/common/models/response/twoFactorYubiKeyResponse";
|
||||||
|
import { AuthResponse } from "@bitwarden/common/types/authResponse";
|
||||||
|
|
||||||
import { TwoFactorBaseComponent } from "./two-factor-base.component";
|
import { TwoFactorBaseComponent } from "./two-factor-base.component";
|
||||||
|
|
||||||
|
interface Key {
|
||||||
|
key: string;
|
||||||
|
existingKey: string;
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-two-factor-yubikey",
|
selector: "app-two-factor-yubikey",
|
||||||
templateUrl: "two-factor-yubikey.component.html",
|
templateUrl: "two-factor-yubikey.component.html",
|
||||||
})
|
})
|
||||||
export class TwoFactorYubiKeyComponent extends TwoFactorBaseComponent {
|
export class TwoFactorYubiKeyComponent extends TwoFactorBaseComponent {
|
||||||
type = TwoFactorProviderType.Yubikey;
|
type = TwoFactorProviderType.Yubikey;
|
||||||
keys: any[];
|
keys: Key[];
|
||||||
nfc = false;
|
nfc = false;
|
||||||
|
|
||||||
formPromise: Promise<any>;
|
formPromise: Promise<TwoFactorYubiKeyResponse>;
|
||||||
disablePromise: Promise<any>;
|
disablePromise: Promise<unknown>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
apiService: ApiService,
|
apiService: ApiService,
|
||||||
@@ -33,7 +39,7 @@ export class TwoFactorYubiKeyComponent extends TwoFactorBaseComponent {
|
|||||||
super(apiService, i18nService, platformUtilsService, logService, userVerificationService);
|
super(apiService, i18nService, platformUtilsService, logService, userVerificationService);
|
||||||
}
|
}
|
||||||
|
|
||||||
auth(authResponse: any) {
|
auth(authResponse: AuthResponse<TwoFactorYubiKeyResponse>) {
|
||||||
super.auth(authResponse);
|
super.auth(authResponse);
|
||||||
this.processResponse(authResponse.response);
|
this.processResponse(authResponse.response);
|
||||||
}
|
}
|
||||||
@@ -59,7 +65,7 @@ export class TwoFactorYubiKeyComponent extends TwoFactorBaseComponent {
|
|||||||
return super.disable(this.disablePromise);
|
return super.disable(this.disablePromise);
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(key: any) {
|
remove(key: Key) {
|
||||||
key.existingKey = null;
|
key.existingKey = null;
|
||||||
key.key = null;
|
key.key = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUti
|
|||||||
templateUrl: "verify-email.component.html",
|
templateUrl: "verify-email.component.html",
|
||||||
})
|
})
|
||||||
export class VerifyEmailComponent {
|
export class VerifyEmailComponent {
|
||||||
actionPromise: Promise<any>;
|
actionPromise: Promise<unknown>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
|||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-export",
|
selector: "app-export",
|
||||||
|
|||||||
@@ -166,8 +166,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="tw-flex tw-flex-row">
|
||||||
<div class="col-6 form-group">
|
<div class="tw-mb-4 tw-w-1/2">
|
||||||
<label for="loginTotp">{{ "authenticatorKeyTotp" | i18n }}</label>
|
<label for="loginTotp">{{ "authenticatorKeyTotp" | i18n }}</label>
|
||||||
<input
|
<input
|
||||||
id="loginTotp"
|
id="loginTotp"
|
||||||
@@ -179,14 +179,41 @@
|
|||||||
[disabled]="cipher.isDeleted || !cipher.viewPassword || viewOnly"
|
[disabled]="cipher.isDeleted || !cipher.viewPassword || viewOnly"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 form-group totp d-flex align-items-end" [ngClass]="{ low: totpLow }">
|
<div class="tw-mb-4 tw-ml-4 tw-flex tw-w-1/2 tw-items-end" [ngClass]="{ low: totpLow }">
|
||||||
<div *ngIf="!cipher.login.totp || !totpCode">
|
<div
|
||||||
<img
|
class="totp tw-flex tw-flex-row tw-items-center"
|
||||||
src="../../images/totp-countdown.png"
|
*ngIf="!cipher.login.totp || (cipher.login.totp && !canAccessPremium)"
|
||||||
id="totpImage"
|
>
|
||||||
|
<span class="totp-countdown">
|
||||||
|
<span class="totp-sec tw-text-muted">15</span>
|
||||||
|
<svg>
|
||||||
|
<g>
|
||||||
|
<circle
|
||||||
|
class="totp-circle-muted inner"
|
||||||
|
r="12.6"
|
||||||
|
cy="16"
|
||||||
|
cx="16"
|
||||||
|
opacity="0.25"
|
||||||
|
[ngStyle]="{ 'stroke-dashoffset.px': 40 }"
|
||||||
|
></circle>
|
||||||
|
<circle
|
||||||
|
class="totp-circle-muted outer"
|
||||||
|
opacity="0.25"
|
||||||
|
r="14"
|
||||||
|
cy="16"
|
||||||
|
cx="16"
|
||||||
|
></circle>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="totp-code tw-mr-3 tw-ml-2 tw-text-muted"
|
||||||
title="{{ 'verificationCodeTotp' | i18n }}"
|
title="{{ 'verificationCodeTotp' | i18n }}"
|
||||||
class="ml-2"
|
>--- ---</span
|
||||||
/>
|
>
|
||||||
|
<i class="bwi bwi-lg bwi-clone tw-text-muted" aria-hidden="true"></i>
|
||||||
|
</div>
|
||||||
|
<div class="tw-pb-2" *ngIf="!cipher.login.totp || !totpCode">
|
||||||
<app-premium-badge
|
<app-premium-badge
|
||||||
*ngIf="!organization && !cipher.organizationId"
|
*ngIf="!organization && !cipher.organizationId"
|
||||||
class="ml-3"
|
class="ml-3"
|
||||||
@@ -209,8 +236,11 @@
|
|||||||
{{ "upgrade" | i18n }}
|
{{ "upgrade" | i18n }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="cipher.login.totp && totpCode" class="d-flex align-items-center">
|
<div
|
||||||
<span class="totp-countdown mr-3 ml-2">
|
*ngIf="cipher.login.totp && totpCode && canAccessPremium"
|
||||||
|
class="totp tw-flex tw-flex-row tw-items-center"
|
||||||
|
>
|
||||||
|
<span class="totp-countdown">
|
||||||
<span class="totp-sec">{{ totpSec }}</span>
|
<span class="totp-sec">{{ totpSec }}</span>
|
||||||
<svg>
|
<svg>
|
||||||
<g>
|
<g>
|
||||||
@@ -225,16 +255,18 @@
|
|||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
<span class="totp-code mr-2" title="{{ 'verificationCodeTotp' | i18n }}">{{
|
<span
|
||||||
totpCodeFormatted
|
class="totp-code tw-mr-2 tw-ml-2 tw-mt-1"
|
||||||
}}</span>
|
title="{{ 'verificationCodeTotp' | i18n }}"
|
||||||
|
>{{ totpCodeFormatted }}</span
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-link"
|
class="tw-items-center tw-border-none tw-bg-transparent tw-text-primary-500"
|
||||||
appA11yTitle="{{ 'copyVerificationCode' | i18n }}"
|
appA11yTitle="{{ 'copyVerificationCode' | i18n }}"
|
||||||
(click)="copy(totpCode, 'verificationCodeTotp', 'TOTP')"
|
(click)="copy(totpCode, 'verificationCodeTotp', 'TOTP')"
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-clone" aria-hidden="true"></i>
|
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -152,6 +152,17 @@ export class AddEditComponent extends BaseAddEditComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showGetPremium() {
|
||||||
|
if (this.canAccessPremium) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.cipher.organizationUseTotp) {
|
||||||
|
this.upgradeOrganization();
|
||||||
|
} else {
|
||||||
|
this.premiumRequired();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
viewHistory() {
|
viewHistory() {
|
||||||
this.viewingPasswordHistory = !this.viewingPasswordHistory;
|
this.viewingPasswordHistory = !this.viewingPasswordHistory;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,6 +142,7 @@
|
|||||||
<span class="sr-only">{{ "loading" | i18n }}</span>
|
<span class="sr-only">{{ "loading" | i18n }}</span>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container *ngIf="loaded">
|
<ng-container *ngIf="loaded">
|
||||||
|
<img class="no-items-image" aria-hidden="true" />
|
||||||
<p>{{ "noItemsInList" | i18n }}</p>
|
<p>{{ "noItemsInList" | i18n }}</p>
|
||||||
<button (click)="addCipher()" class="btn btn-outline-primary" *ngIf="showAddNew">
|
<button (click)="addCipher()" class="btn btn-outline-primary" *ngIf="showAddNew">
|
||||||
<i class="bwi bwi-plus bwi-fw"></i>{{ "addItem" | i18n }}
|
<i class="bwi bwi-plus bwi-fw"></i>{{ "addItem" | i18n }}
|
||||||
|
|||||||
34
apps/web/src/images/search-web-dark.svg
Normal file
34
apps/web/src/images/search-web-dark.svg
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<svg width="120" height="120" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g opacity="0.7">
|
||||||
|
<g opacity="0.7">
|
||||||
|
<g clip-path="url(#clip0_44_9647)">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M40.3599 73.2564C43.579 74.4366 47.0654 75.0822 50.7059 75.0822C66.9882 75.0822 80.1876 62.1696 80.1876 46.2411C80.1876 45.8578 80.1804 45.4762 80.1648 45.0966H108.891V84.6672H40.3599V73.2564Z" fill="#6e7689"/>
|
||||||
|
<path d="M21.5461 46.241C21.5461 62.1696 34.7456 75.0822 51.028 75.0822C67.3104 75.0822 80.5098 62.1696 80.5098 46.241C80.5098 30.3125 67.3104 17.4 51.028 17.4C34.7456 17.4 21.5461 30.3125 21.5461 46.241Z" stroke="#bac0ce" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M35.3603 70.5954C35.3603 69.933 34.823 69.3954 34.1603 69.3954C33.4976 69.3954 32.9603 69.933 32.9603 70.5954H35.3603ZM112.835 40.2387C114.169 40.2387 115.2 41.3027 115.2 42.5698H117.6C117.6 39.9762 115.493 37.8387 112.835 37.8387V40.2387ZM115.2 42.5698V88.6158H117.6V42.5698H115.2ZM115.2 88.6158C115.2 89.9094 114.142 90.9468 112.835 90.9468V93.3468C115.425 93.3468 117.6 91.2774 117.6 88.6158H115.2ZM112.835 90.9468H37.7256V93.3468H112.835V90.9468ZM37.7256 90.9468C36.3913 90.9468 35.3603 89.883 35.3603 88.6158H32.9603C32.9603 91.2096 35.0667 93.3468 37.7256 93.3468V90.9468ZM35.3603 88.6158V70.5954H32.9603V88.6158H35.3603ZM79.8684 40.2387H112.835V37.8387H79.8684V40.2387Z" fill="#bac0ce"/>
|
||||||
|
<path d="M79.9068 45.2867H109.021V84.8574H40.4873V73.0512" stroke="#bac0ce" stroke-width="2" stroke-linejoin="round"/>
|
||||||
|
<path d="M57.3565 102.56H93.2046" stroke="#bac0ce" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M68.9544 92.1468V102.56" stroke="#bac0ce" stroke-width="4" stroke-linejoin="round"/>
|
||||||
|
<path d="M80.553 92.1468V102.56" stroke="#bac0ce" stroke-width="4" stroke-linejoin="round"/>
|
||||||
|
<path d="M27.4398 64.9452L22.9296 69.4554L5.72134 86.6634C4.54976 87.8352 4.54976 89.7342 5.72133 90.906L6.95929 92.1438C8.13085 93.3156 10.0304 93.3156 11.202 92.1438L28.4102 74.9358L32.9204 70.4256" stroke="#bac0ce" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M101.293 53.1537H85.1784" stroke="#bac0ce" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M101.293 59.1966H90.2142" stroke="#bac0ce" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M85.1784 59.1966H77.625" stroke="#bac0ce" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M101.293 65.2392H94.2426" stroke="#bac0ce" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M88.7034 65.2392H73.0926" stroke="#bac0ce" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M101.293 71.2824H85.1784" stroke="#bac0ce" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M79.6392 71.2824H71.0784" stroke="#bac0ce" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M101.293 77.325H78.6318" stroke="#bac0ce" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M73.0926 77.325H59.9997" stroke="#bac0ce" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M54.4604 77.325H46.4032" stroke="#bac0ce" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M29.1638 33.0108H70.6926C72.0181 33.0108 73.0926 34.0853 73.0926 35.4108V41.6894C73.0926 43.0149 72.0181 44.0894 70.6926 44.0894H29.1638C27.8383 44.0894 26.7638 43.0149 26.7638 41.6894V35.4108C26.7638 34.0853 27.8383 33.0108 29.1638 33.0108Z" stroke="#bac0ce" stroke-width="4"/>
|
||||||
|
<path d="M22.7354 54.1609H57.0962C58.4217 54.1609 59.4962 55.2354 59.4962 56.5609V62.8392C59.4962 64.1652 58.4217 65.2392 57.0962 65.2392H28.7783" stroke="#bac0ce" stroke-width="4" stroke-linecap="round"/>
|
||||||
|
<path d="M79.1358 54.1609H72.975C71.6496 54.1609 70.575 55.2354 70.575 56.5609V62.9736C70.575 64.2252 71.5896 65.2392 72.8406 65.2392" stroke="#bac0ce" stroke-width="4" stroke-linecap="round"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_44_9647">
|
||||||
|
<rect width="120" height="120" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.8 KiB |
34
apps/web/src/images/search-web-light.svg
Normal file
34
apps/web/src/images/search-web-light.svg
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<svg width="120" height="120" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g opacity="0.7">
|
||||||
|
<g opacity="0.7">
|
||||||
|
<g clip-path="url(#clip0_44_9647)">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M40.3599 73.2564C43.579 74.4366 47.0654 75.0822 50.7059 75.0822C66.9882 75.0822 80.1876 62.1696 80.1876 46.2411C80.1876 45.8578 80.1804 45.4762 80.1648 45.0966H108.891V84.6672H40.3599V73.2564Z" fill="#ced4dc"/>
|
||||||
|
<path d="M21.5461 46.241C21.5461 62.1696 34.7456 75.0822 51.028 75.0822C67.3104 75.0822 80.5098 62.1696 80.5098 46.241C80.5098 30.3125 67.3104 17.4 51.028 17.4C34.7456 17.4 21.5461 30.3125 21.5461 46.241Z" stroke="#6d757e" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M35.3603 70.5954C35.3603 69.933 34.823 69.3954 34.1603 69.3954C33.4976 69.3954 32.9603 69.933 32.9603 70.5954H35.3603ZM112.835 40.2387C114.169 40.2387 115.2 41.3027 115.2 42.5698H117.6C117.6 39.9762 115.493 37.8387 112.835 37.8387V40.2387ZM115.2 42.5698V88.6158H117.6V42.5698H115.2ZM115.2 88.6158C115.2 89.9094 114.142 90.9468 112.835 90.9468V93.3468C115.425 93.3468 117.6 91.2774 117.6 88.6158H115.2ZM112.835 90.9468H37.7256V93.3468H112.835V90.9468ZM37.7256 90.9468C36.3913 90.9468 35.3603 89.883 35.3603 88.6158H32.9603C32.9603 91.2096 35.0667 93.3468 37.7256 93.3468V90.9468ZM35.3603 88.6158V70.5954H32.9603V88.6158H35.3603ZM79.8684 40.2387H112.835V37.8387H79.8684V40.2387Z" fill="#6d757e"/>
|
||||||
|
<path d="M79.9068 45.2867H109.021V84.8574H40.4873V73.0512" stroke="#6d757e" stroke-width="2" stroke-linejoin="round"/>
|
||||||
|
<path d="M57.3565 102.56H93.2046" stroke="#6d757e" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M68.9544 92.1468V102.56" stroke="#6d757e" stroke-width="4" stroke-linejoin="round"/>
|
||||||
|
<path d="M80.553 92.1468V102.56" stroke="#6d757e" stroke-width="4" stroke-linejoin="round"/>
|
||||||
|
<path d="M27.4398 64.9452L22.9296 69.4554L5.72134 86.6634C4.54976 87.8352 4.54976 89.7342 5.72133 90.906L6.95929 92.1438C8.13085 93.3156 10.0304 93.3156 11.202 92.1438L28.4102 74.9358L32.9204 70.4256" stroke="#6d757e" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M101.293 53.1537H85.1784" stroke="#6d757e" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M101.293 59.1966H90.2142" stroke="#6d757e" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M85.1784 59.1966H77.625" stroke="#6d757e" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M101.293 65.2392H94.2426" stroke="#6d757e" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M88.7034 65.2392H73.0926" stroke="#6d757e" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M101.293 71.2824H85.1784" stroke="#6d757e" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M79.6392 71.2824H71.0784" stroke="#6d757e" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M101.293 77.325H78.6318" stroke="#6d757e" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M73.0926 77.325H59.9997" stroke="#6d757e" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M54.4604 77.325H46.4032" stroke="#6d757e" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M29.1638 33.0108H70.6926C72.0181 33.0108 73.0926 34.0853 73.0926 35.4108V41.6894C73.0926 43.0149 72.0181 44.0894 70.6926 44.0894H29.1638C27.8383 44.0894 26.7638 43.0149 26.7638 41.6894V35.4108C26.7638 34.0853 27.8383 33.0108 29.1638 33.0108Z" stroke="#6d757e" stroke-width="4"/>
|
||||||
|
<path d="M22.7354 54.1609H57.0962C58.4217 54.1609 59.4962 55.2354 59.4962 56.5609V62.8392C59.4962 64.1652 58.4217 65.2392 57.0962 65.2392H28.7783" stroke="#6d757e" stroke-width="4" stroke-linecap="round"/>
|
||||||
|
<path d="M79.1358 54.1609H72.975C71.6496 54.1609 70.575 55.2354 70.575 56.5609V62.9736C70.575 64.2252 71.5896 65.2392 72.8406 65.2392" stroke="#6d757e" stroke-width="4" stroke-linecap="round"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_44_9647">
|
||||||
|
<rect width="120" height="120" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 950 B |
@@ -5227,6 +5227,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"premiumSubcriptionRequired": {
|
||||||
|
"message": "Premium subscription required"
|
||||||
|
},
|
||||||
"scim": {
|
"scim": {
|
||||||
"message": "SCIM Provisioning",
|
"message": "SCIM Provisioning",
|
||||||
"description": "The text, 'SCIM', is an acronymn and should not be translated."
|
"description": "The text, 'SCIM', is an acronymn and should not be translated."
|
||||||
|
|||||||
@@ -306,3 +306,18 @@ button i.bwi,
|
|||||||
a i.bwi {
|
a i.bwi {
|
||||||
margin-right: 0.25rem;
|
margin-right: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.no-items {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.no-items-image {
|
||||||
|
@include themify($themes) {
|
||||||
|
content: url("../images/search-web" + themed("svgSuffix"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -130,6 +130,25 @@
|
|||||||
stroke-width: 2;
|
stroke-width: 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.totp-circle-muted {
|
||||||
|
fill: none;
|
||||||
|
@include themify($themes) {
|
||||||
|
stroke: themed("info");
|
||||||
|
}
|
||||||
|
|
||||||
|
&.inner {
|
||||||
|
stroke-dasharray: 78.6;
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
stroke-width: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.outer {
|
||||||
|
stroke-dasharray: 88;
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
stroke-width: 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> .align-items-center {
|
> .align-items-center {
|
||||||
|
|||||||
@@ -219,6 +219,7 @@ $themes: (
|
|||||||
textMuted: #6c757d,
|
textMuted: #6c757d,
|
||||||
textSuccessColor: $white,
|
textSuccessColor: $white,
|
||||||
textWarningColor: $white,
|
textWarningColor: $white,
|
||||||
|
svgSuffix: "-light.svg",
|
||||||
),
|
),
|
||||||
dark: (
|
dark: (
|
||||||
primary: $darkPrimary,
|
primary: $darkPrimary,
|
||||||
@@ -330,6 +331,7 @@ $themes: (
|
|||||||
textMuted: $darkGrey1,
|
textMuted: $darkGrey1,
|
||||||
textSuccessColor: $darkDarkBlue2,
|
textSuccessColor: $darkDarkBlue2,
|
||||||
textWarningColor: $darkDarkBlue2,
|
textWarningColor: $darkDarkBlue2,
|
||||||
|
svgSuffix: "-dark.svg",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
|||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
import { EventType } from "@bitwarden/common/enums/eventType";
|
import { EventType } from "@bitwarden/common/enums/eventType";
|
||||||
import { PolicyType } from "@bitwarden/common/enums/policyType";
|
import { PolicyType } from "@bitwarden/common/enums/policyType";
|
||||||
|
|
||||||
@@ -142,7 +142,7 @@ export class ExportComponent implements OnInit {
|
|||||||
return this.exportService.getFileName(prefix, extension);
|
return this.exportService.getFileName(prefix, extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async collectEvent(): Promise<any> {
|
protected async collectEvent(): Promise<void> {
|
||||||
await this.eventService.collect(EventType.User_ClientExportedVault);
|
await this.eventService.collect(EventType.User_ClientExportedVault);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Directive, NgZone, OnInit } from "@angular/core";
|
import { Directive, NgZone, OnDestroy, OnInit } from "@angular/core";
|
||||||
import { Router } from "@angular/router";
|
import { Router } from "@angular/router";
|
||||||
|
import { Subscription } from "rxjs";
|
||||||
import { take } from "rxjs/operators";
|
import { take } from "rxjs/operators";
|
||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
@@ -20,7 +21,7 @@ import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetricCry
|
|||||||
import { SecretVerificationRequest } from "@bitwarden/common/models/request/secretVerificationRequest";
|
import { SecretVerificationRequest } from "@bitwarden/common/models/request/secretVerificationRequest";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class LockComponent implements OnInit {
|
export class LockComponent implements OnInit, OnDestroy {
|
||||||
masterPassword = "";
|
masterPassword = "";
|
||||||
pin = "";
|
pin = "";
|
||||||
showPassword = false;
|
showPassword = false;
|
||||||
@@ -39,6 +40,8 @@ export class LockComponent implements OnInit {
|
|||||||
private invalidPinAttempts = 0;
|
private invalidPinAttempts = 0;
|
||||||
private pinSet: [boolean, boolean];
|
private pinSet: [boolean, boolean];
|
||||||
|
|
||||||
|
private activeAccountSubscription: Subscription;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected router: Router,
|
protected router: Router,
|
||||||
protected i18nService: I18nService,
|
protected i18nService: I18nService,
|
||||||
@@ -57,11 +60,15 @@ export class LockComponent implements OnInit {
|
|||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
// Load the first and observe updates
|
// Load the first and observe updates
|
||||||
await this.load();
|
await this.load();
|
||||||
this.stateService.activeAccount.subscribe(async () => {
|
this.activeAccountSubscription = this.stateService.activeAccount$.subscribe(async () => {
|
||||||
await this.load();
|
await this.load();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.activeAccountSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
async submit() {
|
async submit() {
|
||||||
if (this.pinLock && (this.pin == null || this.pin === "")) {
|
if (this.pinLock && (this.pin == null || this.pin === "")) {
|
||||||
this.platformUtilsService.showToast(
|
this.platformUtilsService.showToast(
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwo
|
|||||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||||
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
|
||||||
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
import { VerificationType } from "@bitwarden/common/enums/verificationType";
|
import { VerificationType } from "@bitwarden/common/enums/verificationType";
|
||||||
import { EncString } from "@bitwarden/common/models/domain/encString";
|
import { EncString } from "@bitwarden/common/models/domain/encString";
|
||||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/models/domain/masterPasswordPolicyOptions";
|
import { MasterPasswordPolicyOptions } from "@bitwarden/common/models/domain/masterPasswordPolicyOptions";
|
||||||
@@ -28,7 +28,7 @@ export class UpdatePasswordComponent extends BaseChangePasswordComponent {
|
|||||||
showPassword = false;
|
showPassword = false;
|
||||||
currentMasterPassword: string;
|
currentMasterPassword: string;
|
||||||
|
|
||||||
onSuccessfulChangePassword: () => Promise<any>;
|
onSuccessfulChangePassword: () => Promise<void>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected router: Router,
|
protected router: Router,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { animate, style, transition, trigger } from "@angular/animations";
|
import { animate, style, transition, trigger } from "@angular/animations";
|
||||||
import { Component, OnInit } from "@angular/core";
|
import { Component, OnInit } from "@angular/core";
|
||||||
import { ControlValueAccessor, UntypedFormControl, NG_VALUE_ACCESSOR } from "@angular/forms";
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR, FormControl } from "@angular/forms";
|
||||||
|
|
||||||
import { KeyConnectorService } from "@bitwarden/common/abstractions/keyConnector.service";
|
import { KeyConnectorService } from "@bitwarden/common/abstractions/keyConnector.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
import { VerificationType } from "@bitwarden/common/enums/verificationType";
|
import { VerificationType } from "@bitwarden/common/enums/verificationType";
|
||||||
import { Utils } from "@bitwarden/common/misc/utils";
|
import { Utils } from "@bitwarden/common/misc/utils";
|
||||||
import { Verification } from "@bitwarden/common/types/verification";
|
import { Verification } from "@bitwarden/common/types/verification";
|
||||||
@@ -35,7 +35,7 @@ export class UserVerificationComponent implements ControlValueAccessor, OnInit {
|
|||||||
disableRequestOTP = false;
|
disableRequestOTP = false;
|
||||||
sentCode = false;
|
sentCode = false;
|
||||||
|
|
||||||
secret = new UntypedFormControl("");
|
secret = new FormControl("");
|
||||||
|
|
||||||
private onChange: (value: Verification) => void;
|
private onChange: (value: Verification) => void;
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ import { SyncService as SyncServiceAbstraction } from "@bitwarden/common/abstrac
|
|||||||
import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/abstractions/token.service";
|
import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/abstractions/token.service";
|
||||||
import { TotpService as TotpServiceAbstraction } from "@bitwarden/common/abstractions/totp.service";
|
import { TotpService as TotpServiceAbstraction } from "@bitwarden/common/abstractions/totp.service";
|
||||||
import { TwoFactorService as TwoFactorServiceAbstraction } from "@bitwarden/common/abstractions/twoFactor.service";
|
import { TwoFactorService as TwoFactorServiceAbstraction } from "@bitwarden/common/abstractions/twoFactor.service";
|
||||||
import { UserVerificationService as UserVerificationServiceAbstraction } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationApiServiceAbstraction } from "@bitwarden/common/abstractions/userVerification/userVerification-api.service.abstraction";
|
||||||
|
import { UserVerificationService as UserVerificationServiceAbstraction } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
import { UsernameGenerationService as UsernameGenerationServiceAbstraction } from "@bitwarden/common/abstractions/usernameGeneration.service";
|
import { UsernameGenerationService as UsernameGenerationServiceAbstraction } from "@bitwarden/common/abstractions/usernameGeneration.service";
|
||||||
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "@bitwarden/common/abstractions/vaultTimeout.service";
|
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "@bitwarden/common/abstractions/vaultTimeout.service";
|
||||||
import { StateFactory } from "@bitwarden/common/factories/stateFactory";
|
import { StateFactory } from "@bitwarden/common/factories/stateFactory";
|
||||||
@@ -89,7 +90,8 @@ import { SyncService } from "@bitwarden/common/services/sync.service";
|
|||||||
import { TokenService } from "@bitwarden/common/services/token.service";
|
import { TokenService } from "@bitwarden/common/services/token.service";
|
||||||
import { TotpService } from "@bitwarden/common/services/totp.service";
|
import { TotpService } from "@bitwarden/common/services/totp.service";
|
||||||
import { TwoFactorService } from "@bitwarden/common/services/twoFactor.service";
|
import { TwoFactorService } from "@bitwarden/common/services/twoFactor.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/services/userVerification.service";
|
import { UserVerificationApiService } from "@bitwarden/common/services/userVerification/userVerification-api.service";
|
||||||
|
import { UserVerificationService } from "@bitwarden/common/services/userVerification/userVerification.service";
|
||||||
import { UsernameGenerationService } from "@bitwarden/common/services/usernameGeneration.service";
|
import { UsernameGenerationService } from "@bitwarden/common/services/usernameGeneration.service";
|
||||||
import { VaultTimeoutService } from "@bitwarden/common/services/vaultTimeout.service";
|
import { VaultTimeoutService } from "@bitwarden/common/services/vaultTimeout.service";
|
||||||
import { WebCryptoFunctionService } from "@bitwarden/common/services/webCryptoFunction.service";
|
import { WebCryptoFunctionService } from "@bitwarden/common/services/webCryptoFunction.service";
|
||||||
@@ -476,7 +478,11 @@ export const LOG_MAC_FAILURES = new InjectionToken<string>("LOG_MAC_FAILURES");
|
|||||||
{
|
{
|
||||||
provide: UserVerificationServiceAbstraction,
|
provide: UserVerificationServiceAbstraction,
|
||||||
useClass: UserVerificationService,
|
useClass: UserVerificationService,
|
||||||
deps: [CryptoServiceAbstraction, I18nServiceAbstraction, ApiServiceAbstraction],
|
deps: [
|
||||||
|
CryptoServiceAbstraction,
|
||||||
|
I18nServiceAbstraction,
|
||||||
|
UserVerificationApiServiceAbstraction,
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{ provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService },
|
{ provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService },
|
||||||
{
|
{
|
||||||
@@ -502,6 +508,11 @@ export const LOG_MAC_FAILURES = new InjectionToken<string>("LOG_MAC_FAILURES");
|
|||||||
provide: FormValidationErrorsServiceAbstraction,
|
provide: FormValidationErrorsServiceAbstraction,
|
||||||
useClass: FormValidationErrorsService,
|
useClass: FormValidationErrorsService,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
provide: UserVerificationApiServiceAbstraction,
|
||||||
|
useClass: UserVerificationApiService,
|
||||||
|
deps: [ApiServiceAbstraction],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class JslibServicesModule {}
|
export class JslibServicesModule {}
|
||||||
|
|||||||
@@ -78,25 +78,4 @@ describe("ConsoleLogService", () => {
|
|||||||
error: { 0: "this is an error message" },
|
error: { 0: "this is an error message" },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("times with output to info", async () => {
|
|
||||||
logService.time();
|
|
||||||
await new Promise((r) => setTimeout(r, 250));
|
|
||||||
const duration = logService.timeEnd();
|
|
||||||
expect(duration[0]).toBe(0);
|
|
||||||
expect(duration[1]).toBeGreaterThan(0);
|
|
||||||
expect(duration[1]).toBeLessThan(500 * 10e6);
|
|
||||||
|
|
||||||
expect(caughtMessage).toEqual(expect.arrayContaining([]));
|
|
||||||
expect(caughtMessage.log.length).toBe(1);
|
|
||||||
expect(caughtMessage.log[0]).toEqual(expect.stringMatching(/^default: \d+\.?\d*ms$/));
|
|
||||||
});
|
|
||||||
|
|
||||||
it("filters time output", async () => {
|
|
||||||
logService = new ConsoleLogService(true, () => true);
|
|
||||||
logService.time();
|
|
||||||
logService.timeEnd();
|
|
||||||
|
|
||||||
expect(caughtMessage).toEqual({});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ describe("Folder Service", () => {
|
|||||||
stateService.getEncryptedFolders().resolves({
|
stateService.getEncryptedFolders().resolves({
|
||||||
"1": folderData("1", "test"),
|
"1": folderData("1", "test"),
|
||||||
});
|
});
|
||||||
stateService.activeAccount.returns(activeAccount);
|
stateService.activeAccount$.returns(activeAccount);
|
||||||
stateService.activeAccountUnlocked.returns(activeAccountUnlocked);
|
stateService.activeAccountUnlocked.returns(activeAccountUnlocked);
|
||||||
(window as any).bitwardenContainerService = new ContainerService(cryptoService);
|
(window as any).bitwardenContainerService = new ContainerService(cryptoService);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { OrganizationApiKeyType } from "../enums/organizationApiKeyType";
|
import { OrganizationApiKeyType } from "../enums/organizationApiKeyType";
|
||||||
import { OrganizationConnectionType } from "../enums/organizationConnectionType";
|
import { OrganizationConnectionType } from "../enums/organizationConnectionType";
|
||||||
import { SetKeyConnectorKeyRequest } from "../models/request/account/setKeyConnectorKeyRequest";
|
import { SetKeyConnectorKeyRequest } from "../models/request/account/setKeyConnectorKeyRequest";
|
||||||
import { VerifyOTPRequest } from "../models/request/account/verifyOTPRequest";
|
|
||||||
import { AttachmentRequest } from "../models/request/attachmentRequest";
|
import { AttachmentRequest } from "../models/request/attachmentRequest";
|
||||||
import { BitPayInvoiceRequest } from "../models/request/bitPayInvoiceRequest";
|
import { BitPayInvoiceRequest } from "../models/request/bitPayInvoiceRequest";
|
||||||
import { CipherBulkDeleteRequest } from "../models/request/cipherBulkDeleteRequest";
|
import { CipherBulkDeleteRequest } from "../models/request/cipherBulkDeleteRequest";
|
||||||
@@ -228,8 +227,6 @@ export abstract class ApiService {
|
|||||||
postUserApiKey: (id: string, request: SecretVerificationRequest) => Promise<ApiKeyResponse>;
|
postUserApiKey: (id: string, request: SecretVerificationRequest) => Promise<ApiKeyResponse>;
|
||||||
postUserRotateApiKey: (id: string, request: SecretVerificationRequest) => Promise<ApiKeyResponse>;
|
postUserRotateApiKey: (id: string, request: SecretVerificationRequest) => Promise<ApiKeyResponse>;
|
||||||
putUpdateTempPassword: (request: UpdateTempPasswordRequest) => Promise<any>;
|
putUpdateTempPassword: (request: UpdateTempPasswordRequest) => Promise<any>;
|
||||||
postAccountRequestOTP: () => Promise<void>;
|
|
||||||
postAccountVerifyOTP: (request: VerifyOTPRequest) => Promise<void>;
|
|
||||||
postConvertToKeyConnector: () => Promise<void>;
|
postConvertToKeyConnector: () => Promise<void>;
|
||||||
|
|
||||||
getUserBillingHistory: () => Promise<BillingHistoryResponse>;
|
getUserBillingHistory: () => Promise<BillingHistoryResponse>;
|
||||||
|
|||||||
@@ -6,6 +6,4 @@ export abstract class LogService {
|
|||||||
warning: (message: string) => void;
|
warning: (message: string) => void;
|
||||||
error: (message: string) => void;
|
error: (message: string) => void;
|
||||||
write: (level: LogLevelType, message: string) => void;
|
write: (level: LogLevelType, message: string) => void;
|
||||||
time: (label: string) => void;
|
|
||||||
timeEnd: (label: string) => [number, number];
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,9 +26,8 @@ import { SendView } from "../models/view/sendView";
|
|||||||
|
|
||||||
export abstract class StateService<T extends Account = Account> {
|
export abstract class StateService<T extends Account = Account> {
|
||||||
accounts: BehaviorSubject<{ [userId: string]: T }>;
|
accounts: BehaviorSubject<{ [userId: string]: T }>;
|
||||||
activeAccount: BehaviorSubject<string>;
|
activeAccount$: Observable<string>;
|
||||||
|
activeAccountUnlocked$: Observable<boolean>;
|
||||||
activeAccountUnlocked: Observable<boolean>;
|
|
||||||
|
|
||||||
addAccount: (account: T) => Promise<void>;
|
addAccount: (account: T) => Promise<void>;
|
||||||
setActiveUser: (userId: string) => Promise<void>;
|
setActiveUser: (userId: string) => Promise<void>;
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { VerifyOTPRequest } from "@bitwarden/common/models/request/account/verifyOTPRequest";
|
||||||
|
|
||||||
|
export abstract class UserVerificationApiServiceAbstraction {
|
||||||
|
postAccountVerifyOTP: (request: VerifyOTPRequest) => Promise<void>;
|
||||||
|
postAccountRequestOTP: () => Promise<void>;
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { SecretVerificationRequest } from "../models/request/secretVerificationRequest";
|
import { SecretVerificationRequest } from "../../models/request/secretVerificationRequest";
|
||||||
import { Verification } from "../types/verification";
|
import { Verification } from "../../types/verification";
|
||||||
|
|
||||||
export abstract class UserVerificationService {
|
export abstract class UserVerificationService {
|
||||||
buildRequest: <T extends SecretVerificationRequest>(
|
buildRequest: <T extends SecretVerificationRequest>(
|
||||||
@@ -1,17 +1,28 @@
|
|||||||
/* eslint-disable no-useless-escape */
|
/* eslint-disable no-useless-escape */
|
||||||
import * as tldjs from "tldjs";
|
import * as tldjs from "tldjs";
|
||||||
|
|
||||||
|
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||||
|
|
||||||
import { I18nService } from "../abstractions/i18n.service";
|
import { I18nService } from "../abstractions/i18n.service";
|
||||||
|
|
||||||
const nodeURL = typeof window === "undefined" ? require("url") : null;
|
const nodeURL = typeof window === "undefined" ? require("url") : null;
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
/* eslint-disable-next-line no-var */
|
||||||
|
var bitwardenContainerService: BitwardenContainerService;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BitwardenContainerService {
|
||||||
|
getCryptoService: () => CryptoService;
|
||||||
|
}
|
||||||
|
|
||||||
export class Utils {
|
export class Utils {
|
||||||
static inited = false;
|
static inited = false;
|
||||||
static isNode = false;
|
static isNode = false;
|
||||||
static isBrowser = true;
|
static isBrowser = true;
|
||||||
static isMobileBrowser = false;
|
static isMobileBrowser = false;
|
||||||
static isAppleMobileBrowser = false;
|
static isAppleMobileBrowser = false;
|
||||||
static global: any = null;
|
static global: typeof global = null;
|
||||||
static tldEndingRegex =
|
static tldEndingRegex =
|
||||||
/.*\.(com|net|org|edu|uk|gov|ca|de|jp|fr|au|ru|ch|io|es|us|co|xyz|info|ly|mil)$/;
|
/.*\.(com|net|org|edu|uk|gov|ca|de|jp|fr|au|ru|ch|io|es|us|co|xyz|info|ly|mil)$/;
|
||||||
// Transpiled version of /\p{Emoji_Presentation}/gu using https://mothereff.in/regexpu. Used for compatability in older browsers.
|
// Transpiled version of /\p{Emoji_Presentation}/gu using https://mothereff.in/regexpu. Used for compatability in older browsers.
|
||||||
@@ -29,16 +40,25 @@ export class Utils {
|
|||||||
(process as any).release != null &&
|
(process as any).release != null &&
|
||||||
(process as any).release.name === "node";
|
(process as any).release.name === "node";
|
||||||
Utils.isBrowser = typeof window !== "undefined";
|
Utils.isBrowser = typeof window !== "undefined";
|
||||||
|
|
||||||
Utils.isMobileBrowser = Utils.isBrowser && this.isMobile(window);
|
Utils.isMobileBrowser = Utils.isBrowser && this.isMobile(window);
|
||||||
Utils.isAppleMobileBrowser = Utils.isBrowser && this.isAppleMobile(window);
|
Utils.isAppleMobileBrowser = Utils.isBrowser && this.isAppleMobile(window);
|
||||||
Utils.global = Utils.isNode && !Utils.isBrowser ? global : window;
|
|
||||||
|
if (Utils.isNode) {
|
||||||
|
Utils.global = global;
|
||||||
|
} else if (Utils.isBrowser) {
|
||||||
|
Utils.global = window;
|
||||||
|
} else {
|
||||||
|
// If it's not browser or node then it must be a service worker
|
||||||
|
Utils.global = self;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromB64ToArray(str: string): Uint8Array {
|
static fromB64ToArray(str: string): Uint8Array {
|
||||||
if (Utils.isNode) {
|
if (Utils.isNode) {
|
||||||
return new Uint8Array(Buffer.from(str, "base64"));
|
return new Uint8Array(Buffer.from(str, "base64"));
|
||||||
} else {
|
} else {
|
||||||
const binaryString = window.atob(str);
|
const binaryString = Utils.global.atob(str);
|
||||||
const bytes = new Uint8Array(binaryString.length);
|
const bytes = new Uint8Array(binaryString.length);
|
||||||
for (let i = 0; i < binaryString.length; i++) {
|
for (let i = 0; i < binaryString.length; i++) {
|
||||||
bytes[i] = binaryString.charCodeAt(i);
|
bytes[i] = binaryString.charCodeAt(i);
|
||||||
@@ -93,7 +113,7 @@ export class Utils {
|
|||||||
for (let i = 0; i < bytes.byteLength; i++) {
|
for (let i = 0; i < bytes.byteLength; i++) {
|
||||||
binary += String.fromCharCode(bytes[i]);
|
binary += String.fromCharCode(bytes[i]);
|
||||||
}
|
}
|
||||||
return window.btoa(binary);
|
return Utils.global.btoa(binary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +177,7 @@ export class Utils {
|
|||||||
if (Utils.isNode) {
|
if (Utils.isNode) {
|
||||||
return Buffer.from(utfStr, "utf8").toString("base64");
|
return Buffer.from(utfStr, "utf8").toString("base64");
|
||||||
} else {
|
} else {
|
||||||
return decodeURIComponent(escape(window.btoa(utfStr)));
|
return decodeURIComponent(escape(Utils.global.btoa(utfStr)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,7 +189,7 @@ export class Utils {
|
|||||||
if (Utils.isNode) {
|
if (Utils.isNode) {
|
||||||
return Buffer.from(b64Str, "base64").toString("utf8");
|
return Buffer.from(b64Str, "base64").toString("utf8");
|
||||||
} else {
|
} else {
|
||||||
return decodeURIComponent(escape(window.atob(b64Str)));
|
return decodeURIComponent(escape(Utils.global.atob(b64Str)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,7 +404,7 @@ export class Utils {
|
|||||||
return new nodeURL.URL(uriString);
|
return new nodeURL.URL(uriString);
|
||||||
} else if (typeof URL === "function") {
|
} else if (typeof URL === "function") {
|
||||||
return new URL(uriString);
|
return new URL(uriString);
|
||||||
} else if (window != null) {
|
} else if (typeof window !== "undefined") {
|
||||||
const hasProtocol = uriString.indexOf("://") > -1;
|
const hasProtocol = uriString.indexOf("://") > -1;
|
||||||
if (!hasProtocol && uriString.indexOf(".") > -1) {
|
if (!hasProtocol && uriString.indexOf(".") > -1) {
|
||||||
uriString = "http://" + uriString;
|
uriString = "http://" + uriString;
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export class Attachment extends Domain {
|
|||||||
|
|
||||||
if (this.key != null) {
|
if (this.key != null) {
|
||||||
let cryptoService: CryptoService;
|
let cryptoService: CryptoService;
|
||||||
const containerService = (Utils.global as any).bitwardenContainerService;
|
const containerService = Utils.global.bitwardenContainerService;
|
||||||
if (containerService) {
|
if (containerService) {
|
||||||
cryptoService = containerService.getCryptoService();
|
cryptoService = containerService.getCryptoService();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ export class EncString implements IEncrypted {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let cryptoService: CryptoService;
|
let cryptoService: CryptoService;
|
||||||
const containerService = (Utils.global as any).bitwardenContainerService;
|
const containerService = Utils.global.bitwardenContainerService;
|
||||||
if (containerService) {
|
if (containerService) {
|
||||||
cryptoService = containerService.getCryptoService();
|
cryptoService = containerService.getCryptoService();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { AccountApiService } from "@bitwarden/common/abstractions/account/account-api.service.abstraction";
|
import { AccountApiService } from "@bitwarden/common/abstractions/account/account-api.service.abstraction";
|
||||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||||
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
|
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
|
||||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction";
|
||||||
|
|
||||||
import { AccountService as AccountServiceAbstraction } from "../../abstractions/account/account.service.abstraction";
|
import { AccountService as AccountServiceAbstraction } from "../../abstractions/account/account.service.abstraction";
|
||||||
import { Verification } from "../../types/verification";
|
import { Verification } from "../../types/verification";
|
||||||
@@ -14,7 +14,7 @@ export class AccountService implements AccountServiceAbstraction {
|
|||||||
private logService: LogService
|
private logService: LogService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async delete(verification: Verification): Promise<any> {
|
async delete(verification: Verification): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const verificationRequest = await this.userVerificationService.buildRequest(verification);
|
const verificationRequest = await this.userVerificationService.buildRequest(verification);
|
||||||
await this.accountApiService.deleteAccount(verificationRequest);
|
await this.accountApiService.deleteAccount(verificationRequest);
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import { OrganizationApiKeyType } from "../enums/organizationApiKeyType";
|
|||||||
import { OrganizationConnectionType } from "../enums/organizationConnectionType";
|
import { OrganizationConnectionType } from "../enums/organizationConnectionType";
|
||||||
import { Utils } from "../misc/utils";
|
import { Utils } from "../misc/utils";
|
||||||
import { SetKeyConnectorKeyRequest } from "../models/request/account/setKeyConnectorKeyRequest";
|
import { SetKeyConnectorKeyRequest } from "../models/request/account/setKeyConnectorKeyRequest";
|
||||||
import { VerifyOTPRequest } from "../models/request/account/verifyOTPRequest";
|
|
||||||
import { AttachmentRequest } from "../models/request/attachmentRequest";
|
import { AttachmentRequest } from "../models/request/attachmentRequest";
|
||||||
import { BitPayInvoiceRequest } from "../models/request/bitPayInvoiceRequest";
|
import { BitPayInvoiceRequest } from "../models/request/bitPayInvoiceRequest";
|
||||||
import { CipherBulkDeleteRequest } from "../models/request/cipherBulkDeleteRequest";
|
import { CipherBulkDeleteRequest } from "../models/request/cipherBulkDeleteRequest";
|
||||||
@@ -457,14 +456,6 @@ export class ApiService implements ApiServiceAbstraction {
|
|||||||
return this.send("PUT", "/accounts/update-temp-password", request, true, false);
|
return this.send("PUT", "/accounts/update-temp-password", request, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
postAccountRequestOTP(): Promise<void> {
|
|
||||||
return this.send("POST", "/accounts/request-otp", null, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
postAccountVerifyOTP(request: VerifyOTPRequest): Promise<void> {
|
|
||||||
return this.send("POST", "/accounts/verify-otp", request, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
postConvertToKeyConnector(): Promise<void> {
|
postConvertToKeyConnector(): Promise<void> {
|
||||||
return this.send("POST", "/accounts/convert-to-key-connector", null, true, false);
|
return this.send("POST", "/accounts/convert-to-key-connector", null, true, false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -341,7 +341,7 @@ export class CipherService implements CipherServiceAbstraction {
|
|||||||
throw new Error("No key.");
|
throw new Error("No key.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const promises: any[] = [];
|
const promises: Promise<number>[] = [];
|
||||||
const ciphers = await this.getAll();
|
const ciphers = await this.getAll();
|
||||||
ciphers.forEach(async (cipher) => {
|
ciphers.forEach(async (cipher) => {
|
||||||
promises.push(cipher.decrypt().then((c) => decCiphers.push(c)));
|
promises.push(cipher.decrypt().then((c) => decCiphers.push(c)));
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import * as hrtime from "browser-hrtime";
|
|
||||||
|
|
||||||
import { LogService as LogServiceAbstraction } from "../abstractions/log.service";
|
import { LogService as LogServiceAbstraction } from "../abstractions/log.service";
|
||||||
import { LogLevelType } from "../enums/logLevelType";
|
import { LogLevelType } from "../enums/logLevelType";
|
||||||
|
|
||||||
@@ -56,17 +54,4 @@ export class ConsoleLogService implements LogServiceAbstraction {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
time(label = "default") {
|
|
||||||
if (!this.timersMap.has(label)) {
|
|
||||||
this.timersMap.set(label, hrtime());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
timeEnd(label = "default"): [number, number] {
|
|
||||||
const elapsed = hrtime(this.timersMap.get(label));
|
|
||||||
this.timersMap.delete(label);
|
|
||||||
this.write(LogLevelType.Info, `${label}: ${elapsed[0] * 1000 + elapsed[1] / 10e6}ms`);
|
|
||||||
return elapsed;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
|
|||||||
private scimUrl: string = null;
|
private scimUrl: string = null;
|
||||||
|
|
||||||
constructor(private stateService: StateService) {
|
constructor(private stateService: StateService) {
|
||||||
this.stateService.activeAccount.subscribe(async () => {
|
this.stateService.activeAccount$.subscribe(async () => {
|
||||||
await this.setUrlsFromStorage();
|
await this.setUrlsFromStorage();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export class FolderService implements InternalFolderServiceAbstraction {
|
|||||||
private cipherService: CipherService,
|
private cipherService: CipherService,
|
||||||
private stateService: StateService
|
private stateService: StateService
|
||||||
) {
|
) {
|
||||||
this.stateService.activeAccountUnlocked.subscribe(async (unlocked) => {
|
this.stateService.activeAccountUnlocked$.subscribe(async (unlocked) => {
|
||||||
if ((Utils.global as any).bitwardenContainerService == null) {
|
if ((Utils.global as any).bitwardenContainerService == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
24
libs/common/src/services/noopEvent.service.ts
Normal file
24
libs/common/src/services/noopEvent.service.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { EventService } from "@bitwarden/common/abstractions/event.service";
|
||||||
|
import { EventType } from "@bitwarden/common/enums/eventType";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If you want to use this, don't.
|
||||||
|
* If you think you should use that after the warning, don't.
|
||||||
|
*/
|
||||||
|
export default class NoOpEventService implements EventService {
|
||||||
|
constructor() {
|
||||||
|
if (chrome.runtime.getManifest().manifest_version !== 3) {
|
||||||
|
throw new Error("You are not allowed to use this when not in manifest_version 3");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
collect(eventType: EventType, cipherId?: string, uploadImmediately?: boolean) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
uploadEvents(userId?: string) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
clearEvents(userId?: string) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,8 @@ import { CipherView } from "../models/view/cipherView";
|
|||||||
import { SendView } from "../models/view/sendView";
|
import { SendView } from "../models/view/sendView";
|
||||||
|
|
||||||
export class SearchService implements SearchServiceAbstraction {
|
export class SearchService implements SearchServiceAbstraction {
|
||||||
|
private static registeredPipeline = false;
|
||||||
|
|
||||||
indexedEntityId?: string = null;
|
indexedEntityId?: string = null;
|
||||||
private indexing = false;
|
private indexing = false;
|
||||||
private index: lunr.Index = null;
|
private index: lunr.Index = null;
|
||||||
@@ -31,9 +33,14 @@ export class SearchService implements SearchServiceAbstraction {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Currently have to ensure this is only done a single time. Lunr allows you to register a function
|
||||||
|
// multiple times but they will add a warning message to the console. The way they do that breaks when ran on a service worker.
|
||||||
|
if (!SearchService.registeredPipeline) {
|
||||||
|
SearchService.registeredPipeline = true;
|
||||||
//register lunr pipeline function
|
//register lunr pipeline function
|
||||||
lunr.Pipeline.registerFunction(this.normalizeAccentsPipelineFunction, "normalizeAccents");
|
lunr.Pipeline.registerFunction(this.normalizeAccentsPipelineFunction, "normalizeAccents");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
clearIndex(): void {
|
clearIndex(): void {
|
||||||
this.indexedEntityId = null;
|
this.indexedEntityId = null;
|
||||||
@@ -54,7 +61,6 @@ export class SearchService implements SearchServiceAbstraction {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logService.time("search indexing");
|
|
||||||
this.indexing = true;
|
this.indexing = true;
|
||||||
this.indexedEntityId = indexedEntityId;
|
this.indexedEntityId = indexedEntityId;
|
||||||
this.index = null;
|
this.index = null;
|
||||||
@@ -95,7 +101,7 @@ export class SearchService implements SearchServiceAbstraction {
|
|||||||
|
|
||||||
this.indexing = false;
|
this.indexing = false;
|
||||||
|
|
||||||
this.logService.timeEnd("search indexing");
|
this.logService.info("Finished search indexing");
|
||||||
}
|
}
|
||||||
|
|
||||||
async searchCiphers(
|
async searchCiphers(
|
||||||
|
|||||||
@@ -55,8 +55,11 @@ export class StateService<
|
|||||||
> implements StateServiceAbstraction<TAccount>
|
> implements StateServiceAbstraction<TAccount>
|
||||||
{
|
{
|
||||||
accounts = new BehaviorSubject<{ [userId: string]: TAccount }>({});
|
accounts = new BehaviorSubject<{ [userId: string]: TAccount }>({});
|
||||||
activeAccount = new BehaviorSubject<string>(null);
|
private activeAccountSubject = new BehaviorSubject<string>(null);
|
||||||
activeAccountUnlocked = new BehaviorSubject<boolean>(false);
|
activeAccount$ = this.activeAccountSubject.asObservable();
|
||||||
|
|
||||||
|
private activeAccountUnlockedSubject = new BehaviorSubject<boolean>(false);
|
||||||
|
activeAccountUnlocked$ = this.activeAccountUnlockedSubject.asObservable();
|
||||||
|
|
||||||
private hasBeenInited = false;
|
private hasBeenInited = false;
|
||||||
private isRecoveredSession = false;
|
private isRecoveredSession = false;
|
||||||
@@ -73,17 +76,17 @@ export class StateService<
|
|||||||
protected useAccountCache: boolean = true
|
protected useAccountCache: boolean = true
|
||||||
) {
|
) {
|
||||||
// If the account gets changed, verify the new account is unlocked
|
// If the account gets changed, verify the new account is unlocked
|
||||||
this.activeAccount.subscribe(async (userId) => {
|
this.activeAccountSubject.subscribe(async (userId) => {
|
||||||
if (userId == null && this.activeAccountUnlocked.getValue() == false) {
|
if (userId == null && this.activeAccountUnlockedSubject.getValue() == false) {
|
||||||
return;
|
return;
|
||||||
} else if (userId == null) {
|
} else if (userId == null) {
|
||||||
this.activeAccountUnlocked.next(false);
|
this.activeAccountUnlockedSubject.next(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: This should be refactored into AuthService or a similar service,
|
// FIXME: This should be refactored into AuthService or a similar service,
|
||||||
// as checking for the existance of the crypto key is a low level
|
// as checking for the existance of the crypto key is a low level
|
||||||
// implementation detail.
|
// implementation detail.
|
||||||
this.activeAccountUnlocked.next((await this.getCryptoMasterKey()) != null);
|
this.activeAccountUnlockedSubject.next((await this.getCryptoMasterKey()) != null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +128,7 @@ export class StateService<
|
|||||||
state.activeUserId = storedActiveUser;
|
state.activeUserId = storedActiveUser;
|
||||||
}
|
}
|
||||||
await this.pushAccounts();
|
await this.pushAccounts();
|
||||||
this.activeAccount.next(state.activeUserId);
|
this.activeAccountSubject.next(state.activeUserId);
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
@@ -154,7 +157,7 @@ export class StateService<
|
|||||||
await this.scaffoldNewAccountStorage(account);
|
await this.scaffoldNewAccountStorage(account);
|
||||||
await this.setLastActive(new Date().getTime(), { userId: account.profile.userId });
|
await this.setLastActive(new Date().getTime(), { userId: account.profile.userId });
|
||||||
await this.setActiveUser(account.profile.userId);
|
await this.setActiveUser(account.profile.userId);
|
||||||
this.activeAccount.next(account.profile.userId);
|
this.activeAccountSubject.next(account.profile.userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async setActiveUser(userId: string): Promise<void> {
|
async setActiveUser(userId: string): Promise<void> {
|
||||||
@@ -162,7 +165,7 @@ export class StateService<
|
|||||||
await this.updateState(async (state) => {
|
await this.updateState(async (state) => {
|
||||||
state.activeUserId = userId;
|
state.activeUserId = userId;
|
||||||
await this.storageService.save(keys.activeUserId, userId);
|
await this.storageService.save(keys.activeUserId, userId);
|
||||||
this.activeAccount.next(state.activeUserId);
|
this.activeAccountSubject.next(state.activeUserId);
|
||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -497,12 +500,12 @@ export class StateService<
|
|||||||
this.reconcileOptions(options, await this.defaultInMemoryOptions())
|
this.reconcileOptions(options, await this.defaultInMemoryOptions())
|
||||||
);
|
);
|
||||||
|
|
||||||
if (options.userId == this.activeAccount.getValue()) {
|
if (options.userId == this.activeAccountSubject.getValue()) {
|
||||||
const nextValue = value != null;
|
const nextValue = value != null;
|
||||||
|
|
||||||
// Avoid emitting if we are already unlocked
|
// Avoid emitting if we are already unlocked
|
||||||
if (this.activeAccountUnlocked.getValue() != nextValue) {
|
if (this.activeAccountUnlockedSubject.getValue() != nextValue) {
|
||||||
this.activeAccountUnlocked.next(nextValue);
|
this.activeAccountUnlockedSubject.next(nextValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -607,7 +610,7 @@ export class StateService<
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@withPrototypeForArrayMembers(CipherView)
|
@withPrototypeForArrayMembers(CipherView, CipherView.fromJSON)
|
||||||
async getDecryptedCiphers(options?: StorageOptions): Promise<CipherView[]> {
|
async getDecryptedCiphers(options?: StorageOptions): Promise<CipherView[]> {
|
||||||
return (
|
return (
|
||||||
await this.getAccount(this.reconcileOptions(options, await this.defaultInMemoryOptions()))
|
await this.getAccount(this.reconcileOptions(options, await this.defaultInMemoryOptions()))
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { ApiService } from "../../abstractions/api.service";
|
||||||
|
import { UserVerificationApiServiceAbstraction } from "../../abstractions/userVerification/userVerification-api.service.abstraction";
|
||||||
|
import { VerifyOTPRequest } from "../../models/request/account/verifyOTPRequest";
|
||||||
|
|
||||||
|
export class UserVerificationApiService implements UserVerificationApiServiceAbstraction {
|
||||||
|
constructor(private apiService: ApiService) {}
|
||||||
|
|
||||||
|
postAccountVerifyOTP(request: VerifyOTPRequest): Promise<void> {
|
||||||
|
return this.apiService.send("POST", "/accounts/verify-otp", request, true, false);
|
||||||
|
}
|
||||||
|
async postAccountRequestOTP(): Promise<void> {
|
||||||
|
return this.apiService.send("POST", "/accounts/request-otp", null, true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import { ApiService } from "../abstractions/api.service";
|
import { CryptoService } from "../../abstractions/crypto.service";
|
||||||
import { CryptoService } from "../abstractions/crypto.service";
|
import { I18nService } from "../../abstractions/i18n.service";
|
||||||
import { I18nService } from "../abstractions/i18n.service";
|
import { UserVerificationApiServiceAbstraction } from "../../abstractions/userVerification/userVerification-api.service.abstraction";
|
||||||
import { UserVerificationService as UserVerificationServiceAbstraction } from "../abstractions/userVerification.service";
|
import { UserVerificationService as UserVerificationServiceAbstraction } from "../../abstractions/userVerification/userVerification.service.abstraction";
|
||||||
import { VerificationType } from "../enums/verificationType";
|
import { VerificationType } from "../../enums/verificationType";
|
||||||
import { VerifyOTPRequest } from "../models/request/account/verifyOTPRequest";
|
import { VerifyOTPRequest } from "../../models/request/account/verifyOTPRequest";
|
||||||
import { SecretVerificationRequest } from "../models/request/secretVerificationRequest";
|
import { SecretVerificationRequest } from "../../models/request/secretVerificationRequest";
|
||||||
import { Verification } from "../types/verification";
|
import { Verification } from "../../types/verification";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for general-purpose user verification throughout the app.
|
* Used for general-purpose user verification throughout the app.
|
||||||
@@ -15,7 +15,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti
|
|||||||
constructor(
|
constructor(
|
||||||
private cryptoService: CryptoService,
|
private cryptoService: CryptoService,
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private apiService: ApiService
|
private userVerificationApiService: UserVerificationApiServiceAbstraction
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -56,7 +56,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti
|
|||||||
if (verification.type === VerificationType.OTP) {
|
if (verification.type === VerificationType.OTP) {
|
||||||
const request = new VerifyOTPRequest(verification.secret);
|
const request = new VerifyOTPRequest(verification.secret);
|
||||||
try {
|
try {
|
||||||
await this.apiService.postAccountVerifyOTP(request);
|
await this.userVerificationApiService.postAccountVerifyOTP(request);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(this.i18nService.t("invalidVerificationCode"));
|
throw new Error(this.i18nService.t("invalidVerificationCode"));
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti
|
|||||||
}
|
}
|
||||||
|
|
||||||
async requestOTP() {
|
async requestOTP() {
|
||||||
await this.apiService.postAccountRequestOTP();
|
await this.userVerificationApiService.postAccountRequestOTP();
|
||||||
}
|
}
|
||||||
|
|
||||||
private validateInput(verification: Verification) {
|
private validateInput(verification: Verification) {
|
||||||
@@ -9,7 +9,7 @@ export class WebCryptoFunctionService implements CryptoFunctionService {
|
|||||||
private crypto: Crypto;
|
private crypto: Crypto;
|
||||||
private subtle: SubtleCrypto;
|
private subtle: SubtleCrypto;
|
||||||
|
|
||||||
constructor(win: Window) {
|
constructor(win: Window | typeof global) {
|
||||||
this.crypto = typeof win.crypto !== "undefined" ? win.crypto : null;
|
this.crypto = typeof win.crypto !== "undefined" ? win.crypto : null;
|
||||||
this.subtle =
|
this.subtle =
|
||||||
!!this.crypto && typeof win.crypto.subtle !== "undefined" ? win.crypto.subtle : null;
|
!!this.crypto && typeof win.crypto.subtle !== "undefined" ? win.crypto.subtle : null;
|
||||||
|
|||||||
12
libs/common/src/types/authResponse.ts
Normal file
12
libs/common/src/types/authResponse.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { VerificationType } from "../enums/verificationType";
|
||||||
|
|
||||||
|
import { TwoFactorResponse } from "./twoFactorResponse";
|
||||||
|
|
||||||
|
export type AuthResponseBase = {
|
||||||
|
secret: string;
|
||||||
|
verificationType: VerificationType;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AuthResponse<T extends TwoFactorResponse> = AuthResponseBase & {
|
||||||
|
response: T;
|
||||||
|
};
|
||||||
14
libs/common/src/types/twoFactorResponse.ts
Normal file
14
libs/common/src/types/twoFactorResponse.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { TwoFactorAuthenticatorResponse } from "../models/response/twoFactorAuthenticatorResponse";
|
||||||
|
import { TwoFactorDuoResponse } from "../models/response/twoFactorDuoResponse";
|
||||||
|
import { TwoFactorEmailResponse } from "../models/response/twoFactorEmailResponse";
|
||||||
|
import { TwoFactorRecoverResponse } from "../models/response/twoFactorRescoverResponse";
|
||||||
|
import { TwoFactorWebAuthnResponse } from "../models/response/twoFactorWebAuthnResponse";
|
||||||
|
import { TwoFactorYubiKeyResponse } from "../models/response/twoFactorYubiKeyResponse";
|
||||||
|
|
||||||
|
export type TwoFactorResponse =
|
||||||
|
| TwoFactorRecoverResponse
|
||||||
|
| TwoFactorDuoResponse
|
||||||
|
| TwoFactorEmailResponse
|
||||||
|
| TwoFactorWebAuthnResponse
|
||||||
|
| TwoFactorAuthenticatorResponse
|
||||||
|
| TwoFactorYubiKeyResponse;
|
||||||
@@ -5,23 +5,48 @@ import { ipcMain } from "electron";
|
|||||||
import { AbstractStorageService } from "@bitwarden/common/abstractions/storage.service";
|
import { AbstractStorageService } from "@bitwarden/common/abstractions/storage.service";
|
||||||
import { NodeUtils } from "@bitwarden/common/misc/nodeUtils";
|
import { NodeUtils } from "@bitwarden/common/misc/nodeUtils";
|
||||||
|
|
||||||
|
// See: https://github.com/sindresorhus/electron-store/blob/main/index.d.ts
|
||||||
|
interface ElectronStoreOptions {
|
||||||
|
defaults: unknown;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type ElectronStoreConstructor = new (options: ElectronStoreOptions) => ElectronStore;
|
||||||
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
const Store = require("electron-store");
|
const Store: ElectronStoreConstructor = require("electron-store");
|
||||||
|
|
||||||
|
interface ElectronStore {
|
||||||
|
get: (key: string) => unknown;
|
||||||
|
set: (key: string, obj: unknown) => void;
|
||||||
|
delete: (key: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BaseOptions<T extends string> {
|
||||||
|
action: T;
|
||||||
|
key: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SaveOptions extends BaseOptions<"save"> {
|
||||||
|
obj: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Options = BaseOptions<"get"> | BaseOptions<"has"> | SaveOptions | BaseOptions<"remove">;
|
||||||
|
|
||||||
export class ElectronStorageService implements AbstractStorageService {
|
export class ElectronStorageService implements AbstractStorageService {
|
||||||
private store: any;
|
private store: ElectronStore;
|
||||||
|
|
||||||
constructor(dir: string, defaults = {}) {
|
constructor(dir: string, defaults = {}) {
|
||||||
if (!fs.existsSync(dir)) {
|
if (!fs.existsSync(dir)) {
|
||||||
NodeUtils.mkdirpSync(dir, "700");
|
NodeUtils.mkdirpSync(dir, "700");
|
||||||
}
|
}
|
||||||
const storeConfig: any = {
|
const storeConfig: ElectronStoreOptions = {
|
||||||
defaults: defaults,
|
defaults: defaults,
|
||||||
name: "data",
|
name: "data",
|
||||||
};
|
};
|
||||||
this.store = new Store(storeConfig);
|
this.store = new Store(storeConfig);
|
||||||
|
|
||||||
ipcMain.handle("storageService", (event, options) => {
|
ipcMain.handle("storageService", (event, options: Options) => {
|
||||||
switch (options.action) {
|
switch (options.action) {
|
||||||
case "get":
|
case "get":
|
||||||
return this.get(options.key);
|
return this.get(options.key);
|
||||||
@@ -45,7 +70,7 @@ export class ElectronStorageService implements AbstractStorageService {
|
|||||||
return Promise.resolve(val != null);
|
return Promise.resolve(val != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
save(key: string, obj: any): Promise<any> {
|
save(key: string, obj: unknown): Promise<void> {
|
||||||
if (obj instanceof Set) {
|
if (obj instanceof Set) {
|
||||||
obj = Array.from(obj);
|
obj = Array.from(obj);
|
||||||
}
|
}
|
||||||
@@ -53,7 +78,7 @@ export class ElectronStorageService implements AbstractStorageService {
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(key: string): Promise<any> {
|
remove(key: string): Promise<void> {
|
||||||
this.store.delete(key);
|
this.store.delete(key);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|||||||
15
package-lock.json
generated
15
package-lock.json
generated
@@ -30,7 +30,6 @@
|
|||||||
"big-integer": "^1.6.51",
|
"big-integer": "^1.6.51",
|
||||||
"bootstrap": "4.6.0",
|
"bootstrap": "4.6.0",
|
||||||
"braintree-web-drop-in": "^1.33.1",
|
"braintree-web-drop-in": "^1.33.1",
|
||||||
"browser-hrtime": "^1.1.8",
|
|
||||||
"bufferutil": "^4.0.6",
|
"bufferutil": "^4.0.6",
|
||||||
"chalk": "^4.1.0",
|
"chalk": "^4.1.0",
|
||||||
"commander": "^7.2.0",
|
"commander": "^7.2.0",
|
||||||
@@ -83,7 +82,7 @@
|
|||||||
"@storybook/angular": "^6.5.7",
|
"@storybook/angular": "^6.5.7",
|
||||||
"@storybook/builder-webpack5": "^6.5.7",
|
"@storybook/builder-webpack5": "^6.5.7",
|
||||||
"@storybook/manager-webpack5": "^6.5.7",
|
"@storybook/manager-webpack5": "^6.5.7",
|
||||||
"@types/chrome": "^0.0.139",
|
"@types/chrome": "^0.0.190",
|
||||||
"@types/duo_web_sdk": "^2.7.1",
|
"@types/duo_web_sdk": "^2.7.1",
|
||||||
"@types/firefox-webext-browser": "^82.0.0",
|
"@types/firefox-webext-browser": "^82.0.0",
|
||||||
"@types/inquirer": "^8.2.1",
|
"@types/inquirer": "^8.2.1",
|
||||||
@@ -12504,9 +12503,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/chrome": {
|
"node_modules/@types/chrome": {
|
||||||
"version": "0.0.139",
|
"version": "0.0.190",
|
||||||
"resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.139.tgz",
|
"resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.190.tgz",
|
||||||
"integrity": "sha512-YZDKFlSVGFp4zldJlO+PUpxMH8N9vLke0fD6K9PA+TzXxPXu8LBLo5X2dzlOs2N/n+uMdI1lw7OPT1Emop10lQ==",
|
"integrity": "sha512-lCwwIBfaD+PhG62qFB46mIBpD+xBIa+PedNB24KR9YnmJ0Zn9h0OwP1NQBhI8Cbu1rKwTQHTxhs7GhWGyUvinw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/filesystem": "*",
|
"@types/filesystem": "*",
|
||||||
@@ -52084,9 +52083,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/chrome": {
|
"@types/chrome": {
|
||||||
"version": "0.0.139",
|
"version": "0.0.190",
|
||||||
"resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.139.tgz",
|
"resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.190.tgz",
|
||||||
"integrity": "sha512-YZDKFlSVGFp4zldJlO+PUpxMH8N9vLke0fD6K9PA+TzXxPXu8LBLo5X2dzlOs2N/n+uMdI1lw7OPT1Emop10lQ==",
|
"integrity": "sha512-lCwwIBfaD+PhG62qFB46mIBpD+xBIa+PedNB24KR9YnmJ0Zn9h0OwP1NQBhI8Cbu1rKwTQHTxhs7GhWGyUvinw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/filesystem": "*",
|
"@types/filesystem": "*",
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
"@storybook/angular": "^6.5.7",
|
"@storybook/angular": "^6.5.7",
|
||||||
"@storybook/builder-webpack5": "^6.5.7",
|
"@storybook/builder-webpack5": "^6.5.7",
|
||||||
"@storybook/manager-webpack5": "^6.5.7",
|
"@storybook/manager-webpack5": "^6.5.7",
|
||||||
"@types/chrome": "^0.0.139",
|
"@types/chrome": "^0.0.190",
|
||||||
"@types/duo_web_sdk": "^2.7.1",
|
"@types/duo_web_sdk": "^2.7.1",
|
||||||
"@types/firefox-webext-browser": "^82.0.0",
|
"@types/firefox-webext-browser": "^82.0.0",
|
||||||
"@types/inquirer": "^8.2.1",
|
"@types/inquirer": "^8.2.1",
|
||||||
@@ -155,7 +155,6 @@
|
|||||||
"big-integer": "^1.6.51",
|
"big-integer": "^1.6.51",
|
||||||
"bootstrap": "4.6.0",
|
"bootstrap": "4.6.0",
|
||||||
"braintree-web-drop-in": "^1.33.1",
|
"braintree-web-drop-in": "^1.33.1",
|
||||||
"browser-hrtime": "^1.1.8",
|
|
||||||
"bufferutil": "^4.0.6",
|
"bufferutil": "^4.0.6",
|
||||||
"chalk": "^4.1.0",
|
"chalk": "^4.1.0",
|
||||||
"commander": "^7.2.0",
|
"commander": "^7.2.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user