added an option to reuse private keys stored in the vault

This commit is contained in:
Eugene Pankov 2021-06-28 21:32:12 +02:00
parent 52c37f8988
commit 63355d1a74
No known key found for this signature in database
GPG Key ID: 5896FCBBDD1CF4F4
9 changed files with 72 additions and 21 deletions

View File

@ -25,6 +25,7 @@ export { HomeBaseService } from '../services/homeBase.service'
export { HotkeysService } from '../services/hotkeys.service' export { HotkeysService } from '../services/hotkeys.service'
export { NotificationsService } from '../services/notifications.service' export { NotificationsService } from '../services/notifications.service'
export { ThemesService } from '../services/themes.service' export { ThemesService } from '../services/themes.service'
export { SelectorService } from '../services/selector.service'
export { TabsService } from '../services/tabs.service' export { TabsService } from '../services/tabs.service'
export { UpdaterService } from '../services/updater.service' export { UpdaterService } from '../services/updater.service'
export { VaultService, Vault, VaultSecret, VAULT_SECRET_TYPE_FILE } from '../services/vault.service' export { VaultService, Vault, VaultSecret, VAULT_SECRET_TYPE_FILE } from '../services/vault.service'

View File

@ -2,11 +2,9 @@
import { Observable, Subject, AsyncSubject } from 'rxjs' import { Observable, Subject, AsyncSubject } from 'rxjs'
import { takeUntil } from 'rxjs/operators' import { takeUntil } from 'rxjs/operators'
import { Injectable, Inject } from '@angular/core' import { Injectable, Inject } from '@angular/core'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { BaseTabComponent } from '../components/baseTab.component' import { BaseTabComponent } from '../components/baseTab.component'
import { SplitTabComponent } from '../components/splitTab.component' import { SplitTabComponent } from '../components/splitTab.component'
import { SelectorModalComponent } from '../components/selectorModal.component'
import { SelectorOption } from '../api/selector' import { SelectorOption } from '../api/selector'
import { RecoveryToken } from '../api/tabRecovery' import { RecoveryToken } from '../api/tabRecovery'
import { BootstrapData, BOOTSTRAP_DATA } from '../api/mainProcess' import { BootstrapData, BOOTSTRAP_DATA } from '../api/mainProcess'
@ -16,6 +14,7 @@ import { HostAppService } from '../api/hostApp'
import { ConfigService } from './config.service' import { ConfigService } from './config.service'
import { TabRecoveryService } from './tabRecovery.service' import { TabRecoveryService } from './tabRecovery.service'
import { TabsService, TabComponentType } from './tabs.service' import { TabsService, TabComponentType } from './tabs.service'
import { SelectorService } from './selector.service'
class CompletionObserver { class CompletionObserver {
get done$ (): Observable<void> { return this.done } get done$ (): Observable<void> { return this.done }
@ -77,7 +76,7 @@ export class AppService {
private hostWindow: HostWindowService, private hostWindow: HostWindowService,
private tabRecovery: TabRecoveryService, private tabRecovery: TabRecoveryService,
private tabsService: TabsService, private tabsService: TabsService,
private ngbModal: NgbModal, private selector: SelectorService,
@Inject(BOOTSTRAP_DATA) private bootstrapData: BootstrapData, @Inject(BOOTSTRAP_DATA) private bootstrapData: BootstrapData,
) { ) {
this.tabsChanged$.subscribe(() => { this.tabsChanged$.subscribe(() => {
@ -366,11 +365,8 @@ export class AppService {
this.completionObservers.delete(tab) this.completionObservers.delete(tab)
} }
// Deprecated
showSelector <T> (name: string, options: SelectorOption<T>[]): Promise<T> { showSelector <T> (name: string, options: SelectorOption<T>[]): Promise<T> {
const modal = this.ngbModal.open(SelectorModalComponent) return this.selector.show(name, options)
const instance: SelectorModalComponent<T> = modal.componentInstance
instance.name = name
instance.options = options
return modal.result as Promise<T>
} }
} }

View File

@ -1,11 +1,11 @@
import { Inject, Injectable } from '@angular/core' import { Inject, Injectable } from '@angular/core'
import { AppService, FileProvider, NotificationsService } from '../api' import { FileProvider, NotificationsService, SelectorService } from '../api'
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class FileProvidersService { export class FileProvidersService {
/** @hidden */ /** @hidden */
private constructor ( private constructor (
private app: AppService, private selector: SelectorService,
private notifications: NotificationsService, private notifications: NotificationsService,
@Inject(FileProvider) private fileProviders: FileProvider[], @Inject(FileProvider) private fileProviders: FileProvider[],
) { } ) { }
@ -40,7 +40,7 @@ export class FileProvidersService {
if (providers.length === 1) { if (providers.length === 1) {
return providers[0] return providers[0]
} }
return this.app.showSelector('Select file storage', providers.map(p => ({ return this.selector.show('Select file storage', providers.map(p => ({
name: p.name, name: p.name,
result: p, result: p,
}))) })))

View File

@ -0,0 +1,22 @@
import { Injectable } from '@angular/core'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { SelectorModalComponent } from '../components/selectorModal.component'
import { SelectorOption } from '../api/selector'
@Injectable({ providedIn: 'root' })
export class SelectorService {
/** @hidden */
private constructor (
private ngbModal: NgbModal,
) { }
show <T> (name: string, options: SelectorOption<T>[]): Promise<T> {
const modal = this.ngbModal.open(SelectorModalComponent)
const instance: SelectorModalComponent<T> = modal.componentInstance
instance.name = name
instance.options = options
return modal.result as Promise<T>
}
}

View File

@ -5,7 +5,8 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { AsyncSubject, Subject, Observable } from 'rxjs' import { AsyncSubject, Subject, Observable } from 'rxjs'
import { wrapPromise } from '../utils' import { wrapPromise } from '../utils'
import { UnlockVaultModalComponent } from '../components/unlockVaultModal.component' import { UnlockVaultModalComponent } from '../components/unlockVaultModal.component'
import { NotificationsService } from '../services/notifications.service' import { NotificationsService } from './notifications.service'
import { SelectorService } from './selector.service'
import { FileProvider } from '../api/fileProvider' import { FileProvider } from '../api/fileProvider'
import { PlatformService } from '../api/platform' import { PlatformService } from '../api/platform'
@ -226,6 +227,7 @@ export class VaultFileProvider extends FileProvider {
constructor ( constructor (
private vault: VaultService, private vault: VaultService,
private platform: PlatformService, private platform: PlatformService,
private selector: SelectorService,
private zone: NgZone, private zone: NgZone,
) { ) {
super() super()
@ -236,6 +238,32 @@ export class VaultFileProvider extends FileProvider {
} }
async selectAndStoreFile (description: string): Promise<string> { async selectAndStoreFile (description: string): Promise<string> {
const vault = await this.vault.load()
if (!vault) {
throw new Error('Vault is locked')
}
const files = vault.secrets.filter(x => x.type === VAULT_SECRET_TYPE_FILE)
if (files.length) {
const result = await this.selector.show<VaultSecret|null>('Select file', [
{
name: 'Add a new file',
icon: 'plus',
result: null,
},
...files.map(f => ({
name: f.key.description,
icon: 'file',
result: f,
})),
])
if (result) {
return `${this.prefix}${result.key.id}`
}
}
return this.addNewFile(description)
}
async addNewFile (description: string): Promise<string> {
const transfers = await this.platform.startUpload() const transfers = await this.platform.startUpload()
if (!transfers.length) { if (!transfers.length) {
throw new Error('Nothing selected') throw new Error('Nothing selected')

View File

@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { ToolbarButtonProvider, ToolbarButton, ConfigService, SelectorOption, AppService } from 'terminus-core' import { ToolbarButtonProvider, ToolbarButton, ConfigService, SelectorOption, SelectorService } from 'terminus-core'
import { ElectronService } from 'terminus-electron' import { ElectronService } from 'terminus-electron'
import { TerminalService } from './services/terminal.service' import { TerminalService } from './services/terminal.service'
@ -10,7 +10,7 @@ import { TerminalService } from './services/terminal.service'
export class ButtonProvider extends ToolbarButtonProvider { export class ButtonProvider extends ToolbarButtonProvider {
constructor ( constructor (
electron: ElectronService, electron: ElectronService,
private app: AppService, private selector: SelectorService,
private config: ConfigService, private config: ConfigService,
private terminal: TerminalService, private terminal: TerminalService,
) { ) {
@ -29,7 +29,7 @@ export class ButtonProvider extends ToolbarButtonProvider {
}) })
} }
await this.app.showSelector('Select profile', options) await this.selector.show('Select profile', options)
} }
provide (): ToolbarButton[] { provide (): ToolbarButton[] {

View File

@ -3,6 +3,7 @@ import colors from 'ansi-colors'
import { Spinner } from 'cli-spinner' import { Spinner } from 'cli-spinner'
import { Component, Injector } from '@angular/core' import { Component, Injector } from '@angular/core'
import { first } from 'rxjs/operators' import { first } from 'rxjs/operators'
import { SelectorService } from 'terminus-core'
import { BaseTerminalTabComponent } from 'terminus-terminal' import { BaseTerminalTabComponent } from 'terminus-terminal'
import { SerialService } from '../services/serial.service' import { SerialService } from '../services/serial.service'
import { SerialConnection, SerialSession, BAUD_RATES } from '../api' import { SerialConnection, SerialSession, BAUD_RATES } from '../api'
@ -23,6 +24,7 @@ export class SerialTabComponent extends BaseTerminalTabComponent {
// eslint-disable-next-line @typescript-eslint/no-useless-constructor // eslint-disable-next-line @typescript-eslint/no-useless-constructor
constructor ( constructor (
injector: Injector, injector: Injector,
private selector: SelectorService,
) { ) {
super(injector) super(injector)
this.serialService = injector.get(SerialService) this.serialService = injector.get(SerialService)
@ -122,7 +124,7 @@ export class SerialTabComponent extends BaseTerminalTabComponent {
} }
async changeBaudRate () { async changeBaudRate () {
const rate = await this.app.showSelector('Baud rate', BAUD_RATES.map(x => ({ const rate = await this.selector.show('Baud rate', BAUD_RATES.map(x => ({
name: x.toString(), result: x, name: x.toString(), result: x,
}))) })))
this.serialPort.update({ baudRate: rate }) this.serialPort.update({ baudRate: rate })

View File

@ -1,6 +1,6 @@
import { Injectable, NgZone } from '@angular/core' import { Injectable, NgZone } from '@angular/core'
import SerialPort from 'serialport' import SerialPort from 'serialport'
import { LogService, AppService, SelectorOption, ConfigService, NotificationsService } from 'terminus-core' import { LogService, AppService, SelectorOption, ConfigService, NotificationsService, SelectorService } from 'terminus-core'
import { SettingsTabComponent } from 'terminus-settings' import { SettingsTabComponent } from 'terminus-settings'
import { SerialConnection, SerialSession, SerialPortInfo, BAUD_RATES } from '../api' import { SerialConnection, SerialSession, SerialPortInfo, BAUD_RATES } from '../api'
import { SerialTabComponent } from '../components/serialTab.component' import { SerialTabComponent } from '../components/serialTab.component'
@ -12,6 +12,7 @@ export class SerialService {
private zone: NgZone, private zone: NgZone,
private notifications: NotificationsService, private notifications: NotificationsService,
private app: AppService, private app: AppService,
private selector: SelectorService,
private config: ConfigService, private config: ConfigService,
) { } ) { }
@ -124,7 +125,7 @@ export class SerialService {
}) })
await this.app.showSelector('Open a serial port', options) await this.selector.show('Open a serial port', options)
} }
async connect (connection: SerialConnection): Promise<SerialTabComponent> { async connect (connection: SerialConnection): Promise<SerialTabComponent> {
@ -170,7 +171,7 @@ export class SerialService {
} }
async connectFoundPort (port: SerialPortInfo): Promise<SerialTabComponent> { async connectFoundPort (port: SerialPortInfo): Promise<SerialTabComponent> {
const rate = await this.app.showSelector('Baud rate', BAUD_RATES.map(x => ({ const rate = await this.selector.show('Baud rate', BAUD_RATES.map(x => ({
name: x.toString(), result: x, name: x.toString(), result: x,
}))) })))
return this.quickConnect(`${port.name}@${rate}`) return this.quickConnect(`${port.name}@${rate}`)

View File

@ -5,7 +5,7 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { Client } from 'ssh2' import { Client } from 'ssh2'
import { exec } from 'child_process' import { exec } from 'child_process'
import { Subject, Observable } from 'rxjs' import { Subject, Observable } from 'rxjs'
import { Logger, LogService, AppService, SelectorOption, ConfigService, NotificationsService, HostAppService, Platform, PlatformService } from 'terminus-core' import { Logger, LogService, AppService, SelectorOption, ConfigService, NotificationsService, HostAppService, Platform, PlatformService, SelectorService } from 'terminus-core'
import { SettingsTabComponent } from 'terminus-settings' import { SettingsTabComponent } from 'terminus-settings'
import { ALGORITHM_BLACKLIST, ForwardedPort, SSHConnection, SSHSession } from '../api' import { ALGORITHM_BLACKLIST, ForwardedPort, SSHConnection, SSHSession } from '../api'
import { PromptModalComponent } from '../components/promptModal.component' import { PromptModalComponent } from '../components/promptModal.component'
@ -26,6 +26,7 @@ export class SSHService {
private passwordStorage: PasswordStorageService, private passwordStorage: PasswordStorageService,
private notifications: NotificationsService, private notifications: NotificationsService,
private app: AppService, private app: AppService,
private selector: SelectorService,
private config: ConfigService, private config: ConfigService,
hostApp: HostAppService, hostApp: HostAppService,
private platform: PlatformService, private platform: PlatformService,
@ -230,7 +231,7 @@ export class SSHService {
}) })
await this.app.showSelector('Open an SSH connection', options) await this.selector.show('Open an SSH connection', options)
} }
async connect (connection: SSHConnection): Promise<SSHTabComponent> { async connect (connection: SSHConnection): Promise<SSHTabComponent> {