diff --git a/jslib b/jslib index abb54f00730..72bf18f3690 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 65c3ed7464d..946dba4b988 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 2b2ddd8c584..c6282f01904 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 c6964bc232a..8861dd60f0b 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 326758b90ac..508bc2aea3a 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 838f5b6d694..04b49382490 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 3395aae8480..fe8d36ee1ff 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 c04ff10cadd..f4a90062c9f 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 7a4c6c1cd0e..65f344e29b2 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 5a9872a4fd9..fdecd141d8b 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 9a67f33fab9..7498248bbe3 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 7e4320f7236..cb3f6b016f4 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" + ] } }