diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 79ef6460b5..b091820ab3 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -1,3 +1,4 @@
+---
 name: Build
 
 on:
@@ -10,6 +11,7 @@ on:
 
 jobs:
   cloc:
+    name: CLOC
     runs-on: ubuntu-latest
     steps:
       - name: Checkout repo
@@ -24,6 +26,7 @@ jobs:
 
 
   setup:
+    name: Setup
     runs-on: ubuntu-latest
     outputs:
       repo_url: ${{ steps.gen_vars.outputs.repo_url }}
@@ -38,10 +41,11 @@ jobs:
           repo_url=https://github.com/$GITHUB_REPOSITORY.git
           adj_build_num=${GITHUB_SHA:0:7}
 
-          echo "::set-output name=repo_url::$repo_url" 
-          echo "::set-output name=adj_build_number::$adj_build_num" 
+          echo "::set-output name=repo_url::$repo_url"
+          echo "::set-output name=adj_build_number::$adj_build_num"
 
   locales-test:
+    name: Locales Test
     runs-on: ubuntu-latest
     needs: setup
     steps:
@@ -63,21 +67,21 @@ jobs:
              found_error=true
            fi
          done
-         
+
          if $found_error; then
            echo
            echo "Please fix 'extName' for the locales listed above."
            exit 1
          else
            echo "Test passed!"
-         fi 
+         fi
 
   build:
+    name: Build
     runs-on: windows-latest
-    needs: [ setup, locales-test ]
+    needs: [setup, locales-test]
     env:
-      REPO_URL: ${{ needs.setup.outputs.repo_url }}
-      BUILD_NUMBER: ${{ needs.setup.outputs.adj_build_number }}
+      _BUILD_NUMBER: ${{ needs.setup.outputs.adj_build_number }}
     steps:
       - name: Checkout repo
         uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
@@ -96,41 +100,41 @@ jobs:
           node --version
           npm --version
 
-      - name: npm setup & test
+      - name: NPM setup & test
         run: |
           npm install
           npm run dist
           npm run test
 
-      - name: gulp
+      - name: Gulp
         run: gulp ci
 
-      - name: Upload opera artifact
+      - name: Upload Opera artifact
         uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700
         with:
-          name: dist-opera-${{ env.BUILD_NUMBER }}.zip
-          path: dist/dist-opera-${{ env.BUILD_NUMBER }}.zip
+          name: dist-opera-${{ env._BUILD_NUMBER }}.zip
+          path: dist/dist-opera-${{ env._BUILD_NUMBER }}.zip
 
-      - name: Upload chrome artifact
+      - name: Upload Chrome artifact
         uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700
         with:
-          name: dist-chrome-${{ env.BUILD_NUMBER }}.zip
-          path: dist/dist-chrome-${{ env.BUILD_NUMBER }}.zip
+          name: dist-chrome-${{ env._BUILD_NUMBER }}.zip
+          path: dist/dist-chrome-${{ env._BUILD_NUMBER }}.zip
 
-      - name: Upload firefox artifact
+      - name: Upload Firefox artifact
         uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700
         with:
-          name: dist-firefox-${{ env.BUILD_NUMBER }}.zip
-          path: dist/dist-firefox-${{ env.BUILD_NUMBER }}.zip
+          name: dist-firefox-${{ env._BUILD_NUMBER }}.zip
+          path: dist/dist-firefox-${{ env._BUILD_NUMBER }}.zip
 
-      - name: Upload edge artifact
+      - name: Upload Edge artifact
         uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700
         with:
-          name: dist-edge-${{ env.BUILD_NUMBER }}.zip
-          path: dist/dist-edge-${{ env.BUILD_NUMBER }}.zip
+          name: dist-edge-${{ env._BUILD_NUMBER }}.zip
+          path: dist/dist-edge-${{ env._BUILD_NUMBER }}.zip
 
       - name: Upload coverage artifact
         uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700
         with:
-          name: coverage-${{ env.BUILD_NUMBER }}.zip
-          path: coverage/coverage-${{ env.BUILD_NUMBER }}.zip
+          name: coverage-${{ env._BUILD_NUMBER }}.zip
+          path: coverage/coverage-${{ env._BUILD_NUMBER }}.zip
diff --git a/.github/workflows/crowdin-sync.yml b/.github/workflows/crowdin-sync.yml
index 1adcb6144b..1f99c27e73 100644
--- a/.github/workflows/crowdin-sync.yml
+++ b/.github/workflows/crowdin-sync.yml
@@ -1,10 +1,11 @@
+---
 name: Crowdin Sync
 
 on:
   workflow_dispatch:
     inputs: {}
-  #schedule:
-  #  - cron: '0 0 * * *'
+# schedule:
+#   - cron: '0 0 * * *'
 
 jobs:
   crowdin-sync:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 9b98307bf0..bcce70efb3 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,3 +1,4 @@
+---
 name: Release
 
 on:
@@ -10,6 +11,7 @@ on:
 
 jobs:
   setup:
+    name: Setup
     runs-on: ubuntu-latest
     outputs:
       tag_version: ${{ steps.create_tags.outputs.tag_version }}
@@ -25,7 +27,7 @@ jobs:
             echo "==================================="
             exit 1
           fi
-      
+
       - name: Checkout repo
         uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
 
@@ -37,8 +39,8 @@ jobs:
           $build_num = [int]$env:GITHUB_RUN_NUMBER
           $adj_build_num = $build_num + 3000
 
-          echo "::set-output name=repo_url::$repo_url" 
-          echo "::set-output name=adj_build_number::$adj_build_num" 
+          echo "::set-output name=repo_url::$repo_url"
+          echo "::set-output name=adj_build_number::$adj_build_num"
 
       - name: Create Release Vars
         id: create_tags
@@ -74,6 +76,7 @@ jobs:
 
 
   locales-test:
+    name: Locales Test
     runs-on: ubuntu-latest
     needs: setup
     steps:
@@ -105,11 +108,12 @@ jobs:
          fi
 
   build:
+    name: Build
     runs-on: windows-latest
-    needs: [ setup, locales-test ]
+    needs: [setup, locales-test]
     env:
-      REPO_URL: ${{ needs.setup.outputs.repo_url }}
-      BUILD_NUMBER: ${{ needs.setup.outputs.adj_build_number }}
+      _REPO_URL: ${{ needs.setup.outputs.repo_url }}
+      _BUILD_NUMBER: ${{ needs.setup.outputs.adj_build_number }}
     steps:
       - name: Checkout repo
         uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
@@ -128,84 +132,84 @@ jobs:
           node --version
           npm --version
 
-      - name: npm setup & test
+      - name: NPM setup & test
         run: |
           npm install
           npm run dist
           npm run test
 
-      - name: gulp
+      - name: Gulp
         run: gulp ci
 
       - name: Build sources for reviewers
         shell: cmd
         run: |
           mkdir dist\Source
-          call git clone %REPO_URL% dist\Source
+          call git clone %_REPO_URL% dist\Source
           cd dist\Source
           call git checkout %GITHUB_SHA%
           call git submodule update --init --recursive
           cd ../
           del /S/Q "Source\.git\objects\pack\*"
-          call 7z a browser-source-%BUILD_NUMBER%.zip "Source\*"
+          call 7z a browser-source-%_BUILD_NUMBER%.zip "Source\*"
 
-      - name: upload opera release asset
+      - name: Upload Opera release asset
         uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         with:
           upload_url: ${{ needs.setup.outputs.release_upload_url }}
-          asset_name: dist-opera-${{ env.BUILD_NUMBER }}.zip
-          asset_path: dist/dist-opera-${{ env.BUILD_NUMBER }}.zip
+          asset_name: dist-opera-${{ env._BUILD_NUMBER }}.zip
+          asset_path: dist/dist-opera-${{ env._BUILD_NUMBER }}.zip
           asset_content_type: application
 
-      - name: upload chrome release asset
+      - name: Upload Chrome release asset
         uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         with:
           upload_url: ${{ needs.setup.outputs.release_upload_url }}
-          asset_name: dist-chrome-${{ env.BUILD_NUMBER }}.zip
-          asset_path: dist/dist-chrome-${{ env.BUILD_NUMBER }}.zip
+          asset_name: dist-chrome-${{ env._BUILD_NUMBER }}.zip
+          asset_path: dist/dist-chrome-${{ env._BUILD_NUMBER }}.zip
           asset_content_type: application/zip
 
-      - name: upload firefox release asset
+      - name: Upload Firefox release asset
         uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         with:
           upload_url: ${{ needs.setup.outputs.release_upload_url }}
-          asset_name: dist-firefox-${{ env.BUILD_NUMBER }}.zip
-          asset_path: dist/dist-firefox-${{ env.BUILD_NUMBER }}.zip
+          asset_name: dist-firefox-${{ env._BUILD_NUMBER }}.zip
+          asset_path: dist/dist-firefox-${{ env._BUILD_NUMBER }}.zip
           asset_content_type: application/zip
 
-      - name: upload edge release asset
+      - name: Upload Edge release asset
         uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         with:
           upload_url: ${{ needs.setup.outputs.release_upload_url }}
-          asset_name: dist-edge-${{ env.BUILD_NUMBER }}.zip
-          asset_path: dist/dist-edge-${{ env.BUILD_NUMBER }}.zip
+          asset_name: dist-edge-${{ env._BUILD_NUMBER }}.zip
+          asset_path: dist/dist-edge-${{ env._BUILD_NUMBER }}.zip
           asset_content_type: application/zip
 
-      - name: upload browser source zip release asset
+      - name: Upload browser source zip release asset
         uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         with:
           upload_url: ${{ needs.setup.outputs.release_upload_url }}
-          asset_name: browser-source-${{ env.BUILD_NUMBER }}.zip
-          asset_path: dist/browser-source-${{ env.BUILD_NUMBER }}.zip
+          asset_name: browser-source-${{ env._BUILD_NUMBER }}.zip
+          asset_path: dist/browser-source-${{ env._BUILD_NUMBER }}.zip
           asset_content_type: application/zip
 
-      - name: upload coverage release asset
+      - name: Upload coverage release asset
         if: false
         uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         with:
           upload_url: ${{ needs.setup.outputs.release_upload_url }}
-          asset_name: coverage-${{ env.BUILD_NUMBER }}.zip
-          asset_path: coverage/coverage-${{ env.BUILD_NUMBER }}.zip
+          asset_name: coverage-${{ env._BUILD_NUMBER }}.zip
+          asset_path: coverage/coverage-${{ env._BUILD_NUMBER }}.zip
           asset_content_type: application/zip
diff --git a/jslib b/jslib
index 1f0127966e..30419a625f 160000
--- a/jslib
+++ b/jslib
@@ -1 +1 @@
-Subproject commit 1f0127966e85aa29f9e50144de9b2a03b00de5d4
+Subproject commit 30419a625fbdeefee1b0d0c24ee1d26064b17ba2
diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json
index 643d21d913..7dfa637610 100644
--- a/src/_locales/en/messages.json
+++ b/src/_locales/en/messages.json
@@ -88,6 +88,9 @@
   "generatePasswordCopied": {
     "message": "Generate Password (copied)"
   },
+  "copyElementIdentifier": {
+    "message": "Copy Custom Field Name"
+  },
   "noMatchingLogins": {
     "message": "No matching logins."
   },
@@ -1761,5 +1764,8 @@
   },
   "updateMasterPasswordWarning": {
     "message": "Your Master Password was recently changed by an administrator in your organization. In order to access the vault, you must update it now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour."
+  },
+  "selectFolder": {
+    "message": "Select folder..."
   }
 }
diff --git a/src/background/contextMenus.background.ts b/src/background/contextMenus.background.ts
index 19ee4421c2..f690d28320 100644
--- a/src/background/contextMenus.background.ts
+++ b/src/background/contextMenus.background.ts
@@ -29,6 +29,8 @@ export default class ContextMenusBackground {
         this.contextMenus.onClicked.addListener(async (info: any, tab: any) => {
             if (info.menuItemId === 'generate-password') {
                 await this.generatePasswordToClipboard();
+            } else if (info.menuItemId === 'copy-identifier') {
+                await this.getClickedElement();
             } else if (info.parentMenuItemId === 'autofill' ||
                 info.parentMenuItemId === 'copy-username' ||
                 info.parentMenuItemId === 'copy-password' ||
@@ -45,6 +47,15 @@ export default class ContextMenusBackground {
         this.passwordGenerationService.addHistory(password);
     }
 
+    private async getClickedElement() {
+        const tab = await BrowserApi.getTabFromCurrentWindow();
+        if (tab == null) {
+            return;
+        }
+
+        BrowserApi.tabSendMessageData(tab, 'getClickedElement');
+    }
+
     private async cipherAction(info: any) {
         const id = info.menuItemId.split('_')[1];
         if (id === 'noop') {
diff --git a/src/background/main.background.ts b/src/background/main.background.ts
index 2e7fa19fac..f987591ca7 100644
--- a/src/background/main.background.ts
+++ b/src/background/main.background.ts
@@ -244,7 +244,7 @@ export default class MainBackground {
         this.runtimeBackground = new RuntimeBackground(this, this.autofillService, this.cipherService,
             this.platformUtilsService as BrowserPlatformUtilsService, this.storageService, this.i18nService,
             this.notificationsService, this.systemService, this.vaultTimeoutService,
-            this.environmentService, this.policyService, this.userService, this.messagingService);
+            this.environmentService, this.policyService, this.userService, this.messagingService, this.folderService);
         this.nativeMessagingBackground = new NativeMessagingBackground(this.storageService, this.cryptoService, this.cryptoFunctionService,
             this.vaultTimeoutService, this.runtimeBackground, this.i18nService, this.userService, this.messagingService, this.appIdService,
             this.platformUtilsService);
@@ -512,6 +512,14 @@ export default class MainBackground {
             title: this.i18nService.t('generatePasswordCopied'),
         });
 
+        await this.contextMenusCreate({
+            type: 'normal',
+            id: 'copy-identifier',
+            parentId: 'root',
+            contexts: ['all'],
+            title: this.i18nService.t('copyElementIdentifier'),
+        });
+
         this.buildingContextMenu = false;
     }
 
diff --git a/src/background/runtime.background.ts b/src/background/runtime.background.ts
index e51e5c8161..583cc29f77 100644
--- a/src/background/runtime.background.ts
+++ b/src/background/runtime.background.ts
@@ -6,6 +6,7 @@ import { LoginView } from 'jslib-common/models/view/loginView';
 
 import { CipherService } from 'jslib-common/abstractions/cipher.service';
 import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
+import { FolderService } from 'jslib-common/abstractions/folder.service';
 import { I18nService } from 'jslib-common/abstractions/i18n.service';
 import { MessagingService } from 'jslib-common/abstractions/messaging.service';
 import { NotificationsService } from 'jslib-common/abstractions/notifications.service';
@@ -39,7 +40,8 @@ export default class RuntimeBackground {
         private notificationsService: NotificationsService,
         private systemService: SystemService, private vaultTimeoutService: VaultTimeoutService,
         private environmentService: EnvironmentService, private policyService: PolicyService,
-        private userService: UserService, private messagingService: MessagingService) {
+        private userService: UserService, private messagingService: MessagingService,
+        private folderService: FolderService) {
 
         // onInstalled listener must be wired up before anything else, so we do it in the ctor
         chrome.runtime.onInstalled.addListener((details: any) => {
@@ -107,7 +109,7 @@ export default class RuntimeBackground {
                 this.removeTabFromNotificationQueue(sender.tab);
                 break;
             case 'bgAddSave':
-                await this.saveAddLogin(sender.tab);
+                await this.saveAddLogin(sender.tab, msg.folder);
                 break;
             case 'bgChangeSave':
                 await this.saveChangePassword(sender.tab);
@@ -195,6 +197,8 @@ export default class RuntimeBackground {
                     type: 'info',
                 });
                 break;
+            case 'getClickedElementResponse':
+                this.platformUtilsService.copyToClipboard(msg.identifier, { window: window });
             default:
                 break;
         }
@@ -216,7 +220,7 @@ export default class RuntimeBackground {
         this.pageDetailsToAutoFill = [];
     }
 
-    private async saveAddLogin(tab: any) {
+    private async saveAddLogin(tab: any, folderId: string) {
         if (await this.vaultTimeoutService.isLocked()) {
             return;
         }
@@ -247,6 +251,13 @@ export default class RuntimeBackground {
             model.type = CipherType.Login;
             model.login = loginModel;
 
+            if (!Utils.isNullOrWhitespace(folderId)) {
+                const folders = await this.folderService.getAllDecrypted();
+                if (folders.some(x => x.id === folderId)) {
+                    model.folderId = folderId;
+                }
+            }
+
             const cipher = await this.cipherService.encrypt(model);
             await this.cipherService.saveWithServer(cipher);
         }
@@ -450,24 +461,14 @@ export default class RuntimeBackground {
                 notificationChangeSave: this.i18nService.t('notificationChangeSave'),
                 notificationChangeDesc: this.i18nService.t('notificationChangeDesc'),
             };
+        } else if (responseCommand === 'notificationBarGetFoldersList') {
+            responseData.folders = await this.folderService.getAllDecrypted();
         }
 
         await BrowserApi.tabSendMessageData(tab, responseCommand, responseData);
     }
 
     private async allowPersonalOwnership(): Promise<boolean> {
-        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.canManagePolicies
-                        && org.status === OrganizationUserStatusType.Confirmed) {
-                        return false;
-                    }
-                }
-            }
-        }
-        return true;
+        return !await this.policyService.policyAppliesToUser(PolicyType.PersonalOwnership);
     }
 }
diff --git a/src/content/contextMenuHandler.ts b/src/content/contextMenuHandler.ts
new file mode 100644
index 0000000000..6aae8ca168
--- /dev/null
+++ b/src/content/contextMenuHandler.ts
@@ -0,0 +1,45 @@
+const inputTags = ['input', 'textarea', 'select'];
+const attributes = ['id', 'name', 'label-aria', 'placeholder'];
+let clickedEl: HTMLElement = null;
+
+// Find the best attribute to be used as the Name for an element in a custom field.
+function getClickedElementIdentifier() {
+    if (clickedEl == null) {
+        return 'Unable to identify clicked element.'
+    }
+
+    if (!inputTags.includes(clickedEl.nodeName.toLowerCase())) {
+        return 'Invalid element type.';
+    }
+
+    for (const attr of attributes) {
+        const attributeValue = clickedEl.getAttribute(attr);
+        const selector = '[' + attr + '="' + attributeValue + '"]';
+        if (!isNullOrEmpty(attributeValue) && document.querySelectorAll(selector)?.length === 1) {
+            return attributeValue;
+        }
+    }
+    return 'No unique identifier found.';
+}
+
+function isNullOrEmpty(s: string) {
+    return s == null || s === '';
+}
+
+// We only have access to the element that's been clicked when the context menu is first opened.
+// Remember it for use later.
+document.addEventListener('contextmenu', event => {
+    clickedEl = event.target as HTMLElement;
+});
+
+// Runs when the 'Copy Custom Field Name' context menu item is actually clicked.
+chrome.runtime.onMessage.addListener(event => {
+    if (event.command === 'getClickedElement') {
+        const identifier = getClickedElementIdentifier();
+        chrome.runtime.sendMessage({
+            command: 'getClickedElementResponse',
+            sender: 'contextMenuHandler',
+            identifier: identifier,
+        });
+    }
+});
diff --git a/src/manifest.json b/src/manifest.json
index 74146f72dc..cb79e00627 100644
--- a/src/manifest.json
+++ b/src/manifest.json
@@ -20,7 +20,8 @@
       "js": [
         "content/autofill.js",
         "content/autofiller.js",
-        "content/notificationBar.js"
+        "content/notificationBar.js",
+        "content/contextMenuHandler.js"
       ],
       "matches": [
         "http://*/*",
diff --git a/src/notification/bar.html b/src/notification/bar.html
index 065ca944bb..0403ad1b82 100644
--- a/src/notification/bar.html
+++ b/src/notification/bar.html
@@ -27,8 +27,11 @@
             <tbody>
                 <tr>
                     <td class="add-text"></td>
-                    <td align="right" class="add-buttons">
+                    <td align="right">
                         <button class="never-save link"></button>
+                    </td>
+                    <td align="right" class="add-buttons">
+                        <select class="select-folder"></select>
                         <button class="add-save"></button>
                     </td>
                 </tr>
diff --git a/src/notification/bar.js b/src/notification/bar.js
index a5e55ca664..7bcd2b2eef 100644
--- a/src/notification/bar.js
+++ b/src/notification/bar.js
@@ -17,7 +17,6 @@ document.addEventListener('DOMContentLoaded', () => {
 
     // delay 50ms so that we get proper body dimensions
     setTimeout(load, 50);
-    
 
     function load() {
         var closeButton = document.getElementById('close-button'),
@@ -34,10 +33,12 @@ document.addEventListener('DOMContentLoaded', () => {
         if (bodyRect.width < 768) {
             document.querySelector('#template-add .add-save').textContent = i18n.yes;
             document.querySelector('#template-add .never-save').textContent = i18n.never;
+            document.querySelector('#template-add .select-folder').style.display = 'none';
             document.querySelector('#template-change .change-save').textContent = i18n.yes;
         } else {
             document.querySelector('#template-add .add-save').textContent = i18n.notificationAddSave;
             document.querySelector('#template-add .never-save').textContent = i18n.notificationNeverSave;
+            document.querySelector('#template-add .select-folder').style.display = 'initial';
             document.querySelector('#template-change .change-save').textContent = i18n.notificationChangeSave;
         }
 
@@ -53,7 +54,8 @@ document.addEventListener('DOMContentLoaded', () => {
             addButton.addEventListener('click', (e) => {
                 e.preventDefault();
                 sendPlatformMessage({
-                    command: 'bgAddSave'
+                    command: 'bgAddSave',
+                    folder: document.getElementById("select-folder").value,
                 });
             });
 
@@ -63,6 +65,17 @@ document.addEventListener('DOMContentLoaded', () => {
                     command: 'bgNeverSave'
                 });
             });
+
+            const responseFoldersCommand = 'notificationBarGetFoldersList';
+            chrome.runtime.onMessage.addListener((msg) => {
+                if (msg.command === responseFoldersCommand && msg.data) {
+                    fillSelectorWithFolders(msg.data.folders);
+                }
+            });
+            sendPlatformMessage({
+                command: 'bgGetDataForTab',
+                responseCommand: responseFoldersCommand
+            });
         } else if (getQueryVariable('change')) {
             setContent(document.getElementById('template-change'));
             var changeButton = document.querySelector('#template-change-clone .change-save');
@@ -120,4 +133,13 @@ document.addEventListener('DOMContentLoaded', () => {
     function sendPlatformMessage(msg) {
         chrome.runtime.sendMessage(msg);
     }
+
+    function fillSelectorWithFolders(folders) {
+        const select = document.querySelector('#template-add-clone .select-folder');
+        select.appendChild(new Option(chrome.i18n.getMessage('selectFolder'), null, true));
+        folders.forEach((folder) => {
+            //Select "No Folder" (id=null) folder by default
+            select.appendChild(new Option(folder.name, folder.id || '', false));
+        });
+    }
 });
diff --git a/src/notification/bar.scss b/src/notification/bar.scss
index 1f673d5255..2705ed324b 100644
--- a/src/notification/bar.scss
+++ b/src/notification/bar.scss
@@ -82,7 +82,7 @@ button.link {
     }
 
 body[class*='lang-en'] .add-buttons {
-    width: 175px;
+    width: 50px;
 }
 
 @media (min-width: 768px) {
@@ -96,3 +96,4 @@ body[class*='lang-en'] .add-buttons {
         display: none;
     }
 }
+
diff --git a/src/popup/accounts/environment.component.html b/src/popup/accounts/environment.component.html
index 5654fdc367..dbacca585a 100644
--- a/src/popup/accounts/environment.component.html
+++ b/src/popup/accounts/environment.component.html
@@ -1,4 +1,4 @@
-<form #form class="modal-content" (ngSubmit)="submit()">
+<form #form (ngSubmit)="submit()">
     <header>
         <div class="left">
             <a routerLink="/home">{{'close' | i18n}}</a>
diff --git a/src/popup/accounts/set-password.component.html b/src/popup/accounts/set-password.component.html
index 53ebcbd33a..d0bbc45a64 100644
--- a/src/popup/accounts/set-password.component.html
+++ b/src/popup/accounts/set-password.component.html
@@ -20,22 +20,7 @@
         <div *ngIf="!syncLoading">
             <div class="box">
                 <app-callout type="tip">{{'ssoCompleteRegistration' | i18n}}</app-callout>
-                <app-callout type="info" *ngIf="enforcedPolicyOptions">
-                    {{'masterPasswordPolicyInEffect' | i18n}}
-                    <ul>
-                        <li *ngIf="enforcedPolicyOptions?.minComplexity > 0">
-                            {{'policyInEffectMinComplexity' | i18n : getPasswordScoreAlertDisplay()}}
-                        </li>
-                        <li *ngIf="enforcedPolicyOptions?.minLength > 0">
-                            {{'policyInEffectMinLength' | i18n : enforcedPolicyOptions?.minLength.toString()}}
-                        </li>
-                        <li *ngIf="enforcedPolicyOptions?.requireUpper">{{'policyInEffectUppercase' | i18n}}</li>
-                        <li *ngIf="enforcedPolicyOptions?.requireLower">{{'policyInEffectLowercase' | i18n}}</li>
-                        <li *ngIf="enforcedPolicyOptions?.requireNumbers">{{'policyInEffectNumbers' | i18n}}</li>
-                        <li *ngIf="enforcedPolicyOptions?.requireSpecial">
-                            {{'policyInEffectSpecial' | i18n : '!@#$%^&*'}}
-                        </li>
-                    </ul>
+                <app-callout type="info" [enforcedPolicyOptions]="enforcedPolicyOptions" *ngIf="enforcedPolicyOptions">
                 </app-callout>
             </div>
             <div class="box">
diff --git a/src/popup/accounts/two-factor.component.ts b/src/popup/accounts/two-factor.component.ts
index dd08cd5fbb..65f210dc62 100644
--- a/src/popup/accounts/two-factor.component.ts
+++ b/src/popup/accounts/two-factor.component.ts
@@ -53,7 +53,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
             return syncService.fullSync(true).then(async () => {
                 if (await this.userService.getForcePasswordReset()) {
                     this.router.navigate(['update-temp-password']);
-                };
+                }
             });
         };
         super.successRoute = '/tabs/vault';
diff --git a/src/popup/accounts/update-temp-password.component.html b/src/popup/accounts/update-temp-password.component.html
index df888ea1b5..91ce4d5cbf 100644
--- a/src/popup/accounts/update-temp-password.component.html
+++ b/src/popup/accounts/update-temp-password.component.html
@@ -17,22 +17,7 @@
         <app-callout type="warning" title="{{'updateMasterPassword' | i18n}}">
             {{'updateMasterPasswordWarning' | i18n}}
         </app-callout>
-        <app-callout type="info" *ngIf="enforcedPolicyOptions">
-            {{'masterPasswordPolicyInEffect' | i18n}}
-            <ul>
-                <li *ngIf="enforcedPolicyOptions?.minComplexity > 0">
-                    {{'policyInEffectMinComplexity' | i18n : getPasswordScoreAlertDisplay()}}
-                </li>
-                <li *ngIf="enforcedPolicyOptions?.minLength > 0">
-                    {{'policyInEffectMinLength' | i18n : enforcedPolicyOptions?.minLength.toString()}}
-                </li>
-                <li *ngIf="enforcedPolicyOptions?.requireUpper">{{'policyInEffectUppercase' | i18n}}</li>
-                <li *ngIf="enforcedPolicyOptions?.requireLower">{{'policyInEffectLowercase' | i18n}}</li>
-                <li *ngIf="enforcedPolicyOptions?.requireNumbers">{{'policyInEffectNumbers' | i18n}}</li>
-                <li *ngIf="enforcedPolicyOptions?.requireSpecial">
-                    {{'policyInEffectSpecial' | i18n : '!@#$%^&*'}}
-                </li>
-            </ul>
+        <app-callout type="info" [enforcedPolicyOptions]="enforcedPolicyOptions" *ngIf="enforcedPolicyOptions">
         </app-callout>
         <div class="box">
             <div class="box-content">
@@ -59,8 +44,9 @@
                         </div>
                     </div>
                     <div class="progress">
-                        <div class="progress-bar bg-{{masterPasswordScoreStyle.Color}}" role="progressbar" aria-valuenow="0"
-                            aria-valuemin="0" aria-valuemax="100" [ngStyle]="{width: (masterPasswordScoreStyle.Width + '%')}"
+                        <div class="progress-bar bg-{{masterPasswordScoreStyle.Color}}" role="progressbar"
+                            aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"
+                            [ngStyle]="{width: (masterPasswordScoreStyle.Width + '%')}"
                             attr.aria-valuenow="{{masterPasswordScoreStyle.Width}}"></div>
                     </div>
                 </div>
diff --git a/src/popup/app.component.ts b/src/popup/app.component.ts
index acc78d54ce..b9551efb38 100644
--- a/src/popup/app.component.ts
+++ b/src/popup/app.component.ts
@@ -106,8 +106,6 @@ export class AppComponent implements OnInit {
                 });
             } else if (msg.command === 'showDialog') {
                 await this.showDialog(msg);
-            } else if (msg.command === 'showPasswordDialog') {
-                await this.showPasswordDialog(msg);
             } else if (msg.command === 'showToast') {
                 this.ngZone.run(() => {
                     this.showToast(msg);
@@ -251,30 +249,4 @@ export class AppComponent implements OnInit {
             confirmed: confirmed.value,
         });
     }
-
-    private async showPasswordDialog(msg: any) {
-        const platformUtils = this.platformUtilsService as BrowserPlatformUtilsService;
-        const result = await Swal.fire({
-            heightAuto: false,
-            titleText: msg.title,
-            input: 'password',
-            text: msg.body,
-            confirmButtonText: this.i18nService.t('ok'),
-            showCancelButton: true,
-            cancelButtonText: this.i18nService.t('cancel'),
-            inputAttributes: {
-                autocapitalize: 'off',
-                autocorrect: 'off',
-            },
-            inputValidator: async (value: string): Promise<any> => {
-                if (await platformUtils.resolvePasswordDialogPromise(msg.dialogId, false, value)) {
-                    return false;
-                }
-
-                return this.i18nService.t('invalidMasterPassword');
-            },
-        });
-
-        platformUtils.resolvePasswordDialogPromise(msg.dialogId, true, null);
-    }
 }
diff --git a/src/popup/app.module.ts b/src/popup/app.module.ts
index 0972131644..9702c56731 100644
--- a/src/popup/app.module.ts
+++ b/src/popup/app.module.ts
@@ -72,6 +72,7 @@ import { SearchCiphersPipe } from 'jslib-angular/pipes/search-ciphers.pipe';
 
 import { ActionButtonsComponent } from './components/action-buttons.component';
 import { CipherRowComponent } from './components/cipher-row.component';
+import { PasswordRepromptComponent } from './components/password-reprompt.component';
 import { PopOutComponent } from './components/pop-out.component';
 import { SendListComponent } from './components/send-list.component';
 
@@ -240,6 +241,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
         TwoFactorComponent,
         UpdateTempPasswordComponent,
         ViewComponent,
+        PasswordRepromptComponent,
     ],
     entryComponents: [],
     providers: [
diff --git a/src/popup/components/password-reprompt.component.html b/src/popup/components/password-reprompt.component.html
new file mode 100644
index 0000000000..6a5e670dea
--- /dev/null
+++ b/src/popup/components/password-reprompt.component.html
@@ -0,0 +1,38 @@
+<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="confirmUserTitle">
+    <div class="modal-dialog modal-dialog-scrollable" role="document">
+        <form class="modal-content" #form (ngSubmit)="submit()">
+            <div class="modal-body">
+                <div class="box">
+                    <div class="box-header">{{'passwordConfirmation' | i18n}}</div>
+                    <div class="box-content">
+                        <div class="box-content-row box-content-row-flex" appBoxRow>
+                            <div class="row-main">
+                                <label for="masterPassword">{{'masterPass' | i18n}}</label>
+                                <input id="masterPassword" type="{{showPassword ? 'text' : 'password'}}" name="MasterPassword"
+                                    class="monospaced" [(ngModel)]="masterPassword" required appAutofocus>
+                            </div>
+                            <div class="action-buttons">
+                                <a class="row-btn" href="#" appStopClick appBlurClick role="button"
+                                    appA11yTitle="{{'toggleVisibility' | i18n}}" (click)="togglePassword()">
+                                    <i class="fa fa-lg" aria-hidden="true"
+                                        [ngClass]="{'fa-eye': !showPassword, 'fa-eye-slash': showPassword}"></i>
+                                </a>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="box-footer">
+                        {{'passwordConfirmationDesc' | i18n}}
+                    </div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="submit" class="btn btn-primary btn-submit" appBlurClick>
+                    <span>{{'ok' | i18n}}</span>
+                </button>
+                <button type="button" class="btn btn-outline-secondary" data-dismiss="modal">
+                    {{'cancel' | i18n}}
+                </button>
+            </div>
+        </form>
+    </div>
+</div>
diff --git a/src/popup/components/password-reprompt.component.ts b/src/popup/components/password-reprompt.component.ts
new file mode 100644
index 0000000000..b3204f9422
--- /dev/null
+++ b/src/popup/components/password-reprompt.component.ts
@@ -0,0 +1,8 @@
+import { Component } from '@angular/core';
+
+import { PasswordRepromptComponent as BasePasswordRepromptComponent } from 'jslib-angular/components/password-reprompt.component';
+
+@Component({
+    templateUrl: 'password-reprompt.component.html',
+})
+export class PasswordRepromptComponent extends BasePasswordRepromptComponent {}
diff --git a/src/popup/scss/modal.scss b/src/popup/scss/modal.scss
new file mode 100644
index 0000000000..d7ae2fa80c
--- /dev/null
+++ b/src/popup/scss/modal.scss
@@ -0,0 +1,351 @@
+@import "variables.scss";
+
+$white: white;
+$black: black;
+$line-height-base: 14px;
+$border-radius-lg: $border-radius;
+
+// ref: https://github.com/twbs/bootstrap/blob/v4-dev/scss/_variables.scss
+
+$grid-breakpoints: ( xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px ) !default;
+
+$zindex-modal-backdrop: 1040 !default;
+$zindex-modal: 1050 !default;
+
+// Padding applied to the modal body
+$modal-inner-padding: 10px !default;
+
+$modal-dialog-margin: .5rem !default;
+$modal-dialog-margin-y-sm-up: 1.75rem !default;
+
+$modal-title-line-height: $line-height-base !default;
+
+//$modal-content-bg: $background-color-alt !default;
+$modal-content-border-color: rgba($black, .2) !default;
+$modal-content-border-width: 1px !default;
+$modal-content-box-shadow-xs: none;
+$modal-content-box-shadow-sm-up: none;
+
+$modal-backdrop-bg: $black !default;
+$modal-backdrop-opacity: .5 !default;
+$modal-header-border-color: $border-color-dark !default;
+$modal-footer-border-color: $modal-header-border-color !default;
+$modal-header-border-width: $modal-content-border-width !default;
+$modal-footer-border-width: $modal-header-border-width !default;
+$modal-header-padding: 12px !default;
+
+$modal-lg: 800px !default;
+$modal-md: 500px !default;
+$modal-sm: 300px !default;
+
+$modal-transition: transform .3s ease-out !default;
+
+$close-font-size: $font-size-base * 1.5 !default;
+$close-font-weight: bold !default;
+$close-color: $black !default;
+$close-text-shadow: 0 1px 0 $white !default;
+
+// ref: https://github.com/twbs/bootstrap/blob/v4-dev/scss/mixins/_breakpoints.scss
+
+@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) {
+    $min: breakpoint-min($name, $breakpoints);
+
+    @if $min {
+        @media (min-width: $min) {
+            @content;
+        }
+    }
+    @else {
+        @content;
+    }
+}
+
+@function breakpoint-min($name, $breakpoints: $grid-breakpoints) {
+    $min: map-get($breakpoints, $name);
+    @return if($min != 0, $min, null);
+}
+
+// Custom Added CSS animations
+
+@keyframes modalshow {
+    0% {
+        opacity: 0;
+        transform: translate(0, -25%);
+    }
+
+    100% {
+        opacity: 1;
+        transform: translate(0, 0);
+    }
+}
+
+@keyframes backdropshow {
+    0% {
+        opacity: 0;
+    }
+
+    100% {
+        opacity: $modal-backdrop-opacity;
+    }
+}
+
+// ref: https://github.com/twbs/bootstrap/blob/v4-dev/scss/_modal.scss
+
+// .modal-open      - body class for killing the scroll
+// .modal           - container to scroll within
+// .modal-dialog    - positioning shell for the actual modal
+// .modal-content   - actual modal w/ bg and corners and stuff
+
+
+// Kill the scroll on the body
+.modal-open {
+    overflow: hidden;
+}
+
+// Container that the modal scrolls within
+.modal {
+    position: fixed;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    left: 0;
+    z-index: $zindex-modal;
+    //display: none;
+    overflow: hidden;
+    // Prevent Chrome on Windows from adding a focus outline. For details, see
+    // https://github.com/twbs/bootstrap/pull/10951.
+    outline: 0;
+    // We deliberately don't use `-webkit-overflow-scrolling: touch;` due to a
+    // gnarly iOS Safari bug: https://bugs.webkit.org/show_bug.cgi?id=158342
+    // See also https://github.com/twbs/bootstrap/issues/17695
+    .modal-open & {
+        overflow-x: hidden;
+        overflow-y: auto;
+    }
+}
+
+// Shell div to position the modal with bottom padding
+.modal-dialog {
+    position: relative;
+    width: auto;
+    margin: $modal-dialog-margin;
+    // allow clicks to pass through for custom click handling to close modal
+    pointer-events: none;
+    // When fading in the modal, animate it to slide down
+    .modal.fade & {
+        //@include transition($modal-transition);
+        //transform: translate(0, -25%);
+        animation: modalshow 0.3s ease-in;
+    }
+    //.modal.show & {
+    //    transform: translate(0, 0);
+    //}
+    transform: translate(0, 0);
+}
+
+.modal-dialog-centered {
+    display: flex;
+    align-items: center;
+    min-height: calc(100% - (#{$modal-dialog-margin} * 2));
+}
+
+// Actual modal
+.modal-content {
+    position: relative;
+    display: flex;
+    flex-direction: column;
+    width: 100%; // Ensure `.modal-content` extends the full width of the parent `.modal-dialog`
+    // counteract the pointer-events: none; in the .modal-dialog
+    pointer-events: auto;
+    //background-color: $modal-content-bg;
+    background-clip: padding-box;
+    border: $modal-content-border-width solid $modal-content-border-color;
+    //@include border-radius($border-radius-lg);
+    //@include box-shadow($modal-content-box-shadow-xs);
+    border-radius: $border-radius-lg;
+    box-shadow: $modal-content-box-shadow-xs;
+    // Remove focus outline from opened modal
+    outline: 0;
+
+    @include themify($themes) {
+        background-color: themed('backgroundColorAlt');
+    }
+}
+
+// Modal background
+.modal-backdrop {
+    position: fixed;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    left: 0;
+    z-index: $zindex-modal-backdrop;
+    background-color: $modal-backdrop-bg;
+    // Fade for backdrop
+    &.fade {
+        //opacity: 0;
+        animation: backdropshow 0.1s ease-in;
+    }
+    //&.show {
+    //    opacity: $modal-backdrop-opacity;
+    //}
+    opacity: $modal-backdrop-opacity;
+}
+
+// Modal header
+// Top section of the modal w/ title and dismiss
+.modal-header {
+    display: flex;
+    align-items: flex-start; // so the close btn always stays on the upper right corner
+    justify-content: space-between; // Put modal header elements (title and dismiss) on opposite ends
+    padding: $modal-header-padding $modal-inner-padding;
+    border-bottom: $modal-header-border-width solid $modal-header-border-color;
+    //@include border-top-radius($border-radius-lg);
+
+    @include themify($themes) {
+        border-bottom-color: themed('borderColor');
+    }
+
+    .close {
+        padding: $modal-header-padding $modal-inner-padding;
+        // auto on the left force icon to the right even when there is no .modal-title
+        margin: (-$modal-header-padding) (-$modal-inner-padding) (-$modal-header-padding) auto;
+    }
+
+    h5 {
+        font-size: $font-size-base;
+        font-weight: bold;
+        display: flex;
+        align-items: center;
+
+        .fa {
+            margin-right: 5px;
+        }
+    }
+}
+
+// Title text within header
+.modal-title {
+    margin-bottom: 0;
+    line-height: $modal-title-line-height;
+}
+
+// Modal body
+// Where all modal content resides (sibling of .modal-header and .modal-footer)
+.modal-body {
+    position: relative;
+    // Enable `flex-grow: 1` so that the body take up as much space as possible
+    // when should there be a fixed height on `.modal-dialog`.
+    flex: 1 1 auto;
+    padding: $modal-inner-padding;
+}
+
+// Footer (for actions)
+.modal-footer {
+    display: flex;
+    align-items: center; // vertically center
+    //justify-content: flex-end; // Right align buttons with flex property because text-align doesn't work on flex items
+    padding: $modal-inner-padding;
+    border-top: $modal-footer-border-width solid $modal-footer-border-color;
+
+    @include themify($themes) {
+        border-top-color: themed('borderColor');
+    }
+
+    // Easily place margin between footer elements
+    button {
+        margin-right: 10px;
+
+        &:last-child {
+            margin-right: 0;
+        }
+    }
+
+    .right {
+        margin-left: auto;
+        display: flex;
+    }
+}
+
+// Measure scrollbar width for padding body during modal show/hide
+.modal-scrollbar-measure {
+    position: absolute;
+    top: -9999px;
+    width: 50px;
+    height: 50px;
+    overflow: scroll;
+}
+
+// Scale up the modal
+@include media-breakpoint-up(sm) {
+    // Automatically set modal's width for larger viewports
+    .modal-dialog {
+        max-width: $modal-md;
+        margin: $modal-dialog-margin-y-sm-up auto;
+    }
+
+    .modal-dialog-centered {
+        min-height: calc(100% - (#{$modal-dialog-margin-y-sm-up} * 2));
+    }
+
+    .modal-content {
+        //@include box-shadow($modal-content-box-shadow-sm-up);
+        box-shadow: $modal-content-box-shadow-sm-up;
+    }
+
+    .modal-sm {
+        max-width: $modal-sm;
+    }
+}
+
+@include media-breakpoint-up(lg) {
+    .modal-lg {
+        max-width: $modal-lg;
+    }
+}
+
+// ref: https://github.com/twbs/bootstrap/blob/v4-dev/scss/_close.scss
+
+.close {
+    float: right;
+    font-size: $close-font-size;
+    font-weight: $close-font-weight;
+    line-height: 1;
+    color: $close-color;
+    text-shadow: $close-text-shadow;
+    opacity: .5;
+
+    &:hover, &:focus {
+        color: $close-color;
+        text-decoration: none;
+        opacity: .75;
+    }
+    // Opinionated: add "hand" cursor to non-disabled .close elements
+    &:not(:disabled):not(.disabled) {
+        cursor: pointer;
+    }
+}
+
+// Additional properties for button version
+// iOS requires the button element instead of an anchor tag.
+// If you want the anchor version, it requires `href="#"`.
+// See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile
+
+// stylelint-disable property-no-vendor-prefix, selector-no-qualifying-type
+button.close {
+    padding: 0;
+    background-color: transparent;
+    border: 0;
+    -webkit-appearance: none;
+}
+// stylelint-enable
+
+// box
+
+.modal-content .box {
+    margin-top: 20px;
+
+    &:first-child {
+        margin-top: 0;
+    }
+}
diff --git a/src/popup/scss/popup.scss b/src/popup/scss/popup.scss
index fe77d09b0e..ddeab56523 100644
--- a/src/popup/scss/popup.scss
+++ b/src/popup/scss/popup.scss
@@ -4,6 +4,7 @@
 @import "box.scss";
 @import "buttons.scss";
 @import "misc.scss";
+@import "modal.scss";
 @import "plugins.scss";
 @import "environment.scss";
 @import "pages.scss";
diff --git a/src/popup/services/password-reprompt.service.ts b/src/popup/services/password-reprompt.service.ts
new file mode 100644
index 0000000000..d59026e0aa
--- /dev/null
+++ b/src/popup/services/password-reprompt.service.ts
@@ -0,0 +1,11 @@
+
+import { Injectable } from '@angular/core';
+
+import { PasswordRepromptService as BasePasswordRepromptService } from 'jslib-angular/services/passwordReprompt.service';
+
+import { PasswordRepromptComponent } from '../components/password-reprompt.component';
+
+@Injectable()
+export class PasswordRepromptService extends BasePasswordRepromptService {
+    component = PasswordRepromptComponent;
+}
diff --git a/src/popup/services/services.module.ts b/src/popup/services/services.module.ts
index 707c6a1ea8..4c6967d154 100644
--- a/src/popup/services/services.module.ts
+++ b/src/popup/services/services.module.ts
@@ -9,10 +9,12 @@ import { ToasterModule } from 'angular2-toaster';
 import { DebounceNavigationService } from './debounceNavigationService';
 import { LaunchGuardService } from './launch-guard.service';
 import { LockGuardService } from './lock-guard.service';
+import { PasswordRepromptService } from './password-reprompt.service';
 import { UnauthGuardService } from './unauth-guard.service';
 
 import { AuthGuardService } from 'jslib-angular/services/auth-guard.service';
 import { BroadcasterService } from 'jslib-angular/services/broadcaster.service';
+import { ModalService } from 'jslib-angular/services/modal.service';
 import { ValidationService } from 'jslib-angular/services/validation.service';
 
 import { BrowserApi } from '../../browser/browserApi';
@@ -48,7 +50,6 @@ import { TokenService } from 'jslib-common/abstractions/token.service';
 import { TotpService } from 'jslib-common/abstractions/totp.service';
 import { UserService } from 'jslib-common/abstractions/user.service';
 import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service';
-import { PasswordRepromptService } from 'jslib-common/services/passwordReprompt.service';
 
 import { AutofillService } from '../../services/abstractions/autofill.service';
 import BrowserMessagingService from '../../services/browserMessaging.service';
@@ -76,8 +77,6 @@ const messagingService = new BrowserMessagingService();
 const searchService = isPrivateMode ? null : new PopupSearchService(getBgService<SearchService>('searchService')(),
     getBgService<CipherService>('cipherService')(), getBgService<ConsoleLogService>('consoleLogService')(),
     getBgService<I18nService>('i18nService')());
-const passwordRepromptService = isPrivateMode ? null : new PasswordRepromptService(getBgService<I18nService>('i18nService')(),
-    getBgService<CryptoService>('cryptoService')(), getBgService<PlatformUtilsService>('platformUtilsService')());
 
 export function initFactory(platformUtilsService: PlatformUtilsService, i18nService: I18nService, storageService: StorageService,
     popupUtilsService: PopupUtilsService): Function {
@@ -126,6 +125,7 @@ export function initFactory(platformUtilsService: PlatformUtilsService, i18nServ
         DebounceNavigationService,
         PopupUtilsService,
         BroadcasterService,
+        ModalService,
         { provide: MessagingService, useValue: messagingService },
         { provide: AuthServiceAbstraction, useFactory: getBgService<AuthService>('authService'), deps: [] },
         { provide: StateServiceAbstraction, useValue: stateService },
@@ -188,7 +188,7 @@ export function initFactory(platformUtilsService: PlatformUtilsService, i18nServ
             useFactory: () => isPrivateMode ? null : getBgService<I18nService>('i18nService')().translationLocale,
             deps: [],
         },
-        { provide: PasswordRepromptServiceAbstraction, useValue: passwordRepromptService },
+        { provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService },
     ],
 })
 export class ServicesModule {
diff --git a/src/services/browserPlatformUtils.service.ts b/src/services/browserPlatformUtils.service.ts
index d33d6e2d73..509a9c9f71 100644
--- a/src/services/browserPlatformUtils.service.ts
+++ b/src/services/browserPlatformUtils.service.ts
@@ -150,33 +150,6 @@ export default class BrowserPlatformUtilsService implements PlatformUtilsService
         });
     }
 
-    async showPasswordDialog(title: string, body: string, passwordValidation: (value: string) => Promise<boolean>) {
-        const dialogId = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
-
-        this.messagingService.send('showPasswordDialog', {
-            title: title,
-            body: body,
-            dialogId: dialogId,
-        });
-
-        return new Promise<boolean>(resolve => {
-            this.passwordDialogResolves.set(dialogId, {
-                tryResolve: async (canceled: boolean, password: string) => {
-                    if (canceled) {
-                        resolve(false);
-                        return false;
-                    }
-
-                    if (await passwordValidation(password)) {
-                        resolve(true);
-                        return true;
-                    }
-                },
-                date: new Date(),
-            });
-        });
-    }
-
     isDev(): boolean {
         return process.env.ENV === 'development';
     }
diff --git a/store/icons/chrome-icon128.png b/store/icons/chrome-icon128.png
index a7f6c41af4..9bce320e73 100644
Binary files a/store/icons/chrome-icon128.png and b/store/icons/chrome-icon128.png differ
diff --git a/store/icons/icon64.png b/store/icons/icon64.png
index 89fb3a6b59..5b9d09d51d 100644
Binary files a/store/icons/icon64.png and b/store/icons/icon64.png differ
diff --git a/store/icons/safari-icon256.png b/store/icons/safari-icon256.png
index 2b71c22e81..adb75cbbe7 100644
Binary files a/store/icons/safari-icon256.png and b/store/icons/safari-icon256.png differ
diff --git a/store/icons/windows-icon300.png b/store/icons/windows-icon300.png
index b0be924bda..ba18ac07bb 100644
Binary files a/store/icons/windows-icon300.png and b/store/icons/windows-icon300.png differ
diff --git a/store/windows/Assets/icon_150.png b/store/windows/Assets/icon_150.png
index 668244a56b..cd7fda75d9 100644
Binary files a/store/windows/Assets/icon_150.png and b/store/windows/Assets/icon_150.png differ
diff --git a/store/windows/Assets/icon_44.png b/store/windows/Assets/icon_44.png
index b08bf7fa77..10ab6fe65a 100644
Binary files a/store/windows/Assets/icon_44.png and b/store/windows/Assets/icon_44.png differ
diff --git a/store/windows/Assets/icon_50.png b/store/windows/Assets/icon_50.png
index 6bf4752aa3..4865f4abe3 100644
Binary files a/store/windows/Assets/icon_50.png and b/store/windows/Assets/icon_50.png differ
diff --git a/webpack.config.js b/webpack.config.js
index 6b5ca45301..08918eed55 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -130,6 +130,7 @@ const config = {
         'content/autofill': './src/content/autofill.js',
         'content/autofiller': './src/content/autofiller.ts',
         'content/notificationBar': './src/content/notificationBar.ts',
+        'content/contextMenuHandler': './src/content/contextMenuHandler.ts',
         'content/shortcuts': './src/content/shortcuts.ts',
         'content/message_handler': './src/content/message_handler.ts',
         'notification/bar': './src/notification/bar.js',