1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-11-30 13:03:53 +01:00

Merge pull request #717 from bitwarden/add-totp-quick-copy-buttons

Add main menu copy and shortcut and context copy for totp
This commit is contained in:
Matt Gibson 2021-02-08 13:24:32 -06:00 committed by GitHub
commit a0e80fc486
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 50 additions and 4 deletions

View File

@ -53,6 +53,6 @@ export class SendComponent extends BaseSendComponent implements OnInit {
} }
get selectedSendType() { get selectedSendType() {
return this.sends.find((s) => s.id === this.sendId).type; return this.sends.find(s => s.id === this.sendId).type;
} }
} }

View File

@ -40,11 +40,14 @@ import { EventType } from 'jslib/enums/eventType';
import { CipherView } from 'jslib/models/view/cipherView'; import { CipherView } from 'jslib/models/view/cipherView';
import { FolderView } from 'jslib/models/view/folderView'; import { FolderView } from 'jslib/models/view/folderView';
import { userError } from '@angular/compiler-cli/src/transformers/util';
import { EventService } from 'jslib/abstractions/event.service'; import { EventService } from 'jslib/abstractions/event.service';
import { I18nService } from 'jslib/abstractions/i18n.service'; import { I18nService } from 'jslib/abstractions/i18n.service';
import { MessagingService } from 'jslib/abstractions/messaging.service'; import { MessagingService } from 'jslib/abstractions/messaging.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { SyncService } from 'jslib/abstractions/sync.service'; import { SyncService } from 'jslib/abstractions/sync.service';
import { TotpService } from 'jslib/abstractions/totp.service';
import { UserService } from 'jslib/abstractions/user.service';
const SyncInterval = 6 * 60 * 60 * 1000; // 6 hours const SyncInterval = 6 * 60 * 60 * 1000; // 6 hours
const BroadcasterSubscriptionId = 'VaultComponent'; const BroadcasterSubscriptionId = 'VaultComponent';
@ -77,6 +80,7 @@ export class VaultComponent implements OnInit, OnDestroy {
addCollectionIds: string[] = null; addCollectionIds: string[] = null;
showingModal = false; showingModal = false;
deleted = false; deleted = false;
userHasPremiumAccess = false;
private modal: ModalComponent = null; private modal: ModalComponent = null;
@ -85,9 +89,11 @@ export class VaultComponent implements OnInit, OnDestroy {
private broadcasterService: BroadcasterService, private changeDetectorRef: ChangeDetectorRef, private broadcasterService: BroadcasterService, private changeDetectorRef: ChangeDetectorRef,
private ngZone: NgZone, private syncService: SyncService, private analytics: Angulartics2, private ngZone: NgZone, private syncService: SyncService, private analytics: Angulartics2,
private toasterService: ToasterService, private messagingService: MessagingService, private toasterService: ToasterService, private messagingService: MessagingService,
private platformUtilsService: PlatformUtilsService, private eventService: EventService) { } private platformUtilsService: PlatformUtilsService, private eventService: EventService,
private totpService: TotpService, private userService: UserService) { }
async ngOnInit() { async ngOnInit() {
this.userHasPremiumAccess = await this.userService.canAccessPremium();
this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => { this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => {
this.ngZone.run(async () => { this.ngZone.run(async () => {
let detectChanges = true; let detectChanges = true;
@ -170,6 +176,14 @@ export class VaultComponent implements OnInit, OnDestroy {
this.copyValue(pCipher.login.password, 'password'); this.copyValue(pCipher.login.password, 'password');
} }
break; break;
case 'copyTotp':
const tComponent = this.addEditComponent == null ? this.viewComponent : this.addEditComponent;
const tCipher = tComponent != null ? tComponent.cipher : null;
if (this.cipherId != null && tCipher != null && tCipher.id === this.cipherId &&
tCipher.login != null && tCipher.login.hasTotp && this.userHasPremiumAccess) {
const value = await this.totpService.getCode(tCipher.login.totp);
this.copyValue(value, 'verificationCodeTotp');
}
default: default:
detectChanges = false; detectChanges = false;
break; break;
@ -308,6 +322,15 @@ export class VaultComponent implements OnInit, OnDestroy {
}, },
})); }));
} }
if (cipher.login.hasTotp && (cipher.organizationUseTotp || this.userHasPremiumAccess)) {
menu.append(new remote.MenuItem({
label: this.i18nService.t('copyVerificationCodeTotp'),
click: async () => {
const value = await this.totpService.getCode(cipher.login.totp);
this.copyValue(value, 'verificationCodeTotp');
},
}));
}
break; break;
case CipherType.Card: case CipherType.Card:
if (cipher.card.number != null || cipher.card.code != null) { if (cipher.card.number != null || cipher.card.code != null) {

View File

@ -367,6 +367,9 @@
"copyUri": { "copyUri": {
"message": "Copy URI" "message": "Copy URI"
}, },
"copyVerificationCodeTotp": {
"message": "Copy Verification Code (TOTP)"
},
"length": { "length": {
"message": "Length" "message": "Length"
}, },

View File

@ -38,6 +38,7 @@ export class MenuMain extends BaseMenu {
searchVault: MenuItem; searchVault: MenuItem;
copyUsername: MenuItem; copyUsername: MenuItem;
copyPassword: MenuItem; copyPassword: MenuItem;
copyTotp: MenuItem;
unlockedRequiredMenuItems: MenuItem[] = []; unlockedRequiredMenuItems: MenuItem[] = [];
constructor(private main: Main) { constructor(private main: Main) {
@ -67,6 +68,7 @@ export class MenuMain extends BaseMenu {
this.searchVault = this.menu.getMenuItemById('searchVault'); this.searchVault = this.menu.getMenuItemById('searchVault');
this.copyUsername = this.menu.getMenuItemById('copyUsername'); this.copyUsername = this.menu.getMenuItemById('copyUsername');
this.copyPassword = this.menu.getMenuItemById('copyPassword'); this.copyPassword = this.menu.getMenuItemById('copyPassword');
this.copyTotp = this.menu.getMenuItemById('copyTotp');
this.unlockedRequiredMenuItems = [ this.unlockedRequiredMenuItems = [
this.addNewLogin, this.addNewItem, this.addNewFolder, this.addNewLogin, this.addNewItem, this.addNewFolder,
@ -170,6 +172,12 @@ export class MenuMain extends BaseMenu {
click: () => this.main.messagingService.send('copyPassword'), click: () => this.main.messagingService.send('copyPassword'),
accelerator: 'CmdOrCtrl+P', accelerator: 'CmdOrCtrl+P',
}, },
{
label: this.main.i18nService.t('copyVerificationCodeTotp'),
id: 'copyTotp',
click: () => this.main.messagingService.send('copyTotp'),
accelerator: 'CmdOrCtrl+T',
},
]); ]);
if (!isWindowsStore() && !isMacAppStore()) { if (!isWindowsStore() && !isMacAppStore()) {

View File

@ -73,8 +73,8 @@ export class NativeMessagingMain {
'allowed_origins': [ 'allowed_origins': [
'chrome-extension://nngceckbapebfimnlniiiahkandclblb/', 'chrome-extension://nngceckbapebfimnlniiiahkandclblb/',
'chrome-extension://jbkfoedolllekgbhcbcoahefnbanhhlh/', 'chrome-extension://jbkfoedolllekgbhcbcoahefnbanhhlh/',
'chrome-extension://ccnckbpmaceehanjmeomladnmlffdjgn/' 'chrome-extension://ccnckbpmaceehanjmeomladnmlffdjgn/',
] ],
}}; }};
switch (process.platform) { switch (process.platform) {

View File

@ -58,6 +58,18 @@
"semicolon": [ "semicolon": [
true, true,
"always" "always"
],
"trailing-comma": [
true,
{
"multiline": {
"objects": "always",
"arrays": "always",
"functions": "ignore",
"typeLiterals": "ignore"
},
"singleline": "never"
}
] ]
} }
} }