mirror of
https://github.com/kingToolbox/WindTerm.git
synced 2026-08-18 10:33:28 +08:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21662a08f6 | ||
|
|
479b939b54 | ||
|
|
516b5aaa1f | ||
|
|
067d6e4045 | ||
|
|
1ec05ef658 | ||
|
|
822069d840 | ||
|
|
a246c1d81d |
60
README.md
60
README.md
@@ -1,5 +1,5 @@
|
||||
# WindTerm
|
||||
An innovative fast SSH/Telnet/Serial/Shell/sftp client.
|
||||
A professional SSH/Telnet/Serial/Shell/Sftp client for DevOps.
|
||||
|
||||
_Hello WindTerm :rose:, hello world!_
|
||||
|
||||
@@ -7,6 +7,7 @@ _Hello WindTerm :rose:, hello world!_
|
||||
|
||||
# License
|
||||
**Completely FREE for commercial and non-commercial use without limitations.**
|
||||
**All source codes (except thirdparty directory) are provided under the terms of Apache-2.0 license.**
|
||||
|
||||
# Introduction
|
||||
|
||||
@@ -28,31 +29,41 @@ Main Window:
|
||||
|
||||

|
||||
|
||||
Quick Bar:
|
||||
|
||||

|
||||
|
||||
Split views:
|
||||
|
||||

