Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/terminalstudio/dartssh2
SSH and SFTP client written in pure Dart, aiming to be feature-rich as well as easy to use.
https://github.com/terminalstudio/dartssh2
dart flutter flutter-package sftp sftp-client ssh ssh-client
Last synced: about 10 hours ago
JSON representation
SSH and SFTP client written in pure Dart, aiming to be feature-rich as well as easy to use.
- Host: GitHub
- URL: https://github.com/terminalstudio/dartssh2
- Owner: TerminalStudio
- License: mit
- Created: 2021-10-04T10:47:23.000Z (about 3 years ago)
- Default Branch: master
- Last Pushed: 2024-08-29T16:11:43.000Z (3 months ago)
- Last Synced: 2024-08-30T06:36:19.937Z (3 months ago)
- Topics: dart, flutter, flutter-package, sftp, sftp-client, ssh, ssh-client
- Language: Dart
- Homepage: https://pub.dev/packages/dartssh2
- Size: 517 KB
- Stars: 205
- Watchers: 5
- Forks: 54
- Open Issues: 56
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
DartSSH 2
SSH and SFTP client written in pure Dart, aiming to be feature-rich as well as easy to use.> **dartssh2** is now a complete rewrite of [dartssh].
## โจ Features
- **Pure Dart**: Working with both Dart VM and Flutter.
- **SSH Session**: Executing commands, spawning shells, setting environment variables, pseudo terminals, etc.
- **Authentication**: Supports password, private key and interactive authentication method.
- **Forwarding**: Supports local forwarding and remote forwarding.
- **SFTP**: Supports all operations defined in [SFTPv3 protocol](https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02) including upload, download, list, link, remove, rename, etc.## ๐งฌ Built with dartssh2
ServerBox
Ssh! No Ports
DartShell
> Feel free to add your own app here by opening a pull request.
## ๐งช Try
```sh
# Install the `dartssh` command.
dart pub global activate dartssh2_cli# Then use `dartssh` as regular `ssh` command.
dartssh [email protected]# Example: execute a command on remote host.
dartssh [email protected] ls -al# Example: connect to a non-standard port.
dartssh [email protected]:# Transfer files via SFTP.
dartsftp [email protected]
```> If the `dartssh` command can't be found after installation, you might need to [set up your path](https://dart.dev/tools/pub/cmd/pub-global#running-a-script-from-your-path).
## ๐ Quick start
### Connect to a remote host
```dart
final client = SSHClient(
await SSHSocket.connect('localhost', 22),
username: '',
onPasswordRequest: () => '',
);
```> `SSHSocket` is an interface and it's possible to implement your own `SSHSocket` if you want to use a different underlying transport rather than standard TCP socket. For example WebSocket or Unix domain socket.
### Spawn a shell on remote host
```dart
final shell = await client.shell();
stdout.addStream(shell.stdout); // listening for stdout
stderr.addStream(shell.stderr); // listening for stderr
stdin.cast().listen(shell.write); // writing to stdinawait shell.done; // wait for shell to exit
client.close();
```### Execute a command on remote host
```dart
final uptime = await client.run('uptime');
print(utf8.decode(uptime));
```Ignoring stderr:
```dart
final uptime = await client.run('uptime', stderr: false);
print(utf8.decode(uptime));
```> `client.run()` is a convenience method that wraps `client.execute()` for running non-interactive commands.
### Start a process on remote host
```dart
final session = await client.execute('cat > file.txt');
await session.stdin.addStream(File('local_file.txt').openRead().cast());
await session.stdin.close(); // Close the sink to send EOF to the remote process.await session.done; // Wait for session to exit to ensure all data is flushed to the remote process.
print(session.exitCode); // You can get the exit code after the session is done
```> `session.write()` is a shorthand for `session.stdin.add()`. It's recommended to use `session.stdin.addStream()` instead of `session.write()` when you want to stream large amount of data to the remote process.
**Killing a remote process by sending signal**
```dart
session.kill(SSHSignal.KILL);
await session.done;
print('exitCode: ${session.exitCode}'); // -> exitCode: null
print('signal: ${session.exitSignal?.signalName}'); // -> signal: KILL
```Processes killed by signals do not have an exit code, instead they have an exit signal property.
### Forward connections on local port 8080 to the server
```dart
final serverSocket = await ServerSocket.bind('localhost', 8080);
await for (final socket in serverSocket) {
final forward = await client.forwardLocal('httpbin.org', 80);
forward.stream.cast>().pipe(socket);
socket.pipe(forward.sink);
}
```### Forward connections to port 2222 on the server to local port 22
```dart
final forward = await client.forwardRemote(port: 2222);if (forward == null) {
print('Failed to forward remote port');
return;
}await for (final connection in forward.connections) {
final socket = await Socket.connect('localhost', 22);
connection.stream.cast>().pipe(socket);
socket.pipe(connection.sink);
}
```### Authenticate with public keys
```dart
final client = SSHClient(
socket,
username: '',
identities: [
// A single private key file may contain multiple keys.
...SSHKeyPair.fromPem(await File('path/to/id_rsa').readAsString())
],
);
```### Use encrypted PEM files
```dart
// Test whether the private key is encrypted.
final encrypted = SSHKeyPair.isEncrypted(await File('path/to/id_rsa').readAsString());
print(encrypted);// If the private key is encrypted, you need to provide the passphrase.
final keys = SSHKeyPair.fromPem('', '');
print(keys);
```Decrypt PEM file with [`compute`](https://api.flutter.dev/flutter/foundation/compute-constant.html) in Flutter
```dart
List decryptKeyPairs(List args) {
return SSHKeyPair.fromPem(args[0], args[1]);
}final keypairs = await compute(decryptKeyPairs, ['', '']);
```### Get the version of SSH server
```dart
await client.authenticated;
print(client.remoteVersion); // SSH-2.0-OpenSSH_7.4p1
```### Connect through a jump server
```dart
final jumpServer = SSHClient(
await SSHSocket.connect('', 22),
username: '...',
onPasswordRequest: () => '...',
);final client = SSHClient(
await jumpServer.forwardLocal('', 22),
username: '...',
onPasswordRequest: () => '...',
);print(utf8.decode(await client.run('hostname'))); // -> hostname of
```
}## SFTP
### List remote directory
```dart
final sftp = await client.sftp();
final items = await sftp.listdir('/');
for (final item in items) {
print(item.longname);
}
```### Read remote file
```dart
final sftp = await client.sftp();
final file = await sftp.open('/etc/passwd');
final content = await file.readBytes();
print(latin1.decode(content));
```### Write remote file
```dart
final sftp = await client.sftp();
final file = await sftp.open('file.txt', mode: SftpFileOpenMode.write);
await file.writeBytes(utf8.encode('hello there!') as Uint8List);
```**Write at specific offset**
```dart
final data = utf8.encode('world') as Uint8List
await file.writeBytes(data, offset: 6);
```### File upload
```dart
final sftp = await client.sftp();
final file = await sftp.open('file.txt', mode: SftpFileOpenMode.create | SftpFileOpenMode.write);
await file.write(File('local_file.txt').openRead().cast());
```#### Pause and resume file upload
```dart
final uploader = await file.write(File('local_file.txt').openRead().cast());
// ...
await uploader.pause();
// ...
await uploader.resume();
await uploader.done;
```**Clear the remote file before opening it**
```dart
final file = await sftp.open('file.txt',
mode: SftpFileOpenMode.create | SftpFileOpenMode.truncate | SftpFileOpenMode.write
);
```### Directory operations
```dart
final sftp = await client.sftp();
await sftp.mkdir('/path/to/dir');
await sftp.rmdir('/path/to/dir');
```### Get/Set attributes from/to remote file/directory
```dart
await sftp.stat('/path/to/file');
await sftp.setStat(
'/path/to/file',
SftpFileAttrs(mode: SftpFileMode(userRead: true)),
);
```### Get the type of a remote file
```dart
final stat = await sftp.stat('/path/to/file');
print(stat.type);
// or
print(stat.isDirectory);
print(stat.isSocket);
print(stat.isSymbolicLink);
// ...
```### Create a link
```dart
final sftp = await client.sftp();
sftp.link('/from', '/to');
```### Get (estimated) total and free space on the remote filesystem
```dart
final sftp = await client.sftp();
final statvfs = await sftp.statvfs('/root');
print('total: ${statvfs.blockSize * statvfs.totalBlocks}');
print('free: ${statvfs.blockSize * statvfs.freeBlocks}');
```## ๐ช Example
### SSH client:
- [example/example.dart](https://github.com/TerminalStudio/dartssh2/blob/master/example/example.dart)
- [example/execute.dart](https://github.com/TerminalStudio/dartssh2/blob/master/example/execute.dart)
- [example/forward_local.dart](https://github.com/TerminalStudio/dartssh2/blob/master/example/forward_local.dart)
- [example/forward_remote.dart](https://github.com/TerminalStudio/dartssh2/blob/master/example/forward_remote.dart)
- [example/pubkey.dart](https://github.com/TerminalStudio/dartssh2/blob/master/example/pubkey.dart)
- [example/shell.dart](https://github.com/TerminalStudio/dartssh2/blob/master/example/shell.dart)
- [example/ssh_jump.dart](https://github.com/TerminalStudio/dartssh2/blob/master/example/ssh_jump.dart)### SFTP:
- [example/sftp_read.dart](https://github.com/TerminalStudio/dartssh2/blob/master/example/sftp_read.dart)
- [example/sftp_list.dart](https://github.com/TerminalStudio/dartssh2/blob/master/example/sftp_list.dart)
- [example/sftp_stat.dart](https://github.com/TerminalStudio/dartssh2/blob/master/example/sftp_stat.dart)
- [example/sftp_upload.dart](https://github.com/TerminalStudio/dartssh2/blob/master/example/sftp_upload.dart)
- [example/sftp_filetype.dart](https://github.com/TerminalStudio/dartssh2/blob/master/example/sftp_filetype.dart)## ๐ Supported algorithms
**Host key**:
- `ssh-rsa`
- `rsa-sha2-[256|512]`
- `ecdsa-sha2-nistp[256|384|521]`
- `ssh-ed25519`**Key exchange**:
- `curve25519-sha256`
- `ecdh-sha2-nistp[256|384|521] `
- `diffie-hellman-group-exchange-sha[1|256]`
- `diffie-hellman-group14-sha[1|256]`
- `diffie-hellman-group1-sha1 `
**Cipher**:
- `aes[128|192|256]-ctr`
- `aes[128|192|256]-cbc`**Integrity**:
- `hmac-md5`
- `hmac-sha1`
- `hmac-sha2-[256|512]`**Private key**:
| **Type** | **Decode** | **Decrypt** | **Encode** | **Encrypt** |
|---------------------|------------|-------------|------------|-------------|
| **RSA** | โ๏ธ | โ๏ธ | โ๏ธ | WIP |
| **OpenSSH RSA** | โ๏ธ | โ๏ธ | โ๏ธ | WIP |
| **OpenSSH ECDSA** | โ๏ธ | โ๏ธ | โ๏ธ | WIP |
| **OpenSSH Ed25519** | โ๏ธ | โ๏ธ | โ๏ธ | WIP |
## โณ Roadmap- [x] Fix broken tests.
- [x] Sound null safety.
- [x] Redesign API to allow starting multiple sessions.
- [x] Full SFTP.
- [ ] Server.## References
- [`RFC 4250`](https://datatracker.ietf.org/doc/html/rfc4250) The Secure Shell (SSH) Protocol Assigned Numbers.
- [`RFC 4251`](https://datatracker.ietf.org/doc/html/rfc4251) The Secure Shell (SSH) Protocol Architecture.
- [`RFC 4252`](https://datatracker.ietf.org/doc/html/rfc4252) The Secure Shell (SSH) Authentication Protocol.
- [`RFC 4253`](https://datatracker.ietf.org/doc/html/rfc4253) The Secure Shell (SSH) Transport Layer Protocol.
- [`RFC 4254`](https://datatracker.ietf.org/doc/html/rfc4254) The Secure Shell (SSH) Connection Protocol.
- [`RFC 4255`](https://datatracker.ietf.org/doc/html/rfc4255) Using DNS to Securely Publish Secure Shell (SSH) Key Fingerprints.
- [`RFC 4256`](https://datatracker.ietf.org/doc/html/rfc4256) Generic Message Exchange Authentication for the Secure Shell Protocol (SSH).
- [`RFC 4419`](https://datatracker.ietf.org/doc/html/rfc4419) Diffie-Hellman Group Exchange for the Secure Shell (SSH) Transport Layer Protocol.
- [`RFC 4716`](https://datatracker.ietf.org/doc/html/rfc4716) The Secure Shell (SSH) Public Key File Format.
- [`RFC 5656`](https://datatracker.ietf.org/doc/html/rfc5656) Elliptic Curve Algorithm Integration in the Secure Shell Transport Layer.
- [`RFC 8332`](https://datatracker.ietf.org/doc/html/rfc8332) Use of RSA Keys with SHA-256 and SHA-512 in the Secure Shell (SSH) Protocol.
- [`RFC 8731`](https://datatracker.ietf.org/doc/html/rfc8731) Secure Shell (SSH) Key Exchange Method Using Curve25519 and Curve448.
- [`draft-miller-ssh-agent-03`](https://datatracker.ietf.org/doc/html/draft-miller-ssh-agent-03) SSH Agent Protocol.
- [`draft-ietf-secsh-filexfer-02`](https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02) SSH File Transfer Protocol.
- [`draft-dbider-sha2-mac-for-ssh-06`](https://datatracker.ietf.org/doc/html/draft-dbider-sha2-mac-for-ssh-06) SHA-2 Data Integrity Verification for the Secure Shell (SSH) Transport Layer Protocol.## Credits
- [https://github.com/GreenAppers/dartssh](https://github.com/GreenAppers/dartssh) by GreenAppers.
## License
dartssh is released under the terms of the MIT license. See [LICENSE](LICENSE).
[dartssh]: https://github.com/GreenAppers/dartssh