Compare commits

...

24 Commits

Author SHA1 Message Date
Eugene Pankov
467684d9ab Update api.ts 2021-01-25 21:35:00 +01:00
Eugene Pankov
5069070040 added a 'copy current path' hotkey and context menu item - fixes #2586 2021-01-25 17:30:44 +01:00
Eugene Pankov
ecf5297bc3 Merge branch 'master' of github.com:Eugeny/terminus 2021-01-24 19:27:42 +01:00
Eugene Pankov
78bd90ac55 fixed window re-focusing on linux 2021-01-24 19:27:36 +01:00
Eugene Pankov
712589eb93 fixed #1510 2021-01-24 19:06:51 +01:00
Eugene Pankov
f103e71285 better handling of CLI args - fixes #1436 2021-01-24 19:06:41 +01:00
Eugene Pankov
0cf883cc4a bumped electron 2021-01-24 13:58:47 +01:00
Eugene Pankov
2b0ad0d558 ssh: 15s default keepalive interval 2021-01-24 13:33:54 +01:00
Eugene Pankov
67bacb9dd3 ssh: better session close and reconnect behaviours - fixes #3351, fixes #3010, fixes #3276, fixes #3074, fixes #2825, fixes #3285 2021-01-24 13:28:59 +01:00
Eugene Pankov
d0a597634d ssh: fixed clearing jump host in connection settings 2021-01-24 13:08:07 +01:00
Eugene Pankov
322014c409 Merge branch 'master' of github.com:Eugeny/terminus 2021-01-24 12:43:02 +01:00
Eugene Pankov
c751a8725b rollback node-pty to pre-napi state 2021-01-24 12:42:59 +01:00
Eugene Pankov
5417efe558 ssh: blacklist broken kex algorithms 2021-01-24 11:26:43 +01:00
Eugene
bf356fcd19 Merge pull request #3362 from mi544/readme-fix
Removes unnecessary asterisks from README
2021-01-22 09:37:05 +01:00
Maksim Verkhoturov
10ee66b9dd removes unnecessary asterisks 2021-01-21 15:45:37 -07:00
Eugene
763da0d80c Merge pull request #3310 from Eugeny/dependabot/npm_and_yarn/app/npm-6.14.11
Bump npm from 6.14.10 to 6.14.11 in /app
2021-01-15 15:12:16 +01:00
Eugene
8d46bb2181 Merge pull request #3290 from Eugeny/dependabot/npm_and_yarn/terminus-core/core-js-3.8.2
Bump core-js from 3.7.0 to 3.8.2 in /terminus-core
2021-01-15 15:12:05 +01:00
Eugene Pankov
fe936c7726 fixed #3333 - duplicate color schemes 2021-01-14 09:48:58 +01:00
Eugene Pankov
2f3e32990a Update macos.yml 2021-01-13 13:52:23 +01:00
Eugene Pankov
22344f8d54 Update macos.yml 2021-01-13 10:50:34 +01:00
Eugene Pankov
f6d37a39f4 Update macos.yml 2021-01-12 18:20:17 +01:00
dependabot-preview[bot]
0e4c60ad4b Bump npm from 6.14.10 to 6.14.11 in /app
Bumps [npm](https://github.com/npm/cli) from 6.14.10 to 6.14.11.
- [Release notes](https://github.com/npm/cli/releases)
- [Changelog](https://github.com/npm/cli/blob/v6.14.11/CHANGELOG.md)
- [Commits](https://github.com/npm/cli/compare/v6.14.10...v6.14.11)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-01-12 17:01:34 +00:00
dependabot-preview[bot]
e8c2171d8f Bump core-js from 3.7.0 to 3.8.2 in /terminus-core
Bumps [core-js](https://github.com/zloirock/core-js) from 3.7.0 to 3.8.2.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/compare/v3.7.0...v3.8.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-01-12 17:01:01 +00:00
Eugene Pankov
f7a5be2c67 downgraded electron 2021-01-12 17:59:13 +01:00
24 changed files with 220 additions and 61 deletions

View File

@@ -7,7 +7,9 @@ jobs:
matrix:
include:
- arch: x86_64
electron_setup_cmd: 'true'
- arch: arm64
electron_setup_cmd: 'yarn add -D electron@11.1.1'
steps:
- name: Checkout
@@ -27,6 +29,9 @@ jobs:
rm app/node_modules/.yarn-integrity
yarn
- name: Upgrade Electron for ARM builds
run: ${{ matrix.electron_setup_cmd }}
- name: Build native deps
run: scripts/build-native.js
env:

View File

@@ -1,4 +1,4 @@
****![](https://github.com/Eugeny/terminus/raw/master/docs/readme.png)
![](https://github.com/Eugeny/terminus/raw/master/docs/readme.png)
<p align="center">

View File

@@ -75,7 +75,7 @@ export class Application {
}
onGlobalHotkey (): void {
if (this.windows.some(x => x.isFocused())) {
if (this.windows.some(x => x.isFocused() && x.isVisible())) {
for (const window of this.windows) {
window.hide()
}
@@ -147,7 +147,7 @@ export class Application {
handleSecondInstance (argv: string[], cwd: string): void {
this.presentAllWindows()
this.windows[this.windows.length - 1].handleSecondInstance(argv, cwd)
this.windows[this.windows.length - 1].passCliArguments(argv, cwd, true)
}
private setupMenu () {

View File

@@ -53,7 +53,7 @@ if (argv.d) {
})
}
app.on('ready', () => {
app.on('ready', async () => {
if (process.platform === 'darwin') {
app.dock.setMenu(Menu.buildFromTemplate([
{
@@ -65,5 +65,8 @@ app.on('ready', () => {
]))
}
application.init()
application.newWindow({ hidden: argv.hidden })
const window = await application.newWindow({ hidden: argv.hidden })
await window.ready
window.passCliArguments(process.argv, process.cwd(), false)
})

View File

@@ -65,6 +65,7 @@ export class Window {
enableRemoteModule: true,
contextIsolation: false,
},
maximizable: true,
frame: false,
show: false,
backgroundColor: '#00000000',
@@ -190,6 +191,10 @@ export class Window {
return this.window.isFocused()
}
isVisible (): boolean {
return this.window.isVisible()
}
hide (): void {
if (process.platform === 'darwin') {
// Lose focus
@@ -225,8 +230,8 @@ export class Window {
}
}
handleSecondInstance (argv: string[], cwd: string): void {
this.send('host:second-instance', parseArgs(argv, cwd), cwd)
passCliArguments (argv: string[], cwd: string, secondInstance: boolean): void {
this.send('cli', parseArgs(argv, cwd), cwd, secondInstance)
}
private setupWindowManagement () {

View File

@@ -21,7 +21,7 @@
"@angular/platform-browser": "^9.1.9",
"@angular/platform-browser-dynamic": "^9.1.9",
"@ng-bootstrap/ng-bootstrap": "^6.1.0",
"@terminus-term/node-pty": "0.10.0-beta11",
"@terminus-term/node-pty": "0.10.0-beta10",
"electron-config": "2.0.0",
"electron-debug": "^3.0.1",
"electron-is-dev": "1.1.0",

View File

@@ -117,12 +117,12 @@
dependencies:
debug "^4.1.1"
"@terminus-term/node-pty@0.10.0-beta11":
version "0.10.0-beta11"
resolved "https://registry.yarnpkg.com/@terminus-term/node-pty/-/node-pty-0.10.0-beta11.tgz#9e83041bc0644f17a4329c41a13d09575653c544"
integrity sha512-ZrplD84UNV8qpCNpsG8DAo8fmoRP1Ynb9QsApIleCJjbeNvUP2ZAeR6wo0aV9B7Zqjvq5O4hoUSayIDGtORH+A==
"@terminus-term/node-pty@0.10.0-beta10":
version "0.10.0-beta10"
resolved "https://registry.yarnpkg.com/@terminus-term/node-pty/-/node-pty-0.10.0-beta10.tgz#de9dade3d7549d44b0906ec0d0b9e1bb411f1f21"
integrity sha512-j9RJk7sD/es4vR6+AR5M/p3SicVxY6kZEeE0UQKhHNcaAla90/mcGeBNicAWPaAkjO1uQZVbYh5cJMMu5unQgA==
dependencies:
node-addon-api "^3.0.2"
nan "^2.14.0"
"@types/mz@0.0.32":
version "0.0.32"
@@ -716,7 +716,7 @@ debug@^4.0.1, debug@^4.1.1, debug@^4.3.1:
dependencies:
ms "2.1.2"
debuglog@^1.0.1:
debuglog@*, debuglog@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz"
integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
@@ -1377,7 +1377,7 @@ import-lazy@^2.1.0:
resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=
imurmurhash@^0.1.4:
imurmurhash@*, imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz"
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
@@ -1405,7 +1405,7 @@ inherits@2.0.3:
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz"
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
ini@^1.3.4, ini@^1.3.5, ini@~1.3.0:
ini@^1.3.4, ini@^1.3.5, ini@^1.3.8, ini@~1.3.0:
version "1.3.8"
resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
@@ -1854,6 +1854,11 @@ lockfile@^1.0.4:
dependencies:
signal-exit "^3.0.2"
lodash._baseindexof@*:
version "3.1.0"
resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c"
integrity sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw=
lodash._baseuniq@~4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8"
@@ -1862,11 +1867,33 @@ lodash._baseuniq@~4.6.0:
lodash._createset "~4.0.0"
lodash._root "~3.0.0"
lodash._bindcallback@*:
version "3.0.1"
resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e"
integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4=
lodash._cacheindexof@*:
version "3.0.2"
resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92"
integrity sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI=
lodash._createcache@*:
version "3.1.2"
resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093"
integrity sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=
dependencies:
lodash._getnative "^3.0.0"
lodash._createset@~4.0.0:
version "4.0.3"
resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26"
integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=
lodash._getnative@*, lodash._getnative@^3.0.0:
version "3.9.1"
resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=
lodash._root@~3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692"
@@ -1877,6 +1904,11 @@ lodash.clonedeep@^4.5.0, lodash.clonedeep@~4.5.0:
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
lodash.restparam@*:
version "3.6.1"
resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=
lodash.union@~4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88"
@@ -2073,7 +2105,7 @@ mz@^2.7.0:
object-assign "^4.0.1"
thenify-all "^1.0.0"
nan@^2.13.2, nan@^2.14.2:
nan@^2.13.2, nan@^2.14.0, nan@^2.14.2:
version "2.14.2"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19"
integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==
@@ -2270,9 +2302,9 @@ npm-user-validate@^1.0.1:
integrity sha512-uQwcd/tY+h1jnEaze6cdX/LrhWhoBxfSknxentoqmIuStxUExxjWd3ULMLFPiFUrZKbOVMowH6Jq2FRWfmhcEw==
npm@6:
version "6.14.10"
resolved "https://registry.yarnpkg.com/npm/-/npm-6.14.10.tgz#f45c8e4244294ba793770f2ab0e9ce2d0b93fd29"
integrity sha512-FT23Qy/JMA+qxEYReMOr1MY7642fKn8Onn+72LASPi872Owvmw0svm+/DXTHOC3yO9CheEO+EslyXEpdBdRtIA==
version "6.14.11"
resolved "https://registry.yarnpkg.com/npm/-/npm-6.14.11.tgz#e0b5598d7b9a42d275e61d8bd28cd7eee0074a3b"
integrity sha512-1Zh7LjuIoEhIyjkBflSSGzfjuPQwDlghNloppjruOH5bmj9midT9qcNT0tRUZRR04shU9ekrxNy9+UTBrqeBpQ==
dependencies:
JSONStream "^1.3.5"
abbrev "~1.1.1"
@@ -2292,6 +2324,7 @@ npm@6:
cmd-shim "^3.0.3"
columnify "~1.5.4"
config-chain "^1.1.12"
debuglog "*"
detect-indent "~5.0.0"
detect-newline "^2.1.0"
dezalgo "~1.0.3"
@@ -2306,10 +2339,11 @@ npm@6:
has-unicode "~2.0.1"
hosted-git-info "^2.8.8"
iferr "^1.0.2"
imurmurhash "*"
infer-owner "^1.0.4"
inflight "~1.0.6"
inherits "^2.0.4"
ini "^1.3.5"
ini "^1.3.8"
init-package-json "^1.10.3"
is-cidr "^3.0.0"
json-parse-better-errors "^1.0.2"
@@ -2324,8 +2358,14 @@ npm@6:
libnpx "^10.2.4"
lock-verify "^2.1.0"
lockfile "^1.0.4"
lodash._baseindexof "*"
lodash._baseuniq "~4.6.0"
lodash._bindcallback "*"
lodash._cacheindexof "*"
lodash._createcache "*"
lodash._getnative "*"
lodash.clonedeep "~4.5.0"
lodash.restparam "*"
lodash.union "~4.6.0"
lodash.uniq "~4.5.0"
lodash.without "~4.4.0"
@@ -3025,16 +3065,16 @@ rxjs@^6.5.5:
dependencies:
tslib "^1.9.0"
safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.2.0:
safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
"safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz"

View File

@@ -17,7 +17,7 @@
"core-js": "^3.8.1",
"cross-env": "7.0.2",
"css-loader": "3.4.2",
"electron": "^11.1.1",
"electron": "12.0.0-beta.16",
"electron-builder": "22.10.4",
"electron-download": "^4.1.1",
"electron-installer-snap": "^5.1.0",

View File

@@ -1,14 +1,14 @@
import { Injectable } from '@angular/core'
import { TerminalColorSchemeProvider, TerminalColorScheme } from 'terminus-terminal'
const schemeContents = require.context('../schemes/', true, /.*/)
const schemeContents = require.context('../schemes/', false, /.*/)
@Injectable()
export class ColorSchemes extends TerminalColorSchemeProvider {
async getSchemes (): Promise<TerminalColorScheme[]> {
const schemes: TerminalColorScheme[] = []
schemeContents.keys().forEach(schemeFile => {
schemeContents.keys().filter(x => !x.startsWith('./')).forEach(schemeFile => {
const lines = (schemeContents(schemeFile).default as string).split('\n')
// process #define variables

View File

@@ -1,5 +1,6 @@
import type { BrowserWindow, TouchBar, MenuItemConstructorOptions } from 'electron'
import * as path from 'path'
import * as fs from 'mz/fs'
import shellEscape from 'shell-escape'
import { Observable, Subject } from 'rxjs'
import { Injectable, NgZone, EventEmitter } from '@angular/core'
@@ -150,9 +151,10 @@ export class HostAppService {
this.zone.run(() => this.displaysChanged.next())
})
electron.ipcRenderer.on('host:second-instance', (_$event, argv: any, cwd: string) => this.zone.run(() => {
electron.ipcRenderer.on('cli', (_$event, argv: any, cwd: string, secondInstance: boolean) => this.zone.run(async () => {
this.logger.info('Second instance', argv)
const op = argv._[0]
const opAsPath = path.resolve(cwd, op)
if (op === 'open') {
this.cliOpenDirectory.next(path.resolve(cwd, argv.directory))
} else if (op === 'run') {
@@ -167,7 +169,11 @@ export class HostAppService {
this.cliOpenProfile.next(argv.profileName)
} else if (op === undefined) {
this.newWindow()
} else {
} else if ((await fs.lstat(opAsPath)).isDirectory()) {
this.cliOpenDirectory.next(opAsPath)
}
if (secondInstance) {
this.secondInstance.next()
}
}))

View File

@@ -124,9 +124,9 @@ colorspace@1.1.x:
text-hex "1.0.x"
core-js@^3.1.2:
version "3.7.0"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.7.0.tgz#b0a761a02488577afbf97179e4681bf49568520f"
integrity sha512-NwS7fI5M5B85EwpWuIwJN4i/fbisQUwLwiSNUWeXlkAZ0sbBjLEvLvFLf1uzAUV66PcEPt4xCGCmOZSxVf3xzA==
version "3.8.2"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.8.2.tgz#0a1fd6709246da9ca8eff5bb0cbd15fba9ac7044"
integrity sha512-FfApuSRgrR6G5s58casCBd9M2k+4ikuu4wbW6pJyYU7bd9zvFc9qf7vr5xmrZOhT9nn+8uwlH1oRR9jTnFoA3A==
core-util-is@~1.0.0:
version "1.0.2"

View File

@@ -131,6 +131,10 @@ export class SerialSession extends BaseSession {
this.kill('TERM')
}
supportsWorkingDirectory (): boolean {
return false
}
async getWorkingDirectory (): Promise<string|null> {
return null
}

View File

@@ -363,6 +363,10 @@ export class SSHSession extends BaseSession {
this.kill('TERM')
}
supportsWorkingDirectory (): boolean {
return true
}
async getWorkingDirectory (): Promise<string|null> {
return null
}
@@ -398,3 +402,9 @@ export interface SSHConnectionGroup {
name: string
connections: SSHConnection[]
}
export const ALGORITHM_BLACKLIST = [
// cause native crashes in node crypto, use EC instead
'diffie-hellman-group-exchange-sha256',
'diffie-hellman-group-exchange-sha1',
]

View File

@@ -103,7 +103,7 @@
.header
.title Jump host
select.form-control([(ngModel)]='connection.jumpHost')
option([ngValue]='null') None
option(value='') None
option([ngValue]='x.name', *ngFor='let x of config.store.ssh.connections') {{x.name}}
.form-line

View File

@@ -3,7 +3,7 @@ import { Component } from '@angular/core'
import { NgbModal, NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import { ElectronService, HostAppService, ConfigService } from 'terminus-core'
import { PasswordStorageService } from '../services/passwordStorage.service'
import { SSHConnection, LoginScript, SSHAlgorithmType } from '../api'
import { SSHConnection, LoginScript, SSHAlgorithmType, ALGORITHM_BLACKLIST } from '../api'
import { PromptModalComponent } from './promptModal.component'
import { ALGORITHMS } from 'ssh2-streams/lib/constants'
@@ -40,8 +40,8 @@ export class EditConnectionModalComponent {
[SSHAlgorithmType.CIPHER]: 'CIPHER',
[SSHAlgorithmType.HMAC]: 'HMAC',
}[k]
this.supportedAlgorithms[k] = ALGORITHMS[supportedAlg]
this.defaultAlgorithms[k] = ALGORITHMS[defaultAlg]
this.supportedAlgorithms[k] = ALGORITHMS[supportedAlg].filter(x => !ALGORITHM_BLACKLIST.includes(x))
this.defaultAlgorithms[k] = ALGORITHMS[defaultAlg].filter(x => !ALGORITHM_BLACKLIST.includes(x))
}
}

View File

@@ -23,6 +23,9 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
session?: SSHSession
private sessionStack: SSHSession[] = []
private homeEndSubscription: Subscription
private recentInputs = ''
private reconnectOffered = false
private sessionHandlers: Subscription[] = []
constructor (
injector: Injector,
@@ -57,6 +60,10 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
this.frontendReady$.pipe(first()).subscribe(() => {
this.initializeSession()
this.input$.subscribe(data => {
this.recentInputs += data
this.recentInputs = this.recentInputs.substring(this.recentInputs.length - 32)
})
})
super.ngOnInit()
@@ -68,12 +75,19 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
async setupOneSession (session: SSHSession): Promise<void> {
if (session.connection.jumpHost) {
const jumpConnection = this.config.store.ssh.connections.find(x => x.name === session.connection.jumpHost)
const jumpConnection: SSHConnection|null = this.config.store.ssh.connections.find(x => x.name === session.connection.jumpHost)
if (!jumpConnection) {
throw new Error(`${session.connection.host}: jump host "${session.connection.jumpHost}" not found in your config`)
}
const jumpSession = this.ssh.createSession(jumpConnection)
await this.setupOneSession(jumpSession)
jumpSession.destroyed$.subscribe(() => session.destroy())
this.sessionHandlers.push(
jumpSession.destroyed$.subscribe(() => session.destroy())
)
session.jumpStream = await new Promise((resolve, reject) => jumpSession.ssh.forwardOut(
'127.0.0.1', 0, session.connection.host, session.connection.port ?? 22,
@@ -93,15 +107,31 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
this.sessionStack.push(session)
}
session.serviceMessage$.subscribe(msg => {
this.sessionHandlers.push(session.serviceMessage$.subscribe(msg => {
this.write(`\r\n${colors.black.bgWhite(' SSH ')} ${msg}\r\n`)
session.resize(this.size.columns, this.size.rows)
})
}))
session.destroyed$.subscribe(() => {
this.write('\r\n' + colors.black.bgCyan(' SSH ') + ` ${session.connection.host}: session closed\r\n`)
})
this.sessionHandlers.push(session.destroyed$.subscribe(() => {
if (
// Ctrl-D
this.recentInputs.charCodeAt(this.recentInputs.length - 1) === 4 ||
this.recentInputs.endsWith('exit\r')
) {
// User closed the session
this.destroy()
} else {
// Session was closed abruptly
this.write('\r\n' + colors.black.bgCyan(' SSH ') + ` ${session.connection.host}: session closed\r\n`)
if (!this.reconnectOffered) {
this.reconnectOffered = true
this.write('Press any key to reconnect\r\n')
this.input$.pipe(first()).subscribe(() => {
this.reconnect()
})
}
}
}))
this.write('\r\n' + colors.black.bgCyan(' SSH ') + ` Connecting to ${session.connection.host}\r\n`)
@@ -129,6 +159,7 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
}
async initializeSession (): Promise<void> {
this.reconnectOffered = false
if (!this.connection) {
this.logger.error('No SSH connection info supplied')
return
@@ -136,7 +167,11 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
this.session = this.ssh.createSession(this.connection)
await this.setupOneSession(this.session)
try {
await this.setupOneSession(this.session)
} catch (e) {
this.write(colors.black.bgRed(' X ') + ' ' + colors.red(e.message) + '\r\n')
}
this.attachSessionHandlers()
@@ -158,6 +193,10 @@ export class SSHTabComponent extends BaseTerminalTabComponent {
}
async reconnect (): Promise<void> {
for (const s of this.sessionHandlers) {
s.unsubscribe()
}
this.sessionHandlers = []
this.session?.destroy()
await this.initializeSession()
this.session?.releaseInitialDataBuffer()

View File

@@ -12,7 +12,7 @@ import * as sshpk from 'sshpk'
import { ToastrService } from 'ngx-toastr'
import { HostAppService, Platform, Logger, LogService, ElectronService, AppService, SelectorOption, ConfigService } from 'terminus-core'
import { SettingsTabComponent } from 'terminus-settings'
import { SSHConnection, SSHSession } from '../api'
import { ALGORITHM_BLACKLIST, SSHConnection, SSHSession } from '../api'
import { PromptModalComponent } from '../components/promptModal.component'
import { PasswordStorageService } from './passwordStorage.service'
import { SSHTabComponent } from '../components/sshTab.component'
@@ -147,6 +147,10 @@ export class SSHService {
session.ssh = ssh
let connected = false
let savedPassword: string|null = null
const algorithms = {}
for (const key of Object.keys(session.connection.algorithms ?? {})) {
algorithms[key] = session.connection.algorithms![key].filter(x => !ALGORITHM_BLACKLIST.includes(x))
}
await new Promise(async (resolve, reject) => {
ssh.on('ready', () => {
connected = true
@@ -258,7 +262,7 @@ export class SSHService {
tryKeyboard: true,
agent: agent ?? undefined,
agentForward: session.connection.agentForward && !!agent,
keepaliveInterval: session.connection.keepaliveInterval,
keepaliveInterval: session.connection.keepaliveInterval ?? 15000,
keepaliveCountMax: session.connection.keepaliveCountMax,
readyTimeout: session.connection.readyTimeout,
hostVerifier: (digest: string) => {
@@ -267,7 +271,7 @@ export class SSHService {
return true
},
hostHash: 'sha256' as any,
algorithms: session.connection.algorithms,
algorithms,
sock: session.jumpStream,
authHandler: methodsLeft => {
while (true) {

View File

@@ -18,6 +18,7 @@ import { TerminalDecorator } from './decorator'
/** @hidden */
export interface ToastrServiceProxy {
info: (_: string) => void
error: (_: string) => void
}
/**
* A class to base your custom terminal tabs on
@@ -140,7 +141,7 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
this.logger = this.log.create('baseTerminalTab')
this.setTitle('Terminal')
this.hotkeysSubscription = this.hotkeys.matchedHotkey.subscribe(hotkey => {
this.hotkeysSubscription = this.hotkeys.matchedHotkey.subscribe(async hotkey => {
if (!this.hasFocus) {
return
}
@@ -207,6 +208,9 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
case 'pane-focus-all':
this.focusAllPanes()
break
case 'copy-current-path':
this.copyCurrentPath()
break
}
})
this.bellPlayer = document.createElement('audio')
@@ -438,6 +442,19 @@ export class BaseTerminalTabComponent extends BaseTabComponent implements OnInit
}
}
async copyCurrentPath (): Promise<void> {
let cwd: string|null = null
if (this.session?.supportsWorkingDirectory()) {
cwd = await this.session.getWorkingDirectory()
}
if (cwd) {
this.electron.clipboard.writeText(cwd)
this.toastr.info('Copied')
} else {
this.toastr.error('Shell does not support current path detection')
}
}
/** @hidden */
ngOnDestroy (): void {
this.frontend?.detach(this.content.nativeElement)

View File

@@ -4,6 +4,7 @@ import { ConfigProvider, Platform } from 'terminus-core'
export class TerminalConfigProvider extends ConfigProvider {
defaults = {
hotkeys: {
'copy-current-path': [],
shell: {
__nonStructural: true,
},

View File

@@ -62,6 +62,10 @@ export class TerminalHotkeyProvider extends HotkeyProvider {
id: 'ctrl-c',
name: 'Intelligent Ctrl-C (copy/abort)',
},
{
id: 'copy-current-path',
name: 'Copy current path',
},
{
id: 'search',
name: 'Search',

View File

@@ -194,6 +194,9 @@ export default class TerminalModule { // eslint-disable-line @typescript-eslint/
})
hostApp.cliOpenDirectory$.subscribe(async directory => {
if (directory.length > 1 && (directory.endsWith('/') || directory.endsWith('\\'))) {
directory = directory.substring(0, directory.length - 1)
}
if (await fs.exists(directory)) {
if ((await fs.stat(directory)).isDirectory()) {
terminal.openTab(undefined, directory)

View File

@@ -87,6 +87,7 @@ export abstract class BaseSession {
abstract kill (signal?: string): void
abstract async getChildProcesses (): Promise<ChildProcess[]>
abstract async gracefullyKillProcess (): Promise<void>
abstract supportsWorkingDirectory (): boolean
abstract async getWorkingDirectory (): Promise<string|null>
}
@@ -259,6 +260,16 @@ export class Session extends BaseSession {
}
}
supportsWorkingDirectory (): boolean {
if (this.reportedCWD || this.guessedCWD) {
return true
}
if (!this.truePID) {
return false
}
return process.platform !== 'win32'
}
async getWorkingDirectory (): Promise<string|null> {
if (this.reportedCWD) {
return this.reportedCWD

View File

@@ -123,6 +123,13 @@ export class NewTabContextMenu extends TabContextMenuItemProvider {
})
}
if (tab instanceof TerminalTabComponent && tab.session?.supportsWorkingDirectory()) {
items.push({
label: 'Copy current path',
click: () => this.zone.run(() => tab.copyCurrentPath()),
})
}
return items
}
}

View File

@@ -359,10 +359,10 @@
resolved "https://registry.npmjs.org/@types/node/-/node-14.14.14.tgz"
integrity sha512-UHnOPWVWV1z+VV8k6L1HhG7UbGBgIdghqF3l9Ny9ApPghbjICXkUJSd/b9gOgQfjM1r+37cipdw/HJ3F6ICEnQ==
"@types/node@^12.0.12":
version "12.19.9"
resolved "https://registry.npmjs.org/@types/node/-/node-12.19.9.tgz"
integrity sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q==
"@types/node@^14.6.2":
version "14.14.22"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.22.tgz#0d29f382472c4ccf3bd96ff0ce47daf5b7b84b18"
integrity sha512-g+f/qj/cNcqKkc3tFqlXOYjrmZA+jNBiDzbP3kH+B+otKFqAdPgVTGP1IeKRdMml/aE69as5S4FqtxAbl+LaMw==
"@types/plist@^3.0.1":
version "3.0.2"
@@ -2482,13 +2482,13 @@ electron-to-chromium@^1.3.621:
resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.629.tgz"
integrity sha512-iSPPJtPvHrMAvYOt+9cdbDmTasPqwnwz4lkP8Dn200gDNUBQOLQ96xUsWXBwXslAo5XxdoXAoQQ3RAy4uao9IQ==
electron@^11.1.1:
version "11.1.1"
resolved "https://registry.yarnpkg.com/electron/-/electron-11.1.1.tgz#188f036f8282798398dca9513e9bb3b10213e3aa"
integrity sha512-tlbex3xosJgfileN6BAQRotevPRXB/wQIq48QeQ08tUJJrXwE72c8smsM/hbHx5eDgnbfJ2G3a60PmRjHU2NhA==
electron@12.0.0-beta.16:
version "12.0.0-beta.16"
resolved "https://registry.yarnpkg.com/electron/-/electron-12.0.0-beta.16.tgz#8142fe7af8ee85a181575063db689d6da4175899"
integrity sha512-8fsosa7PLnfheNqVK5G+NToZBh4audSVJIwff4vKorCkNK3XDMQCoHD9JKFeVRczYlb4YEY2mh7SsX4C8p9FMQ==
dependencies:
"@electron/get" "^1.0.1"
"@types/node" "^12.0.12"
"@types/node" "^14.6.2"
extract-zip "^1.0.3"
emoji-regex@^7.0.1: