From daa338a8e00626e3f031caffde7b96e780c1d8ba Mon Sep 17 00:00:00 2001 From: Jonathan Tron Date: Sat, 30 Dec 2023 15:29:54 +0100 Subject: [PATCH 01/13] Generate a new insecure cert with a 2048bits key, as smaller key size fails in newer implementation --- insecure-test-cert.pem | 75 +++++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 27 deletions(-) diff --git a/insecure-test-cert.pem b/insecure-test-cert.pem index 5db7394..fab3ec2 100644 --- a/insecure-test-cert.pem +++ b/insecure-test-cert.pem @@ -1,29 +1,50 @@ -----BEGIN CERTIFICATE----- -MIICIzCCAYwCCQDPNA1ZOq8CbzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJV -UzEPMA0GA1UECAwGRGVuaWFsMRQwEgYDVQQHDAtTcHJpbmdmaWVsZDEMMAoGA1UE -CgwDRGlzMRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMTIwNjIyMTMyMTI1WhcNMjIw -NjIwMTMyMTI1WjBWMQswCQYDVQQGEwJVUzEPMA0GA1UECAwGRGVuaWFsMRQwEgYD -VQQHDAtTcHJpbmdmaWVsZDEMMAoGA1UECgwDRGlzMRIwEAYDVQQDDAlsb2NhbGhv -c3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKyacIYurNopaS1tHCE5VrUb -1tFveP5kWm6kyeE42dYFMcb0wSKofKDWPju+jEwxZ/SLBnF/IvDKqfFH8A7bzdTi -mdtiWZgqMjs1QxFWF3ohoHm0bB2l0zSWufefjSjstSJanazOW4seq3Zm9ut233Mm -7h2fKgmM8mzUIKqqLCFfAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAJdwBZm4BI+7y -Ul0TJtzdLuKo5lKJXX/l8v7hlvziR6Vbv0H7bdqJ+5N3DLDDHZ4DEbypP67lxf2i -cyKdbash/nJsMUVUr+MsvJ9VyRRiSyhzqCN/RgaN9nx4Z0fl5I8aQp2qcZi1t8R5 -ZLgk9oqiPOEca6i22DDBSg0cnhBH9Lk= +MIIDjTCCAnWgAwIBAgIUECO44Y4B6XglzVsHPBT80R0AjQowDQYJKoZIhvcNAQEL +BQAwVjELMAkGA1UEBhMCVVMxDzANBgNVBAgMBkRlbmlhbDEUMBIGA1UEBwwLU3By +aW5nZmllbGQxDDAKBgNVBAoMA0RpczESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIz +MTIyOTE5MjkzMFoXDTMzMTIyNjE5MjkzMFowVjELMAkGA1UEBhMCVVMxDzANBgNV +BAgMBkRlbmlhbDEUMBIGA1UEBwwLU3ByaW5nZmllbGQxDDAKBgNVBAoMA0RpczES +MBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAtsUdUMjshetMW7os9eOO4iadPlwxBncS14PLeSb3Lc6wLvU8CTaRA/l1OR76 +p5WDMnoplC+NQ3N+opN//KuFXV5zU9h/0wRy7WynxvVtdu91Zw3ac+1cz9TBhnVf +AFaiwZ7Hz5uWj58sM9zfRiqLO5CSGV5zO7qwk3JNG1e+Tb1gr29sbWKFcPG1bIAl +oPsP7XzQcPq4M2QCdwBtBHDbzuL3IfMualW6oc1VyLcGXmZQl5ooq2yQybQNzdeR +lcVR4QfqprPNpS602DI5DkcqFpY/sIWORdWK6MmjzipWU52HNCRgQQpyoF32/KtY +K94EtDrizLhj7jugmwX57+YIrQIDAQABo1MwUTAdBgNVHQ4EFgQUL7wU5Slj9ztk +RU4ZCoBhqSBbPCowHwYDVR0jBBgwFoAUL7wU5Slj9ztkRU4ZCoBhqSBbPCowDwYD +VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAGTpdr7KmIajGHdngtHWh +N4z40JFbNaivfi5vsm7cLzO+aVybclgQKaaKyOWl3Tp4HtiRp8p6lPFJiwKY/3Vw +V/e7Yr9AQVvuU05Dy76WnyW4oDdbyHIRP54q7xjRTrJMcLGrd3EyrAkEu+p+KGuD +Hy+i6DVFv7SWKsTTFOSGgrq69LoS/dBt3V71vzhTqEGXQGoTEzhT9lDlCe4GnpeL +WuSOu4FLtehYLhigxzzRGagM2jxw8DGarT3ocEWO4oRTXYGyECAawm4PGQnIRYqQ +ps0+6Z1jX/q1Gs011WAIAE56x/xS+aPmrRMpI9448DUiY0lAyD/aFYvujA7U1x4L +Zg== -----END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQCsmnCGLqzaKWktbRwhOVa1G9bRb3j+ZFpupMnhONnWBTHG9MEi -qHyg1j47voxMMWf0iwZxfyLwyqnxR/AO283U4pnbYlmYKjI7NUMRVhd6IaB5tGwd -pdM0lrn3n40o7LUiWp2szluLHqt2Zvbrdt9zJu4dnyoJjPJs1CCqqiwhXwIDAQAB -AoGAcyj/1qchsNVcVXCtCgXFskSGyWnEooa2R4gvIdPak48XrRT0H3mm3XDUSOxT -kyqLn396pxMabunpBRDoPCGvbDdphhcSKIJPRga0LJBnMVp87xeaw0JvNB1EsdzP -xbsXwSt39zjJeAE1IAOgMCHC/GRisvRnkZuKOM7XYe7UAGECQQDeawf/5Zgfcvgc -Bqxv6ZPCJxAh7FKyWDUqa8RTtD0qWuXOYnlVzaEkN8FfimrPdmQBx+eMacsqCrLG -v8hvubt5AkEAxqnzo+IU4bsUdezndEjYKOVH3qs9qO+8bneKCqD4h2k2Db2va8OG -sP44hRMvgkkRiZjHWAUeG+ytgWGU7CK1lwJAe1fvv8GbcxVW8nPg/M8T2f+/upBL -7AtusG/DGIhDw1FVT/bcQvEeA+/HlSw1v4dwPmyVxBCHUnFMY1vH0+20QQJBAI6s -4eCx7qNLM1+Z24RFCJEeUWZWfzsDqcWALnCBuNuvMPXfY8u2KdaVTUwtQjKEfYbf -ZVMOodgWO2mvBkAskVMCQE98evHiZkDEpVU89TbbClYpmGOSRjQTrXEaVePLb0Hr -GwylNdJEAClM4gK+GnXa4m57xs13eBwuXsM+77fdU2I= ------END RSA PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC2xR1QyOyF60xb +uiz1447iJp0+XDEGdxLXg8t5JvctzrAu9TwJNpED+XU5HvqnlYMyeimUL41Dc36i +k3/8q4VdXnNT2H/TBHLtbKfG9W1273VnDdpz7VzP1MGGdV8AVqLBnsfPm5aPnywz +3N9GKos7kJIZXnM7urCTck0bV75NvWCvb2xtYoVw8bVsgCWg+w/tfNBw+rgzZAJ3 +AG0EcNvO4vch8y5qVbqhzVXItwZeZlCXmiirbJDJtA3N15GVxVHhB+qms82lLrTY +MjkORyoWlj+whY5F1YroyaPOKlZTnYc0JGBBCnKgXfb8q1gr3gS0OuLMuGPuO6Cb +Bfnv5gitAgMBAAECggEABkWH/qS3L9aimxb6iHrlK5/EfD/4tn6H0O/jkuLYqNB9 +Gk6aRdZ19InO/f8Kl41DAEyRvshz8G+j4otgeq8RdDvNUsz5mk5xub5yMmeFElRf +6U5svT1U1qF345FSL9/vlU78wpDvW9QyYnQ1KcJd3tUhTxZyRCD6z3bX+QGr7moF +YV0/TdARG4SXKc02sEA7/712aMD5ruTSAikxkC3JD96XYPP09DPgOapwIFYgnzxF +LX8c96N8osEJZnJxwWazBPqP6NJCKL3l81dtuYeBw/9caGgy8bwD+aZhcqcW/yN2 +41yjIKOsdnU1AIOM1sRgCeTTwQWDvGAFZUo+edF7eQKBgQDhKcPOm0gU2gYAYUVY +DwssXRYKDZIgPt+Bvmw/9bond1wuQZPOhPvap6UkmZlblybDshyFpwtT/c5X6G0d +yGL0ZAwG7XpSxx+2JkAAkEok0Zvqpeulg1aup6N0CsmA1Wk48EwVIsGWB3uxJZdJ +FZRgDolNSPxoba0WtEXNCAVkeQKBgQDPzQrZfgzVh5ThhrLlN8PXEVqA5qbdAvUQ +RTHHdkavav34m8hHgttX0xqkDw8rTDK5qo2hEIrwQojao3ilvKfO99UFh2zJvRdB +K7gIFR57taZQoNL1PPEsYEy52pLgVpxk8Cq5J6Fi0U3umvMwQE8BEYjNdCdbe/Cg +9pkK4Pjw1QKBgQCyvY3T4E7bRqwG9zCuE9shz49kUZuTf3W8MCcMqwuossb5bVNh +WQ35aKXfJROpspayOR0NOCr09QEtpbOhNebf7N/jS/eT6MCSv1CFYgWJrt+f6TDk +hht0sF1ADCQj4sYRzigHizyz1aLqYFX1TW0ox8FVGcBNQetqn5bdiSWGuQKBgCT4 +ihGgB5CGCssFOBboEQPWpo+AefegaxF1/iFKvdC/7Geq77spYPUDLh46P6yoZe36 +ljAtzUppzAd6RiDWq9R663+MVKKf7d8+dAOcHkxMSUbXFjFjolUO3RfD95XKUxDy +WeePUXtPWdo130aaanP6Nqi3Hbl9F5bLyPbSh/fxAoGBANBxFwB1T1mBi7xRTxeV +kYp3aRq8TW/NbHVLoOzOVQ5aQCSsP1oHvtVcwzFqefB0lOI373saNseWdldjHKM3 +KMAtwCrSjULdfuYIRJNfk1WUYnA9aVVx2HXjXlFy6aX336R1/KoP045jK9LEu8bG +Stg6MZ1uwtsXNUgcY8ifRKdL +-----END PRIVATE KEY----- From 5900631712d54515a71c960c4c6b9aee4c1aabdb Mon Sep 17 00:00:00 2001 From: Jonathan Tron Date: Sat, 30 Dec 2023 15:30:23 +0100 Subject: [PATCH 02/13] Update README to add indication on how to run tests on MacOS --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 05fc2e3..0a8135e 100644 --- a/README.md +++ b/README.md @@ -278,7 +278,7 @@ use for TLS does not work in Ruby 2.4. Ftpd runs on: * Linux -* OSX +* MacOS ## Windows @@ -302,6 +302,12 @@ major version. ### Tests +On MacOS, you need to add a loopback alias for 127.0.0.2 (used in specs): + +```bash +sudo ifconfig lo0 alias 127.0.0.2 up +``` + To run the cucumber (functional) tests: $ rake test:features From 38afc3c0e8dc21e63af654254bb0e40838660322 Mon Sep 17 00:00:00 2001 From: Jonathan Tron Date: Sat, 30 Dec 2023 16:34:05 +0100 Subject: [PATCH 03/13] Switch from TravisCI to Github action for CI --- .github/workflows/ci.yml | 29 +++++++++++++++++++++++++++++ .travis.yml | 12 ------------ 2 files changed, 29 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..e1040d4 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,29 @@ +name: CI + +on: + push: + branches: [ master ] + pull_request: + branches: ['**'] + +jobs: + tests: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + ruby: + - "2.7" + - "3.0" + - "3.1" + - "3.2" + - "3.3" + name: Ruby ${{ matrix.ruby }} + steps: + - uses: actions/checkout@v3 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + - name: Run all tests + run: bundle exec rake test diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 9439b92..0000000 --- a/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -language: ruby -rvm: -- 1.9.3 -- 2.0 -- 2.1 -- 2.2 -- 2.3 -- 2.4 -sudo: false -script: bundle exec rake test -dist: precise -install: "bundle install --jobs=3 --retry=3" From a78fd8b3b422fa15c4c747ef2110d85d3e8b751d Mon Sep 17 00:00:00 2001 From: Jonathan Tron Date: Sat, 30 Dec 2023 16:43:44 +0100 Subject: [PATCH 04/13] Update dependencies, drop "double-bag-ftps" in favor of "net-ftp", and update minimum ruby version supported to >= 2.7 --- Gemfile.lock | 103 ++++++++++++++++----------- README.md | 17 +++-- cucumber.yml | 1 + features/ftp_server/features.feature | 2 + features/ftp_server/timeout.feature | 6 +- features/step_definitions/connect.rb | 5 +- features/support/test_client.rb | 29 +++----- ftpd.gemspec | 16 ++--- rake_tasks/cucumber.rake | 2 +- spec/protocols_spec.rb | 21 ++++-- 10 files changed, 113 insertions(+), 89 deletions(-) create mode 100644 cucumber.yml diff --git a/Gemfile.lock b/Gemfile.lock index 1f35893..4ed74d4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -7,58 +7,81 @@ PATH GEM remote: https://rubygems.org/ specs: - builder (3.2.3) - cucumber (2.4.0) - builder (>= 2.1.2) - cucumber-core (~> 1.5.0) - cucumber-wire (~> 0.0.1) - diff-lcs (>= 1.1.3) - gherkin (~> 4.0) - multi_json (>= 1.7.5, < 2.0) - multi_test (>= 0.1.2) - cucumber-core (1.5.0) - gherkin (~> 4.0) - cucumber-wire (0.0.1) - diff-lcs (1.3) - double-bag-ftps (0.1.4) - gherkin (4.1.3) + builder (3.2.4) + cucumber (9.1.0) + builder (~> 3.2, >= 3.2.4) + cucumber-ci-environment (~> 9.2, >= 9.2.0) + cucumber-core (~> 12.0) + cucumber-cucumber-expressions (~> 17.0) + cucumber-gherkin (>= 24, < 27) + cucumber-html-formatter (~> 20.4, >= 20.4.0) + cucumber-messages (>= 19, < 23) + diff-lcs (~> 1.5, >= 1.5.0) + mini_mime (~> 1.1, >= 1.1.5) + multi_test (~> 1.1, >= 1.1.0) + sys-uname (~> 1.2, >= 1.2.3) + cucumber-ci-environment (9.2.0) + cucumber-core (12.0.0) + cucumber-gherkin (>= 25, < 27) + cucumber-messages (>= 20, < 23) + cucumber-tag-expressions (~> 5.0, >= 5.0.4) + cucumber-cucumber-expressions (17.0.1) + cucumber-gherkin (26.2.0) + cucumber-messages (>= 19.1.4, < 22.1) + cucumber-html-formatter (20.4.0) + cucumber-messages (>= 18.0, < 22.1) + cucumber-messages (22.0.0) + cucumber-tag-expressions (5.0.6) + date (3.3.4) + diff-lcs (1.5.0) + ffi (1.16.3) memoizer (1.0.3) - multi_json (1.12.1) - multi_test (0.1.2) - rake (11.3.0) - redcarpet (3.4.0) - rspec (3.6.0) - rspec-core (~> 3.6.0) - rspec-expectations (~> 3.6.0) - rspec-mocks (~> 3.6.0) - rspec-core (3.6.0) - rspec-support (~> 3.6.0) - rspec-expectations (3.6.0) + mini_mime (1.1.5) + multi_test (1.1.0) + net-ftp (0.3.3) + net-protocol + time + net-protocol (0.2.2) + timeout + rake (13.1.0) + redcarpet (3.6.0) + rspec (3.12.0) + rspec-core (~> 3.12.0) + rspec-expectations (~> 3.12.0) + rspec-mocks (~> 3.12.0) + rspec-core (3.12.2) + rspec-support (~> 3.12.0) + rspec-expectations (3.12.3) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.6.0) - rspec-its (1.2.0) + rspec-support (~> 3.12.0) + rspec-its (1.3.0) rspec-core (>= 3.0.0) rspec-expectations (>= 3.0.0) - rspec-mocks (3.6.0) + rspec-mocks (3.12.6) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.6.0) - rspec-support (3.6.0) - timecop (0.9.1) - yard (0.8.7.6) + rspec-support (~> 3.12.0) + rspec-support (3.12.1) + sys-uname (1.2.3) + ffi (~> 1.1) + time (0.3.0) + date + timecop (0.9.8) + timeout (0.4.1) + yard (0.9.34) PLATFORMS ruby DEPENDENCIES - cucumber (~> 2.0) - double-bag-ftps (~> 0.1, >= 0.1.4) + cucumber (~> 9.1) ftpd! - rake (~> 11.1) - redcarpet (~> 3.1) + net-ftp (~> 0.3) + rake (~> 13.1) + redcarpet (~> 3.6) rspec (~> 3.1) rspec-its (~> 1.0) - timecop (~> 0.7) - yard (~> 0.8.7) + timecop (~> 0.9) + yard (~> 0.9) BUNDLED WITH - 1.15.3 + 2.5.3 diff --git a/README.md b/README.md index 0a8135e..2ff20f5 100644 --- a/README.md +++ b/README.md @@ -256,20 +256,19 @@ See [RFC Compliance](doc/rfc-compliance.md) for details The tests pass with these Rubies: -* ruby-1.9.3 -* ruby-2.0 -* ruby-2.1 -* ruby-2.2 -* ruby-2.3 -* ruby-2.4 (but see below) +* ruby-2.7 (EOL: 2023-03-31) +* ruby-3.0 (EOL: 2024-03-31) +* ruby-3.1 +* ruby-3.2 +* ruby-3.3 For Ruby 1.8, use an ftpd version before 0.8. In your Gemfile: gem 'ftpd', '<0.8' -This gem runs fine in Ruby 2.4, but the tests that use TLS are skipped -in Ruby 2.4. That is because the double_bag_ftps gem that the tests -use for TLS does not work in Ruby 2.4. +For Ruby 2.6, use ftpd version 2.1.0. In your Gemfile: + + gem 'ftpd', '2.1.0' ## OS compatability diff --git a/cucumber.yml b/cucumber.yml new file mode 100644 index 0000000..fea5edc --- /dev/null +++ b/cucumber.yml @@ -0,0 +1 @@ +default: --publish-quiet diff --git a/features/ftp_server/features.feature b/features/ftp_server/features.feature index 1cbe678..d7598f9 100644 --- a/features/ftp_server/features.feature +++ b/features/ftp_server/features.feature @@ -27,12 +27,14 @@ Feature: Features Scenario: IPV6 Extensions Given the test server is started + And the client connects When the client successfully requests features Then the response should include feature "EPRT" And the response should include feature "EPSV" Scenario: RFC 3659 Extensions Given the test server is started + And the client connects When the client successfully requests features Then the response should include feature "SIZE" Then the response should include feature "MDTM" diff --git a/features/ftp_server/timeout.feature b/features/ftp_server/timeout.feature index ec6b18a..f7c8456 100644 --- a/features/ftp_server/timeout.feature +++ b/features/ftp_server/timeout.feature @@ -5,14 +5,14 @@ Feature: Port So that I can claim RFC compliance Scenario: Session idle too long - Given the test server has session timeout set to 0.5 seconds + Given the test server has session timeout set to 1 seconds And the test server is started And a successful login - When the client is idle for 0.6 seconds + When the client is idle for 1.1 seconds Then the client should not be connected Scenario: Session not idle too long - Given the test server has session timeout set to 0.5 seconds + Given the test server has session timeout set to 1 seconds And the test server is started And a successful login When the client is idle for 0 seconds diff --git a/features/step_definitions/connect.rb b/features/step_definitions/connect.rb index b90a326..83eb744 100644 --- a/features/step_definitions/connect.rb +++ b/features/step_definitions/connect.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true -require 'double_bag_ftps' require 'net/ftp' When /^the( \w+)? client connects(?: with (\w+) TLS)?$/ do @@ -17,9 +16,9 @@ end When /^the (\d+)rd client tries to connect$/ do |client_name| - client(client_name).start + client(client_name.to_s).start capture_error do - client(client_name).connect(server.host, server.port) + client(client_name.to_s).connect(server.host, server.port) end end diff --git a/features/support/test_client.rb b/features/support/test_client.rb index 81656e5..0a48f7b 100644 --- a/features/support/test_client.rb +++ b/features/support/test_client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true -require 'double_bag_ftps' require 'net/ftp' class TestClient @@ -135,8 +134,8 @@ def connected? ftp.noop true rescue Net::FTPTempError => e - !!e.to_s =~ /^421/ - rescue EOFError + e.message !~ /^421/ + rescue EOFError, Net::FTPConnectionError false end end @@ -146,7 +145,7 @@ def set_option(option) end private - + RAW_METHOD_REGEX = /^send_(.*)$/ def ftp @@ -180,28 +179,20 @@ def make_ftp def make_tls_ftp(ftps_mode) ensure_can_test_tls - ftp = DoubleBagFTPS.new - context_opts = { - :verify_mode => OpenSSL::SSL::VERIFY_NONE + opts = { + :ssl => { + :verify_mode => OpenSSL::SSL::VERIFY_NONE, + }, + :implicit_ftps => ftps_mode==:implicit } - ftp.ssl_context = DoubleBagFTPS.create_ssl_context(context_opts) - ftp.ftps_mode = ftps_mode - ftp + Net::FTP.new nil, opts end def ensure_can_test_tls - return if can_test_tls? + return if defined?(OpenSSL::SSL) raise CannotTestTls, "Cannot test TLS with this Ruby version" end - def can_test_tls? - !double_bag_ftps_busted? - end - - def double_bag_ftps_busted? - Gem::Dependency.new('', '~> 2.4.0').match?('', RUBY_VERSION) - end - def make_non_tls_ftp Net::FTP.new end diff --git a/ftpd.gemspec b/ftpd.gemspec index 3e700f3..91fdb23 100644 --- a/ftpd.gemspec +++ b/ftpd.gemspec @@ -21,7 +21,7 @@ class Readme README_PATH = File.expand_path("README.md", File.dirname(__FILE__)) private_constant :README_PATH - + def remove_markdown_link(description) regex = %r{ \[ @@ -76,16 +76,16 @@ Gem::Specification.new do |s| s.files += Dir["lib/**/*.rb"] s.homepage = "http://github.com/wconrad/ftpd" s.licenses = ["MIT"] - s.required_ruby_version = ">= 1.9.3" + s.required_ruby_version = ">= 2.7.8" s.rubygems_version = "2.5.1" s.summary = "Pure Ruby FTP server library" s.add_runtime_dependency("memoizer", "~> 1.0") - s.add_development_dependency("cucumber", "~> 2.0") - s.add_development_dependency("double-bag-ftps", "~> 0.1", ">= 0.1.4") - s.add_development_dependency("rake", "~> 11.1") - s.add_development_dependency("redcarpet", "~> 3.1") + s.add_development_dependency("net-ftp", "~> 0.3") + s.add_development_dependency("cucumber", "~> 9.1") + s.add_development_dependency("rake", "~> 13.1") + s.add_development_dependency("redcarpet", "~> 3.6") s.add_development_dependency("rspec", "~> 3.1") s.add_development_dependency("rspec-its", "~> 1.0") - s.add_development_dependency("timecop", "~> 0.7") - s.add_development_dependency("yard", "~> 0.8.7") + s.add_development_dependency("timecop", "~> 0.9") + s.add_development_dependency("yard", "~> 0.9") end diff --git a/rake_tasks/cucumber.rake b/rake_tasks/cucumber.rake index a5ea191..ee7eb06 100644 --- a/rake_tasks/cucumber.rake +++ b/rake_tasks/cucumber.rake @@ -2,7 +2,7 @@ require 'cucumber/rake/task' Cucumber::Rake::Task.new 'test:features' do |t| t.fork = true - t.cucumber_opts = '--format progress' + t.cucumber_opts = ['--format progress'] end task 'test:cucumber' => ['test:features'] diff --git a/spec/protocols_spec.rb b/spec/protocols_spec.rb index d4c1c31..517843f 100644 --- a/spec/protocols_spec.rb +++ b/spec/protocols_spec.rb @@ -41,10 +41,19 @@ def initialize(bind_address, connect_address) Thread.new do queue.enq @listening_socket.accept end + _client_socket = TCPSocket.new(connect_address, port) @connected_socket = queue.deq end + def ipv6_dual_stack? + @connected_socket.local_address.ipv6? && + !@connected_socket.getsockopt( + Socket::IPPROTO_IPV6, + Socket::IPV6_V6ONLY + ).bool + end + end context 'IPV4 server' do @@ -77,13 +86,12 @@ def initialize(bind_address, connect_address) let(:bind_address) {'::1'} let(:connect_address) {'::1'} - let(:connected_socket) do - TestServer.new(bind_address, connect_address).connected_socket - end + let(:test_server) {TestServer.new(bind_address, connect_address)} + let(:connected_socket) {test_server.connected_socket} subject(:protocols) {Protocols.new(connected_socket)} it 'should not support IPV4' do - expect(protocols.supports_protocol?(Protocols::IPV4)).to be_falsey + expect(protocols.supports_protocol?(Protocols::IPV4)).to be(test_server.ipv6_dual_stack?) end it 'should support IPV6' do @@ -92,8 +100,9 @@ def initialize(bind_address, connect_address) it 'should list the supported protocols' do expect(protocols.protocol_codes).to eq [ - Protocols::IPV6, - ] + (Protocols::IPV4 if test_server.ipv6_dual_stack?), + Protocols::IPV6 + ].compact end end From 8c98d16f56bb427830d49c9cdde08fec53de171d Mon Sep 17 00:00:00 2001 From: Jonathan Tron Date: Sat, 30 Dec 2023 16:45:09 +0100 Subject: [PATCH 05/13] require "stringio" where used --- lib/ftpd/cmd_list.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ftpd/cmd_list.rb b/lib/ftpd/cmd_list.rb index 7fa4b85..1394912 100644 --- a/lib/ftpd/cmd_list.rb +++ b/lib/ftpd/cmd_list.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require_relative 'command_handler' +require 'stringio' module Ftpd From 26bcbd714c309d8ae37bf6ecb6e8d08ab90a94de Mon Sep 17 00:00:00 2001 From: Jonathan Tron Date: Sat, 30 Dec 2023 16:47:04 +0100 Subject: [PATCH 06/13] Fix explicit TLS issues in Ruby >= 3.1 In older rubies, using an `SSLSocket` before a session was started worked as a normal (plain text) `Socket` (displaying a warning). After ruby 3.1 it raised an error, the workaround is to use the underlying `Socket` (via `to_io`) until an SSL session is started. --- lib/ftpd/command_loop.rb | 3 ++- lib/ftpd/tls_server.rb | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/ftpd/command_loop.rb b/lib/ftpd/command_loop.rb index 5802b7f..4ea66c5 100644 --- a/lib/ftpd/command_loop.rb +++ b/lib/ftpd/command_loop.rb @@ -57,8 +57,9 @@ def get_command config.log.debug s.sub(/^PASS .*/, 'PASS **FILTERED**') # Filter real password s end - + def gets_with_timeout(socket) + socket = socket.to_io if @session.tls_enabled? && !socket.encrypted? ready = IO.select([socket], nil, nil, config.session_timeout) timeout if ready.nil? ready[0].first.gets diff --git a/lib/ftpd/tls_server.rb b/lib/ftpd/tls_server.rb index a2f18d4..3cf17ac 100644 --- a/lib/ftpd/tls_server.rb +++ b/lib/ftpd/tls_server.rb @@ -99,6 +99,22 @@ def encrypt accept end + def readline + if session + super + else + to_io.readline + end + end + + def write(data) + if session + super(data) + else + to_io.write(data) + end + end + end end From c8afadfa816bdf9ee798f6b923e4a18e0094bac5 Mon Sep 17 00:00:00 2001 From: Wayne Conrad Date: Sun, 31 Dec 2023 18:41:14 -0700 Subject: [PATCH 07/13] Add Jonathan Tron to list of contributors --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2ff20f5..397f679 100644 --- a/README.md +++ b/README.md @@ -376,6 +376,7 @@ Among those who have improved ftpd are: * Michael de Silva * Mike Ragalie * cransom +* Jonathan Tron If I've forgotten to add you, please remind me, or submit a merge request. From 38588308784d5b32881c4a9da331a59c481f7c11 Mon Sep 17 00:00:00 2001 From: Wayne Conrad Date: Sun, 31 Dec 2023 17:57:33 -0700 Subject: [PATCH 08/13] Set up github actions for running the tests on every push --- .github/workflows/ruby.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/ruby.yml diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml new file mode 100644 index 0000000..a4b7339 --- /dev/null +++ b/.github/workflows/ruby.yml @@ -0,0 +1,26 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. +# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake +# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby + +name: Ruby +on: [push] +permissions: + contents: read +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + ruby-version: [ '2.7', '3.0', '3.1', '3.2', '3.3' ] + steps: + - uses: actions/checkout@v3 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby-version }} + bundler-cache: true # runs 'bundle install' and caches installed gems automatically + - name: Run tests + run: bundle exec rake From be1452c24dbcf72d8586dad352a471d34f17e081 Mon Sep 17 00:00:00 2001 From: Jonathan Tron Date: Wed, 7 Feb 2024 08:25:51 +0100 Subject: [PATCH 09/13] Fix features for TLS on linux --- features/support/test_client.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/features/support/test_client.rb b/features/support/test_client.rb index 0a48f7b..7e807f7 100644 --- a/features/support/test_client.rb +++ b/features/support/test_client.rb @@ -2,6 +2,14 @@ require 'net/ftp' +if defined? Net::FTP::BufferedSSLSocket + class Net::FTP::BufferedSSLSocket + def shutdown(*args) + @io.__send__(:stop) + end + end +end + class TestClient CannotTestTls = Class.new(StandardError) From 84401d3370968ded1b7f8f2f471d4cfc4904790d Mon Sep 17 00:00:00 2001 From: Jonathan Tron Date: Wed, 7 Feb 2024 08:29:26 +0100 Subject: [PATCH 10/13] Drop Gemfile.lock --- Gemfile.lock | 87 ---------------------------------------------------- 1 file changed, 87 deletions(-) delete mode 100644 Gemfile.lock diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index 4ed74d4..0000000 --- a/Gemfile.lock +++ /dev/null @@ -1,87 +0,0 @@ -PATH - remote: . - specs: - ftpd (2.1.0) - memoizer (~> 1.0) - -GEM - remote: https://rubygems.org/ - specs: - builder (3.2.4) - cucumber (9.1.0) - builder (~> 3.2, >= 3.2.4) - cucumber-ci-environment (~> 9.2, >= 9.2.0) - cucumber-core (~> 12.0) - cucumber-cucumber-expressions (~> 17.0) - cucumber-gherkin (>= 24, < 27) - cucumber-html-formatter (~> 20.4, >= 20.4.0) - cucumber-messages (>= 19, < 23) - diff-lcs (~> 1.5, >= 1.5.0) - mini_mime (~> 1.1, >= 1.1.5) - multi_test (~> 1.1, >= 1.1.0) - sys-uname (~> 1.2, >= 1.2.3) - cucumber-ci-environment (9.2.0) - cucumber-core (12.0.0) - cucumber-gherkin (>= 25, < 27) - cucumber-messages (>= 20, < 23) - cucumber-tag-expressions (~> 5.0, >= 5.0.4) - cucumber-cucumber-expressions (17.0.1) - cucumber-gherkin (26.2.0) - cucumber-messages (>= 19.1.4, < 22.1) - cucumber-html-formatter (20.4.0) - cucumber-messages (>= 18.0, < 22.1) - cucumber-messages (22.0.0) - cucumber-tag-expressions (5.0.6) - date (3.3.4) - diff-lcs (1.5.0) - ffi (1.16.3) - memoizer (1.0.3) - mini_mime (1.1.5) - multi_test (1.1.0) - net-ftp (0.3.3) - net-protocol - time - net-protocol (0.2.2) - timeout - rake (13.1.0) - redcarpet (3.6.0) - rspec (3.12.0) - rspec-core (~> 3.12.0) - rspec-expectations (~> 3.12.0) - rspec-mocks (~> 3.12.0) - rspec-core (3.12.2) - rspec-support (~> 3.12.0) - rspec-expectations (3.12.3) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.12.0) - rspec-its (1.3.0) - rspec-core (>= 3.0.0) - rspec-expectations (>= 3.0.0) - rspec-mocks (3.12.6) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.12.0) - rspec-support (3.12.1) - sys-uname (1.2.3) - ffi (~> 1.1) - time (0.3.0) - date - timecop (0.9.8) - timeout (0.4.1) - yard (0.9.34) - -PLATFORMS - ruby - -DEPENDENCIES - cucumber (~> 9.1) - ftpd! - net-ftp (~> 0.3) - rake (~> 13.1) - redcarpet (~> 3.6) - rspec (~> 3.1) - rspec-its (~> 1.0) - timecop (~> 0.9) - yard (~> 0.9) - -BUNDLED WITH - 2.5.3 From 263325a44624356237d7d84c774b01a2fb14c4b1 Mon Sep 17 00:00:00 2001 From: Jonathan Tron Date: Wed, 7 Feb 2024 08:35:29 +0100 Subject: [PATCH 11/13] Remove CI github workflow --- .github/workflows/ci.yml | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index e1040d4..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: CI - -on: - push: - branches: [ master ] - pull_request: - branches: ['**'] - -jobs: - tests: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - ruby: - - "2.7" - - "3.0" - - "3.1" - - "3.2" - - "3.3" - name: Ruby ${{ matrix.ruby }} - steps: - - uses: actions/checkout@v3 - - uses: ruby/setup-ruby@v1 - with: - ruby-version: ${{ matrix.ruby }} - bundler-cache: true - - name: Run all tests - run: bundle exec rake test From 79b7026a913bc9f1a2b8884c5669d9a173728424 Mon Sep 17 00:00:00 2001 From: Jonathan Tron Date: Thu, 13 Feb 2025 11:51:08 +0100 Subject: [PATCH 12/13] Fix TLS issue with net-ftp only in versions needing it (ie: `<= 0.3.8`) --- .github/workflows/ruby.yml | 2 +- features/support/test_client.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index a4b7339..7a7c481 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby-version: [ '2.7', '3.0', '3.1', '3.2', '3.3' ] + ruby-version: [ '2.7', '3.0', '3.1', '3.2', '3.3', '3.4' ] steps: - uses: actions/checkout@v3 - name: Set up Ruby diff --git a/features/support/test_client.rb b/features/support/test_client.rb index 7e807f7..549efc0 100644 --- a/features/support/test_client.rb +++ b/features/support/test_client.rb @@ -2,7 +2,7 @@ require 'net/ftp' -if defined? Net::FTP::BufferedSSLSocket +if Gem::Version.new(Net::FTP::VERSION) <= Gem::Version.new("0.3.8") && defined? Net::FTP::BufferedSSLSocket class Net::FTP::BufferedSSLSocket def shutdown(*args) @io.__send__(:stop) From ddb7d9e3ee4c85a079cbd70cfa7f5cce350035cd Mon Sep 17 00:00:00 2001 From: Jonathan Tron Date: Thu, 13 Feb 2025 12:09:44 +0100 Subject: [PATCH 13/13] Update README with supported ruby versions --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ef84b8d..1797686 100644 --- a/README.md +++ b/README.md @@ -258,9 +258,10 @@ The tests pass with these Rubies: * ruby-2.7 (EOL: 2023-03-31) * ruby-3.0 (EOL: 2024-03-31) -* ruby-3.1 +* ruby-3.1 (EOL: 2025-03-31) * ruby-3.2 * ruby-3.3 +* ruby-3.4 For Ruby 1.8, use an ftpd version before 0.8. In your Gemfile: