{"id":19506847,"url":"https://github.com/regis-leray/fs2-ftp","last_synced_at":"2025-07-16T20:36:37.479Z","repository":{"id":40545460,"uuid":"192927696","full_name":"regis-leray/fs2-ftp","owner":"regis-leray","description":"Simple client for Ftp/Ftps/Sftp","archived":false,"fork":false,"pushed_at":"2024-10-11T00:31:57.000Z","size":204,"stargazers_count":33,"open_issues_count":13,"forks_count":9,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-26T02:51:16.697Z","etag":null,"topics":["cats","cats-effect","fs2","ftp","ftp-client","ftps","scala","sftp"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/regis-leray.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-06-20T13:45:09.000Z","updated_at":"2024-10-14T12:43:43.000Z","dependencies_parsed_at":"2024-11-10T22:38:48.270Z","dependency_job_id":null,"html_url":"https://github.com/regis-leray/fs2-ftp","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/regis-leray/fs2-ftp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/regis-leray%2Ffs2-ftp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/regis-leray%2Ffs2-ftp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/regis-leray%2Ffs2-ftp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/regis-leray%2Ffs2-ftp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/regis-leray","download_url":"https://codeload.github.com/regis-leray/fs2-ftp/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/regis-leray%2Ffs2-ftp/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265538745,"owners_count":23784644,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cats","cats-effect","fs2","ftp","ftp-client","ftps","scala","sftp"],"created_at":"2024-11-10T22:38:43.987Z","updated_at":"2025-07-16T20:36:37.296Z","avatar_url":"https://github.com/regis-leray.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FS2 with SFTP - FTP / FTPS\n\nfs2 ftp client built on top of [Cats Effect](https://typelevel.org/cats-effect/), [Fs2](http://fs2.io/) and the sftp java client [sshj](https://github.com/hierynomus/sshj) and ftp/ftps client [commons-net](https://commons.apache.org/proper/commons-net/) \n\n[![Build Status](https://github.com/regis-leray/fs2-ftp/actions/workflows/ci.yml/badge.svg)](https://github.com/regis-leray/fs2-ftp/actions?query=branch%3Amaster)\n[![codecov](https://codecov.io/gh/regis-leray/fs2-ftp/branch/master/graph/badge.svg)](https://codecov.io/gh/regis-leray/fs2-ftp)\n[![Maven Central](https://img.shields.io/maven-central/v/com.github.regis-leray/fs2-ftp_2.12.svg)](http://search.maven.org/#search%7Cga%7C1%7Cfs2-ftp) \n\u003ca href=\"https://typelevel.org/cats/\"\u003e\u003cimg src=\"https://typelevel.org/cats/img/cats-badge.svg\" height=\"40px\" align=\"right\" alt=\"Cats friendly\" /\u003e\u003c/a\u003e\n\n## Setup\n\n```\n// Supports scala versions (2.12 / 2.13 / 3.1.x)\n\nlibraryDependencies += \"com.github.regis-leray\" %% \"fs2-ftp\" % \"\u003cversion\u003e\"\n```\n\n## How to use it ?\n\n### FTP / FTPS\n\n```scala\nimport cats.effect.IO\nimport fs2.ftp.UnsecureFtp._\nimport fs2.ftp.FtpSettings._\n\n// FTP\nval settings = UnsecureFtpSettings(\"127.0.0.1\", 21, FtpCredentials(\"foo\", \"bar\"))\n// FTP-SSL \nval settings = UnsecureFtpSettings.ssl(\"127.0.0.1\", 21, FtpCredentials(\"foo\", \"bar\"))\n\nconnect[IO](settings).use{\n  _.ls(\"/\").compile.toList\n}\n```\n\n### SFTP\n\n#### Password authentication\n```scala\nimport fs2.ftp.SecureFtp._\nimport fs2.ftp.FtpSettings._\nimport cats.effect.IO\n\nval settings = SecureFtpSettings(\"127.0.0.1\", 22, FtpCredentials(\"foo\", \"bar\"))\n\nconnect[IO](settings).use(\n  _.ls(\"/\").compile.toList\n)     \n ```\n\n#### private key authentication\n```scala\nimport fs2.ftp.SecureFtp._\nimport fs2.ftp.FtpSettings._\nimport java.nio.file.Paths._\nimport cats.effect.IO\n\n// Provide a SftpIdentity implementation\n\nval keyFile = KeyFileSftpIdentity(Paths.get(\"privateKeyStringPath\"))\n\nval settings = SecureFtpSettings(\"127.0.0.1\", 22, FtpCredentials(\"foo\", \"\"), keyFile)\n\nconnect[IO](settings).use(\n  _.ls(\"/\").compile.toList\n)     \n ```\n\n## Required Runtime\n\nSince all (s)ftp command are IO bound task , it needs to be executed on specific runtime.\nMore information about IO and Cats Effect can be found here https://typelevel.org/cats-effect/docs/tutorial\n\n\nThe following example show how to create a `FtpClient[F[_], +A]` by using `connect()`\n\n* Here the runtime is provided by `IOApp.Simple`\n```scala\nimport cats.effect.{IO, IOApp}\nimport fs2.ftp.FtpSettings._\n\nobject MyApp extends IOApp.Simple {\n  //F[_] Effect will be set as cats.effect.IO\n\n  private val settings = SecureFtpSettings(\"127.0.0.1\", 22, FtpCredentials(\"foo\", \"bar\"))\n\n  //print all files/directories\n  def run: IO[Unit] = {\n    connect[IO, SecureFtp.Client](settings).use {\n      _.ls(\"/mypath\")\n        .evalTap(r =\u003e IO(println(r)))\n        .compile\n        .drain\n    }\n  }\n}\n```\n\n## Support any commands ?\nThe underlying client is safely exposed and you have access to all possible ftp commands\n\n```scala\nimport cats.effect.IO\nimport fs2.ftp.SecureFtp._\nimport fs2.ftp.FtpSettings._\n\nval settings = SecureFtpSettings(\"127.0.0.1\", 22, FtpCredentials(\"foo\", \"bar\"))\n\nconnect[IO](settings).use(\n  _.execute(_.version())\n)     \n ```\n\n## Support any effect (IO, Monix, ZIO)\n\nSince the library support polymorphic in the effect type `F[_]` (as long as it is compatible with cats-effect typeclasses), fs2-ftp can be used with other effect libraries such as Monix / ZIO.\n\nThe library is by default bringing with `cats-effect` dependency as the default effect system implementation.\n\n### exemple for monix\n\nYou will need to use add in build.sbt [monix-eval](https://github.com/monix/monix)\n\n```\nlibraryDependencies += \"io.monix\" %% \"monix-eval\" % \"\u003cversion\u003e\"\n```\n\n```scala\nimport fs2.ftp.FtpSettings._\nimport fs2.ftp._\nimport monix.eval.Task\nimport monix.execution.Scheduler.Implicits.global\nimport Task.contextShift\n\nval settings = SecureFtpSettings(\"127.0.0.1\", 22, FtpCredentials(\"foo\", \"bar\"))\n\nval _: monix.Task[List[FtpResource]] = connect(settings).use {\n  _.ls(\"/\").compile.toList\n}\n```\n\n### exemple for zio\n\nYou will need to use add in build.sbt [zio-cats-interop](https://github.com/zio/interop-cats)\n\n```\nlibraryDependencies += \"dev.zio\" %% \"zio-interop-cats\" % \"\u003cversion\u003e\"\n```\n\n```scala\nimport fs2.ftp.FtpSettings._\nimport zio.interop.catz._\nimport zio.ZIO\n\nval settings = SecureFtpSettings(\"127.0.0.1\", 22, FtpCredentials(\"foo\", \"bar\"))\n\nZIO.runtime.map { implicit r: zio.Runtime[Any] =\u003e\n  implicit val CE: ConcurrentEffect[zio.Task] = implicitly\n  implicit val CS: ContextShift[zio.Task] = implicitly\n\n  val _: zio.Task[List[FtpResource]] = connect(settings).use {\n    _.ls(\"/\").compile.toList\n  }\n}\n```\n\n\n## How to release\n\n1. How to create a key to signed artifact\n\n```\n# generate key\n$ gpg --gen-key\n\n# list the keys\n$ gpg --list-keys\n\n/home/foo/.gnupg/pubring.gpg\n------------------------------\n\npub   rsa4096 2018-08-22 [SC]\n      1234517530FB96F147C6A146A326F592D39AAAAA\nuid           [ultimate] your name \u003cyou@example.com\u003e\nsub   rsa4096 2018-08-22 [E]\n\n$\u003eLONG_ID=1234517530FB96F147C6A146A326F592D39AAAAA \n\n#send key to server\n$\u003e gpg --keyserver hkp://keyserver.ubuntu.com --send-key $LONG_ID \u0026\u0026 \\\n gpg --keyserver hkp://pgp.mit.edu --send-key $LONG_ID \u0026\u0026 \\\n gpg --keyserver hkp://pool.sks-keyservers.net --send-key $LONG_ID \n\n\n\n\n```\n\n2. Github secrets\n\ndeclare in github / repo / settings / secrets (new repository secret)\n\n```\n#  PGP_SECRET in base64 (with no return carriage), dont put \"\" around the value !\ngpg --armor --export-secret-keys $LONG_ID | base64 -w0 | pbcopy\n\n# declare in github (settings) PGP_PASSPHRASE in plain text\nThe randomly generated password you used to create a fresh gpg key\n\n\n# declare in github (settings) SONATYPE_PASSWORD in plain text\nThe password you use to log into https://s01.oss.sonatype.org/ (or https://oss.sonatype.org/ if your Sonatype account was created before February 2021). \n***IMPORTANT*** Login s01.oss.sonatype.org and after profile, and select \"User token\"\n Alternatively, the password part of the user token if you generated one above.\n\n# declare in github (settings) SONATYPE_USERNAME in plain text \n***IMPORTANT*** Login s01.oss.sonatype.org, got to profile, and select \"User token\"\nAlternatively, the username part of the user token if you generated one above.\n```\n\n2. create a tag and push\n\nmore information here =\u003e https://github.com/olafurpg/sbt-ci-release\n\n## LICENSE\n\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use this project except in compliance with\nthe License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.\n\nUnless required by applicable law or agreed to in writing, software distributed under the License is distributed on an\n\"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific\nlanguage governing permissions and limitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fregis-leray%2Ffs2-ftp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fregis-leray%2Ffs2-ftp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fregis-leray%2Ffs2-ftp/lists"}