|
||||
|
||||
# Features
|
||||
- **Supports highlighting the opening and closing delimiter, such as (), [], {} and the customed delimiters.**
|
||||
- **Integrated sftp, scp client, supports download, upload, remove, rename, make new file/directory and so on.**
|
||||
- **Local and remote modes with vim keybindings. (Using Shift+Enter key to switch between remote and local mode**)
|
||||
- **Command palette.**
|
||||
- **Command sender.**
|
||||
- SSH v2, Telnet, Raw Tcp, Serial, Shell protocols implemented.
|
||||
- Support vt100, vt220, vt340, vt420, vt520, xterm, xterm-256-colors.
|
||||
- Support color schemes like vscode.
|
||||
- Support time stamp, folding, outlining, split views.
|
||||
- Support unicode, true-color, mouse protocol, etc.
|
||||
- Support auto wrap mode.
|
||||
- Support SSH auto login with password, public-key, keyboard-interactive, gssapi-with-mic.
|
||||
- Support SSH auto execution when session authenticated.
|
||||
- Support searching and previewing.
|
||||
- **Supports highlighting the opening and closing delimiter, such as (), [], {} and the customed delimiters.** [Intro Video](https://kingtoolbox.github.io/2020/06/28/pair/)
|
||||
- **Integrated sftp, scp client, supports download, upload, remove, rename, make new file/directory and so on.** [Intro Video](https://kingtoolbox.github.io/tags/transfer/)
|
||||
- **Local and remote modes with vim keybindings. (Using Shift+Enter key to switch between remote and local mode**) [Intro Video](https://kingtoolbox.github.io/2020/06/21/keyboard-modes/)
|
||||
- **Command palette.** [Intro Video](https://kingtoolbox.github.io/tags/command-palette/)
|
||||
- **Command sender.** [Intro Video](https://kingtoolbox.github.io/tags/sender/)
|
||||
- **Quick Bar.** [Intro Video](https://kingtoolbox.github.io/2020/08/22/quickbar/)
|
||||
- **Paste Dialog.** [Intro Video](https://kingtoolbox.github.io/2020/08/22/paste_dialog/)
|
||||
- SSH v2, Telnet, Raw Tcp, Serial, Shell protocols implemented. [Intro Video](https://kingtoolbox.github.io/2020/01/22/new-session/)
|
||||
- Supports vt100, vt220, vt340, vt420, vt520, xterm, xterm-256-colors.
|
||||
- Supports color schemes like vscode. [Intro Video](https://kingtoolbox.github.io/2020/01/23/highlight/)
|
||||
- Supports time stamp, folding, outlining, split views.
|
||||
- Supports unicode, true-color, mouse protocol, etc.
|
||||
- Supports auto wrap mode. [Intro Video](https://kingtoolbox.github.io/2020/01/22/auto-wrap/)
|
||||
- Supports SSH auto login with password, public-key, keyboard-interactive, gssapi-with-mic. [Intro Video](https://kingtoolbox.github.io/2020/01/23/auto-login/)
|
||||
- Supports session logging. [Intro Video](https://kingtoolbox.github.io/2020/07/21/logging/)
|
||||
- Supports SSH auto execution when session authenticated.
|
||||
- Supports SSH agent forwarding. [Intro Video](https://kingtoolbox.github.io/2020/08/22/ssh_agent_forwarding/)
|
||||
- Supports X11 forwarding. [Intro Video](https://kingtoolbox.github.io/2020/07/21/x11_forwarding/)
|
||||
- Supports direct/local port forwarding, reverse/remote port forwarding and dynamic port forwarding. [Intro Video](https://kingtoolbox.github.io/2020/07/21/port_forwarding/)
|
||||
- Supports searching and previewing. [Intro Video](https://kingtoolbox.github.io/2020/01/22/search-and-mark/)
|
||||
- Session dialog and session tree.
|
||||
- Rename and duplicate session.
|
||||
- Restore last sessions and layouts when restart.
|
||||
- Rename and duplicate session. [Intro Video](https://kingtoolbox.github.io/tags/tabbar/)
|
||||
- Restore last sessions and layouts when restart. [Intro Video](https://kingtoolbox.github.io/2020/01/22/restore-sessions/)
|
||||
- Protocols and terms can be customed.
|
||||
- All vttest tests have passed except Tektronix 4014.
|
||||
- High performance, low memory, low latency.
|
||||
- High performance, low memory, low latency. [Intro Video](https://kingtoolbox.github.io/2020/01/23/windterm-putty-performance/)
|
||||
|
||||
# Sftp Performance
|
||||
|
||||
@@ -258,30 +269,27 @@ DIGEdit is the text component of WindTerm.
|
||||
|
||||
**Release cycle:**
|
||||
|
||||
2-3 weeks.
|
||||
2-4 weeks.
|
||||
|
||||
**Next release (Early July,for reference only):**
|
||||
- X11 forwarding
|
||||
- Port forwarding (Tunnel)
|
||||
**Next release (Early September,for reference only):**
|
||||
- Auto complete
|
||||
- External tools
|
||||
|
||||
**Todo list:**
|
||||
- Protocols:
|
||||
- Rlogin
|
||||
- SSH
|
||||
- X11 Forwarding
|
||||
- Port forwarding (Tunnel)
|
||||
- ProxyCommand
|
||||
- UI:
|
||||
- Config dialog
|
||||
- Local filer for cmd, powershell
|
||||
- Quick command bar.
|
||||
- Terminal:
|
||||
- Linux bash
|
||||
- MacOs bash
|
||||
- Session:
|
||||
- Proxy
|
||||
- Chat mode
|
||||
- Log and log viewer
|
||||
- Log viewer
|
||||
- File transfer:
|
||||
- ftp, ftps
|
||||
- Xmodem, Ymodem, Zmodem(sz, rz)
|
||||
|
||||
BIN
images/screenshots/QuickBar.png
Normal file
BIN
images/screenshots/QuickBar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 185 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 234 KiB |
90
src/CircularBuffer.h
Normal file
90
src/CircularBuffer.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2020, WindTerm.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef CIRCULARBUFFER_H
|
||||
#define CIRCULARBUFFER_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtAlgorithms>
|
||||
#include <QtGlobal>
|
||||
|
||||
#define ROUND_UP_POW2(value) { (1 << (32 - qCountLeadingZeroBits(value))) }
|
||||
|
||||
template <typename T>
|
||||
class CircularBuffer {
|
||||
public:
|
||||
CircularBuffer(quint32 capacity)
|
||||
: m_currentIndex(0) {
|
||||
Q_ASSERT(capacity < (1 << 31));
|
||||
|
||||
m_capacity = ROUND_UP_POW2(capacity);
|
||||
m_mask = m_capacity - 1;
|
||||
m_buffer = static_cast<qint64 *>(calloc(m_capacity, sizeof(qint64)));
|
||||
|
||||
clear();
|
||||
}
|
||||
|
||||
~CircularBuffer() {
|
||||
free(m_buffer);
|
||||
m_buffer = nullptr;
|
||||
}
|
||||
|
||||
void append(const T &value) {
|
||||
m_buffer[++m_currentIndex & m_mask] = value;
|
||||
}
|
||||
|
||||
const T &at(qint64 index) const {
|
||||
Q_ASSERT(index >= std::max<qint64>(0, m_currentIndex + 1 - m_capacity) && index <= m_currentIndex);
|
||||
return m_buffer[index & m_mask];
|
||||
}
|
||||
|
||||
int capacity() const { return m_capacity; }
|
||||
void clear() {
|
||||
m_currentIndex = -1;
|
||||
memset(m_buffer, 0xFF, m_capacity * sizeof(qint64));
|
||||
|
||||
#ifdef _DEBUG
|
||||
for (int i = 0; i < m_capacity; i++) {
|
||||
Q_ASSERT(m_buffer[i] == -1);
|
||||
}
|
||||
#endif // _DEBUG
|
||||
}
|
||||
|
||||
qint64 currentIndex() const { return m_currentIndex; }
|
||||
qint64 minIndex() const { return std::max<qint64>(0, m_currentIndex + 1 - m_capacity); }
|
||||
|
||||
const T &operator [](qint64 index) const {
|
||||
Q_ASSERT(index >= std::max<qint64>(0, m_currentIndex + 1 - m_capacity) && index <= m_currentIndex);
|
||||
return m_buffer[index & m_mask];
|
||||
}
|
||||
|
||||
private:
|
||||
T *m_buffer;
|
||||
qint64 m_currentIndex;
|
||||
|
||||
int m_capacity;
|
||||
int m_mask;
|
||||
};
|
||||
|
||||
class Int64CircularBuffer : public CircularBuffer<qint64> {
|
||||
public:
|
||||
Int64CircularBuffer(quint32 capacity)
|
||||
: CircularBuffer<qint64>(capacity)
|
||||
{}
|
||||
};
|
||||
|
||||
#endif // CIRCULARBUFFER_H
|
||||
91
src/Cryptographic.cpp
Normal file
91
src/Cryptographic.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2020, WindTerm.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "Cryptographic.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <qpassworddigestor.h>
|
||||
#include <QRandomGenerator>
|
||||
|
||||
#include "openssl/evp.h"
|
||||
|
||||
constexpr int AES_256_IV_LENGTH = 16;
|
||||
constexpr int AES_256_KEY_LENGTH = 32;
|
||||
constexpr int PBKDF2_LENGTH = AES_256_IV_LENGTH + AES_256_KEY_LENGTH;
|
||||
constexpr int PBKDF2_ITERATION_COUNT = 100000;
|
||||
|
||||
QByteArray Cryptographic::decrypt(const QByteArray &data, const QByteArray &pbkdf2) {
|
||||
return doCrypt(QByteArray::fromBase64(data), Cryptographic::key(pbkdf2), Cryptographic::iv(pbkdf2), 0);
|
||||
}
|
||||
|
||||
QByteArray Cryptographic::doCrypt(QByteArray data, const QByteArray &key, const QByteArray &iv, int enc) {
|
||||
QByteArray crypted(data.length() + EVP_MAX_BLOCK_LENGTH, '\0');
|
||||
int cryptedLength = 0;
|
||||
int length;
|
||||
|
||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
||||
|
||||
EVP_CipherInit_ex(
|
||||
ctx,
|
||||
EVP_aes_256_cbc(),
|
||||
nullptr,
|
||||
reinterpret_cast<const uchar *>(key.constData()),
|
||||
reinterpret_cast<const uchar *>(iv.constData()),
|
||||
enc
|
||||
);
|
||||
|
||||
EVP_CipherUpdate(
|
||||
ctx,
|
||||
reinterpret_cast<uchar *>(crypted.data()),
|
||||
&length,
|
||||
reinterpret_cast<const uchar *>(data.constData()),
|
||||
data.length()
|
||||
);
|
||||
cryptedLength += length;
|
||||
|
||||
EVP_CipherFinal_ex(ctx, reinterpret_cast<uchar *>(crypted.data() + cryptedLength), &length);
|
||||
cryptedLength += length;
|
||||
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
|
||||
crypted.resize(cryptedLength);
|
||||
return crypted;
|
||||
}
|
||||
|
||||
QByteArray Cryptographic::encrypt(const QByteArray &data, const QByteArray &pbkdf2) {
|
||||
QByteArray encrypted = doCrypt(data, Cryptographic::key(pbkdf2), Cryptographic::iv(pbkdf2), 1);
|
||||
return encrypted.toBase64();
|
||||
}
|
||||
|
||||
QByteArray Cryptographic::iv(const QByteArray &pbkdf2) {
|
||||
Q_ASSERT(pbkdf2.length() == PBKDF2_LENGTH);
|
||||
return QByteArray::fromRawData(pbkdf2.constData() + AES_256_KEY_LENGTH, AES_256_IV_LENGTH);
|
||||
}
|
||||
|
||||
QByteArray Cryptographic::key(const QByteArray &pbkdf2) {
|
||||
Q_ASSERT(pbkdf2.length() == PBKDF2_LENGTH);
|
||||
return QByteArray::fromRawData(pbkdf2.constData(), AES_256_KEY_LENGTH);
|
||||
}
|
||||
|
||||
QByteArray Cryptographic::pbkdf2(const QByteArray &password, const QByteArray &salt) {
|
||||
return QPasswordDigestor::deriveKeyPbkdf2(QCryptographicHash::Sha3_512, password, salt, PBKDF2_ITERATION_COUNT, PBKDF2_LENGTH);
|
||||
}
|
||||
|
||||
QByteArray Cryptographic::salt() {
|
||||
QByteArray number = QByteArray::number(QRandomGenerator::system()->generate64());
|
||||
QByteArray numberHash = QCryptographicHash::hash(number, QCryptographicHash::Sha512);
|
||||
return numberHash.toBase64();
|
||||
}
|
||||
39
src/Cryptographic.h
Normal file
39
src/Cryptographic.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2020, WindTerm.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef CRYPTOGRAPHIC_H
|
||||
#define CRYPTOGRAPHIC_H
|
||||
|
||||
#pragma once
|
||||
|
||||
class QByteArray;
|
||||
|
||||
class Cryptographic {
|
||||
public:
|
||||
Cryptographic() = default;
|
||||
|
||||
static QByteArray decrypt(const QByteArray &data, const QByteArray &pbkdf2);
|
||||
static QByteArray encrypt(const QByteArray &data, const QByteArray &pbkdf2);
|
||||
static QByteArray pbkdf2(const QByteArray &password, const QByteArray &salt);
|
||||
static QByteArray salt();
|
||||
|
||||
private:
|
||||
static QByteArray doCrypt(QByteArray data, const QByteArray &key, const QByteArray &iv, int enc);
|
||||
static QByteArray iv(const QByteArray &pbkdf2);
|
||||
static QByteArray key(const QByteArray &pbkdf2);
|
||||
};
|
||||
|
||||
#endif // CRYPTOGRAPHIC_H
|
||||
@@ -4,6 +4,22 @@
|
||||
|
||||
Below is a list of (some) WindTerm components in alphabetical order, along with a brief description of each.
|
||||
|
||||
## CircularBuffer.h
|
||||
|
||||
A quick circular buffer template class.
|
||||
|
||||
## Cryptographic.h/cpp
|
||||
|
||||
A very safe encryption class using the PBKDF2-algorithm as defined in RFC 8018. WindTerm uses this class together with the user's master password to protect user data, including passwords, private keys and so on.
|
||||
|
||||
## Onigmo
|
||||
|
||||
An improved version based on Onigmo 5.13.5. In particular, **the addition of iterator makes it possible to match gap buffer or nonadjacent memory blocks.** Please refer to the sample files for how to use.
|
||||
An improved version based on Onigmo 5.13.5. In particular, **the addition of iterator makes it possible to match gap buffer or nonadjacent memory blocks.** Please refer to the sample files for how to use.
|
||||
|
||||
## ScopeGuard.h
|
||||
|
||||
A class of which the sole purpose is to run the function f in its destructor. This is useful for guaranteeing your cleanup code is executed.
|
||||
|
||||
## Spin.h
|
||||
|
||||
A high-performance spin mutex and locker.
|
||||
57
src/ScopeGuard.h
Normal file
57
src/ScopeGuard.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2020, WindTerm.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef SCOPEGUARD_H
|
||||
#define SCOPEGUARD_H
|
||||
|
||||
class ScopeGuard {
|
||||
typedef std::function<void()> GuardFunction;
|
||||
|
||||
public:
|
||||
ScopeGuard(GuardFunction acquire, GuardFunction release)
|
||||
: m_active(true)
|
||||
, m_release(std::move(release))
|
||||
{
|
||||
acquire();
|
||||
}
|
||||
|
||||
~ScopeGuard() {
|
||||
if (m_active) {
|
||||
m_release();
|
||||
}
|
||||
}
|
||||
|
||||
ScopeGuard() = delete;
|
||||
ScopeGuard(const ScopeGuard &) = delete;
|
||||
ScopeGuard &operator=(const ScopeGuard &) = delete;
|
||||
|
||||
ScopeGuard(ScopeGuard &&other)
|
||||
: m_active(other.m_active)
|
||||
, m_release(std::move(other.m_release))
|
||||
{
|
||||
other.cancel();
|
||||
}
|
||||
|
||||
void cancel() {
|
||||
m_active = false;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_active;
|
||||
GuardFunction m_release;
|
||||
};
|
||||
|
||||
#endif // SCOPEGUARD_H
|
||||
79
src/Spin.h
Normal file
79
src/Spin.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2020, WindTerm.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef SPIN_H
|
||||
#define SPIN_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
class SpinMutex {
|
||||
public:
|
||||
SpinMutex() {
|
||||
unlock();
|
||||
}
|
||||
|
||||
void yield(size_t nCount) {
|
||||
if (nCount < 2) {
|
||||
} else if (nCount < 16) {
|
||||
std::this_thread::yield();
|
||||
} else if (nCount < 32) {
|
||||
std::this_thread::sleep_for(std::chrono::nanoseconds(100));
|
||||
} else {
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(10));
|
||||
}
|
||||
}
|
||||
|
||||
void lock() {
|
||||
for (size_t i = 0; !try_lock(); i++) {
|
||||
yield(i);
|
||||
}
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
flag.clear(std::memory_order_release);
|
||||
}
|
||||
|
||||
bool try_lock() {
|
||||
return flag.test_and_set(std::memory_order_acquire) == false;
|
||||
}
|
||||
|
||||
private:
|
||||
SpinMutex(const SpinMutex &) = delete;
|
||||
SpinMutex &operator=(const SpinMutex &) = delete;
|
||||
|
||||
std::atomic_flag flag;
|
||||
};
|
||||
|
||||
template <typename LockType>
|
||||
class ThreadLocker {
|
||||
public:
|
||||
ThreadLocker(LockType& m_, bool bLock_ = true) : m(m_), bLock(bLock_) {
|
||||
if (bLock) m.lock();
|
||||
}
|
||||
|
||||
~ThreadLocker() {
|
||||
if (bLock) m.unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
LockType& m;
|
||||
bool bLock;
|
||||
};
|
||||
|
||||
#endif // SPIN_H
|
||||
Reference in New Issue
Block a user