Skip to content

[DRAFT] Support for SFTP #3697

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

joandrsn
Copy link
Contributor

@joandrsn joandrsn commented May 17, 2025

Summary

I have added a module for handling SFTP connections directly from Business Central.
image

This requires a SFTP service. A raspberry pi on the local network is sufficent for testing, but Azure Blob Storage can also provides a testing scenario.

Work Item(s)

Fixes #3686

DLL install process

  1. Download these two nuget packages:
    https://www.nuget.org/packages/ssh.net/
    https://www.nuget.org/packages/BouncyCastle.Cryptography/
  2. Extract the DLL's:
    lib\net8.0\Renci.SshNet.dll
    lib\net6.0\BouncyCastle.Cryptography.dll
  3. Place in service tier's Add-Ins-folder and in one of the al.assemblyProbingPaths.

My internal checklist for this PR:

  • Get approval of SSH.NET + BouncyCastle.Cryptography for Business Central
  • Get a different number range (Not 50000..100000)
  • Update app.json to reflect the module
  • Namespaces for all files
  • Handle different types of exceptions (Connection errors, etc)
  • Remove SFTP Client debugging page
  • Expand the "SFTP Operation Response" to contain Errors (Like ABS Operation Response)
  • Consider a stateless API
  • Add tests
  • Handle upload/download better if possible
    • Currently I'm downloading all the bytes and passing it to a MemoryStream, but I would like to simply get a stream. However I cannot seem to invoke the functions (The last parameter Action<ulong>? downloadCallback = null is tricky to make in Business Central dotnet integration).
    • Upload could use UploadFile(Stream, string, Action?)
    • Download could use DownloadFile(string, Stream, Action?)

Fixes AB#351397

Sorry, something went wrong.

@github-actions github-actions bot added AL: System Application From Fork Pull request is coming from a fork labels May 17, 2025
@JesperSchulz JesperSchulz added the Integration GitHub request for Integration area label May 23, 2025
@github-actions github-actions bot added the Linked Issue is linked to a Azure Boards work item label May 23, 2025
@github-actions github-actions bot added this to the Version 27.0 milestone May 23, 2025
@JesperSchulz JesperSchulz changed the title Support for SFTP [DRAFT] Support for SFTP Jun 2, 2025
@joandrsn
Copy link
Contributor Author

joandrsn commented Jun 7, 2025

Sorry about the delay. I have been working on testing the client and handling exceptions (essentially dogfooding the SFTP client to myself via our implementation).
Previously, I started handling the state of the SSH.NET client, but that seems redundant. Now instead whenever I do an operation, I use it in a TryFunction and from there, read the Dotnet exception and expose that to the client via an Enum.
@JesperSchulz could I get a review of the code that I have written?

I want to keep the debugging page - since the connections can be finicky.
image

Here is a list of the objects and their intended functionality:

  • codeunit SFTP Client: The codeunit to use for others
  • codeunit SFTP Client Implementation: Internal functions. Holds the ISFTPClient
  • interface ISFTPClient: Abstract client - determines the functions available for the SFTP Client Implementation to call
  • interface ISFTPFile: Abstract SFTP file.
  • codeunit DotnetSFTPClient: The SSH.NET file
  • codeunit DotnetSFTPFile: The SSH.NET file
  • page SFTP Client Debug: A debug page
  • enum SFTP Exception Type: An enum to expose via SFTP Operation Response. Makes error handling easier
  • page SFTP Folder Content: A page to show contents of a folder
  • table SFTP Folder Content: A temporary table to hold contents of a folder
  • codeunit SFTP Operation Response: A codeunit to respond to every request from the SFTP Client

I have included mock implementations of SFTP Client and SFTP File.
These are used in the SFTP Client Test to mock the functionality of the client without actually connecting to a remote host.

Currently I'm quite happy with the implementation. It does as I expect.

For future work, I would like to add HostKey fingerprinting which would add the ability for the user to check if the server had the correct hostkey. However, I can live without it for now.

One thing I may need is the functionality to disable SFTP connections.
You know for when you create a Sandbox environment and Business Central disables HTTP requests in the extensions settings.
Do you have any suggestions on what would be a good solution here? Maybe an event I can subscribe to to test? A subscription may also be the wrong tool since the boolean flag specifically states HTTP-requests?

@joandrsn joandrsn marked this pull request as ready for review June 7, 2025 10:29
@joandrsn joandrsn requested review from a team as code owners June 7, 2025 10:29
@JesperSchulz
Copy link
Contributor

Sorry about the delay. I have been working on testing the client and handling exceptions (essentially dogfooding the SFTP client to myself via our implementation). Previously, I started handling the state of the SSH.NET client, but that seems redundant. Now instead whenever I do an operation, I use it in a TryFunction and from there, read the Dotnet exception and expose that to the client via an Enum. @JesperSchulz could I get a review of the code that I have written?

I want to keep the debugging page - since the connections can be finicky. image

Here is a list of the objects and their intended functionality:

  • codeunit SFTP Client: The codeunit to use for others
  • codeunit SFTP Client Implementation: Internal functions. Holds the ISFTPClient
  • interface ISFTPClient: Abstract client - determines the functions available for the SFTP Client Implementation to call
  • interface ISFTPFile: Abstract SFTP file.
  • codeunit DotnetSFTPClient: The SSH.NET file
  • codeunit DotnetSFTPFile: The SSH.NET file
  • page SFTP Client Debug: A debug page
  • enum SFTP Exception Type: An enum to expose via SFTP Operation Response. Makes error handling easier
  • page SFTP Folder Content: A page to show contents of a folder
  • table SFTP Folder Content: A temporary table to hold contents of a folder
  • codeunit SFTP Operation Response: A codeunit to respond to every request from the SFTP Client

I have included mock implementations of SFTP Client and SFTP File. These are used in the SFTP Client Test to mock the functionality of the client without actually connecting to a remote host.

Currently I'm quite happy with the implementation. It does as I expect.

For future work, I would like to add HostKey fingerprinting which would add the ability for the user to check if the server had the correct hostkey. However, I can live without it for now.

One thing I may need is the functionality to disable SFTP connections. You know for when you create a Sandbox environment and Business Central disables HTTP requests in the extensions settings. Do you have any suggestions on what would be a good solution here? Maybe an event I can subscribe to to test? A subscription may also be the wrong tool since the boolean flag specifically states HTTP-requests?

Yes, I'll get to this soon! Promise. We're a bit low on capacity these weeks due to events, but from mid next week, we should be back to normal operations! Hang in there 😊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
AL: System Application From Fork Pull request is coming from a fork Integration GitHub request for Integration area Linked Issue is linked to a Azure Boards work item
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BC Idea]: SFTP module using 3rd party library
2 participants