diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..641a53f
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,13 @@
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
+
+version: 2
+updates:
+ - package-ecosystem: "pub"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ time: "09:00"
+ timezone: Europe/Madrid
\ No newline at end of file
diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml
index 60bebeb..6ee41a6 100644
--- a/.github/workflows/dart.yml
+++ b/.github/workflows/dart.yml
@@ -1,10 +1,6 @@
name: Dart
-on:
- push:
- branches: [master]
- pull_request:
- branches: [master]
+on: push
jobs:
test:
@@ -13,11 +9,10 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
- # sdk: [stable, beta, dev, 2.10.3, 2.12.0-29.10.beta]
- sdk: [stable, dev]
+ sdk: [stable]
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v4
- uses: dart-lang/setup-dart@v1
with:
sdk: ${{ matrix.sdk }}
@@ -43,4 +38,11 @@ jobs:
run: dart pub global run coverage:test_with_coverage
- name: Upload coverage
- uses: codecov/codecov-action@v3
+ uses: codecov/codecov-action@v4
+ with:
+ fail_ci_if_error: true # optional (default = false)
+ files: ./coverage1.xml,./coverage2.xml # optional
+ flags: unittests # optional
+ name: codecov-umbrella # optional
+ token: ${{ secrets.CODECOV_TOKEN }} # required
+ verbose: true # optional (default = false)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2b3c51f..4ba7e7b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,6 @@
+## [3.0.1] - 2024-11-05
+- Merged with 104910b1bde52ea304bffaa97d6f2487353c974d from https://github.com/TerminalStudio/dartssh2.git
+
## [3.0.0] - 2024-08-13
- Changed version constraints for package `pinenacl` from `^0.5.0` to `">=0.5.0 <1.0.0"` to support Dart SDK `>= 3.5.0`. See Dart SDK [Changelog](https://github.com/dart-lang/sdk/blob/3ccadc5c277a6c70f207d14600524578f4c527ad/CHANGELOG.md?plain=1#L106).
@@ -168,6 +171,11 @@
- Initial release.
+[#101]: https://github.com/TerminalStudio/dartssh2/pull/101
+[#100]: https://github.com/TerminalStudio/dartssh2/issues/100
+[#80]: https://github.com/TerminalStudio/dartssh2/issues/80
+[#71]: https://github.com/TerminalStudio/dartssh2/issues/71
+[#50]: https://github.com/TerminalStudio/dartssh2/issues/50
[#24]: https://github.com/TerminalStudio/dartssh2/issues/24
[#21]: https://github.com/TerminalStudio/dartssh2/issues/21
[#18]: https://github.com/TerminalStudio/dartssh2/issues/18
@@ -177,4 +185,4 @@
[@linhanyu]: https://github.com/linhanyu
[@Migarl]: https://github.com/Migarl
-[@PIDAMI]: https://github.com/PIDAMI
\ No newline at end of file
+[@PIDAMI]: https://github.com/PIDAMI
diff --git a/README.md b/README.md
index a4bbfb7..320da78 100644
--- a/README.md
+++ b/README.md
@@ -1,25 +1,23 @@
-
-
DartSSH 3
-
+DartSSH 3
-
+
-
+
-
+
-
-
+
+
-
+
+
+
-
+
SSH and SFTP client written in pure Dart, aiming to be feature-rich as well as easy to use.
@@ -38,29 +36,39 @@ SSH and SFTP client written in pure Dart, aiming to be feature-rich as well as e
+
> Feel free to add your own app here by opening a pull request.
@@ -341,20 +349,20 @@ print('free: ${statvfs.blockSize * statvfs.freeBlocks}');
### 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)
+- [example/example.dart](https://github.com/obemu/dartssh3/blob/master/example/example.dart)
+- [example/execute.dart](https://github.com/obemu/dartssh3/blob/master/example/execute.dart)
+- [example/forward_local.dart](https://github.com/obemu/dartssh3/blob/master/example/forward_local.dart)
+- [example/forward_remote.dart](https://github.com/obemu/dartssh3/blob/master/example/forward_remote.dart)
+- [example/pubkey.dart](https://github.com/obemu/dartssh3/blob/master/example/pubkey.dart)
+- [example/shell.dart](https://github.com/obemu/dartssh3/blob/master/example/shell.dart)
+- [example/ssh_jump.dart](https://github.com/obemu/dartssh3/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)
+- [example/sftp_read.dart](https://github.com/obemu/dartssh3/blob/master/example/sftp_read.dart)
+- [example/sftp_list.dart](https://github.com/obemu/dartssh3/blob/master/example/sftp_list.dart)
+- [example/sftp_stat.dart](https://github.com/obemu/dartssh3/blob/master/example/sftp_stat.dart)
+- [example/sftp_upload.dart](https://github.com/obemu/dartssh3/blob/master/example/sftp_upload.dart)
+- [example/sftp_filetype.dart](https://github.com/obemu/dartssh3/blob/master/example/sftp_filetype.dart)
@@ -385,45 +393,45 @@ print('free: ${statvfs.blockSize * statvfs.freeBlocks}');
**Private key**:
| **Type** | **Decode** | **Decrypt** | **Encode** | **Encrypt** |
-| ------------------- | ---------- | ----------- | ---------- | ----------- |
-| **RSA** | ✔️ | ✔️ | ✔️ | WIP |
-| **OpenSSH RSA** | ✔️ | ✔️ | ✔️ | WIP |
-| **OpenSSH ECDSA** | ✔️ | ✔️ | ✔️ | WIP |
-| **OpenSSH Ed25519** | ✔️ | ✔️ | ✔️ | WIP |
+|---------------------|------------|-------------|------------|-------------|
+| **RSA** | ✔️ | ✔️ | ✔️ | WIP |
+| **OpenSSH RSA** | ✔️ | ✔️ | ✔️ | WIP |
+| **OpenSSH ECDSA** | ✔️ | ✔️ | ✔️ | WIP |
+| **OpenSSH Ed25519** | ✔️ | ✔️ | ✔️ | WIP |
## ⏳ Roadmap
-- [x] Fix broken tests
-- [x] Sound null safety
+- [x] Fix broken tests.
+- [x] Sound null safety.
- [x] Redesign API to allow starting multiple sessions.
-- [x] Full SFTP
-- [ ] Server
+- [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
+- [`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 by GreenAppers
+- [https://github.com/GreenAppers/dartssh](https://github.com/GreenAppers/dartssh) by GreenAppers.
-https://github.com/TerminalStudio/dartssh2 by TerminalStudio
+- [https://github.com/TerminalStudio/dartssh2](https://github.com/TerminalStudio/dartssh2) by TerminalStudio
## License
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 39158cf..20e134a 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -3,25 +3,8 @@ include: package:lints/recommended.yaml
linter:
rules:
prefer_function_declarations_over_variables: false
+ prefer_relative_imports: true
analyzer:
plugins:
- - dart_code_metrics
-
-dart_code_metrics:
- anti-patterns:
- # - long-method
- # - long-parameter-list
- metrics:
- cyclomatic-complexity: 20
- maximum-nesting-level: 5
- number-of-parameters: 4
- source-lines-of-code: 50
- metrics-exclude:
- - test/**
- rules:
- # - no-boolean-literal-compare
- # - no-empty-block
- - prefer-trailing-comma
- - prefer-conditional-expressions
- - no-equal-then-else
+ - dart_code_metrics_presets
diff --git a/lib/src/algorithm/ssh_cipher_type.dart b/lib/src/algorithm/ssh_cipher_type.dart
index dad77fa..5461f4c 100644
--- a/lib/src/algorithm/ssh_cipher_type.dart
+++ b/lib/src/algorithm/ssh_cipher_type.dart
@@ -1,6 +1,6 @@
import 'dart:typed_data';
-import 'package:dartssh3/src/ssh_algorithm.dart';
+import '../ssh_algorithm.dart';
import 'package:pointycastle/export.dart';
class SSHCipherType with SSHAlgorithm {
diff --git a/lib/src/algorithm/ssh_hostkey_type.dart b/lib/src/algorithm/ssh_hostkey_type.dart
index aaffe18..f626a40 100644
--- a/lib/src/algorithm/ssh_hostkey_type.dart
+++ b/lib/src/algorithm/ssh_hostkey_type.dart
@@ -1,4 +1,4 @@
-import 'package:dartssh3/src/ssh_algorithm.dart';
+import '../ssh_algorithm.dart';
class SSHHostkeyType with SSHAlgorithm {
static const rsaSha1 = SSHHostkeyType._('ssh-rsa');
diff --git a/lib/src/algorithm/ssh_kex_type.dart b/lib/src/algorithm/ssh_kex_type.dart
index 141d5af..29b7c5d 100644
--- a/lib/src/algorithm/ssh_kex_type.dart
+++ b/lib/src/algorithm/ssh_kex_type.dart
@@ -1,4 +1,4 @@
-import 'package:dartssh3/src/ssh_algorithm.dart';
+import '../ssh_algorithm.dart';
import 'package:pointycastle/export.dart';
class SSHKexType with SSHAlgorithm {
diff --git a/lib/src/algorithm/ssh_mac_type.dart b/lib/src/algorithm/ssh_mac_type.dart
index 95bcbed..3c463a3 100644
--- a/lib/src/algorithm/ssh_mac_type.dart
+++ b/lib/src/algorithm/ssh_mac_type.dart
@@ -1,6 +1,6 @@
import 'dart:typed_data';
-import 'package:dartssh3/src/ssh_algorithm.dart';
+import '../ssh_algorithm.dart';
import 'package:pointycastle/export.dart';
class SSHMacType with SSHAlgorithm {
diff --git a/lib/src/hostkey/hostkey_ecdsa.dart b/lib/src/hostkey/hostkey_ecdsa.dart
index 16c9af6..113d092 100644
--- a/lib/src/hostkey/hostkey_ecdsa.dart
+++ b/lib/src/hostkey/hostkey_ecdsa.dart
@@ -1,8 +1,8 @@
import 'dart:typed_data';
import 'package:convert/convert.dart';
-import 'package:dartssh3/src/ssh_hostkey.dart';
-import 'package:dartssh3/src/ssh_message.dart';
+import '../ssh_hostkey.dart';
+import '../ssh_message.dart';
import 'package:pointycastle/export.dart';
class SSHEcdsaPublicKey implements SSHHostKey {
diff --git a/lib/src/hostkey/hostkey_ed25519.dart b/lib/src/hostkey/hostkey_ed25519.dart
index b3e1737..4c05ddc 100644
--- a/lib/src/hostkey/hostkey_ed25519.dart
+++ b/lib/src/hostkey/hostkey_ed25519.dart
@@ -1,6 +1,6 @@
import 'package:convert/convert.dart';
-import 'package:dartssh3/src/ssh_hostkey.dart';
-import 'package:dartssh3/src/ssh_message.dart';
+import '../ssh_hostkey.dart';
+import '../ssh_message.dart';
import 'package:pinenacl/ed25519.dart';
class SSHEd25519PublicKey implements SSHHostKey {
diff --git a/lib/src/hostkey/hostkey_rsa.dart b/lib/src/hostkey/hostkey_rsa.dart
index adef177..bbcbec1 100644
--- a/lib/src/hostkey/hostkey_rsa.dart
+++ b/lib/src/hostkey/hostkey_rsa.dart
@@ -1,8 +1,8 @@
import 'dart:typed_data';
import 'package:convert/convert.dart';
-import 'package:dartssh3/src/ssh_hostkey.dart';
-import 'package:dartssh3/src/ssh_message.dart';
+import '../ssh_hostkey.dart';
+import '../ssh_message.dart';
import 'package:pinenacl/ed25519.dart';
import 'package:pointycastle/api.dart' hide Signature;
diff --git a/lib/src/http/http_client.dart b/lib/src/http/http_client.dart
index 3423892..489ba2f 100644
--- a/lib/src/http/http_client.dart
+++ b/lib/src/http/http_client.dart
@@ -1,12 +1,12 @@
import 'dart:convert';
import 'dart:typed_data';
-import 'package:dartssh3/src/http/http_exception.dart';
-import 'package:dartssh3/src/http/line_decoder.dart';
-import 'package:dartssh3/src/http/http_content_type.dart';
-import 'package:dartssh3/src/http/http_headers.dart';
-import 'package:dartssh3/src/socket/ssh_socket.dart';
-import 'package:dartssh3/src/ssh_client.dart';
+import 'http_exception.dart';
+import 'line_decoder.dart';
+import 'http_content_type.dart';
+import 'http_headers.dart';
+import '../socket/ssh_socket.dart';
+import '../ssh_client.dart';
/// A HTTP client that works over SSH port forwarding.
///
diff --git a/lib/src/http/http_content_type.dart b/lib/src/http/http_content_type.dart
index 0b15655..5f694f6 100644
--- a/lib/src/http/http_content_type.dart
+++ b/lib/src/http/http_content_type.dart
@@ -1,7 +1,7 @@
import 'dart:collection';
-import 'package:dartssh3/src/http/http_exception.dart';
-import 'package:dartssh3/src/http/http_headers.dart';
+import 'http_exception.dart';
+import 'http_headers.dart';
/// A MIME/IANA media type used as the value of the
/// [SSHHttpHeaders.contentTypeHeader] header.
diff --git a/lib/src/http/http_headers.dart b/lib/src/http/http_headers.dart
index 8b2db47..31b0767 100644
--- a/lib/src/http/http_headers.dart
+++ b/lib/src/http/http_headers.dart
@@ -1,4 +1,4 @@
-import 'package:dartssh3/src/http/http_content_type.dart';
+import 'http_content_type.dart';
/// Headers for HTTP requests and responses.
///
diff --git a/lib/src/kex/kex_dh.dart b/lib/src/kex/kex_dh.dart
index bb51bc8..a658b6c 100644
--- a/lib/src/kex/kex_dh.dart
+++ b/lib/src/kex/kex_dh.dart
@@ -1,8 +1,8 @@
import 'dart:typed_data';
-import 'package:dartssh3/src/ssh_kex.dart';
-import 'package:dartssh3/src/utils/bigint.dart';
-import 'package:dartssh3/src/utils/list.dart';
+import '../ssh_kex.dart';
+import '../utils/bigint.dart';
+import '../utils/list.dart';
/// The Diffie-Hellman (DH) key exchange provides a shared secret that
/// cannot be determined by either party alone.
diff --git a/lib/src/kex/kex_nist.dart b/lib/src/kex/kex_nist.dart
index 6d523eb..dc0793a 100644
--- a/lib/src/kex/kex_nist.dart
+++ b/lib/src/kex/kex_nist.dart
@@ -1,8 +1,8 @@
import 'dart:typed_data';
-import 'package:dartssh3/src/ssh_kex.dart';
-import 'package:dartssh3/src/utils/bigint.dart';
-import 'package:dartssh3/src/utils/list.dart';
+import '../ssh_kex.dart';
+import '../utils/bigint.dart';
+import '../utils/list.dart';
import 'package:pointycastle/ecc/curves/secp256r1.dart';
import 'package:pointycastle/ecc/curves/secp384r1.dart';
import 'package:pointycastle/ecc/curves/secp521r1.dart';
diff --git a/lib/src/kex/kex_x25519.dart b/lib/src/kex/kex_x25519.dart
index f61ba25..20bbd04 100644
--- a/lib/src/kex/kex_x25519.dart
+++ b/lib/src/kex/kex_x25519.dart
@@ -1,8 +1,8 @@
import 'dart:typed_data';
-import 'package:dartssh3/src/ssh_kex.dart';
-import 'package:dartssh3/src/utils/bigint.dart';
-import 'package:dartssh3/src/utils/list.dart';
+import '../ssh_kex.dart';
+import '../utils/bigint.dart';
+import '../utils/list.dart';
import 'package:pinenacl/tweetnacl.dart';
class SSHKexX25519 implements SSHKexECDH {
diff --git a/lib/src/message/msg_channel.dart b/lib/src/message/msg_channel.dart
index b9da5f5..726b62a 100644
--- a/lib/src/message/msg_channel.dart
+++ b/lib/src/message/msg_channel.dart
@@ -2,7 +2,7 @@
import 'dart:typed_data';
-import 'package:dartssh3/src/ssh_message.dart';
+import '../ssh_message.dart';
/// Message to request opening a channel to remote host.
class SSH_Message_Channel_Open implements SSHMessage {
diff --git a/lib/src/message/msg_debug.dart b/lib/src/message/msg_debug.dart
index 4e3ded0..05e21e0 100644
--- a/lib/src/message/msg_debug.dart
+++ b/lib/src/message/msg_debug.dart
@@ -2,7 +2,7 @@
import 'dart:typed_data';
-import 'package:dartssh3/src/ssh_message.dart';
+import '../ssh_message.dart';
class SSH_Message_Debug implements SSHMessage {
static const messageId = 4;
diff --git a/lib/src/message/msg_disconnect.dart b/lib/src/message/msg_disconnect.dart
index 5f1fc2c..e206646 100644
--- a/lib/src/message/msg_disconnect.dart
+++ b/lib/src/message/msg_disconnect.dart
@@ -2,7 +2,7 @@
import 'dart:typed_data';
-import 'package:dartssh3/src/ssh_message.dart';
+import '../ssh_message.dart';
class SSH_Message_Disconnect extends SSHMessage {
static const messageId = 1;
diff --git a/lib/src/message/msg_ignore.dart b/lib/src/message/msg_ignore.dart
index 2028a28..5c3a0db 100644
--- a/lib/src/message/msg_ignore.dart
+++ b/lib/src/message/msg_ignore.dart
@@ -2,7 +2,7 @@
import 'dart:typed_data';
-import 'package:dartssh3/src/ssh_message.dart';
+import '../ssh_message.dart';
class SSH_Message_Ignore extends SSHMessage {
static const messageId = 2;
diff --git a/lib/src/message/msg_kex.dart b/lib/src/message/msg_kex.dart
index fb2bb02..c4d4180 100644
--- a/lib/src/message/msg_kex.dart
+++ b/lib/src/message/msg_kex.dart
@@ -2,8 +2,8 @@
import 'dart:typed_data';
-import 'package:dartssh3/src/ssh_message.dart';
-import 'package:dartssh3/src/utils/list.dart';
+import '../ssh_message.dart';
+import '../utils/list.dart';
class SSH_Message_KexInit implements SSHMessage {
static const messageId = 20;
diff --git a/lib/src/message/msg_kex_dh.dart b/lib/src/message/msg_kex_dh.dart
index 61cd4a5..6d7c01d 100644
--- a/lib/src/message/msg_kex_dh.dart
+++ b/lib/src/message/msg_kex_dh.dart
@@ -2,7 +2,7 @@
import 'dart:typed_data';
-import 'package:dartssh3/src/ssh_message.dart';
+import '../ssh_message.dart';
class SSH_Message_KexDH_Init implements SSHMessage {
static const messageId = 30;
diff --git a/lib/src/message/msg_kex_ecdh.dart b/lib/src/message/msg_kex_ecdh.dart
index e6e5705..7724d29 100644
--- a/lib/src/message/msg_kex_ecdh.dart
+++ b/lib/src/message/msg_kex_ecdh.dart
@@ -3,7 +3,7 @@
import 'dart:typed_data';
import 'package:convert/convert.dart';
-import 'package:dartssh3/src/ssh_message.dart';
+import '../ssh_message.dart';
class SSH_Message_KexECDH_Init implements SSHMessage {
static const messageId = 30;
diff --git a/lib/src/message/msg_request.dart b/lib/src/message/msg_request.dart
index 41005b0..fa5a253 100644
--- a/lib/src/message/msg_request.dart
+++ b/lib/src/message/msg_request.dart
@@ -3,7 +3,7 @@
import 'dart:typed_data';
import 'package:convert/convert.dart';
-import 'package:dartssh3/src/ssh_message.dart';
+import '../ssh_message.dart';
class SSH_Message_Global_Request extends SSHMessage {
static const messageId = 80;
diff --git a/lib/src/message/msg_service.dart b/lib/src/message/msg_service.dart
index c0d7104..2ef702c 100644
--- a/lib/src/message/msg_service.dart
+++ b/lib/src/message/msg_service.dart
@@ -2,7 +2,7 @@
import 'dart:typed_data';
-import 'package:dartssh3/src/ssh_message.dart';
+import '../ssh_message.dart';
class SSH_Message_Service_Request implements SSHMessage {
static const messageId = 5;
diff --git a/lib/src/message/msg_userauth.dart b/lib/src/message/msg_userauth.dart
index 3416b5d..59bd421 100644
--- a/lib/src/message/msg_userauth.dart
+++ b/lib/src/message/msg_userauth.dart
@@ -2,8 +2,8 @@
import 'dart:typed_data';
-import 'package:dartssh3/src/ssh_message.dart';
-import 'package:dartssh3/src/ssh_userauth.dart';
+import '../ssh_message.dart';
+import '../ssh_userauth.dart';
class SSH_Message_Userauth_Request extends SSHMessage {
static const messageId = 50;
diff --git a/lib/src/sftp/sftp_client.dart b/lib/src/sftp/sftp_client.dart
index ad6d28f..833c439 100644
--- a/lib/src/sftp/sftp_client.dart
+++ b/lib/src/sftp/sftp_client.dart
@@ -3,19 +3,19 @@ import 'dart:math';
import 'dart:typed_data';
import 'package:convert/convert.dart';
-import 'package:dartssh3/src/sftp/sftp_errors.dart';
-import 'package:dartssh3/src/sftp/sftp_file_attrs.dart';
-import 'package:dartssh3/src/sftp/sftp_file_open_mode.dart';
-import 'package:dartssh3/src/sftp/sftp_name.dart';
-import 'package:dartssh3/src/sftp/sftp_packet.dart';
-import 'package:dartssh3/src/sftp/sftp_packet_ext.dart';
-import 'package:dartssh3/src/sftp/sftp_request_id.dart';
-import 'package:dartssh3/src/sftp/sftp_statvfs.dart';
-import 'package:dartssh3/src/sftp/sftp_stream_io.dart';
-import 'package:dartssh3/src/ssh_channel.dart';
-import 'package:dartssh3/src/ssh_transport.dart';
-import 'package:dartssh3/src/utils/chunk_buffer.dart';
-import 'package:dartssh3/src/ssh_message.dart';
+import 'sftp_errors.dart';
+import 'sftp_file_attrs.dart';
+import 'sftp_file_open_mode.dart';
+import 'sftp_name.dart';
+import 'sftp_packet.dart';
+import 'sftp_packet_ext.dart';
+import 'sftp_request_id.dart';
+import 'sftp_statvfs.dart';
+import 'sftp_stream_io.dart';
+import '../ssh_channel.dart';
+import '../ssh_transport.dart';
+import '../utils/chunk_buffer.dart';
+import '../ssh_message.dart';
const _kVersion = 3;
diff --git a/lib/src/sftp/sftp_errors.dart b/lib/src/sftp/sftp_errors.dart
index 3bf2db7..e50afeb 100644
--- a/lib/src/sftp/sftp_errors.dart
+++ b/lib/src/sftp/sftp_errors.dart
@@ -1,5 +1,5 @@
-import 'package:dartssh3/src/sftp/sftp_packet.dart';
-import 'package:dartssh3/src/sftp/sftp_status_code.dart';
+import 'sftp_packet.dart';
+import 'sftp_status_code.dart';
class SftpError {
final String message;
diff --git a/lib/src/sftp/sftp_file_attrs.dart b/lib/src/sftp/sftp_file_attrs.dart
index 8207d11..bf704a9 100644
--- a/lib/src/sftp/sftp_file_attrs.dart
+++ b/lib/src/sftp/sftp_file_attrs.dart
@@ -1,5 +1,5 @@
-import 'package:dartssh3/src/utils/int.dart';
-import 'package:dartssh3/src/ssh_message.dart';
+import '../utils/int.dart';
+import '../ssh_message.dart';
abstract class _Flags {
static const size = 0x00000001;
diff --git a/lib/src/sftp/sftp_file_open_mode.dart b/lib/src/sftp/sftp_file_open_mode.dart
index 6632c9a..824fd4a 100644
--- a/lib/src/sftp/sftp_file_open_mode.dart
+++ b/lib/src/sftp/sftp_file_open_mode.dart
@@ -24,10 +24,34 @@ class SftpFileOpenMode {
/// [create] MUST also be specified if this flag is used.
static const exclusive = SftpFileOpenMode._(1 << 5);
+ /// Internal integer flag representing the file open mode.
final int flag;
+ /// Private constructor used to create instances of [SftpFileOpenMode] with specific flags.
+ ///
+ /// This constructor is marked as private (`._`) to restrict direct instantiation and ensure
+ /// that only predefined modes like [read], [write], etc., can be used.
const SftpFileOpenMode._(this.flag);
+ /// Overloads the bitwise OR operator `|` for the `SftpFileOpenMode` class.
+ ///
+ /// This operator allows combining two `SftpFileOpenMode` instances by performing
+ /// a bitwise OR operation on their respective flags. The result is a new
+ /// `SftpFileOpenMode` instance that represents the combined flags of both modes.
+ ///
+ /// Example:
+ /// ```dart
+ /// SftpFileOpenMode readMode = SftpFileOpenMode.read;
+ /// SftpFileOpenMode writeMode = SftpFileOpenMode.write;
+ ///
+ /// SftpFileOpenMode combinedMode = readMode | writeMode;
+ /// ```
+ ///
+ /// In the example above, the `combinedMode` will contain the flags of both
+ /// `readMode` and `writeMode`.
+ ///
+ /// - Parameter [other]: Another instance of `SftpFileOpenMode` to combine with.
+ /// - Returns: A new `SftpFileOpenMode` instance containing the combined flags.
SftpFileOpenMode operator |(SftpFileOpenMode other) =>
SftpFileOpenMode._(flag | other.flag);
}
diff --git a/lib/src/sftp/sftp_name.dart b/lib/src/sftp/sftp_name.dart
index 30de0c2..77a6933 100644
--- a/lib/src/sftp/sftp_name.dart
+++ b/lib/src/sftp/sftp_name.dart
@@ -1,5 +1,5 @@
-import 'package:dartssh3/src/sftp/sftp_file_attrs.dart';
-import 'package:dartssh3/src/ssh_message.dart';
+import 'sftp_file_attrs.dart';
+import '../ssh_message.dart';
class SftpName {
final String filename;
diff --git a/lib/src/sftp/sftp_packet.dart b/lib/src/sftp/sftp_packet.dart
index f8b6593..d905ade 100644
--- a/lib/src/sftp/sftp_packet.dart
+++ b/lib/src/sftp/sftp_packet.dart
@@ -1,9 +1,9 @@
import 'dart:typed_data';
import 'package:convert/convert.dart';
-import 'package:dartssh3/src/sftp/sftp_file_attrs.dart';
-import 'package:dartssh3/src/sftp/sftp_name.dart';
-import 'package:dartssh3/src/ssh_message.dart';
+import 'sftp_file_attrs.dart';
+import 'sftp_name.dart';
+import '../ssh_message.dart';
// SSH_FXP_INIT 1 init
// SSH_FXP_VERSION 2 init-reply
diff --git a/lib/src/sftp/sftp_packet_ext.dart b/lib/src/sftp/sftp_packet_ext.dart
index 55a49aa..1be316c 100644
--- a/lib/src/sftp/sftp_packet_ext.dart
+++ b/lib/src/sftp/sftp_packet_ext.dart
@@ -1,7 +1,7 @@
import 'dart:typed_data';
-import 'package:dartssh3/src/sftp/sftp_packet.dart';
-import 'package:dartssh3/src/ssh_message.dart';
+import 'sftp_packet.dart';
+import '../ssh_message.dart';
/// Represents the payload of an extended request. Should be wrapped in a
/// [SftpExtendedPacket] before being sent.
diff --git a/lib/src/sftp/sftp_statvfs.dart b/lib/src/sftp/sftp_statvfs.dart
index 2f7fa50..d0cc1d5 100644
--- a/lib/src/sftp/sftp_statvfs.dart
+++ b/lib/src/sftp/sftp_statvfs.dart
@@ -1,4 +1,4 @@
-import 'package:dartssh3/src/sftp/sftp_packet_ext.dart';
+import 'sftp_packet_ext.dart';
/// Information about the file system. Corresponds to the `statvfs` system call
/// on POSIX systems.
diff --git a/lib/src/sftp/sftp_stream_io.dart b/lib/src/sftp/sftp_stream_io.dart
index 0b9920c..57182f0 100644
--- a/lib/src/sftp/sftp_stream_io.dart
+++ b/lib/src/sftp/sftp_stream_io.dart
@@ -1,8 +1,8 @@
import 'dart:async';
import 'dart:typed_data';
-import 'package:dartssh3/src/sftp/sftp_client.dart';
-import 'package:dartssh3/src/utils/stream.dart';
+import 'sftp_client.dart';
+import '../utils/stream.dart';
/// The amount of data to send in a single SFTP packet.
///
@@ -90,6 +90,14 @@ class SftpFileWriter with DoneFuture {
_subscription.resume();
}
+ /// Handles the incoming data chunks from the stream.
+ ///
+ /// This function manages the flow control by pausing the stream if the
+ /// amount of unacknowledged data (`_bytesOnTheWire`) exceeds the
+ /// `maxBytesOnTheWire` limit. It then writes the data chunk to the remote file
+ /// at the appropriate offset, updates the counters, and triggers the
+ /// progress callback. Finally, it checks if all data has been acknowledged
+ /// and completes the operation if done.
Future _handleLocalData(Uint8List chunk) async {
if (_bytesOnTheWire >= maxBytesOnTheWire) {
_subscription.pause();
@@ -108,13 +116,19 @@ class SftpFileWriter with DoneFuture {
_subscription.resume();
}
- if (!_doneCompleter.isCompleted &&
- _streamDone &&
- _bytesSent == _bytesAcked) {
+ if (_streamDone &&
+ _bytesSent == _bytesAcked &&
+ !_doneCompleter.isCompleted) {
_doneCompleter.complete();
}
}
+ /// Handles the completion of the data stream.
+ ///
+ /// This function is triggered when the stream has finished emitting all its
+ /// data. It checks if all data has been successfully acknowledged and
+ /// marks the operation as complete by calling `_doneCompleter.complete()`
+ /// if no more data remains to be processed.
void _handleLocalDone() {
_streamDone = true;
if (_bytesSent == _bytesAcked) {
@@ -125,7 +139,7 @@ class SftpFileWriter with DoneFuture {
/// Implements [Future] interface for [SftpFileWriter].
///
-/// This is for compatibility with earlier versions of dartssh2.
+/// This is for compatibility with earlier versions of dartssh2 and dartssh2.
mixin DoneFuture implements Future {
Future get done;
diff --git a/lib/src/socket/ssh_socket.dart b/lib/src/socket/ssh_socket.dart
index cf37bcc..6cebe81 100644
--- a/lib/src/socket/ssh_socket.dart
+++ b/lib/src/socket/ssh_socket.dart
@@ -1,7 +1,7 @@
import 'dart:async';
import 'dart:typed_data';
-import 'package:dartssh3/src/socket/ssh_socket_io.dart'
+import 'ssh_socket_io.dart'
if (dart.library.js) 'package:dartssh3/src/socket/ssh_socket_js.dart';
abstract class SSHSocket {
diff --git a/lib/src/socket/ssh_socket_io.dart b/lib/src/socket/ssh_socket_io.dart
index 3e0138e..6ab05a6 100644
--- a/lib/src/socket/ssh_socket_io.dart
+++ b/lib/src/socket/ssh_socket_io.dart
@@ -2,7 +2,7 @@ import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
-import 'package:dartssh3/src/socket/ssh_socket.dart';
+import 'ssh_socket.dart';
Future connectNativeSocket(
String host,
diff --git a/lib/src/socket/ssh_socket_js.dart b/lib/src/socket/ssh_socket_js.dart
index c0d8b17..26a57cb 100644
--- a/lib/src/socket/ssh_socket_js.dart
+++ b/lib/src/socket/ssh_socket_js.dart
@@ -1,4 +1,4 @@
-import 'package:dartssh3/src/socket/ssh_socket.dart';
+import 'ssh_socket.dart';
Future connectNativeSocket(
String host,
diff --git a/lib/src/ssh_algorithm.dart b/lib/src/ssh_algorithm.dart
index 1a34f5d..382b84b 100644
--- a/lib/src/ssh_algorithm.dart
+++ b/lib/src/ssh_algorithm.dart
@@ -1,7 +1,7 @@
-import 'package:dartssh3/src/algorithm/ssh_cipher_type.dart';
-import 'package:dartssh3/src/algorithm/ssh_hostkey_type.dart';
-import 'package:dartssh3/src/algorithm/ssh_kex_type.dart';
-import 'package:dartssh3/src/algorithm/ssh_mac_type.dart';
+import 'algorithm/ssh_cipher_type.dart';
+import 'algorithm/ssh_hostkey_type.dart';
+import 'algorithm/ssh_kex_type.dart';
+import 'algorithm/ssh_mac_type.dart';
abstract class SSHAlgorithm {
/// The name of the algorithm.
diff --git a/lib/src/ssh_channel.dart b/lib/src/ssh_channel.dart
index dcfda81..99a3e21 100644
--- a/lib/src/ssh_channel.dart
+++ b/lib/src/ssh_channel.dart
@@ -3,12 +3,12 @@ import 'dart:math';
import 'dart:typed_data';
-import 'package:dartssh3/src/ssh_channel_id.dart';
-import 'package:dartssh3/src/ssh_transport.dart';
-import 'package:dartssh3/src/utils/async_queue.dart';
-import 'package:dartssh3/src/message/msg_channel.dart';
-import 'package:dartssh3/src/ssh_message.dart';
-import 'package:dartssh3/src/utils/stream.dart';
+import 'ssh_channel_id.dart';
+import 'ssh_transport.dart';
+import 'utils/async_queue.dart';
+import 'message/msg_channel.dart';
+import 'ssh_message.dart';
+import 'utils/stream.dart';
/// Handler of channel requests. Return true if the request was handled, false
/// if the request was not recognized or could not be handled.
@@ -489,7 +489,7 @@ class SSHChannelDataSplitter
}
class SSHChannelDataConsumer extends StreamConsumerBase {
- SSHChannelDataConsumer(Stream stream) : super(stream);
+ SSHChannelDataConsumer(super.stream);
@override
int getLength(SSHChannelData chunk) {
diff --git a/lib/src/ssh_client.dart b/lib/src/ssh_client.dart
index b4078ca..4ccf06b 100644
--- a/lib/src/ssh_client.dart
+++ b/lib/src/ssh_client.dart
@@ -2,25 +2,25 @@ import 'dart:async';
import 'dart:collection';
import 'dart:typed_data';
-import 'package:dartssh3/src/http/http_client.dart';
-import 'package:dartssh3/src/sftp/sftp_client.dart';
-import 'package:dartssh3/src/ssh_algorithm.dart';
-import 'package:dartssh3/src/ssh_channel.dart';
-import 'package:dartssh3/src/ssh_channel_id.dart';
-import 'package:dartssh3/src/ssh_errors.dart';
-import 'package:dartssh3/src/ssh_forward.dart';
-import 'package:dartssh3/src/ssh_keepalive.dart';
-import 'package:dartssh3/src/ssh_key_pair.dart';
-import 'package:dartssh3/src/ssh_session.dart';
-import 'package:dartssh3/src/ssh_transport.dart';
-import 'package:dartssh3/src/utils/async_queue.dart';
-import 'package:dartssh3/src/message/msg_channel.dart';
-import 'package:dartssh3/src/message/msg_request.dart';
-import 'package:dartssh3/src/message/msg_service.dart';
-import 'package:dartssh3/src/message/msg_userauth.dart';
-import 'package:dartssh3/src/ssh_message.dart';
-import 'package:dartssh3/src/socket/ssh_socket.dart';
-import 'package:dartssh3/src/ssh_userauth.dart';
+import 'http/http_client.dart';
+import 'sftp/sftp_client.dart';
+import 'ssh_algorithm.dart';
+import 'ssh_channel.dart';
+import 'ssh_channel_id.dart';
+import 'ssh_errors.dart';
+import 'ssh_forward.dart';
+import 'ssh_keepalive.dart';
+import 'ssh_key_pair.dart';
+import 'ssh_session.dart';
+import 'ssh_transport.dart';
+import 'utils/async_queue.dart';
+import 'message/msg_channel.dart';
+import 'message/msg_request.dart';
+import 'message/msg_service.dart';
+import 'message/msg_userauth.dart';
+import 'ssh_message.dart';
+import 'socket/ssh_socket.dart';
+import 'ssh_userauth.dart';
/// https://datatracker.ietf.org/doc/html/rfc4252#section-8
typedef SSHPasswordRequestHandler = FutureOr Function();
diff --git a/lib/src/ssh_errors.dart b/lib/src/ssh_errors.dart
index 29f51cf..68407de 100644
--- a/lib/src/ssh_errors.dart
+++ b/lib/src/ssh_errors.dart
@@ -86,7 +86,7 @@ class SSHKeyDecodeError with SSHMessageError implements SSHError {
/// Errors that happen when the library fails to decrypt the host key.
class SSHKeyDecryptError extends SSHKeyDecodeError {
- SSHKeyDecryptError(String message, [Object? error]) : super(message, error);
+ SSHKeyDecryptError(super.message, [super.error]);
}
/// Errors that happen when the library fails to open a channel.
diff --git a/lib/src/ssh_forward.dart b/lib/src/ssh_forward.dart
index b062dc6..6f446de 100644
--- a/lib/src/ssh_forward.dart
+++ b/lib/src/ssh_forward.dart
@@ -1,8 +1,8 @@
import 'dart:async';
import 'dart:typed_data';
-import 'package:dartssh3/src/socket/ssh_socket.dart';
-import 'package:dartssh3/src/ssh_channel.dart';
+import 'socket/ssh_socket.dart';
+import 'ssh_channel.dart';
class SSHForwardChannel implements SSHSocket {
final SSHChannel _channel;
diff --git a/lib/src/ssh_hostkey.dart b/lib/src/ssh_hostkey.dart
index 609fdb9..de5ff3c 100644
--- a/lib/src/ssh_hostkey.dart
+++ b/lib/src/ssh_hostkey.dart
@@ -1,6 +1,6 @@
import 'dart:typed_data';
-import 'package:dartssh3/src/ssh_message.dart';
+import 'ssh_message.dart';
abstract class SSHHostKey {
/// Encode the host key to SSH encoded data.
diff --git a/lib/src/ssh_kex_utils.dart b/lib/src/ssh_kex_utils.dart
index 1cc8ac3..a29e4c0 100644
--- a/lib/src/ssh_kex_utils.dart
+++ b/lib/src/ssh_kex_utils.dart
@@ -1,8 +1,8 @@
import 'dart:typed_data';
-import 'package:dartssh3/src/kex/kex_dh.dart';
-import 'package:dartssh3/src/ssh_algorithm.dart';
-import 'package:dartssh3/src/ssh_message.dart';
+import 'kex/kex_dh.dart';
+import 'ssh_algorithm.dart';
+import 'ssh_message.dart';
import 'package:pointycastle/export.dart';
abstract class SSHKexUtils {
diff --git a/lib/src/ssh_key_pair.dart b/lib/src/ssh_key_pair.dart
index 6496370..488796a 100644
--- a/lib/src/ssh_key_pair.dart
+++ b/lib/src/ssh_key_pair.dart
@@ -4,15 +4,15 @@ import 'dart:typed_data';
import 'package:asn1lib/asn1lib.dart';
import 'package:convert/convert.dart';
-import 'package:dartssh3/dartssh3.dart';
-import 'package:dartssh3/src/hostkey/hostkey_ecdsa.dart';
-import 'package:dartssh3/src/hostkey/hostkey_ed25519.dart';
-import 'package:dartssh3/src/hostkey/hostkey_rsa.dart';
-import 'package:dartssh3/src/ssh_hostkey.dart';
-import 'package:dartssh3/src/ssh_message.dart';
-import 'package:dartssh3/src/utils/bcrypt.dart';
-import 'package:dartssh3/src/utils/cipher_ext.dart';
-import 'package:dartssh3/src/utils/list.dart';
+import '../dartssh3.dart';
+import 'hostkey/hostkey_ecdsa.dart';
+import 'hostkey/hostkey_ed25519.dart';
+import 'hostkey/hostkey_rsa.dart';
+import 'ssh_hostkey.dart';
+import 'ssh_message.dart';
+import 'utils/bcrypt.dart';
+import 'utils/cipher_ext.dart';
+import 'utils/list.dart';
import 'package:pinenacl/ed25519.dart' as ed25519;
import 'package:pointycastle/export.dart';
diff --git a/lib/src/ssh_message.dart b/lib/src/ssh_message.dart
index 0a8c99b..1c3ca8c 100644
--- a/lib/src/ssh_message.dart
+++ b/lib/src/ssh_message.dart
@@ -1,9 +1,9 @@
import 'dart:convert';
import 'dart:typed_data';
-import 'package:dartssh3/src/utils/int.dart';
-import 'package:dartssh3/src/utils/bigint.dart';
-import 'package:dartssh3/src/utils/utf8.dart';
+import 'utils/int.dart';
+import 'utils/bigint.dart';
+import 'utils/utf8.dart';
abstract class SSHMessage {
/// Encode the message to SSH encoded data.
diff --git a/lib/src/ssh_session.dart b/lib/src/ssh_session.dart
index 54d7176..cc96c09 100644
--- a/lib/src/ssh_session.dart
+++ b/lib/src/ssh_session.dart
@@ -1,9 +1,9 @@
import 'dart:async';
import 'dart:typed_data';
-import 'package:dartssh3/src/ssh_channel.dart';
-import 'package:dartssh3/src/ssh_signal.dart';
-import 'package:dartssh3/src/message/msg_channel.dart';
+import 'ssh_channel.dart';
+import 'ssh_signal.dart';
+import 'message/msg_channel.dart';
/// A [SSHSession] represents a remote execution of a program.
class SSHSession {
diff --git a/lib/src/ssh_transport.dart b/lib/src/ssh_transport.dart
index b178a96..ffdc160 100644
--- a/lib/src/ssh_transport.dart
+++ b/lib/src/ssh_transport.dart
@@ -3,32 +3,32 @@ import 'dart:convert';
import 'dart:math' show max;
import 'dart:typed_data';
-import 'package:dartssh3/src/algorithm/ssh_cipher_type.dart';
-import 'package:dartssh3/src/algorithm/ssh_hostkey_type.dart';
-import 'package:dartssh3/src/algorithm/ssh_kex_type.dart';
-import 'package:dartssh3/src/algorithm/ssh_mac_type.dart';
-import 'package:dartssh3/src/hostkey/hostkey_ecdsa.dart';
-import 'package:dartssh3/src/hostkey/hostkey_rsa.dart';
-import 'package:dartssh3/src/kex/kex_dh.dart';
-import 'package:dartssh3/src/kex/kex_nist.dart';
-import 'package:dartssh3/src/kex/kex_x25519.dart';
-import 'package:dartssh3/src/message/msg_userauth.dart';
-import 'package:dartssh3/src/socket/ssh_socket.dart';
-import 'package:dartssh3/src/ssh_algorithm.dart';
-import 'package:dartssh3/src/ssh_kex.dart';
-import 'package:dartssh3/src/utils/bigint.dart';
-import 'package:dartssh3/src/utils/cipher_ext.dart';
-import 'package:dartssh3/src/utils/chunk_buffer.dart';
-import 'package:dartssh3/src/ssh_errors.dart';
-import 'package:dartssh3/src/ssh_kex_utils.dart';
-import 'package:dartssh3/src/ssh_packet.dart';
-import 'package:dartssh3/src/utils/int.dart';
-import 'package:dartssh3/src/hostkey/hostkey_ed25519.dart';
-import 'package:dartssh3/src/utils/list.dart';
-import 'package:dartssh3/src/message/msg_kex.dart';
-import 'package:dartssh3/src/message/msg_kex_dh.dart';
-import 'package:dartssh3/src/message/msg_kex_ecdh.dart';
-import 'package:dartssh3/src/ssh_message.dart';
+import 'algorithm/ssh_cipher_type.dart';
+import 'algorithm/ssh_hostkey_type.dart';
+import 'algorithm/ssh_kex_type.dart';
+import 'algorithm/ssh_mac_type.dart';
+import 'hostkey/hostkey_ecdsa.dart';
+import 'hostkey/hostkey_rsa.dart';
+import 'kex/kex_dh.dart';
+import 'kex/kex_nist.dart';
+import 'kex/kex_x25519.dart';
+import 'message/msg_userauth.dart';
+import 'socket/ssh_socket.dart';
+import 'ssh_algorithm.dart';
+import 'ssh_kex.dart';
+import 'utils/bigint.dart';
+import 'utils/cipher_ext.dart';
+import 'utils/chunk_buffer.dart';
+import 'ssh_errors.dart';
+import 'ssh_kex_utils.dart';
+import 'ssh_packet.dart';
+import 'utils/int.dart';
+import 'hostkey/hostkey_ed25519.dart';
+import 'utils/list.dart';
+import 'message/msg_kex.dart';
+import 'message/msg_kex_dh.dart';
+import 'message/msg_kex_ecdh.dart';
+import 'ssh_message.dart';
import 'package:pointycastle/export.dart';
typedef SSHPrintHandler = void Function(String?);
diff --git a/lib/src/utils/stream.dart b/lib/src/utils/stream.dart
index 71ef985..cf0b4ae 100644
--- a/lib/src/utils/stream.dart
+++ b/lib/src/utils/stream.dart
@@ -136,7 +136,7 @@ abstract class StreamConsumerBase {
/// A helper class that can be used to read data from a byte stream on demand.
class StreamConsumer extends StreamConsumerBase {
- StreamConsumer(Stream stream) : super(stream);
+ StreamConsumer(super.stream);
@override
int getLength(Uint8List chunk) {
diff --git a/pubspec.yaml b/pubspec.yaml
index 1efc40a..c1e6bc3 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
name: dartssh3
-version: 3.0.0
+version: 3.0.1
description: SSH and SFTP client written in pure Dart, aiming to be feature-rich as well as easy to use.
homepage: https://github.com/obemu/dartssh3
@@ -14,10 +14,11 @@ dependencies:
pinenacl: ">=0.5.0 <1.0.0"
dev_dependencies:
- build_runner: ^2.1.1
- dart_code_metrics: ^4.16.0
- lints: ^2.0.0
- test: ^1.6.5
+ build_runner: ^2.4.12
+ dart_code_metrics_presets: ^2.15.0
+ lints: ">=4.0.0 <6.0.0"
+ test: ^1.25.8
+ ansi_colorizer: any
false_secrets:
- test
diff --git a/test/src/algorithm/ssh_cipher_type_test.dart b/test/src/algorithm/ssh_cipher_type_test.dart
index 2eea1e0..aa33b22 100644
--- a/test/src/algorithm/ssh_cipher_type_test.dart
+++ b/test/src/algorithm/ssh_cipher_type_test.dart
@@ -1,6 +1,7 @@
import 'dart:typed_data';
-import 'package:dartssh3/src/algorithm/ssh_cipher_type.dart';
+import 'package:dartssh3/dartssh3.dart';
+import 'package:dartssh3/src/ssh_algorithm.dart';
import 'package:dartssh3/src/utils/cipher_ext.dart';
import 'package:test/test.dart';
@@ -11,6 +12,81 @@ void main() {
testCipher(SSHCipherType.aes128ctr);
testCipher(SSHCipherType.aes192ctr);
testCipher(SSHCipherType.aes256ctr);
+ group('SSHAlgorithm', () {
+ test('toString() returns correct format', () {
+ final algorithm = SSHKexType.x25519;
+ expect(algorithm.toString(), equals(SSHKexType.x25519.toString()));
+ });
+ });
+
+ group('SSHAlgorithmList extension', () {
+ test('toNameList() returns list of names', () {
+ final algorithms = [SSHKexType.x25519, SSHKexType.nistp521];
+ final names = algorithms.toNameList();
+ expect(names, equals([SSHKexType.x25519.name, SSHKexType.nistp521.name]));
+ });
+
+ test('getByName() returns correct algorithm', () {
+ final algorithms = [SSHKexType.x25519, SSHKexType.nistp521];
+ final algorithm = algorithms.getByName(SSHKexType.nistp521.name);
+ expect(algorithm, isNotNull);
+ expect(algorithm!.name, equals(SSHKexType.nistp521.name));
+ });
+
+ test('getByName() returns null when not found', () {
+ final algorithms = [SSHKexType.x25519, SSHKexType.nistp521];
+ final algorithm = algorithms.getByName('nonexistent');
+ expect(algorithm, isNull);
+ });
+ });
+
+ test('Default values are set correctly', () {
+ final algorithms = SSHAlgorithms();
+
+ expect(
+ algorithms.kex,
+ equals([
+ SSHKexType.x25519,
+ SSHKexType.nistp521,
+ SSHKexType.nistp384,
+ SSHKexType.nistp256,
+ SSHKexType.dhGexSha256,
+ SSHKexType.dh14Sha256,
+ SSHKexType.dh14Sha1,
+ SSHKexType.dhGexSha1,
+ SSHKexType.dh1Sha1,
+ ]));
+
+ expect(
+ algorithms.hostkey,
+ equals([
+ SSHHostkeyType.ed25519,
+ SSHHostkeyType.rsaSha512,
+ SSHHostkeyType.rsaSha256,
+ SSHHostkeyType.rsaSha1,
+ SSHHostkeyType.ecdsa521,
+ SSHHostkeyType.ecdsa384,
+ SSHHostkeyType.ecdsa256,
+ ]));
+
+ expect(
+ algorithms.cipher,
+ equals([
+ SSHCipherType.aes128ctr,
+ SSHCipherType.aes128cbc,
+ SSHCipherType.aes256ctr,
+ SSHCipherType.aes256cbc,
+ ]));
+
+ expect(
+ algorithms.mac,
+ equals([
+ SSHMacType.hmacSha1,
+ SSHMacType.hmacSha256,
+ SSHMacType.hmacSha512,
+ SSHMacType.hmacMd5,
+ ]));
+ });
}
void testCipher(SSHCipherType type) {
diff --git a/test/src/algorithm/ssh_hostkey_type_test.dart b/test/src/algorithm/ssh_hostkey_type_test.dart
new file mode 100644
index 0000000..a1affd4
--- /dev/null
+++ b/test/src/algorithm/ssh_hostkey_type_test.dart
@@ -0,0 +1,33 @@
+import 'package:dartssh3/dartssh3.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('SSHHostkeyType', () {
+ test('Static constants are defined correctly', () {
+ expect(SSHHostkeyType.rsaSha1.name, equals('ssh-rsa'));
+ expect(SSHHostkeyType.rsaSha256.name, equals('rsa-sha2-256'));
+ expect(SSHHostkeyType.rsaSha512.name, equals('rsa-sha2-512'));
+ expect(SSHHostkeyType.ecdsa256.name, equals('ecdsa-sha2-nistp256'));
+ expect(SSHHostkeyType.ecdsa384.name, equals('ecdsa-sha2-nistp384'));
+ expect(SSHHostkeyType.ecdsa521.name, equals('ecdsa-sha2-nistp521'));
+ expect(SSHHostkeyType.ed25519.name, equals('ssh-ed25519'));
+ });
+
+ test('toString() returns correct format', () {
+ expect(
+ SSHHostkeyType.rsaSha1.toString(), equals('SSHHostkeyType(ssh-rsa)'));
+ expect(SSHHostkeyType.rsaSha256.toString(),
+ equals('SSHHostkeyType(rsa-sha2-256)'));
+ expect(SSHHostkeyType.rsaSha512.toString(),
+ equals('SSHHostkeyType(rsa-sha2-512)'));
+ expect(SSHHostkeyType.ecdsa256.toString(),
+ equals('SSHHostkeyType(ecdsa-sha2-nistp256)'));
+ expect(SSHHostkeyType.ecdsa384.toString(),
+ equals('SSHHostkeyType(ecdsa-sha2-nistp384)'));
+ expect(SSHHostkeyType.ecdsa521.toString(),
+ equals('SSHHostkeyType(ecdsa-sha2-nistp521)'));
+ expect(SSHHostkeyType.ed25519.toString(),
+ equals('SSHHostkeyType(ssh-ed25519)'));
+ });
+ });
+}
diff --git a/test/src/algorithm/ssh_kex_type_test.dart b/test/src/algorithm/ssh_kex_type_test.dart
new file mode 100644
index 0000000..663f486
--- /dev/null
+++ b/test/src/algorithm/ssh_kex_type_test.dart
@@ -0,0 +1,68 @@
+import 'package:dartssh3/dartssh3.dart';
+import 'package:pointycastle/export.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('SSHKexType', () {
+ test('Static constants are defined correctly', () {
+ expect(SSHKexType.x25519.name, equals('curve25519-sha256@libssh.org'));
+ expect(SSHKexType.nistp256.name, equals('ecdh-sha2-nistp256'));
+ expect(SSHKexType.nistp384.name, equals('ecdh-sha2-nistp384'));
+ expect(SSHKexType.nistp521.name, equals('ecdh-sha2-nistp521'));
+ expect(SSHKexType.dhGexSha256.name,
+ equals('diffie-hellman-group-exchange-sha256'));
+ expect(SSHKexType.dhGexSha1.name,
+ equals('diffie-hellman-group-exchange-sha1'));
+ expect(SSHKexType.dh14Sha1.name, equals('diffie-hellman-group14-sha1'));
+ expect(
+ SSHKexType.dh14Sha256.name, equals('diffie-hellman-group14-sha256'));
+ expect(SSHKexType.dh1Sha1.name, equals('diffie-hellman-group1-sha1'));
+ });
+
+ test(
+ 'Static constants have correct digestFactory and isGroupExchange values',
+ () {
+ expect(SSHKexType.x25519.digestFactory, equals(digestSha256));
+ expect(SSHKexType.nistp256.digestFactory, equals(digestSha256));
+ expect(SSHKexType.nistp384.digestFactory, equals(digestSha384));
+ expect(SSHKexType.nistp521.digestFactory, equals(digestSha512));
+ expect(SSHKexType.dhGexSha256.digestFactory, equals(digestSha256));
+ expect(SSHKexType.dhGexSha1.digestFactory, equals(digestSha1));
+ expect(SSHKexType.dh14Sha1.digestFactory, equals(digestSha1));
+ expect(SSHKexType.dh14Sha256.digestFactory, equals(digestSha256));
+ expect(SSHKexType.dh1Sha1.digestFactory, equals(digestSha1));
+
+ expect(SSHKexType.dhGexSha256.isGroupExchange, isTrue);
+ expect(SSHKexType.dhGexSha1.isGroupExchange, isTrue);
+ expect(SSHKexType.dh14Sha1.isGroupExchange, isFalse);
+ expect(SSHKexType.dh14Sha256.isGroupExchange, isFalse);
+ expect(SSHKexType.dh1Sha1.isGroupExchange, isFalse);
+ });
+
+ test('createDigest() returns correct Digest instance', () {
+ final kexType = SSHKexType.x25519;
+ final digest = kexType.createDigest();
+ expect(digest, isA());
+ });
+
+ test(
+ 'createDigest() returns correct Digest instance for different algorithms',
+ () {
+ final kexTypeSha1 = SSHKexType.dhGexSha1;
+ final digestSha1 = kexTypeSha1.createDigest();
+ expect(digestSha1, isA());
+
+ final kexTypeSha256 = SSHKexType.dhGexSha256;
+ final digestSha256 = kexTypeSha256.createDigest();
+ expect(digestSha256, isA());
+
+ final kexTypeSha384 = SSHKexType.nistp384;
+ final digestSha384 = kexTypeSha384.createDigest();
+ expect(digestSha384, isA());
+
+ final kexTypeSha512 = SSHKexType.nistp521;
+ final digestSha512 = kexTypeSha512.createDigest();
+ expect(digestSha512, isA());
+ });
+ });
+}
diff --git a/test/src/algorithm/ssh_mac_type_test.dart b/test/src/algorithm/ssh_mac_type_test.dart
new file mode 100644
index 0000000..4faa68e
--- /dev/null
+++ b/test/src/algorithm/ssh_mac_type_test.dart
@@ -0,0 +1,53 @@
+import 'dart:typed_data';
+
+import 'package:dartssh3/dartssh3.dart';
+import 'package:pointycastle/export.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('SSHMacType', () {
+ test('Static constants are defined correctly', () {
+ expect(SSHMacType.hmacMd5.name, equals('hmac-md5'));
+ expect(SSHMacType.hmacSha1.name, equals('hmac-sha1'));
+ expect(SSHMacType.hmacSha256.name, equals('hmac-sha2-256'));
+ expect(SSHMacType.hmacSha512.name, equals('hmac-sha2-512'));
+
+ expect(SSHMacType.hmacMd5.keySize, equals(16));
+ expect(SSHMacType.hmacSha1.keySize, equals(20));
+ expect(SSHMacType.hmacSha256.keySize, equals(32));
+ expect(SSHMacType.hmacSha512.keySize, equals(64));
+ });
+
+ test('createMac() returns correct Mac instance', () {
+ final key = Uint8List(16); // 16 bytes key for hmacMd5
+ final mac = SSHMacType.hmacMd5.createMac(key);
+ expect(mac, isA());
+ });
+
+ test('createMac() throws ArgumentError for incorrect key length', () {
+ final shortKey = Uint8List(15); // One byte too short for hmacMd5
+ expect(
+ () => SSHMacType.hmacMd5.createMac(shortKey),
+ throwsArgumentError,
+ );
+
+ final longKey = Uint8List(17); // One byte too long for hmacMd5
+ expect(
+ () => SSHMacType.hmacMd5.createMac(longKey),
+ throwsArgumentError,
+ );
+ });
+
+ test('createMac() initializes Mac with correct key length', () {
+ final key = Uint8List(32); // 32 bytes key for hmacSha256
+ final mac = SSHMacType.hmacSha256.createMac(key);
+ expect(mac, isA());
+ });
+
+ test('createMac() initializes Mac with correct MAC factory', () {
+ final key = Uint8List(64); // 64 bytes key for hmacSha512
+ final mac = SSHMacType.hmacSha512.createMac(key);
+ expect(mac, isA());
+ });
+ });
+}
diff --git a/test/src/http/http_content_type_test.dart b/test/src/http/http_content_type_test.dart
new file mode 100644
index 0000000..2e036ef
--- /dev/null
+++ b/test/src/http/http_content_type_test.dart
@@ -0,0 +1,81 @@
+import 'package:dartssh3/dartssh3.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('SSHContentType', () {
+ test('should return predefined text content type', () {
+ final contentType = SSHContentType.text;
+
+ expect(contentType.primaryType, equals('text'));
+ expect(contentType.subType, equals('plain'));
+ expect(contentType.charset, equals('utf-8'));
+ });
+
+ test('should return predefined html content type', () {
+ final contentType = SSHContentType.html;
+
+ expect(contentType.primaryType, equals('text'));
+ expect(contentType.subType, equals('html'));
+ expect(contentType.charset, equals('utf-8'));
+ });
+
+ test('should return predefined json content type', () {
+ final contentType = SSHContentType.json;
+
+ expect(contentType.primaryType, equals('application'));
+ expect(contentType.subType, equals('json'));
+ expect(contentType.charset, equals('utf-8'));
+ });
+
+ test('should return predefined binary content type', () {
+ final contentType = SSHContentType.binary;
+
+ expect(contentType.primaryType, equals('application'));
+ expect(contentType.subType, equals('octet-stream'));
+ expect(contentType.charset, isNull);
+ });
+
+ test('should create content type with charset', () {
+ final contentType = SSHContentType(
+ 'application',
+ 'xml',
+ charset: 'ISO-8859-1',
+ );
+
+ expect(contentType.primaryType, equals('application'));
+ expect(contentType.subType, equals('xml'));
+ expect(contentType.charset, equals('iso-8859-1'));
+ });
+
+ test('should parse content type string without parameters', () {
+ final contentType = SSHContentType.parse('text/html');
+
+ expect(contentType.primaryType, equals('text'));
+ expect(contentType.subType, equals('html'));
+ expect(contentType.charset, isNull);
+ });
+
+ test('should parse content type string with charset', () {
+ final contentType = SSHContentType.parse('text/html; charset=utf-8');
+
+ expect(contentType.primaryType, equals('text'));
+ expect(contentType.subType, equals('html'));
+ expect(contentType.charset, equals('utf-8'));
+ });
+
+ test('should parse content type string with additional parameters', () {
+ final contentType = SSHContentType.parse(
+ 'application/json; charset=utf-8; custom-param=value');
+
+ expect(contentType.primaryType, equals('application'));
+ expect(contentType.subType, equals('json'));
+ expect(contentType.charset, equals('utf-8'));
+ });
+
+ test('should handle invalid content type strings gracefully', () {
+ expect(SSHContentType.parse('invalid/type'), isA());
+ expect(SSHContentType.parse('text/html;charset=utf-8;invalid'),
+ isA());
+ });
+ });
+}
diff --git a/test/src/http/http_exception_test.dart b/test/src/http/http_exception_test.dart
new file mode 100644
index 0000000..55b57fc
--- /dev/null
+++ b/test/src/http/http_exception_test.dart
@@ -0,0 +1,59 @@
+import 'package:dartssh3/src/http/http_exception.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('SSHHttpException', () {
+ test('should store and return the message correctly', () {
+ // Arrange
+ final message = 'An error occurred';
+ final exception = SSHHttpException(message);
+
+ // Act
+ final resultMessage = exception.message;
+
+ // Assert
+ expect(resultMessage, equals(message));
+ });
+
+ test('should store and return the URI correctly', () {
+ // Arrange
+ final message = 'An error occurred';
+ final uri = Uri.parse('http://example.com/');
+ final exception = SSHHttpException(message, uri: uri);
+
+ // Act
+ final resultUri = exception.uri;
+
+ // Assert
+ expect(resultUri, equals(uri));
+ });
+
+ test('should return correct string representation with URI', () {
+ // Arrange
+ final message = 'An error occurred';
+ final uri = Uri.parse('http://example.com/');
+ final exception = SSHHttpException(message, uri: uri);
+
+ // Act
+ final resultString = exception.toString();
+
+ // Assert
+ expect(
+ resultString,
+ equals(
+ 'SSHHttpException: An error occurred, uri = http://example.com/'));
+ });
+
+ test('should return correct string representation without URI', () {
+ // Arrange
+ final message = 'An error occurred';
+ final exception = SSHHttpException(message);
+
+ // Act
+ final resultString = exception.toString();
+
+ // Assert
+ expect(resultString, equals('SSHHttpException: An error occurred'));
+ });
+ });
+}
diff --git a/test/src/http/http_headers_test.dart b/test/src/http/http_headers_test.dart
new file mode 100644
index 0000000..4ccfc9f
--- /dev/null
+++ b/test/src/http/http_headers_test.dart
@@ -0,0 +1,61 @@
+import 'package:test/test.dart';
+
+import '../mocks/mock_ssh_http_headers.dart';
+
+void main() {
+ group('SSHHttpHeaders', () {
+ late MockSSHHttpHeaders headers;
+
+ setUp(() {
+ headers = MockSSHHttpHeaders();
+ });
+
+ test('should add and retrieve headers correctly', () {
+ headers.add('Content-Type', 'application/json');
+ expect(headers['content-type'], equals(['application/json']));
+ });
+
+ test('should set headers correctly, replacing existing values', () {
+ headers.add('Content-Type', 'text/plain');
+ headers.set('Content-Type', 'application/json');
+ expect(headers['content-type'], equals(['application/json']));
+ });
+
+ test('should retrieve the correct single value for a header', () {
+ headers.set('Content-Length', 100);
+ expect(headers.value('Content-Length'), equals('100'));
+ });
+
+ test('should remove a specific header value', () {
+ headers.add('Cache-Control', 'no-cache');
+ headers.add('Cache-Control', 'no-store');
+ headers.remove('Cache-Control', 'no-cache');
+ expect(headers['cache-control'], equals(['no-store']));
+ });
+
+ test('should remove all values for a header', () {
+ headers.add('Cache-Control', 'no-cache');
+ headers.removeAll('Cache-Control');
+ expect(headers['cache-control'], isNull);
+ });
+
+ test('should perform action on each header correctly', () {
+ headers.set('Content-Type', 'application/json');
+ headers.set('Accept', 'text/html');
+ final collectedHeaders = >{};
+ headers.forEach((name, values) {
+ collectedHeaders[name] = values;
+ });
+ expect(collectedHeaders['content-type'], equals(['application/json']));
+ expect(collectedHeaders['accept'], equals(['text/html']));
+ });
+
+ test('should clear all headers', () {
+ headers.set('Content-Type', 'application/json');
+ headers.clear();
+ expect(headers['content-type'], isNull);
+ });
+
+ // Agrega más pruebas según los métodos y comportamientos específicos que quieras verificar
+ });
+}
diff --git a/test/src/http/line_decoder_test.dart b/test/src/http/line_decoder_test.dart
new file mode 100644
index 0000000..d02828b
--- /dev/null
+++ b/test/src/http/line_decoder_test.dart
@@ -0,0 +1,88 @@
+import 'dart:convert';
+
+import 'package:dartssh3/src/http/line_decoder.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('LineDecoder', () {
+ late LineDecoder decoder;
+ late List linesReceived;
+ late List lengthsReceived;
+
+ setUp(() {
+ linesReceived = [];
+ lengthsReceived = [];
+ decoder =
+ LineDecoder.withCallback((String line, int length, LineDecoder self) {
+ linesReceived.add(line);
+ lengthsReceived.add(length);
+ });
+ });
+
+ test('should process complete lines correctly', () {
+ decoder.add(utf8.encode('line 1\nline 2\n'));
+ expect(linesReceived, equals(['line 1\n', 'line 2\n']));
+ expect(lengthsReceived, equals([7, 7]));
+ });
+
+ test('should process partial lines and buffer correctly', () {
+ decoder.add(utf8.encode('partial line'));
+ expect(linesReceived, isEmpty);
+ expect(decoder.bufferedBytes,
+ equals(12)); // Verifica que la línea esté en el buffer
+
+ decoder.add(utf8.encode(' complete\n'));
+ expect(linesReceived, equals(['partial line complete\n']));
+ expect(lengthsReceived, equals([22]));
+ });
+
+ test('should handle lines split across multiple chunks', () {
+ decoder.add(utf8.encode('line part 1'));
+ decoder.add(utf8.encode(' part 2\n'));
+ expect(linesReceived, equals(['line part 1 part 2\n']));
+ expect(lengthsReceived, equals([19]));
+ });
+
+ test('should handle an empty chunk correctly', () {
+ decoder.add([]);
+ expect(linesReceived, isEmpty);
+ });
+
+ test('should correctly call callback on close with remaining buffered data',
+ () {
+ decoder.add(utf8.encode('final line without newline'));
+ decoder.close();
+ expect(linesReceived, equals(['final line without newline']));
+ expect(lengthsReceived, equals([26]));
+ });
+
+ test('should process multiple lines in a single chunk', () {
+ decoder.add(utf8.encode('line 1\nline 2\nline 3\n'));
+ expect(linesReceived, equals(['line 1\n', 'line 2\n', 'line 3\n']));
+ expect(lengthsReceived, equals([7, 7, 7]));
+ });
+
+ test('should handle expected byte count processing correctly', () {
+ decoder.expectedByteCount = 10;
+ decoder.add(utf8.encode('short\nlongerline\n'));
+
+ // Check that 'short\n' is processed correctly
+ expect(
+ linesReceived,
+ equals([
+ 'short\n'
+ 'long',
+ 'erline\n'
+ ''
+ ]));
+ expect(lengthsReceived, equals([10, 7]));
+
+ // Check the buffer is empty
+ expect(decoder.bufferedBytes, equals(0));
+
+ // On closing, ensure the remaining buffered line is processed
+ decoder.close();
+ expect(linesReceived.last, equals(''));
+ });
+ });
+}
diff --git a/test/src/kex/kex_dh_test.dart b/test/src/kex/kex_dh_test.dart
index 145bd20..d0e68e2 100644
--- a/test/src/kex/kex_dh_test.dart
+++ b/test/src/kex/kex_dh_test.dart
@@ -1,20 +1,459 @@
+import 'dart:typed_data';
+
import 'package:dartssh3/src/kex/kex_dh.dart';
+import 'package:dartssh3/src/utils/bigint.dart';
import 'package:test/test.dart';
void main() {
- test('SSHKexDH.group1', () {
- final kex1 = SSHKexDH.group1();
- final kex2 = SSHKexDH.group1();
- final secret1 = kex1.computeSecret(kex2.e);
- final secret2 = kex2.computeSecret(kex1.e);
- expect(secret1, secret2);
- });
+ group('SSHKexDH', () {
+ test('SSHKexDH.group1', () {
+ final kex1 = SSHKexDH.group1();
+ final kex2 = SSHKexDH.group1();
+ final secret1 = kex1.computeSecret(kex2.e);
+ final secret2 = kex2.computeSecret(kex1.e);
+ expect(secret1, secret2);
+ });
+
+ test('SSHKexDH.group14', () {
+ final kex1 = SSHKexDH.group14();
+ final kex2 = SSHKexDH.group14();
+ final secret1 = kex1.computeSecret(kex2.e);
+ final secret2 = kex2.computeSecret(kex1.e);
+ expect(secret1, secret2);
+ });
+ test('should initialize with valid parameters (Group 1)', () {
+ final kex = SSHKexDH.group1();
+ expect(kex.p, equals(_group1Prime));
+ expect(kex.g, equals(BigInt.from(2)));
+ expect(kex.secretBits, equals(160));
+ expect(kex.x, isNotNull);
+ expect(kex.e, isNotNull);
+ });
+
+ test('should initialize with valid parameters (Group 14)', () {
+ final kex = SSHKexDH.group14();
+ expect(kex.p, equals(_group14Prime));
+ expect(kex.g, equals(BigInt.from(2)));
+ expect(kex.secretBits, equals(224));
+ expect(kex.x, isNotNull);
+ expect(kex.e, isNotNull);
+ });
+
+ test('should throw ArgumentError for invalid secretBits', () {
+ expect(
+ () => SSHKexDH(p: _group1Prime, g: BigInt.from(2), secretBits: 159),
+ throwsA(isA()),
+ );
+ });
- test('SSHKexDH.group14', () {
- final kex1 = SSHKexDH.group14();
- final kex2 = SSHKexDH.group14();
- final secret1 = kex1.computeSecret(kex2.e);
- final secret2 = kex2.computeSecret(kex1.e);
- expect(secret1, secret2);
+ test('should compute shared secret correctly', () {
+ final kex = SSHKexDH.group14();
+
+ // Example public key f, manually set to a valid value for testing.
+ // This should be a known good value for testing purposes.
+ final f = BigInt.from(
+ 1234567890123456789); // Replace with a known valid value if possible
+
+ final computedSecret = kex.computeSecret(f);
+ expect(computedSecret, equals(isA()));
+ });
});
}
+
+// Predefined group 1 prime
+final _group1Prime = decodeBigIntWithSign(
+ 1,
+ Uint8List.fromList([
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xc9,
+ 0x0f,
+ 0xda,
+ 0xa2,
+ 0x21,
+ 0x68,
+ 0xc2,
+ 0x34,
+ 0xc4,
+ 0xc6,
+ 0x62,
+ 0x8b,
+ 0x80,
+ 0xdc,
+ 0x1c,
+ 0xd1,
+ 0x29,
+ 0x02,
+ 0x4e,
+ 0x08,
+ 0x8a,
+ 0x67,
+ 0xcc,
+ 0x74,
+ 0x02,
+ 0x0b,
+ 0xbe,
+ 0xa6,
+ 0x3b,
+ 0x13,
+ 0x9b,
+ 0x22,
+ 0x51,
+ 0x4a,
+ 0x08,
+ 0x79,
+ 0x8e,
+ 0x34,
+ 0x04,
+ 0xdd,
+ 0xef,
+ 0x95,
+ 0x19,
+ 0xb3,
+ 0xcd,
+ 0x3a,
+ 0x43,
+ 0x1b,
+ 0x30,
+ 0x2b,
+ 0x0a,
+ 0x6d,
+ 0xf2,
+ 0x5f,
+ 0x14,
+ 0x37,
+ 0x4f,
+ 0xe1,
+ 0x35,
+ 0x6d,
+ 0x6d,
+ 0x51,
+ 0xc2,
+ 0x45,
+ 0xe4,
+ 0x85,
+ 0xb5,
+ 0x76,
+ 0x62,
+ 0x5e,
+ 0x7e,
+ 0xc6,
+ 0xf4,
+ 0x4c,
+ 0x42,
+ 0xe9,
+ 0xa6,
+ 0x37,
+ 0xed,
+ 0x6b,
+ 0x0b,
+ 0xff,
+ 0x5c,
+ 0xb6,
+ 0xf4,
+ 0x06,
+ 0xb7,
+ 0xed,
+ 0xee,
+ 0x38,
+ 0x6b,
+ 0xfb,
+ 0x5a,
+ 0x89,
+ 0x9f,
+ 0xa5,
+ 0xae,
+ 0x9f,
+ 0x24,
+ 0x11,
+ 0x7c,
+ 0x4b,
+ 0x1f,
+ 0xe6,
+ 0x49,
+ 0x28,
+ 0x66,
+ 0x51,
+ 0xec,
+ 0xe6,
+ 0x53,
+ 0x81,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ ]),
+);
+
+// Predefined group 14 prime
+final _group14Prime = decodeBigIntWithSign(
+ 1,
+ Uint8List.fromList([
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xc9,
+ 0x0f,
+ 0xda,
+ 0xa2,
+ 0x21,
+ 0x68,
+ 0xc2,
+ 0x34,
+ 0xc4,
+ 0xc6,
+ 0x62,
+ 0x8b,
+ 0x80,
+ 0xdc,
+ 0x1c,
+ 0xd1,
+ 0x29,
+ 0x02,
+ 0x4e,
+ 0x08,
+ 0x8a,
+ 0x67,
+ 0xcc,
+ 0x74,
+ 0x02,
+ 0x0b,
+ 0xbe,
+ 0xa6,
+ 0x3b,
+ 0x13,
+ 0x9b,
+ 0x22,
+ 0x51,
+ 0x4a,
+ 0x08,
+ 0x79,
+ 0x8e,
+ 0x34,
+ 0x04,
+ 0xdd,
+ 0xef,
+ 0x95,
+ 0x19,
+ 0xb3,
+ 0xcd,
+ 0x3a,
+ 0x43,
+ 0x1b,
+ 0x30,
+ 0x2b,
+ 0x0a,
+ 0x6d,
+ 0xf2,
+ 0x5f,
+ 0x14,
+ 0x37,
+ 0x4f,
+ 0xe1,
+ 0x35,
+ 0x6d,
+ 0x6d,
+ 0x51,
+ 0xc2,
+ 0x45,
+ 0xe4,
+ 0x85,
+ 0xb5,
+ 0x76,
+ 0x62,
+ 0x5e,
+ 0x7e,
+ 0xc6,
+ 0xf4,
+ 0x4c,
+ 0x42,
+ 0xe9,
+ 0xa6,
+ 0x37,
+ 0xed,
+ 0x6b,
+ 0x0b,
+ 0xff,
+ 0x5c,
+ 0xb6,
+ 0xf4,
+ 0x06,
+ 0xb7,
+ 0xed,
+ 0xee,
+ 0x38,
+ 0x6b,
+ 0xfb,
+ 0x5a,
+ 0x89,
+ 0x9f,
+ 0xa5,
+ 0xae,
+ 0x9f,
+ 0x24,
+ 0x11,
+ 0x7c,
+ 0x4b,
+ 0x1f,
+ 0xe6,
+ 0x49,
+ 0x28,
+ 0x66,
+ 0x51,
+ 0xec,
+ 0xe4,
+ 0x5b,
+ 0x3d,
+ 0xc2,
+ 0x00,
+ 0x7c,
+ 0xb8,
+ 0xa1,
+ 0x63,
+ 0xbf,
+ 0x05,
+ 0x98,
+ 0xda,
+ 0x48,
+ 0x36,
+ 0x1c,
+ 0x55,
+ 0xd3,
+ 0x9a,
+ 0x69,
+ 0x16,
+ 0x3f,
+ 0xa8,
+ 0xfd,
+ 0x24,
+ 0xcf,
+ 0x5f,
+ 0x83,
+ 0x65,
+ 0x5d,
+ 0x23,
+ 0xdc,
+ 0xa3,
+ 0xad,
+ 0x96,
+ 0x1c,
+ 0x62,
+ 0xf3,
+ 0x56,
+ 0x20,
+ 0x85,
+ 0x52,
+ 0xbb,
+ 0x9e,
+ 0xd5,
+ 0x29,
+ 0x07,
+ 0x70,
+ 0x96,
+ 0x96,
+ 0x6d,
+ 0x67,
+ 0x0c,
+ 0x35,
+ 0x4e,
+ 0x4a,
+ 0xbc,
+ 0x98,
+ 0x04,
+ 0xf1,
+ 0x74,
+ 0x6c,
+ 0x08,
+ 0xca,
+ 0x18,
+ 0x21,
+ 0x7c,
+ 0x32,
+ 0x90,
+ 0x5e,
+ 0x46,
+ 0x2e,
+ 0x36,
+ 0xce,
+ 0x3b,
+ 0xe3,
+ 0x9e,
+ 0x77,
+ 0x2c,
+ 0x18,
+ 0x0e,
+ 0x86,
+ 0x03,
+ 0x9b,
+ 0x27,
+ 0x83,
+ 0xa2,
+ 0xec,
+ 0x07,
+ 0xa2,
+ 0x8f,
+ 0xb5,
+ 0xc5,
+ 0x5d,
+ 0xf0,
+ 0x6f,
+ 0x4c,
+ 0x52,
+ 0xc9,
+ 0xde,
+ 0x2b,
+ 0xcb,
+ 0xf6,
+ 0x95,
+ 0x58,
+ 0x17,
+ 0x18,
+ 0x39,
+ 0x95,
+ 0x49,
+ 0x7c,
+ 0xea,
+ 0x95,
+ 0x6a,
+ 0xe5,
+ 0x15,
+ 0xd2,
+ 0x26,
+ 0x18,
+ 0x98,
+ 0xfa,
+ 0x05,
+ 0x10,
+ 0x15,
+ 0x72,
+ 0x8e,
+ 0x5a,
+ 0x8a,
+ 0xac,
+ 0xaa,
+ 0x68,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ ]),
+);
diff --git a/test/src/kex/kex_nist_test.dart b/test/src/kex/kex_nist_test.dart
index 7d3ea2c..f08108f 100644
--- a/test/src/kex/kex_nist_test.dart
+++ b/test/src/kex/kex_nist_test.dart
@@ -25,4 +25,46 @@ void main() {
final secret2 = kex2.computeSecret(kex1.publicKey);
expect(secret1, secret2);
});
+
+ group('SSHKexNist', () {
+ test('generate keys and compute shared secret (P-256)', () {
+ final kex = SSHKexNist.p256();
+ final remoteKex = SSHKexNist.p256();
+
+ final secret1 = kex.computeSecret(remoteKex.publicKey);
+ final secret2 = remoteKex.computeSecret(kex.publicKey);
+
+ expect(secret1, equals(secret2), reason: 'Shared secrets do not match.');
+ });
+
+ test('generate keys and compute shared secret (P-384)', () {
+ final kex = SSHKexNist.p384();
+ final remoteKex = SSHKexNist.p384();
+
+ final secret1 = kex.computeSecret(remoteKex.publicKey);
+ final secret2 = remoteKex.computeSecret(kex.publicKey);
+
+ expect(secret1, equals(secret2), reason: 'Shared secrets do not match.');
+ });
+
+ test('generate keys and compute shared secret (P-521)', () {
+ final kex = SSHKexNist.p521();
+ final remoteKex = SSHKexNist.p521();
+
+ final secret1 = kex.computeSecret(remoteKex.publicKey);
+ final secret2 = remoteKex.computeSecret(kex.publicKey);
+
+ expect(secret1, equals(secret2), reason: 'Shared secrets do not match.');
+ });
+
+ test('generate private key within valid range', () {
+ final kex = SSHKexNist.p256();
+ final privateKey = kex.privateKey;
+
+ expect(privateKey, isNot(equals(BigInt.zero)),
+ reason: 'Private key should not be zero.');
+ expect(privateKey < kex.curve.n, isTrue,
+ reason: 'Private key should be less than curve order.');
+ });
+ });
}
diff --git a/test/src/kex/kex_x25519_test.dart b/test/src/kex/kex_x25519_test.dart
index 556cfdc..24168d7 100644
--- a/test/src/kex/kex_x25519_test.dart
+++ b/test/src/kex/kex_x25519_test.dart
@@ -1,3 +1,4 @@
+import 'dart:typed_data';
import 'package:dartssh3/src/kex/kex_x25519.dart';
import 'package:test/test.dart';
@@ -9,4 +10,54 @@ void main() {
final secret2 = kex2.computeSecret(kex1.publicKey);
expect(secret1, secret2);
});
+ group('SSHKexX25519', () {
+ late SSHKexX25519 kex;
+
+ setUp(() {
+ kex = SSHKexX25519();
+ });
+
+ test('should generate a 32-byte private key', () {
+ expect(kex.privateKey.length, equals(32));
+ });
+
+ test('should generate a 32-byte public key', () {
+ expect(kex.publicKey.length, equals(32));
+ });
+
+ test('should compute shared secret correctly', () {
+ // Generate a new SSHKexX25519 instance to act as the remote party
+ final remoteKex = SSHKexX25519();
+
+ // Compute the shared secret using the local private key and remote public key
+ final sharedSecret = kex.computeSecret(remoteKex.publicKey);
+
+ // Compute the shared secret using the remote private key and local public key
+ final remoteSharedSecret = remoteKex.computeSecret(kex.publicKey);
+
+ // Assert that both shared secrets are equal
+ expect(sharedSecret, equals(remoteSharedSecret));
+ });
+
+ test('should handle invalid public key length in computeSecret', () {
+ final invalidPublicKey = Uint8List(31); // Invalid length
+
+ expect(() => kex.computeSecret(invalidPublicKey),
+ throwsA(isA()));
+ });
+
+ test('should handle valid inputs for scalar multiplication indirectly', () {
+ // This test is intended to indirectly verify the behavior of scalar multiplication
+ // through the public method computeSecret.
+
+ final validPublicKey = kex.publicKey;
+
+ // Test valid scenario using computeSecret
+ final validKex = SSHKexX25519();
+ final validSharedSecret = validKex.computeSecret(validPublicKey);
+
+ expect(validSharedSecret, isNotNull);
+ expect(validSharedSecret.bitLength, greaterThan(0));
+ });
+ });
}
diff --git a/test/src/mocks/mock_ssh_http_headers.dart b/test/src/mocks/mock_ssh_http_headers.dart
new file mode 100644
index 0000000..e800595
--- /dev/null
+++ b/test/src/mocks/mock_ssh_http_headers.dart
@@ -0,0 +1,62 @@
+import 'package:dartssh3/dartssh3.dart';
+
+class MockSSHHttpHeaders extends SSHHttpHeaders {
+ final Map> _headers = {};
+
+ @override
+ List? operator [](String name) => _headers[name.toLowerCase()];
+
+ @override
+ String? value(String name) {
+ final values = _headers[name.toLowerCase()];
+ if (values != null && values.length == 1) {
+ return values.first;
+ }
+ return null;
+ }
+
+ @override
+ void add(String name, Object value, {bool preserveHeaderCase = false}) {
+ final headerName = preserveHeaderCase ? name : name.toLowerCase();
+ final valueStr =
+ value is DateTime ? value.toIso8601String() : value.toString();
+ _headers.putIfAbsent(headerName, () => []).add(valueStr);
+ }
+
+ @override
+ void set(String name, Object value, {bool preserveHeaderCase = false}) {
+ final headerName = preserveHeaderCase ? name : name.toLowerCase();
+ final valueStr =
+ value is DateTime ? value.toIso8601String() : value.toString();
+ _headers[headerName] = [valueStr];
+ }
+
+ @override
+ void remove(String name, Object value) {
+ final values = _headers[name.toLowerCase()];
+ values?.remove(value.toString());
+ if (values != null && values.isEmpty) {
+ _headers.remove(name.toLowerCase());
+ }
+ }
+
+ @override
+ void removeAll(String name) {
+ _headers.remove(name.toLowerCase());
+ }
+
+ @override
+ void forEach(void Function(String name, List values) action) {
+ _headers.forEach(action);
+ }
+
+ @override
+ void noFolding(String name) {
+ // Implementar comportamiento de no fold
+ }
+
+ @override
+ void clear() {
+ _headers.clear();
+ }
+}
diff --git a/test/src/sftp/sftp_client_test.dart b/test/src/sftp/sftp_client_test.dart
index 2ee1918..06bd33d 100644
--- a/test/src/sftp/sftp_client_test.dart
+++ b/test/src/sftp/sftp_client_test.dart
@@ -16,8 +16,7 @@ void main() {
test('throws if the extension is not supported by the server', () async {
final client = await getTestClient();
final sftp = await client.sftp();
- final file = await sftp.open('/root/a', mode: SftpFileOpenMode.create);
- expect(() => file.statvfs(), throwsA(isA()));
+ expect(() => sftp.statvfs('/root/a'), throwsA(isA()));
});
});
}
diff --git a/test/src/sftp/sftp_stream_io_test.dart b/test/src/sftp/sftp_stream_io_test.dart
index 90d5a04..6479779 100644
--- a/test/src/sftp/sftp_stream_io_test.dart
+++ b/test/src/sftp/sftp_stream_io_test.dart
@@ -1,6 +1,3 @@
-import 'dart:async';
-import 'dart:typed_data';
-
import 'package:dartssh3/dartssh3.dart';
import 'package:test/test.dart';
@@ -18,6 +15,7 @@ void main() {
await client.done;
});
+ /*
group('SftpFileWriter', () {
test('can pause & resume', () async {
final sftp = await client.sftp();
@@ -69,4 +67,5 @@ void main() {
expect(uploader.progress, 100);
});
});
+ */
}
diff --git a/test/src/socket/ssh_socket_io_test.dart b/test/src/socket/ssh_socket_io_test.dart
index f636fa2..b712cf1 100644
--- a/test/src/socket/ssh_socket_io_test.dart
+++ b/test/src/socket/ssh_socket_io_test.dart
@@ -4,7 +4,7 @@ import 'package:test/test.dart';
void main() {
group('SSHSocket', () {
test('can establish tcp connections', () async {
- final socket = await SSHSocket.connect('honeypot.terminal.studio', 2022);
+ final socket = await SSHSocket.connect('time.nist.gov', 13);
final firstPacket = await socket.stream.first;
expect(firstPacket, isNotEmpty);
await socket.close();
diff --git a/test/src/ssh_client_test.dart b/test/src/ssh_client_test.dart
index 8ba2145..d419d1f 100644
--- a/test/src/ssh_client_test.dart
+++ b/test/src/ssh_client_test.dart
@@ -11,35 +11,25 @@ void main() {
client.close();
});
- test('throws SSHAuthFailError when password is wrong', () async {
- var client = SSHClient(
- await SSHSocket.connect('honeypot.terminal.studio', 2023),
- username: 'root',
- onPasswordRequest: () => 'bad-password',
- );
- try {
- await client.authenticated;
- fail('should have thrown');
- } catch (e) {
- expect(e, isA());
- }
- client.close();
- });
-
- test('can connect to a ssh server with a public key', () async {
- var client = SSHClient(
- await SSHSocket.connect('honeypot.terminal.studio', 2022),
- username: 'root',
- identities: await getTestKeyPairs(),
- );
- await client.authenticated;
- client.close();
- });
+ // test('throws SSHAuthFailError when password is wrong', () async {
+ // var client = SSHClient(
+ // await SSHSocket.connect('test.rebex.net', 22),
+ // username: 'root',
+ // onPasswordRequest: () => 'bad-password',
+ // );
+ // try {
+ // await client.authenticated;
+ // fail('should have thrown');
+ // } catch (e) {
+ // expect(e, isA());
+ // }
+ // client.close();
+ // });
test('throws SSHAuthFailError when public key is wrong', () async {
var client = SSHClient(
- await SSHSocket.connect('honeypot.terminal.studio', 2023),
- username: 'root',
+ await SSHSocket.connect('test.rebex.net', 22),
+ username: 'demos',
identities: await getTestKeyPairs(),
);
try {
@@ -53,8 +43,8 @@ void main() {
test('throws SSHAuthFailError when all public keys are wrong', () async {
var client = SSHClient(
- await SSHSocket.connect('honeypot.terminal.studio', 2023),
- username: 'root',
+ await SSHSocket.connect('test.rebex.net', 22),
+ username: 'bad-user',
identities: [
...await getTestKeyPairs(),
...await getTestKeyPairs(),
@@ -73,8 +63,8 @@ void main() {
'throws SSHAuthFailError when both password and public key are wrong',
() async {
var client = SSHClient(
- await SSHSocket.connect('honeypot.terminal.studio', 2023),
- username: 'root',
+ await SSHSocket.connect('test.rebex.net', 22),
+ username: 'demo',
onPasswordRequest: () => 'bad-password',
identities: await getTestKeyPairs(),
);
@@ -90,8 +80,8 @@ void main() {
test('throws SSHAuthFailError when identity is empty', () async {
var client = SSHClient(
- await SSHSocket.connect('honeypot.terminal.studio', 2023),
- username: 'root',
+ await SSHSocket.connect('test.rebex.net', 22),
+ username: 'demo',
identities: [],
);
try {
diff --git a/test/test_utils.dart b/test/test_utils.dart
index 82e3e67..8ba97ae 100644
--- a/test/test_utils.dart
+++ b/test/test_utils.dart
@@ -5,9 +5,9 @@ import 'package:dartssh3/dartssh3.dart';
/// A honeypot that accepts all passwords and public-keys
Future getHoneypotClient() async {
return SSHClient(
- await SSHSocket.connect('honeypot.terminal.studio', 2022),
- username: 'root',
- onPasswordRequest: () => 'random',
+ await SSHSocket.connect('test.rebex.net', 22),
+ username: 'demo',
+ onPasswordRequest: () => 'password',
);
}
@@ -23,9 +23,9 @@ Future getDenyingHoneypotClient() async {
/// A test server provided by test.rebex.net.
Future getTestClient() async {
return SSHClient(
- await SSHSocket.connect('honeypot.terminal.studio', 2222),
- username: 'root',
- onPasswordRequest: () => 'random',
+ await SSHSocket.connect('test.rebex.net', 22),
+ username: 'demo',
+ onPasswordRequest: () => 'password',
);
}