diff --git a/jslib b/jslib index abb54f0073..72bf18f369 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit abb54f007305eabd77996623dd20cbe45345e82a +Subproject commit 72bf18f369068d36767794bdc0ca377f734cf373 diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index 65c3ed7464..946dba4b98 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -609,6 +609,9 @@ "exportWarningDesc": { "message": "This export contains your vault data in an unencrypted format. You should not store or send the exported file over unsecure channels (such as email). Delete it immediately after you are done using it." }, + "encExportWarningDesc": { + "message": "This export encrypts your data using your account's encryption key. If you ever rotate your account's encryption key you should export again since you will not be able to decrypt this export file." + }, "exportMasterPassword": { "message": "Enter your master password to export your vault data." }, @@ -1410,5 +1413,8 @@ }, "nativeMessagingInvalidEncryptionTitle": { "message": "Desktop communication interupted" + }, + "personalOwnershipSubmitError": { + "message": "Due to an Enterprise Policy, you are restricted from saving items to your personal vault. Change the Ownership option to an organization and choose from available Collections." } } diff --git a/src/background/main.background.ts b/src/background/main.background.ts index 2b2ddd8c58..c6282f0190 100644 --- a/src/background/main.background.ts +++ b/src/background/main.background.ts @@ -157,7 +157,7 @@ export default class MainBackground { const promise = this.nativeMessagingBackground.getResponse(); try { - await this.nativeMessagingBackground.send({command: 'biometricUnlock'}); + await this.nativeMessagingBackground.send({ command: 'biometricUnlock' }); } catch (e) { return Promise.reject(e); } @@ -243,7 +243,7 @@ export default class MainBackground { this.runtimeBackground = new RuntimeBackground(this, this.autofillService, this.cipherService, this.platformUtilsService as BrowserPlatformUtilsService, this.storageService, this.i18nService, this.analytics, this.notificationsService, this.systemService, this.vaultTimeoutService, - this.environmentService); + this.environmentService, this.policyService, this.userService); this.nativeMessagingBackground = new NativeMessagingBackground(this.storageService, this.cryptoService, this.cryptoFunctionService, this.vaultTimeoutService, this.runtimeBackground, this.i18nService, this.userService, this.messagingService); this.commandsBackground = new CommandsBackground(this, this.passwordGenerationService, @@ -290,7 +290,7 @@ export default class MainBackground { } async setIcon() { - if ((!chrome.browserAction && !this.sidebarAction)) { + if (!chrome.browserAction && !this.sidebarAction) { return; } diff --git a/src/background/runtime.background.ts b/src/background/runtime.background.ts index c6964bc232..8861dd60f0 100644 --- a/src/background/runtime.background.ts +++ b/src/background/runtime.background.ts @@ -11,8 +11,10 @@ import { ConstantsService } from 'jslib/services/constants.service'; import { EnvironmentService } from 'jslib/abstractions/environment.service'; import { I18nService } from 'jslib/abstractions/i18n.service'; import { NotificationsService } from 'jslib/abstractions/notifications.service'; +import { PolicyService } from 'jslib/abstractions/policy.service'; import { StorageService } from 'jslib/abstractions/storage.service'; import { SystemService } from 'jslib/abstractions/system.service'; +import { UserService } from 'jslib/abstractions/user.service'; import { VaultTimeoutService } from 'jslib/abstractions/vaultTimeout.service'; import { BrowserApi } from '../browser/browserApi'; @@ -22,6 +24,9 @@ import MainBackground from './main.background'; import { Analytics } from 'jslib/misc'; import { Utils } from 'jslib/misc/utils'; +import { OrganizationUserStatusType } from 'jslib/enums/organizationUserStatusType'; +import { PolicyType } from 'jslib/enums/policyType'; + export default class RuntimeBackground { private runtime: any; private autofillTimeout: any; @@ -33,7 +38,8 @@ export default class RuntimeBackground { private storageService: StorageService, private i18nService: I18nService, private analytics: Analytics, private notificationsService: NotificationsService, private systemService: SystemService, private vaultTimeoutService: VaultTimeoutService, - private environmentService: EnvironmentService) { + private environmentService: EnvironmentService, private policyService: PolicyService, + private userService: UserService) { this.runtime = chrome.runtime; // onInstalled listener must be wired up before anything else, so we do it in the ctor @@ -309,6 +315,11 @@ export default class RuntimeBackground { if (disabledAddLogin) { return; } + + if (!(await this.allowPersonalOwnership())) { + return; + } + // remove any old messages for this tab this.removeTabFromNotificationQueue(tab); this.main.notificationQueue.push({ @@ -413,8 +424,9 @@ export default class RuntimeBackground { const responseData: any = {}; if (responseCommand === 'notificationBarDataResponse') { responseData.neverDomains = await this.storageService.get(ConstantsService.neverDomainsKey); - responseData.disabledAddLoginNotification = await this.storageService.get( + const disableAddLoginFromOptions = await this.storageService.get( ConstantsService.disableAddLoginNotificationKey); + responseData.disabledAddLoginNotification = disableAddLoginFromOptions || !(await this.allowPersonalOwnership()); responseData.disabledChangedPasswordNotification = await this.storageService.get( ConstantsService.disableChangedPasswordNotificationKey); } else if (responseCommand === 'autofillerAutofillOnPageLoadEnabledResponse') { @@ -436,4 +448,20 @@ export default class RuntimeBackground { await BrowserApi.tabSendMessageData(tab, responseCommand, responseData); } + + private async allowPersonalOwnership(): Promise { + const personalOwnershipPolicies = await this.policyService.getAll(PolicyType.PersonalOwnership); + if (personalOwnershipPolicies != null) { + for (const policy of personalOwnershipPolicies) { + if (policy.enabled) { + const org = await this.userService.getOrganization(policy.organizationId); + if (org != null && org.enabled && org.usePolicies && !org.isAdmin + && org.status == OrganizationUserStatusType.Confirmed) { + return false; + } + } + } + } + return true; + } } diff --git a/src/content/sso.ts b/src/content/sso.ts index 326758b90a..508bc2aea3 100644 --- a/src/content/sso.ts +++ b/src/content/sso.ts @@ -10,4 +10,4 @@ window.addEventListener('message', (event) => { referrer: event.source.location.hostname, }); } -}, false) +}, false); diff --git a/src/popup/accounts/home.component.ts b/src/popup/accounts/home.component.ts index 838f5b6d69..04b4938249 100644 --- a/src/popup/accounts/home.component.ts +++ b/src/popup/accounts/home.component.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; -import { ConstantsService } from 'jslib/services/constants.service' +import { ConstantsService } from 'jslib/services/constants.service'; import { CryptoFunctionService } from 'jslib/abstractions/cryptoFunction.service'; import { EnvironmentService } from 'jslib/abstractions/environment.service'; import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; diff --git a/src/popup/accounts/two-factor.component.ts b/src/popup/accounts/two-factor.component.ts index 3395aae848..fe8d36ee1f 100644 --- a/src/popup/accounts/two-factor.component.ts +++ b/src/popup/accounts/two-factor.component.ts @@ -25,6 +25,7 @@ import { BroadcasterService } from 'jslib/angular/services/broadcaster.service'; import { TwoFactorComponent as BaseTwoFactorComponent } from 'jslib/angular/components/two-factor.component'; import { PopupUtilsService } from '../services/popup-utils.service'; +import { BrowserApi } from '../../browser/browserApi'; const BroadcasterSubscriptionId = 'TwoFactorComponent'; @@ -37,7 +38,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent { constructor(authService: AuthService, router: Router, i18nService: I18nService, apiService: ApiService, - platformUtilsService: PlatformUtilsService, syncService: SyncService, + platformUtilsService: PlatformUtilsService, private syncService: SyncService, environmentService: EnvironmentService, private ngZone: NgZone, private broadcasterService: BroadcasterService, private changeDetectorRef: ChangeDetectorRef, private popupUtilsService: PopupUtilsService, stateService: StateService, @@ -80,6 +81,20 @@ export class TwoFactorComponent extends BaseTwoFactorComponent { this.popupUtilsService.popOut(window); } } + + const queryParamsSub = this.route.queryParams.subscribe(async (qParams) => { + if (qParams.sso === 'true') { + super.onSuccessfulLogin = () => { + BrowserApi.reloadOpenWindows(); + const thisWindow = window.open('', '_self'); + thisWindow.close(); + return this.syncService.fullSync(true); + }; + if (queryParamsSub != null) { + queryParamsSub.unsubscribe(); + } + } + }); } ngOnDestroy() { diff --git a/src/popup/settings/export.component.html b/src/popup/settings/export.component.html index c04ff10cad..f4a90062c9 100644 --- a/src/popup/settings/export.component.html +++ b/src/popup/settings/export.component.html @@ -21,6 +21,7 @@
@@ -40,7 +41,13 @@
diff --git a/src/popup/vault/add-edit.component.html b/src/popup/vault/add-edit.component.html index 7a4c6c1cd0..65f344e29b 100644 --- a/src/popup/vault/add-edit.component.html +++ b/src/popup/vault/add-edit.component.html @@ -340,7 +340,7 @@ -
+
{{'ownership' | i18n}}
diff --git a/src/popup/vault/add-edit.component.ts b/src/popup/vault/add-edit.component.ts index 5a9872a4fd..fdecd141d8 100644 --- a/src/popup/vault/add-edit.component.ts +++ b/src/popup/vault/add-edit.component.ts @@ -15,6 +15,7 @@ import { FolderService } from 'jslib/abstractions/folder.service'; import { I18nService } from 'jslib/abstractions/i18n.service'; import { MessagingService } from 'jslib/abstractions/messaging.service'; import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; +import { PolicyService } from 'jslib/abstractions/policy.service'; import { StateService } from 'jslib/abstractions/state.service'; import { UserService } from 'jslib/abstractions/user.service'; @@ -36,9 +37,9 @@ export class AddEditComponent extends BaseAddEditComponent { userService: UserService, collectionService: CollectionService, messagingService: MessagingService, private route: ActivatedRoute, private router: Router, private location: Location, - eventService: EventService) { + eventService: EventService, policyService: PolicyService) { super(cipherService, folderService, i18nService, platformUtilsService, auditService, stateService, - userService, collectionService, messagingService, eventService); + userService, collectionService, messagingService, eventService, policyService); } async ngOnInit() { @@ -161,4 +162,9 @@ export class AddEditComponent extends BaseAddEditComponent { const u = (uri as any); u.showCurrentUris = !u.showCurrentUris; } + + allowOwnershipOptions(): boolean { + return (!this.editMode || this.cloneMode) && this.ownershipOptions + && (this.ownershipOptions.length > 1 || !this.allowPersonal); + } } diff --git a/src/services/autofill.service.ts b/src/services/autofill.service.ts index 9a67f33fab..7498248bbe 100644 --- a/src/services/autofill.service.ts +++ b/src/services/autofill.service.ts @@ -42,14 +42,14 @@ const FirstnameFieldNames: string[] = [ 'f-name', 'first-name', 'given-name', 'first-n', // German 'vorname' -] +]; const LastnameFieldNames: string[] = [ // English 'l-name', 'last-name', 's-name', 'surname', 'family-name', 'family-n', 'last-n', // German 'nachname', 'familienname' -] +]; const ExcludedAutofillTypes: string[] = ['radio', 'checkbox', 'hidden', 'file', 'button', 'image', 'reset', 'search']; diff --git a/tslint.json b/tslint.json index 7e4320f723..cb3f6b016f 100644 --- a/tslint.json +++ b/tslint.json @@ -49,6 +49,10 @@ "check-separator", "check-type" ], - "max-classes-per-file": false + "max-classes-per-file": false, + "semicolon": [ + true, + "always" + ] } }