1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-12 14:23:32 +00:00

Merge branch 'master' into hotfix/fix-crowdin-sync

This commit is contained in:
Joseph Flinn
2021-09-03 11:28:58 -07:00
committed by GitHub
34 changed files with 606 additions and 171 deletions

View File

@@ -1,3 +1,4 @@
---
name: Build name: Build
on: on:
@@ -10,6 +11,7 @@ on:
jobs: jobs:
cloc: cloc:
name: CLOC
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repo - name: Checkout repo
@@ -24,6 +26,7 @@ jobs:
setup: setup:
name: Setup
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
repo_url: ${{ steps.gen_vars.outputs.repo_url }} repo_url: ${{ steps.gen_vars.outputs.repo_url }}
@@ -42,6 +45,7 @@ jobs:
echo "::set-output name=adj_build_number::$adj_build_num" echo "::set-output name=adj_build_number::$adj_build_num"
locales-test: locales-test:
name: Locales Test
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: setup needs: setup
steps: steps:
@@ -73,11 +77,11 @@ jobs:
fi fi
build: build:
name: Build
runs-on: windows-latest runs-on: windows-latest
needs: [ setup, locales-test ] needs: [setup, locales-test]
env: 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: steps:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
@@ -96,41 +100,41 @@ jobs:
node --version node --version
npm --version npm --version
- name: npm setup & test - name: NPM setup & test
run: | run: |
npm install npm install
npm run dist npm run dist
npm run test npm run test
- name: gulp - name: Gulp
run: gulp ci run: gulp ci
- name: Upload opera artifact - name: Upload Opera artifact
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700 uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700
with: with:
name: dist-opera-${{ env.BUILD_NUMBER }}.zip name: dist-opera-${{ env._BUILD_NUMBER }}.zip
path: dist/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 uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700
with: with:
name: dist-chrome-${{ env.BUILD_NUMBER }}.zip name: dist-chrome-${{ env._BUILD_NUMBER }}.zip
path: dist/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 uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700
with: with:
name: dist-firefox-${{ env.BUILD_NUMBER }}.zip name: dist-firefox-${{ env._BUILD_NUMBER }}.zip
path: dist/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 uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700
with: with:
name: dist-edge-${{ env.BUILD_NUMBER }}.zip name: dist-edge-${{ env._BUILD_NUMBER }}.zip
path: dist/dist-edge-${{ env.BUILD_NUMBER }}.zip path: dist/dist-edge-${{ env._BUILD_NUMBER }}.zip
- name: Upload coverage artifact - name: Upload coverage artifact
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700 uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700
with: with:
name: coverage-${{ env.BUILD_NUMBER }}.zip name: coverage-${{ env._BUILD_NUMBER }}.zip
path: coverage/coverage-${{ env.BUILD_NUMBER }}.zip path: coverage/coverage-${{ env._BUILD_NUMBER }}.zip

View File

@@ -1,10 +1,11 @@
---
name: Crowdin Sync name: Crowdin Sync
on: on:
workflow_dispatch: workflow_dispatch:
inputs: {} inputs: {}
#schedule: # schedule:
# - cron: '0 0 * * *' # - cron: '0 0 * * *'
jobs: jobs:
crowdin-sync: crowdin-sync:

View File

@@ -1,3 +1,4 @@
---
name: Release name: Release
on: on:
@@ -10,6 +11,7 @@ on:
jobs: jobs:
setup: setup:
name: Setup
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
tag_version: ${{ steps.create_tags.outputs.tag_version }} tag_version: ${{ steps.create_tags.outputs.tag_version }}
@@ -74,6 +76,7 @@ jobs:
locales-test: locales-test:
name: Locales Test
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: setup needs: setup
steps: steps:
@@ -105,11 +108,12 @@ jobs:
fi fi
build: build:
name: Build
runs-on: windows-latest runs-on: windows-latest
needs: [ setup, locales-test ] needs: [setup, locales-test]
env: env:
REPO_URL: ${{ needs.setup.outputs.repo_url }} _REPO_URL: ${{ needs.setup.outputs.repo_url }}
BUILD_NUMBER: ${{ needs.setup.outputs.adj_build_number }} _BUILD_NUMBER: ${{ needs.setup.outputs.adj_build_number }}
steps: steps:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
@@ -128,84 +132,84 @@ jobs:
node --version node --version
npm --version npm --version
- name: npm setup & test - name: NPM setup & test
run: | run: |
npm install npm install
npm run dist npm run dist
npm run test npm run test
- name: gulp - name: Gulp
run: gulp ci run: gulp ci
- name: Build sources for reviewers - name: Build sources for reviewers
shell: cmd shell: cmd
run: | run: |
mkdir dist\Source mkdir dist\Source
call git clone %REPO_URL% dist\Source call git clone %_REPO_URL% dist\Source
cd dist\Source cd dist\Source
call git checkout %GITHUB_SHA% call git checkout %GITHUB_SHA%
call git submodule update --init --recursive call git submodule update --init --recursive
cd ../ cd ../
del /S/Q "Source\.git\objects\pack\*" 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 uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
upload_url: ${{ needs.setup.outputs.release_upload_url }} upload_url: ${{ needs.setup.outputs.release_upload_url }}
asset_name: dist-opera-${{ env.BUILD_NUMBER }}.zip asset_name: dist-opera-${{ env._BUILD_NUMBER }}.zip
asset_path: dist/dist-opera-${{ env.BUILD_NUMBER }}.zip asset_path: dist/dist-opera-${{ env._BUILD_NUMBER }}.zip
asset_content_type: application asset_content_type: application
- name: upload chrome release asset - name: Upload Chrome release asset
uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
upload_url: ${{ needs.setup.outputs.release_upload_url }} upload_url: ${{ needs.setup.outputs.release_upload_url }}
asset_name: dist-chrome-${{ env.BUILD_NUMBER }}.zip asset_name: dist-chrome-${{ env._BUILD_NUMBER }}.zip
asset_path: dist/dist-chrome-${{ env.BUILD_NUMBER }}.zip asset_path: dist/dist-chrome-${{ env._BUILD_NUMBER }}.zip
asset_content_type: application/zip asset_content_type: application/zip
- name: upload firefox release asset - name: Upload Firefox release asset
uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
upload_url: ${{ needs.setup.outputs.release_upload_url }} upload_url: ${{ needs.setup.outputs.release_upload_url }}
asset_name: dist-firefox-${{ env.BUILD_NUMBER }}.zip asset_name: dist-firefox-${{ env._BUILD_NUMBER }}.zip
asset_path: dist/dist-firefox-${{ env.BUILD_NUMBER }}.zip asset_path: dist/dist-firefox-${{ env._BUILD_NUMBER }}.zip
asset_content_type: application/zip asset_content_type: application/zip
- name: upload edge release asset - name: Upload Edge release asset
uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
upload_url: ${{ needs.setup.outputs.release_upload_url }} upload_url: ${{ needs.setup.outputs.release_upload_url }}
asset_name: dist-edge-${{ env.BUILD_NUMBER }}.zip asset_name: dist-edge-${{ env._BUILD_NUMBER }}.zip
asset_path: dist/dist-edge-${{ env.BUILD_NUMBER }}.zip asset_path: dist/dist-edge-${{ env._BUILD_NUMBER }}.zip
asset_content_type: application/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 uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
upload_url: ${{ needs.setup.outputs.release_upload_url }} upload_url: ${{ needs.setup.outputs.release_upload_url }}
asset_name: browser-source-${{ env.BUILD_NUMBER }}.zip asset_name: browser-source-${{ env._BUILD_NUMBER }}.zip
asset_path: dist/browser-source-${{ env.BUILD_NUMBER }}.zip asset_path: dist/browser-source-${{ env._BUILD_NUMBER }}.zip
asset_content_type: application/zip asset_content_type: application/zip
- name: upload coverage release asset - name: Upload coverage release asset
if: false if: false
uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
upload_url: ${{ needs.setup.outputs.release_upload_url }} upload_url: ${{ needs.setup.outputs.release_upload_url }}
asset_name: coverage-${{ env.BUILD_NUMBER }}.zip asset_name: coverage-${{ env._BUILD_NUMBER }}.zip
asset_path: coverage/coverage-${{ env.BUILD_NUMBER }}.zip asset_path: coverage/coverage-${{ env._BUILD_NUMBER }}.zip
asset_content_type: application/zip asset_content_type: application/zip

2
jslib

Submodule jslib updated: 1f0127966e...30419a625f

View File

@@ -88,6 +88,9 @@
"generatePasswordCopied": { "generatePasswordCopied": {
"message": "Generate Password (copied)" "message": "Generate Password (copied)"
}, },
"copyElementIdentifier": {
"message": "Copy Custom Field Name"
},
"noMatchingLogins": { "noMatchingLogins": {
"message": "No matching logins." "message": "No matching logins."
}, },
@@ -1761,5 +1764,8 @@
}, },
"updateMasterPasswordWarning": { "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." "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..."
} }
} }

View File

@@ -29,6 +29,8 @@ export default class ContextMenusBackground {
this.contextMenus.onClicked.addListener(async (info: any, tab: any) => { this.contextMenus.onClicked.addListener(async (info: any, tab: any) => {
if (info.menuItemId === 'generate-password') { if (info.menuItemId === 'generate-password') {
await this.generatePasswordToClipboard(); await this.generatePasswordToClipboard();
} else if (info.menuItemId === 'copy-identifier') {
await this.getClickedElement();
} else if (info.parentMenuItemId === 'autofill' || } else if (info.parentMenuItemId === 'autofill' ||
info.parentMenuItemId === 'copy-username' || info.parentMenuItemId === 'copy-username' ||
info.parentMenuItemId === 'copy-password' || info.parentMenuItemId === 'copy-password' ||
@@ -45,6 +47,15 @@ export default class ContextMenusBackground {
this.passwordGenerationService.addHistory(password); 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) { private async cipherAction(info: any) {
const id = info.menuItemId.split('_')[1]; const id = info.menuItemId.split('_')[1];
if (id === 'noop') { if (id === 'noop') {

View File

@@ -244,7 +244,7 @@ export default class MainBackground {
this.runtimeBackground = new RuntimeBackground(this, this.autofillService, this.cipherService, this.runtimeBackground = new RuntimeBackground(this, this.autofillService, this.cipherService,
this.platformUtilsService as BrowserPlatformUtilsService, this.storageService, this.i18nService, this.platformUtilsService as BrowserPlatformUtilsService, this.storageService, this.i18nService,
this.notificationsService, this.systemService, this.vaultTimeoutService, 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.nativeMessagingBackground = new NativeMessagingBackground(this.storageService, this.cryptoService, this.cryptoFunctionService,
this.vaultTimeoutService, this.runtimeBackground, this.i18nService, this.userService, this.messagingService, this.appIdService, this.vaultTimeoutService, this.runtimeBackground, this.i18nService, this.userService, this.messagingService, this.appIdService,
this.platformUtilsService); this.platformUtilsService);
@@ -512,6 +512,14 @@ export default class MainBackground {
title: this.i18nService.t('generatePasswordCopied'), 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; this.buildingContextMenu = false;
} }

View File

@@ -6,6 +6,7 @@ import { LoginView } from 'jslib-common/models/view/loginView';
import { CipherService } from 'jslib-common/abstractions/cipher.service'; import { CipherService } from 'jslib-common/abstractions/cipher.service';
import { EnvironmentService } from 'jslib-common/abstractions/environment.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 { I18nService } from 'jslib-common/abstractions/i18n.service';
import { MessagingService } from 'jslib-common/abstractions/messaging.service'; import { MessagingService } from 'jslib-common/abstractions/messaging.service';
import { NotificationsService } from 'jslib-common/abstractions/notifications.service'; import { NotificationsService } from 'jslib-common/abstractions/notifications.service';
@@ -39,7 +40,8 @@ export default class RuntimeBackground {
private notificationsService: NotificationsService, private notificationsService: NotificationsService,
private systemService: SystemService, private vaultTimeoutService: VaultTimeoutService, private systemService: SystemService, private vaultTimeoutService: VaultTimeoutService,
private environmentService: EnvironmentService, private policyService: PolicyService, 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 // onInstalled listener must be wired up before anything else, so we do it in the ctor
chrome.runtime.onInstalled.addListener((details: any) => { chrome.runtime.onInstalled.addListener((details: any) => {
@@ -107,7 +109,7 @@ export default class RuntimeBackground {
this.removeTabFromNotificationQueue(sender.tab); this.removeTabFromNotificationQueue(sender.tab);
break; break;
case 'bgAddSave': case 'bgAddSave':
await this.saveAddLogin(sender.tab); await this.saveAddLogin(sender.tab, msg.folder);
break; break;
case 'bgChangeSave': case 'bgChangeSave':
await this.saveChangePassword(sender.tab); await this.saveChangePassword(sender.tab);
@@ -195,6 +197,8 @@ export default class RuntimeBackground {
type: 'info', type: 'info',
}); });
break; break;
case 'getClickedElementResponse':
this.platformUtilsService.copyToClipboard(msg.identifier, { window: window });
default: default:
break; break;
} }
@@ -216,7 +220,7 @@ export default class RuntimeBackground {
this.pageDetailsToAutoFill = []; this.pageDetailsToAutoFill = [];
} }
private async saveAddLogin(tab: any) { private async saveAddLogin(tab: any, folderId: string) {
if (await this.vaultTimeoutService.isLocked()) { if (await this.vaultTimeoutService.isLocked()) {
return; return;
} }
@@ -247,6 +251,13 @@ export default class RuntimeBackground {
model.type = CipherType.Login; model.type = CipherType.Login;
model.login = loginModel; 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); const cipher = await this.cipherService.encrypt(model);
await this.cipherService.saveWithServer(cipher); await this.cipherService.saveWithServer(cipher);
} }
@@ -450,24 +461,14 @@ export default class RuntimeBackground {
notificationChangeSave: this.i18nService.t('notificationChangeSave'), notificationChangeSave: this.i18nService.t('notificationChangeSave'),
notificationChangeDesc: this.i18nService.t('notificationChangeDesc'), notificationChangeDesc: this.i18nService.t('notificationChangeDesc'),
}; };
} else if (responseCommand === 'notificationBarGetFoldersList') {
responseData.folders = await this.folderService.getAllDecrypted();
} }
await BrowserApi.tabSendMessageData(tab, responseCommand, responseData); await BrowserApi.tabSendMessageData(tab, responseCommand, responseData);
} }
private async allowPersonalOwnership(): Promise<boolean> { private async allowPersonalOwnership(): Promise<boolean> {
const personalOwnershipPolicies = await this.policyService.getAll(PolicyType.PersonalOwnership); return !await this.policyService.policyAppliesToUser(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;
} }
} }

View File

@@ -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,
});
}
});

View File

@@ -20,7 +20,8 @@
"js": [ "js": [
"content/autofill.js", "content/autofill.js",
"content/autofiller.js", "content/autofiller.js",
"content/notificationBar.js" "content/notificationBar.js",
"content/contextMenuHandler.js"
], ],
"matches": [ "matches": [
"http://*/*", "http://*/*",

View File

@@ -27,8 +27,11 @@
<tbody> <tbody>
<tr> <tr>
<td class="add-text"></td> <td class="add-text"></td>
<td align="right" class="add-buttons"> <td align="right">
<button class="never-save link"></button> <button class="never-save link"></button>
</td>
<td align="right" class="add-buttons">
<select class="select-folder"></select>
<button class="add-save"></button> <button class="add-save"></button>
</td> </td>
</tr> </tr>

View File

@@ -18,7 +18,6 @@ document.addEventListener('DOMContentLoaded', () => {
// delay 50ms so that we get proper body dimensions // delay 50ms so that we get proper body dimensions
setTimeout(load, 50); setTimeout(load, 50);
function load() { function load() {
var closeButton = document.getElementById('close-button'), var closeButton = document.getElementById('close-button'),
body = document.querySelector('body'), body = document.querySelector('body'),
@@ -34,10 +33,12 @@ document.addEventListener('DOMContentLoaded', () => {
if (bodyRect.width < 768) { if (bodyRect.width < 768) {
document.querySelector('#template-add .add-save').textContent = i18n.yes; document.querySelector('#template-add .add-save').textContent = i18n.yes;
document.querySelector('#template-add .never-save').textContent = i18n.never; 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; document.querySelector('#template-change .change-save').textContent = i18n.yes;
} else { } else {
document.querySelector('#template-add .add-save').textContent = i18n.notificationAddSave; document.querySelector('#template-add .add-save').textContent = i18n.notificationAddSave;
document.querySelector('#template-add .never-save').textContent = i18n.notificationNeverSave; 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; document.querySelector('#template-change .change-save').textContent = i18n.notificationChangeSave;
} }
@@ -53,7 +54,8 @@ document.addEventListener('DOMContentLoaded', () => {
addButton.addEventListener('click', (e) => { addButton.addEventListener('click', (e) => {
e.preventDefault(); e.preventDefault();
sendPlatformMessage({ sendPlatformMessage({
command: 'bgAddSave' command: 'bgAddSave',
folder: document.getElementById("select-folder").value,
}); });
}); });
@@ -63,6 +65,17 @@ document.addEventListener('DOMContentLoaded', () => {
command: 'bgNeverSave' 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')) { } else if (getQueryVariable('change')) {
setContent(document.getElementById('template-change')); setContent(document.getElementById('template-change'));
var changeButton = document.querySelector('#template-change-clone .change-save'); var changeButton = document.querySelector('#template-change-clone .change-save');
@@ -120,4 +133,13 @@ document.addEventListener('DOMContentLoaded', () => {
function sendPlatformMessage(msg) { function sendPlatformMessage(msg) {
chrome.runtime.sendMessage(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));
});
}
}); });

View File

@@ -82,7 +82,7 @@ button.link {
} }
body[class*='lang-en'] .add-buttons { body[class*='lang-en'] .add-buttons {
width: 175px; width: 50px;
} }
@media (min-width: 768px) { @media (min-width: 768px) {
@@ -96,3 +96,4 @@ body[class*='lang-en'] .add-buttons {
display: none; display: none;
} }
} }

View File

@@ -1,4 +1,4 @@
<form #form class="modal-content" (ngSubmit)="submit()"> <form #form (ngSubmit)="submit()">
<header> <header>
<div class="left"> <div class="left">
<a routerLink="/home">{{'close' | i18n}}</a> <a routerLink="/home">{{'close' | i18n}}</a>

View File

@@ -20,22 +20,7 @@
<div *ngIf="!syncLoading"> <div *ngIf="!syncLoading">
<div class="box"> <div class="box">
<app-callout type="tip">{{'ssoCompleteRegistration' | i18n}}</app-callout> <app-callout type="tip">{{'ssoCompleteRegistration' | i18n}}</app-callout>
<app-callout type="info" *ngIf="enforcedPolicyOptions"> <app-callout type="info" [enforcedPolicyOptions]="enforcedPolicyOptions" *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> </app-callout>
</div> </div>
<div class="box"> <div class="box">

View File

@@ -53,7 +53,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
return syncService.fullSync(true).then(async () => { return syncService.fullSync(true).then(async () => {
if (await this.userService.getForcePasswordReset()) { if (await this.userService.getForcePasswordReset()) {
this.router.navigate(['update-temp-password']); this.router.navigate(['update-temp-password']);
}; }
}); });
}; };
super.successRoute = '/tabs/vault'; super.successRoute = '/tabs/vault';

View File

@@ -17,22 +17,7 @@
<app-callout type="warning" title="{{'updateMasterPassword' | i18n}}"> <app-callout type="warning" title="{{'updateMasterPassword' | i18n}}">
{{'updateMasterPasswordWarning' | i18n}} {{'updateMasterPasswordWarning' | i18n}}
</app-callout> </app-callout>
<app-callout type="info" *ngIf="enforcedPolicyOptions"> <app-callout type="info" [enforcedPolicyOptions]="enforcedPolicyOptions" *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> </app-callout>
<div class="box"> <div class="box">
<div class="box-content"> <div class="box-content">
@@ -59,8 +44,9 @@
</div> </div>
</div> </div>
<div class="progress"> <div class="progress">
<div class="progress-bar bg-{{masterPasswordScoreStyle.Color}}" role="progressbar" aria-valuenow="0" <div class="progress-bar bg-{{masterPasswordScoreStyle.Color}}" role="progressbar"
aria-valuemin="0" aria-valuemax="100" [ngStyle]="{width: (masterPasswordScoreStyle.Width + '%')}" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"
[ngStyle]="{width: (masterPasswordScoreStyle.Width + '%')}"
attr.aria-valuenow="{{masterPasswordScoreStyle.Width}}"></div> attr.aria-valuenow="{{masterPasswordScoreStyle.Width}}"></div>
</div> </div>
</div> </div>

View File

@@ -106,8 +106,6 @@ export class AppComponent implements OnInit {
}); });
} else if (msg.command === 'showDialog') { } else if (msg.command === 'showDialog') {
await this.showDialog(msg); await this.showDialog(msg);
} else if (msg.command === 'showPasswordDialog') {
await this.showPasswordDialog(msg);
} else if (msg.command === 'showToast') { } else if (msg.command === 'showToast') {
this.ngZone.run(() => { this.ngZone.run(() => {
this.showToast(msg); this.showToast(msg);
@@ -251,30 +249,4 @@ export class AppComponent implements OnInit {
confirmed: confirmed.value, 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);
}
} }

View File

@@ -72,6 +72,7 @@ import { SearchCiphersPipe } from 'jslib-angular/pipes/search-ciphers.pipe';
import { ActionButtonsComponent } from './components/action-buttons.component'; import { ActionButtonsComponent } from './components/action-buttons.component';
import { CipherRowComponent } from './components/cipher-row.component'; import { CipherRowComponent } from './components/cipher-row.component';
import { PasswordRepromptComponent } from './components/password-reprompt.component';
import { PopOutComponent } from './components/pop-out.component'; import { PopOutComponent } from './components/pop-out.component';
import { SendListComponent } from './components/send-list.component'; import { SendListComponent } from './components/send-list.component';
@@ -240,6 +241,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
TwoFactorComponent, TwoFactorComponent,
UpdateTempPasswordComponent, UpdateTempPasswordComponent,
ViewComponent, ViewComponent,
PasswordRepromptComponent,
], ],
entryComponents: [], entryComponents: [],
providers: [ providers: [

View File

@@ -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>

View File

@@ -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 {}

351
src/popup/scss/modal.scss Normal file
View File

@@ -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;
}
}

View File

@@ -4,6 +4,7 @@
@import "box.scss"; @import "box.scss";
@import "buttons.scss"; @import "buttons.scss";
@import "misc.scss"; @import "misc.scss";
@import "modal.scss";
@import "plugins.scss"; @import "plugins.scss";
@import "environment.scss"; @import "environment.scss";
@import "pages.scss"; @import "pages.scss";

View File

@@ -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;
}

View File

@@ -9,10 +9,12 @@ import { ToasterModule } from 'angular2-toaster';
import { DebounceNavigationService } from './debounceNavigationService'; import { DebounceNavigationService } from './debounceNavigationService';
import { LaunchGuardService } from './launch-guard.service'; import { LaunchGuardService } from './launch-guard.service';
import { LockGuardService } from './lock-guard.service'; import { LockGuardService } from './lock-guard.service';
import { PasswordRepromptService } from './password-reprompt.service';
import { UnauthGuardService } from './unauth-guard.service'; import { UnauthGuardService } from './unauth-guard.service';
import { AuthGuardService } from 'jslib-angular/services/auth-guard.service'; import { AuthGuardService } from 'jslib-angular/services/auth-guard.service';
import { BroadcasterService } from 'jslib-angular/services/broadcaster.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 { ValidationService } from 'jslib-angular/services/validation.service';
import { BrowserApi } from '../../browser/browserApi'; 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 { TotpService } from 'jslib-common/abstractions/totp.service';
import { UserService } from 'jslib-common/abstractions/user.service'; import { UserService } from 'jslib-common/abstractions/user.service';
import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.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 { AutofillService } from '../../services/abstractions/autofill.service';
import BrowserMessagingService from '../../services/browserMessaging.service'; import BrowserMessagingService from '../../services/browserMessaging.service';
@@ -76,8 +77,6 @@ const messagingService = new BrowserMessagingService();
const searchService = isPrivateMode ? null : new PopupSearchService(getBgService<SearchService>('searchService')(), const searchService = isPrivateMode ? null : new PopupSearchService(getBgService<SearchService>('searchService')(),
getBgService<CipherService>('cipherService')(), getBgService<ConsoleLogService>('consoleLogService')(), getBgService<CipherService>('cipherService')(), getBgService<ConsoleLogService>('consoleLogService')(),
getBgService<I18nService>('i18nService')()); 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, export function initFactory(platformUtilsService: PlatformUtilsService, i18nService: I18nService, storageService: StorageService,
popupUtilsService: PopupUtilsService): Function { popupUtilsService: PopupUtilsService): Function {
@@ -126,6 +125,7 @@ export function initFactory(platformUtilsService: PlatformUtilsService, i18nServ
DebounceNavigationService, DebounceNavigationService,
PopupUtilsService, PopupUtilsService,
BroadcasterService, BroadcasterService,
ModalService,
{ provide: MessagingService, useValue: messagingService }, { provide: MessagingService, useValue: messagingService },
{ provide: AuthServiceAbstraction, useFactory: getBgService<AuthService>('authService'), deps: [] }, { provide: AuthServiceAbstraction, useFactory: getBgService<AuthService>('authService'), deps: [] },
{ provide: StateServiceAbstraction, useValue: stateService }, { provide: StateServiceAbstraction, useValue: stateService },
@@ -188,7 +188,7 @@ export function initFactory(platformUtilsService: PlatformUtilsService, i18nServ
useFactory: () => isPrivateMode ? null : getBgService<I18nService>('i18nService')().translationLocale, useFactory: () => isPrivateMode ? null : getBgService<I18nService>('i18nService')().translationLocale,
deps: [], deps: [],
}, },
{ provide: PasswordRepromptServiceAbstraction, useValue: passwordRepromptService }, { provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService },
], ],
}) })
export class ServicesModule { export class ServicesModule {

View File

@@ -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 { isDev(): boolean {
return process.env.ENV === 'development'; return process.env.ENV === 'development';
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 878 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -130,6 +130,7 @@ const config = {
'content/autofill': './src/content/autofill.js', 'content/autofill': './src/content/autofill.js',
'content/autofiller': './src/content/autofiller.ts', 'content/autofiller': './src/content/autofiller.ts',
'content/notificationBar': './src/content/notificationBar.ts', 'content/notificationBar': './src/content/notificationBar.ts',
'content/contextMenuHandler': './src/content/contextMenuHandler.ts',
'content/shortcuts': './src/content/shortcuts.ts', 'content/shortcuts': './src/content/shortcuts.ts',
'content/message_handler': './src/content/message_handler.ts', 'content/message_handler': './src/content/message_handler.ts',
'notification/bar': './src/notification/bar.js', 'notification/bar': './src/notification/bar.js',