Add support for browser biometrics on Firefox >= 87 (#1668)

This commit is contained in:
Oscar Hinton 2021-03-10 21:27:05 +01:00 committed by Chad Scharf
parent d0b307d36a
commit faf4c3e94a
5 changed files with 39 additions and 29 deletions

View File

@ -58,7 +58,6 @@ function dist(browserName, manifest) {
function distFirefox() {
return dist('firefox', (manifest) => {
delete manifest.content_security_policy;
delete manifest.optional_permissions;
removeShortcuts(manifest);
return manifest;
});

View File

@ -1441,18 +1441,18 @@
"biometricsNotSupportedDesc": {
"message": "Browser biometrics is not supported on this device."
},
"nativeMessagingPermissionPromptTitle": {
"message": "Additional Permission required"
},
"nativeMessagingPermissionPromptDesc": {
"message": "To enable browser biometrics we need to request an additional permission. Once allowed, the browser extension will reload and you may need to unlock your vault again."
},
"nativeMessaginPermissionErrorTitle": {
"message": "Permission not provided"
},
"nativeMessaginPermissionErrorDesc": {
"message": "Without permission to communicate with the Bitwarden Desktop Application we cannot provide biometrics in the browser extension. Please try again."
},
"nativeMessaginPermissionSidebarTitle": {
"message": "Permission request error"
},
"nativeMessaginPermissionSidebarDesc": {
"message": "This action cannot be done in the sidebar, please retry the action in the popup or popout."
},
"personalOwnershipSubmitError": {
"message": "Due to an Enterprise Policy, you are restricted from saving items to your personal vault. Change the Ownership option to an organization and choose from available Collections."
},

View File

@ -167,4 +167,13 @@ export class BrowserApi {
return chrome.runtime.connectNative(application);
}
}
static requestPermission(permission: any) {
if (BrowserApi.isWebExtensionsApi) {
return browser.permissions.request(permission);
}
return new Promise((resolve, reject) => {
chrome.permissions.request(permission, resolve);
});
}
}

View File

@ -23,6 +23,7 @@ import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { StorageService } from 'jslib/abstractions/storage.service';
import { UserService } from 'jslib/abstractions/user.service';
import { VaultTimeoutService } from 'jslib/abstractions/vaultTimeout.service';
import { PopupUtilsService } from '../services/popup-utils.service';
const RateUrls = {
[DeviceType.ChromeExtension]:
@ -59,7 +60,8 @@ export class SettingsComponent implements OnInit {
private analytics: Angulartics2, private vaultTimeoutService: VaultTimeoutService,
private storageService: StorageService, public messagingService: MessagingService,
private router: Router, private environmentService: EnvironmentService,
private cryptoService: CryptoService, private userService: UserService) {
private cryptoService: CryptoService, private userService: UserService,
private popupUtilsService: PopupUtilsService) {
}
async ngOnInit() {
@ -212,31 +214,30 @@ export class SettingsComponent implements OnInit {
async updateBiometric() {
if (this.biometric && this.supportsBiometric) {
// Request permission to use the optional permission for nativeMessaging
if (!this.platformUtilsService.isFirefox()) {
const hasPermission = await new Promise(resolve => {
chrome.permissions.contains({ permissions: ['nativeMessaging'] }, resolve);
});
let granted;
try {
granted = await BrowserApi.requestPermission({ permissions: ['nativeMessaging'] });
} catch (e) {
// tslint:disable-next-line
console.error(e);
if (!hasPermission) {
if (this.platformUtilsService.isFirefox() && this.popupUtilsService.inSidebar(window)) {
await this.platformUtilsService.showDialog(
this.i18nService.t('nativeMessagingPermissionPromptDesc'), this.i18nService.t('nativeMessagingPermissionPromptTitle'),
this.i18nService.t('nativeMessaginPermissionSidebarDesc'), this.i18nService.t('nativeMessaginPermissionSidebarTitle'),
this.i18nService.t('ok'), null);
const granted = await new Promise((resolve, reject) => {
chrome.permissions.request({ permissions: ['nativeMessaging'] }, resolve);
});
if (!granted) {
await this.platformUtilsService.showDialog(
this.i18nService.t('nativeMessaginPermissionErrorDesc'), this.i18nService.t('nativeMessaginPermissionErrorTitle'),
this.i18nService.t('ok'), null);
this.biometric = false;
return;
}
this.biometric = false;
return;
}
}
if (!granted) {
await this.platformUtilsService.showDialog(
this.i18nService.t('nativeMessaginPermissionErrorDesc'), this.i18nService.t('nativeMessaginPermissionErrorTitle'),
this.i18nService.t('ok'), null);
this.biometric = false;
return;
}
const submitted = Swal.fire({
heightAuto: false,
buttonsStyling: false,

View File

@ -292,8 +292,9 @@ export default class BrowserPlatformUtilsService implements PlatformUtilsService
});
}
supportsBiometric() {
return Promise.resolve(!this.isFirefox() && !this.isSafari());
async supportsBiometric() {
const isUnsuportedFirefox = this.isFirefox() && parseInt((await browser.runtime.getBrowserInfo()).version.split('.')[0], 10) < 87;
return !isUnsuportedFirefox && !this.isSafari();
}
authenticateBiometric() {