sshProfileSettings.component.ts 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. /* eslint-disable @typescript-eslint/explicit-module-boundary-types */
  2. import { Component, ViewChild } from '@angular/core'
  3. import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
  4. import { firstBy } from 'thenby'
  5. import { FileProvidersService, Platform, HostAppService, PromptModalComponent, PartialProfile, ProfilesService } from 'tabby-core'
  6. import { LoginScriptsSettingsComponent } from 'tabby-terminal'
  7. import { PasswordStorageService } from '../services/passwordStorage.service'
  8. import { ForwardedPortConfig, SSHAlgorithmType, SSHProfile } from '../api'
  9. import { supportedAlgorithms } from '../algorithms'
  10. /** @hidden */
  11. @Component({
  12. templateUrl: './sshProfileSettings.component.pug',
  13. })
  14. export class SSHProfileSettingsComponent {
  15. Platform = Platform
  16. profile: SSHProfile
  17. hasSavedPassword: boolean
  18. connectionMode: 'direct'|'proxyCommand'|'jumpHost'|'socksProxy'|'httpProxy' = 'direct'
  19. supportedAlgorithms = supportedAlgorithms
  20. algorithms: Record<string, Record<string, boolean>> = {}
  21. jumpHosts: PartialProfile<SSHProfile>[]
  22. @ViewChild('loginScriptsSettings') loginScriptsSettings: LoginScriptsSettingsComponent|null
  23. constructor (
  24. public hostApp: HostAppService,
  25. private profilesService: ProfilesService,
  26. private passwordStorage: PasswordStorageService,
  27. private ngbModal: NgbModal,
  28. private fileProviders: FileProvidersService,
  29. ) { }
  30. async ngOnInit () {
  31. this.jumpHosts = (await this.profilesService.getProfiles({ includeBuiltin: false })).filter(x => x.type === 'ssh' && x !== this.profile)
  32. this.jumpHosts.sort(firstBy(x => this.getJumpHostLabel(x)))
  33. for (const k of Object.values(SSHAlgorithmType)) {
  34. this.algorithms[k] = {}
  35. for (const alg of this.profile.options.algorithms?.[k] ?? []) {
  36. this.algorithms[k][alg] = true
  37. }
  38. }
  39. this.profile.options.auth = this.profile.options.auth ?? null
  40. this.profile.options.privateKeys ??= []
  41. if (this.profile.options.proxyCommand) {
  42. this.connectionMode = 'proxyCommand'
  43. } else if (this.profile.options.jumpHost) {
  44. this.connectionMode = 'jumpHost'
  45. } else if (this.profile.options.socksProxyHost) {
  46. this.connectionMode = 'socksProxy'
  47. } else if (this.profile.options.httpProxyHost) {
  48. this.connectionMode = 'httpProxy'
  49. }
  50. if (this.profile.options.user) {
  51. try {
  52. this.hasSavedPassword = !!await this.passwordStorage.loadPassword(this.profile)
  53. } catch (e) {
  54. console.error('Could not check for saved password', e)
  55. }
  56. }
  57. }
  58. getJumpHostLabel (p: PartialProfile<SSHProfile>) {
  59. return p.group ? `${this.profilesService.resolveProfileGroupName(p.group)} / ${p.name}` : p.name
  60. }
  61. async setPassword () {
  62. const modal = this.ngbModal.open(PromptModalComponent)
  63. modal.componentInstance.prompt = `Password for ${this.profile.options.user}@${this.profile.options.host}`
  64. modal.componentInstance.password = true
  65. try {
  66. const result = await modal.result.catch(() => null)
  67. if (result?.value) {
  68. this.passwordStorage.savePassword(this.profile, result.value)
  69. this.hasSavedPassword = true
  70. }
  71. } catch { }
  72. }
  73. clearSavedPassword () {
  74. this.hasSavedPassword = false
  75. this.passwordStorage.deletePassword(this.profile)
  76. }
  77. async addPrivateKey () {
  78. const ref = await this.fileProviders.selectAndStoreFile(`private key for ${this.profile.name}`).catch(() => null)
  79. if (ref) {
  80. this.profile.options.privateKeys = [
  81. ...this.profile.options.privateKeys!,
  82. ref,
  83. ]
  84. }
  85. }
  86. removePrivateKey (path: string) {
  87. this.profile.options.privateKeys = this.profile.options.privateKeys?.filter(x => x !== path)
  88. }
  89. save () {
  90. for (const k of Object.values(SSHAlgorithmType)) {
  91. this.profile.options.algorithms![k] = Object.entries(this.algorithms[k])
  92. .filter(([_, v]) => !!v)
  93. .map(([key, _]) => key)
  94. if(k !== SSHAlgorithmType.COMPRESSION) { this.profile.options.algorithms![k].sort() }
  95. }
  96. if (this.connectionMode !== 'jumpHost') {
  97. this.profile.options.jumpHost = undefined
  98. }
  99. if (this.connectionMode !== 'proxyCommand') {
  100. this.profile.options.proxyCommand = undefined
  101. }
  102. if (this.connectionMode !== 'socksProxy') {
  103. this.profile.options.socksProxyHost = undefined
  104. this.profile.options.socksProxyPort = undefined
  105. }
  106. if (this.connectionMode !== 'httpProxy') {
  107. this.profile.options.httpProxyHost = undefined
  108. this.profile.options.httpProxyPort = undefined
  109. }
  110. this.loginScriptsSettings?.save()
  111. }
  112. onForwardAdded (fw: ForwardedPortConfig) {
  113. this.profile.options.forwardedPorts = this.profile.options.forwardedPorts ?? []
  114. this.profile.options.forwardedPorts.push(fw)
  115. }
  116. onForwardRemoved (fw: ForwardedPortConfig) {
  117. this.profile.options.forwardedPorts = this.profile.options.forwardedPorts?.filter(x => x !== fw)
  118. }
  119. getConnectionDropdownTitle () {
  120. return {
  121. direct: 'Direct',
  122. proxyCommand: 'Proxy command',
  123. jumpHost: 'Jump host',
  124. socksProxy: 'SOCKS proxy',
  125. httpProxy: 'HTTP proxy',
  126. }[this.connectionMode]
  127. }
  128. }