Code Monkey home page Code Monkey logo

citadel's People

Contributors

andyzaharia avatar finestructure avatar gaetanzanella avatar gwynne avatar jaapwijnen avatar jdmcd avatar jhoughjr avatar joannis avatar marcocanc avatar michalbencur avatar simplykyra avatar typ0genius avatar waylybaye avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

citadel's Issues

Support shell channel

Hi Joannis, Do you have any plans to support a shell channel? I noticed that you already support streaming in executeCommand, and it would be really cool if you could also support a shell channel. Thank you!

Support custom SSHAuthenticationMethod

I would like to suggest adding support for custom SSHAuthenticationMethod. Currently, I need to provide multiple authentication methods for one SSH connection, such as auto-attempting all available keys or implementing two-factor login. It would be great if SSHClient.connect could use NIOSSHClientUserAuthenticationDelegate as a generic parameter so that users can implement their own authentication logic.

iOS 14 support

Hi Joannis, great job on this library! I'm wondering why you set the iOS 15 as minimum deployment target, I tried to change it to iOS 14 and it works as expected on iOS 14.

Streaming `stdin` and `stdout` in SSHClient

The executeCommand function accumulated information into a contiguous ByteBuffer. This is useful for non-interactive commands such as cat and ls. Citadel currently does not expose APIs for streaming into a process' stdin or streaming the stdout elsewhere. If you want this, please create an issue.

We are planning to work on adding streaming support for Citadel as our app requires the use of interactive commands (a shell). Would you shed some lights on how we might approach this? :)

Unit test fails assertion in key exchange

Trying to run unit test Citadel2Tests.testSFTPUpload and it fails with:

Test Case '-[CitadelTests.Citadel2Tests testSFTPUpload]' started.
2023-07-14 09:46:50.680986+1000 xctest[82987:3661392] [si_destination_compare] send failed: Invalid argument
2023-07-14 09:46:50.681103+1000 xctest[82987:3661392] [si_destination_compare] send failed: Undefined error: 0
NIOSSH/SSHKeyExchangeStateMachine.swift:299: Assertion failed: Negotiated MAC was not supported by negotiated transport protection
2023-07-14 09:46:50.688181+1000 xctest[82987:3661397] NIOSSH/SSHKeyExchangeStateMachine.swift:299: Assertion failed: Negotiated MAC was not supported by negotiated transport protection

I've tried fiddling with the algorithms for both server and client along the lines suggested in the project README but without success

Error while connecting to SFTP

Trying to connect to an SFTP server with the following config:

    let ssh = try await SSHClient.connect (
        host: "sftp012.successfactors.eu",
        authenticationMethod: .passwordBased(username: "UUUU", password: "PPPP"),
        hostKeyValidator: .acceptAnything(),
        reconnect: .never )

Receiving the following error:
Citadel.ClientHandshakeHandler.(unknown context at $10122d328).(unknown context at $10122d3a4).AuthenticationFailed error 1.

Connection to this server via an SFTP client like CyberDuck works fine.
Connecting via Citadel to this sftp Testserver works fine https://www.sftp.net/public-online-sftp-servers

Help would be much appreciated :)

SFTP write error

Describe the bug
The write file example produces an error:

2024-04-16T13:21:15+0400 info nl.orlandos.citadel.sftp : [Citadel] SFTP connection opened and ready
2024-04-16T13:21:15+0400 info nl.orlandos.citadel.sftp : [Citadel] SFTP requesting to open file at '/flightbriefing/file.txt' with flags 0x00000023
(lldb) po error
▿ {1}(code: SSH_FX_NO_SUCH_FILE, #'No such file')

  • requestId : 1
  • errorCode : SSH_FX_NO_SUCH_FILE
  • message : "No such file"
  • languageTag : ""

Reproducer Sample

 func testDirectWriting() async throws {
        guard let data = "Hello world".data(using: .utf8) else {
            XCTFail()
            return
        }

        do {
            let file = try await sut?.sftp?.openFile(filePath: "/flightbriefing/file.txt", flags: [.read, .write, .forceCreate])
            try await file?.write(ByteBuffer(data: data), at: 0)
            try await file?.close()
        } catch {
            print(error)
            XCTFail()
        }
    }

(Where sftp is an SSHClient.SFTPClient)

Expected behavior
The file should be written (even if it does not exist as the .forceCreate flag is there). No error should be thrown.

Client (please complete the following information):

  • Xcode 15.3
  • Client: Citadel via SPM
  • Version of Citadel, if applicable: 0.7.1

product '_CryptoExtras' not found in 'swift-crypto'

product '_CryptoExtras' required by package 'citadel' target 'Citadel' not found in package 'swift-crypto'

Thats the error I get. I just added version version 0.7.0 as dependency to my package. I tried 0.6.0 as well, but the error persists

SFTP server with Exec

Adding an exec handler to an SFTP server causes this crash:

NIOCore/NIOAny.swift:200: Fatal error: tried to decode as type SSHChannelData but found IOData with contents ioData(IOData { ByteBuffer { readerIndex: 0, writerIndex: 9, readableBytes: 9, capacity: 9, storageCapacity: 32, slice: _ByteBufferSlice { 9..<18 }, storage: 0x00006000002058c0 (32 bytes) } })
2023-10-01 15:55:39.527637-0400 citadel-backend[53048:39683831] NIOCore/NIOAny.swift:200: Fatal error: tried to decode as type SSHChannelData but found IOData with contents ioData(IOData { ByteBuffer { readerIndex: 0, writerIndex: 9, readableBytes: 9, capacity: 9, storageCapacity: 32, slice: _ByteBufferSlice { 9..<18 }, storage: 0x00006000002058c0 (32 bytes) } })

CC @Joannis

Is plain FTP possible?

I have to connect to an external FTP server to search for and download files. I do not control this server, I just need to get the files to put them in S3 for future use. Up until now I’ve used a wrapper around curl that I wrote with my Vapor server, but I’d love to replace this. Can I leverage citadel to do this instead?

For example, could I use citadel’s SFTP client in an plain FTP mode? Or, extend the package to support plain FTP?

invalidOpenSSHBoundary error while trying to connect to a server with a private key

Describe the bug
Trying to connect to a server using a RSA private key throws a invalidOpenSSHBoundary error without any other details.

Reproducer Sample

import Citadel
import CryptoKit

let host:String = "...server ip address..."

let port:Int = 22
let username: String = "root"

let sshFile = try String(contentsOfFile: "path_to_key")
let privateKey = try Insecure.RSA.PrivateKey(sshRsa: sshFile)

let client = try await SSHClient.connect(
    host: host,
    port: port,
    authenticationMethod: .rsa(username: username, privateKey: privateKey),
    hostKeyValidator: .acceptAnything(),
    reconnect: .never
)

let result = try await client.executeCommand("ls -l /")
print(String(buffer: result))

Expected behavior
It should connect to the server.

Client (please complete the following information):

  • OS: macOS sonoma 14.4.1 (23E224)
  • Client: Citadel
  • Version of Citadel, if applicable: 0.7.2

Server (please complete the following information):

  • OS: Ubuntu 22.04
  • Server: OpenSSH_8.9p1 Ubuntu-3ubuntu0.1, OpenSSL 3.0.2 15 Mar 2022
  • Version of Citadel, if applicable: none

Additional context
Using the same key from the command line with "ssh -i key root@server" works.
The key starts with "-----BEGIN RSA PRIVATE KEY-----" and ends with "-----END RSA PRIVATE KEY-----"

Not sure if related (feel free to delete this part if not): on another server I get a Citadel.SSHClientError.allAuthenticationOptionsFailed error.
That key uses "-----BEGIN OPENSSH PRIVATE KEY-----" and "-----END OPENSSH PRIVATE KEY-----" as bondaries. It was generated on macOs 14.4.1 with this comand: "ssh-keygen -t rsa -b 4096". When connecting from the command line it works.

Buffering/backpressure issue

As discussed on Slack, there seems to be an issue around buffering or back pressure support when logging output from Citadel.

I'm running a task as follows:

        let stream = try await executeCommandStream("script.sh", inShell: true)
        for try await output in stream {
            switch output {
                case let .stdout(buffer):
                    print(String(buffer: buffer), terminator: "")
                case let .stderr(buffer):
                    print(String(buffer: buffer), terminator: "")
            }
        }

where "script.sh" is a simple

echo "❌  this must fail"
exit 1

but the echo isn't showing up in the logs.

An ugly fix for this is to introduce a delay before exiting:

echo "❌  this must fail"
sleep 0.1
exit 1

Best I can tell, there's no way on the consumer side of the AsyncThorwingStream to ensure all messages have been delivered before the stream terminates.

TTY executing function may stuck forever when inShell is true

截屏2023-10-20 23 46 52

TTY added ";exit\n" in its code. However, if a command has already ended with ";", a parse error of ";;" is risen and the in shell can't quit.

Since the in shell is not quit, the app calls this api won't get the buffer and the app waits forever.

related function:

public func executeCommand(_ command: String, maxResponseSize: Int = .max, mergeStreams: Bool = false, inShell: Bool = false) async throws -> ByteBuffer

Try: "ls abc;" as command.

Unable to parse RSA private key with no padding

In OpenSSHKey init(string key: String, decryptionKey: Data? = nil) there is an assumption that there will be padding. However generating an RSA key using ssh-keygen -t rsa -b 4096 produces a private key without padding and the below for loop results in a RangeException as paddingLength is 0

for i in 1..<paddingLength { guard padding[i - 1] == UInt8(i) else { throw InvalidKey() } }

Support keyboard-interactive login

          Great news! I have tested the branch, and it works perfectly. However, I did encounter an issue when testing 2-factor login, as `swift-nio-ssh` currently does not support keyboard-interactive authentication. If I have the time, I will attempt to make a pull request to address this issue. Thank you for your efforts in developing this feature!

Originally posted by @waylybaye in #28 (comment)

TCP-IP Forwarding example in readme throws error

Describe the bug
I am currently trying to get the direct TCP tunnel from the readme to work. Unfortunately I am getting the following error:

Cannot convert value of type '(UnboundedRange_) -> ()' to expected argument type '[any ChannelHandler]'

in this line:

proxyChannel.pipeline.addHandlers(...)

Reproducer Sample

        Task {
            let client = try? await SSHClient.connect(
                host: "example.com",
                authenticationMethod: .passwordBased(username: "root", password: "password"),
                hostKeyValidator: .acceptAnything(),
                reconnect: .never
            )
            
            let address = try SocketAddress(ipAddress: "fe80::1", port: 27017)
            let configuredProxyChannel = try await client?.createDirectTCPIPChannel(
                using: SSHChannelType.DirectTCPIP(
                    targetHost: "localhost",
                    targetPort: 27017,
                    originatorAddress: address
                )
            ) { proxyChannel in
              proxyChannel.pipeline.addHandlers(...)
            }
        }

I would really appreciate your help!

P.S. Also I would actually be interested in setting up a forwardedTCPIP tunnel instead of a direct one. Am I correct that Citadel currently doesn't support this?

Passing environment variables triggers `channelFailure` error

My recent addition #53 is failing with a channelFailure. As discussed, I'm fairly sure this worked initially but I'm certainly now hitting the channelFailure very reliably.

The error can be avoided by sending the env request with wantReply: false but in that case the env variable isn't actually being set:

try await executeCommandStream("printing", inShell: true, environment: ["FOO": "bar"])

USER=admin
LOGNAME=admin
HOME=/Users/admin
PATH=/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/Library/Apple/usr/bin
SHELL=/bin/zsh
SSH_CLIENT=172.29.29.8 53247 22
SSH_CONNECTION=172.29.29.8 53247 192.168.64.5 22
TMPDIR=/var/folders/fs/0w3t9t1d28xc3bj0tgb8hcrw0000gn/T/
SHLVL=1
PWD=/Users/admin
OLDPWD=/Users/admin
HOMEBREW_PREFIX=/opt/homebrew
HOMEBREW_CELLAR=/opt/homebrew/Cellar
HOMEBREW_REPOSITORY=/opt/homebrew
MANPATH=/opt/homebrew/share/man::
INFOPATH=/opt/homebrew/share/info:
_=/usr/bin/printenv

Also, inShell true or false does not make a difference.

I've tried moving the env request's triggerUserOutboundEvent into createChannel but also to no effect.

I'm not sure what else to try 🤔

Storing Insecure.RSA.PrivateKey in Keychain

Is it possible to store and retrieve an RSA Private key in Keychain? I have successfully gotten the raw data or the private key and stored it as Data, but when I try to recreate the key with Insecure.RSA.PrivateKey(sshRsa: [data]), Citadel throws an InvalidKey exception. I'm sure I've missed something obvious - thank you for any help!

Support dynamic-tcpip port forwarding

Hi Orlandos,

Will it be possible to introduce dynamic port forwarding aka socks proxy over ssh tunnel?
The aim is to route all macOS or iOS traffic over a configured socks5 port using swift nio ssh.

Any guidance on how to implement this functionality would be very helpful.

Thanks

Interactive standard stream processing.

There is requirement in our project to catch script output it prints out to its STDOUT/STDERR and send response back to STDIN when it prompts for it.

Any solution allowing to catch STDOUT/STDERR stream output in realtime in couple with ability to immediately send data to ssh STDIN will satisfy us.

For now we implemented alternative ssh interaction based on low-level swift Process class. We transferring ssh command with arguments as Process.arguments then interacting with it like any other child UNIX process.

        task.executableURL = URL(fileURLWithPath: "/opt/homebrew/bin/sshpass")
        // https://github.com/hudochenkov/homebrew-sshpass
        // brew install hudochenkov/sshpass/sshpass
        task.arguments = [
            "-p", password,
            "ssh",
            "-o", "StrictHostKeyChecking no",
            "-o", "UserKnownHostsFile=/dev/null",
            "-q",
            "\(login)@\(host)",
        ]

We found this solution horrible especially in contrast with nice Citadel interface and still use Citadel for sftp, so we very appreciate you to implement real-time interaction in citadel.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.