From b2020af8da057deab74241bed11e9da0a2132687 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Wed, 8 Feb 2023 22:23:21 +1300 Subject: [PATCH 1/4] Modernize gem. --- .github/workflows/coverage.yaml | 57 +++++++++++ .github/workflows/documentation.yaml | 61 ++++++++++++ .github/workflows/documentation.yml | 32 ------- .github/workflows/test-external.yaml | 37 ++++++++ .../workflows/{development.yml => test.yaml} | 18 ++-- .gitignore | 14 +-- .mailmap | 1 + README.md | 52 ---------- bake/localhost.rb | 6 +- gems.rb | 3 + guides/example-server/https.rb | 5 + lib/localhost.rb | 23 +---- lib/localhost/authority.rb | 27 ++---- lib/localhost/version.rb | 23 +---- license.md | 28 ++++++ localhost.gemspec | 8 +- readme.md | 30 ++++++ release.cert | 51 +++++----- spec/localhost/authority_spec.rb | 83 ---------------- spec/localhost/protocol_spec.rb | 95 ------------------- spec/localhost_spec.rb | 27 ------ spec/spec_helper.rb | 20 ---- ssl/localhost.crt | 21 ++++ ssl/localhost.key | 27 ++++++ ssl/localhost.lock | 0 test/localhost.rb | 12 +++ test/localhost/authority.rb | 84 ++++++++++++++++ test/localhost/protocol.rb | 87 +++++++++++++++++ 28 files changed, 519 insertions(+), 413 deletions(-) create mode 100644 .github/workflows/coverage.yaml create mode 100644 .github/workflows/documentation.yaml delete mode 100644 .github/workflows/documentation.yml create mode 100644 .github/workflows/test-external.yaml rename .github/workflows/{development.yml => test.yaml} (79%) create mode 100644 .mailmap delete mode 100644 README.md create mode 100644 license.md create mode 100644 readme.md delete mode 100644 spec/localhost/authority_spec.rb delete mode 100644 spec/localhost/protocol_spec.rb delete mode 100644 spec/localhost_spec.rb delete mode 100644 spec/spec_helper.rb create mode 100644 ssl/localhost.crt create mode 100644 ssl/localhost.key create mode 100644 ssl/localhost.lock create mode 100644 test/localhost.rb create mode 100644 test/localhost/authority.rb create mode 100644 test/localhost/protocol.rb diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml new file mode 100644 index 0000000..81f3c65 --- /dev/null +++ b/.github/workflows/coverage.yaml @@ -0,0 +1,57 @@ +name: Coverage + +on: [push, pull_request] + +permissions: + contents: read + +env: + CONSOLE_OUTPUT: XTerm + COVERAGE: PartialSummary + +jobs: + test: + name: ${{matrix.ruby}} on ${{matrix.os}} + runs-on: ${{matrix.os}}-latest + + strategy: + matrix: + os: + - ubuntu + - macos + + ruby: + - "3.2" + + steps: + - uses: actions/checkout@v3 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{matrix.ruby}} + bundler-cache: true + + - name: Run tests + timeout-minutes: 5 + run: bundle exec bake test + + - uses: actions/upload-artifact@v2 + with: + name: coverage-${{matrix.os}}-${{matrix.ruby}} + path: .covered.db + + validate: + needs: test + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.2" + bundler-cache: true + + - uses: actions/download-artifact@v3 + + - name: Validate coverage + timeout-minutes: 5 + run: bundle exec bake covered:validate --paths */.covered.db \; diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml new file mode 100644 index 0000000..3d483fc --- /dev/null +++ b/.github/workflows/documentation.yaml @@ -0,0 +1,61 @@ +name: Documentation + +on: + push: + branches: + - main + + # Allows you to run this workflow manually from the Actions tab: + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages: +permissions: + contents: read + pages: write + id-token: write + +# Allow one concurrent deployment: +concurrency: + group: "pages" + cancel-in-progress: true + +env: + CONSOLE_OUTPUT: XTerm + BUNDLE_WITH: maintenance + +jobs: + generate: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.2" + bundler-cache: true + + - name: Installing packages + run: sudo apt-get install wget + + - name: Generate documentation + timeout-minutes: 5 + run: bundle exec bake utopia:project:static --force no + + - name: Upload documentation artifact + uses: actions/upload-pages-artifact@v1 + with: + path: docs + + deploy: + runs-on: ubuntu-latest + + environment: + name: github-pages + url: ${{steps.deployment.outputs.page_url}} + + needs: generate + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v1 diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml deleted file mode 100644 index 0b6e329..0000000 --- a/.github/workflows/documentation.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Documentation - -on: - push: - branches: - - main - -jobs: - deploy: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - uses: ruby/setup-ruby@v1 - env: - BUNDLE_WITH: maintenance - with: - ruby-version: 2.7 - bundler-cache: true - - - name: Installing packages - run: sudo apt-get install wget - - - name: Generate documentation - timeout-minutes: 5 - run: bundle exec bake utopia:project:static - - - name: Deploy documentation - uses: JamesIves/github-pages-deploy-action@4.0.0 - with: - branch: docs - folder: docs diff --git a/.github/workflows/test-external.yaml b/.github/workflows/test-external.yaml new file mode 100644 index 0000000..214149c --- /dev/null +++ b/.github/workflows/test-external.yaml @@ -0,0 +1,37 @@ +name: Test External + +on: [push, pull_request] + +permissions: + contents: read + +env: + CONSOLE_OUTPUT: XTerm + +jobs: + test: + name: ${{matrix.ruby}} on ${{matrix.os}} + runs-on: ${{matrix.os}}-latest + + strategy: + matrix: + os: + - ubuntu + - macos + + ruby: + - "2.7" + - "3.0" + - "3.1" + - "3.2" + + steps: + - uses: actions/checkout@v3 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{matrix.ruby}} + bundler-cache: true + + - name: Run tests + timeout-minutes: 10 + run: bundle exec bake test:external diff --git a/.github/workflows/development.yml b/.github/workflows/test.yaml similarity index 79% rename from .github/workflows/development.yml rename to .github/workflows/test.yaml index 0b1a9ba..5c765b6 100644 --- a/.github/workflows/development.yml +++ b/.github/workflows/test.yaml @@ -1,7 +1,13 @@ -name: Development +name: Test on: [push, pull_request] +permissions: + contents: read + +env: + CONSOLE_OUTPUT: XTerm + jobs: test: name: ${{matrix.ruby}} on ${{matrix.os}} @@ -15,12 +21,12 @@ jobs: - macos ruby: - - "2.6" - "2.7" - "3.0" + - "3.1" + - "3.2" experimental: [false] - env: [""] include: - os: ubuntu @@ -34,12 +40,12 @@ jobs: experimental: true steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 with: ruby-version: ${{matrix.ruby}} bundler-cache: true - name: Run tests - timeout-minutes: 5 - run: ${{matrix.env}} bundle exec rspec + timeout-minutes: 10 + run: bundle exec bake test diff --git a/.gitignore b/.gitignore index a4d1f2c..09a72e0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,5 @@ /.bundle/ -/.yardoc -/_yardoc/ -/coverage/ -/doc/ /pkg/ -/spec/reports/ -/tmp/ - -# rspec failure tracking -.rspec_status - -/ssl/ - /gems.locked +/.covered.db +/external diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..90d5239 --- /dev/null +++ b/.mailmap @@ -0,0 +1 @@ +Juri Hahn diff --git a/README.md b/README.md deleted file mode 100644 index 5cec0c7..0000000 --- a/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# Localhost - -This gem provides a convenient API for generating per-user self-signed root certificates. - -[![Development Status](https://github.com/socketry/localhost/workflows/Development/badge.svg)](https://github.com/socketry/localhost/actions?workflow=Development) - -## Motivation - -HTTP/2 requires SSL in web browsers. If you want to use HTTP/2 for development (and you should), you need to start using URLs like `https://localhost:8080`. In most cases, this requires adding a self-signed certificate to your certificate store (e.g. Keychain on macOS), and storing the private key for the web-server to use. - -I wanted to provide a server-agnostic way of doing this, primarily because I think it makes sense to minimise the amount of junky self-signed keys you add to your certificate store for `localhost`. - -## Usage - -Please see the [project documentation](https://socketry.github.io/localhost/). - -## Contributing - -1. Fork it -2. Create your feature branch (`git checkout -b my-new-feature`) -3. Commit your changes (`git commit -am 'Add some feature'`) -4. Push to the branch (`git push origin my-new-feature`) -5. Create new Pull Request - -## See Also - -- [Falcon](https://github.com/socketry/falcon) — Uses `Localhost::Authority` to provide HTTP/2 with minimal configuration. -- [Puma](https://github.com/puma/puma) — Supports `Localhost::Authority` to provide self-signed HTTP for local development. - -## License - -Released under the MIT license. - -Copyright, 2018, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams). - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/bake/localhost.rb b/bake/localhost.rb index 2e6d4a6..48ff753 100644 --- a/bake/localhost.rb +++ b/bake/localhost.rb @@ -1,3 +1,7 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2021-2023, by Samuel Williams. # List all local authorities. def list @@ -28,4 +32,4 @@ def terminal(out = $stdout) terminal[:name] = terminal.style(:blue) return terminal -end \ No newline at end of file +end diff --git a/gems.rb b/gems.rb index 5f8429d..7961d88 100644 --- a/gems.rb +++ b/gems.rb @@ -1,5 +1,8 @@ # frozen_string_literal: true +# Released under the MIT License. +# Copyright, 2018-2023, by Samuel Williams. + source 'https://rubygems.org' gemspec diff --git a/guides/example-server/https.rb b/guides/example-server/https.rb index bb45efb..60b33fa 100755 --- a/guides/example-server/https.rb +++ b/guides/example-server/https.rb @@ -1,4 +1,9 @@ #!/usr/bin/env ruby +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2018-2023, by Samuel Williams. +# Copyright, 2021, by Ye Lin Aung. # Require the required libraries: require 'async' diff --git a/lib/localhost.rb b/lib/localhost.rb index cbf8996..19033c2 100644 --- a/lib/localhost.rb +++ b/lib/localhost.rb @@ -1,22 +1,7 @@ -# Copyright, 2018, by Samuel G. D. Williams. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2018-2023, by Samuel Williams. require_relative 'localhost/version' require_relative 'localhost/authority' diff --git a/lib/localhost/authority.rb b/lib/localhost/authority.rb index 806d2d5..a8c7540 100644 --- a/lib/localhost/authority.rb +++ b/lib/localhost/authority.rb @@ -1,22 +1,11 @@ -# Copyright, 2018, by Samuel G. D. Williams. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2018-2023, by Samuel Williams. +# Copyright, 2019, by Richard S. Leung. +# Copyright, 2021, by Akshay Birajdar. +# Copyright, 2021, by Ye Lin Aung. +# Copyright, 2023, by Antonio Terceiro. require 'yaml' require 'openssl' diff --git a/lib/localhost/version.rb b/lib/localhost/version.rb index 5b82229..fcaa9ef 100644 --- a/lib/localhost/version.rb +++ b/lib/localhost/version.rb @@ -1,22 +1,7 @@ -# Copyright, 2018, by Samuel G. D. Williams. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2018-2023, by Samuel Williams. module Localhost VERSION = "1.1.9" diff --git a/license.md b/license.md new file mode 100644 index 0000000..e91abef --- /dev/null +++ b/license.md @@ -0,0 +1,28 @@ +# MIT License + +Copyright, 2018-2023, by Samuel Williams. +Copyright, 2018, by Gabriel Sobrinho. +Copyright, 2019, by Richard S. Leung. +Copyright, 2020-2021, by Olle Jonsson. +Copyright, 2021, by Akshay Birajdar. +Copyright, 2021, by Ye Lin Aung. +Copyright, 2022, by Juri Hahn. +Copyright, 2023, by Antonio Terceiro. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/localhost.gemspec b/localhost.gemspec index ac65093..808ed0f 100644 --- a/localhost.gemspec +++ b/localhost.gemspec @@ -1,3 +1,4 @@ +# frozen_string_literal: true require_relative "lib/localhost/version" @@ -6,7 +7,7 @@ Gem::Specification.new do |spec| spec.version = Localhost::VERSION spec.summary = "Manage a local certificate authority for self-signed localhost development servers." - spec.authors = ["Samuel Williams"] + spec.authors = ["Samuel Williams", "Olle Jonsson", "Ye Lin Aung", "Akshay Birajdar", "Antonio Terceiro", "Gabriel Sobrinho", "Juri Hahn", "Richard S. Leung"] spec.license = "MIT" spec.cert_chain = ['release.cert'] @@ -14,9 +15,10 @@ Gem::Specification.new do |spec| spec.homepage = "https://github.com/socketry/localhost" - spec.files = Dir.glob('{lib}/**/*', File::FNM_DOTMATCH, base: __dir__) + spec.files = Dir.glob(['{lib}/**/*', '*.md'], File::FNM_DOTMATCH, base: __dir__) spec.add_development_dependency "bundler" spec.add_development_dependency "covered" - spec.add_development_dependency "rspec", "~> 3.0" + spec.add_development_dependency "sus", "~> 0.16" + spec.add_development_dependency "sus-fixtures-async" end diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..795192b --- /dev/null +++ b/readme.md @@ -0,0 +1,30 @@ +# Localhost + +This gem provides a convenient API for generating per-user self-signed root certificates. + +[![Development Status](https://github.com/socketry/localhost/workflows/Test/badge.svg)](https://github.com/socketry/localhost/actions?workflow=Test) + +## Motivation + +HTTP/2 requires SSL in web browsers. If you want to use HTTP/2 for development (and you should), you need to start using URLs like `https://localhost:8080`. In most cases, this requires adding a self-signed certificate to your certificate store (e.g. Keychain on macOS), and storing the private key for the web-server to use. + +I wanted to provide a server-agnostic way of doing this, primarily because I think it makes sense to minimise the amount of junky self-signed keys you add to your certificate store for `localhost`. + +## Usage + +Please see the [project documentation](https://socketry.github.io/localhost/). + +## Contributing + +We welcome contributions to this project. + +1. Fork it. +2. Create your feature branch (`git checkout -b my-new-feature`). +3. Commit your changes (`git commit -am 'Add some feature'`). +4. Push to the branch (`git push origin my-new-feature`). +5. Create new Pull Request. + +## See Also + + - [Falcon](https://github.com/socketry/falcon) — Uses `Localhost::Authority` to provide HTTP/2 with minimal configuration. + - [Puma](https://github.com/puma/puma) — Supports `Localhost::Authority` to provide self-signed HTTP for local development. diff --git a/release.cert b/release.cert index f036666..d98e595 100644 --- a/release.cert +++ b/release.cert @@ -1,27 +1,28 @@ -----BEGIN CERTIFICATE----- -MIIEhDCCAuygAwIBAgIBATANBgkqhkiG9w0BAQsFADA3MTUwMwYDVQQDDCxzYW11 -ZWwud2lsbGlhbXMvREM9b3Jpb250cmFuc2Zlci9EQz1jby9EQz1uejAeFw0yMTA4 -MTYwNjMzNDRaFw0yMjA4MTYwNjMzNDRaMDcxNTAzBgNVBAMMLHNhbXVlbC53aWxs -aWFtcy9EQz1vcmlvbnRyYW5zZmVyL0RDPWNvL0RDPW56MIIBojANBgkqhkiG9w0B -AQEFAAOCAY8AMIIBigKCAYEAyXLSS/cw+fXJ5e7hi+U/TeChPWeYdwJojDsFY1xr -xvtqbTTL8gbLHz5LW3QD2nfwCv3qTlw0qI3Ie7a9VMJMbSvgVEGEfQirqIgJXWMj -eNMDgKsMJtC7u/43abRKx7TCURW3iWyR19NRngsJJmaR51yGGGm2Kfsr+JtKKLtL -L188Wm3f13KAx7QJU8qyuBnj1/gWem076hzdA7xi1DbrZrch9GCRz62xymJlrJHn -9iZEZ7AxrS7vokhMlzSr/XMUihx/8aFKtk+tMLClqxZSmBWIErWdicCGTULXCBNb -E/mljo4zEVKhlTWpJklMIhr55ZRrSarKFuW7en0+tpJrfsYiAmXMJNi4XAYJH7uL -rgJuJwSaa/dMz+VmUoo7VKtSfCoOI+6v5/z0sK3oT6sG6ZwyI47DBq2XqNC6tnAj -w+XmCywiTQrFzMMAvcA7rPI4F0nU1rZId51rOvvfxaONp+wgTi4P8owZLw0/j0m4 -8C20DYi6EYx4AHDXiLpElWh3AgMBAAGjgZowgZcwCQYDVR0TBAIwADALBgNVHQ8E -BAMCBLAwHQYDVR0OBBYEFB6ZaeWKxQjGTI+pmz7cKRmMIywwMC4GA1UdEQQnMCWB -I3NhbXVlbC53aWxsaWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MC4GA1UdEgQnMCWB -I3NhbXVlbC53aWxsaWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MA0GCSqGSIb3DQEB -CwUAA4IBgQBVoM+pu3dpdUhZM1w051iw5GfiqclAr1Psypf16Tiod/ho//4oAu6T -9fj3DPX/acWV9P/FScvqo4Qgv6g4VWO5ZU7z2JmPoTXZtYMunRAmQPFL/gSUc6aK -vszMHIyhtyzRc6DnfW2AiVOjMBjaYv8xXZc9bduniRVPrLR4J7ozmGLh4o4uJp7w -x9KCFaR8Lvn/r0oJWJOqb/DMAYI83YeN2Dlt3jpwrsmsONrtC5S3gOUle5afSGos -bYt5ocnEpKSomR9ZtnCGljds/aeO1Xgpn2r9HHcjwnH346iNrnHmMlC7BtHUFPDg -Ts92S47PTOXzwPBDsrFiq3VLbRjHSwf8rpqybQBH9MfzxGGxTaETQYOd6b4e4Ag6 -y92abGna0bmIEb4+Tx9rQ10Uijh1POzvr/VTH4bbIPy9FbKrRsIQ24qDbNJRtOpE -RAOsIl+HOBTb252nx1kIRN5hqQx272AJCbCjKx8egcUQKffFVVCI0nye09v5CK+a -HiLJ8VOFx6w= +MIIE2DCCA0CgAwIBAgIBATANBgkqhkiG9w0BAQsFADBhMRgwFgYDVQQDDA9zYW11 +ZWwud2lsbGlhbXMxHTAbBgoJkiaJk/IsZAEZFg1vcmlvbnRyYW5zZmVyMRIwEAYK +CZImiZPyLGQBGRYCY28xEjAQBgoJkiaJk/IsZAEZFgJuejAeFw0yMjA4MDYwNDUz +MjRaFw0zMjA4MDMwNDUzMjRaMGExGDAWBgNVBAMMD3NhbXVlbC53aWxsaWFtczEd +MBsGCgmSJomT8ixkARkWDW9yaW9udHJhbnNmZXIxEjAQBgoJkiaJk/IsZAEZFgJj +bzESMBAGCgmSJomT8ixkARkWAm56MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIB +igKCAYEAomvSopQXQ24+9DBB6I6jxRI2auu3VVb4nOjmmHq7XWM4u3HL+pni63X2 +9qZdoq9xt7H+RPbwL28LDpDNflYQXoOhoVhQ37Pjn9YDjl8/4/9xa9+NUpl9XDIW +sGkaOY0eqsQm1pEWkHJr3zn/fxoKPZPfaJOglovdxf7dgsHz67Xgd/ka+Wo1YqoE +e5AUKRwUuvaUaumAKgPH+4E4oiLXI4T1Ff5Q7xxv6yXvHuYtlMHhYfgNn8iiW8WN +XibYXPNP7NtieSQqwR/xM6IRSoyXKuS+ZNGDPUUGk8RoiV/xvVN4LrVm9upSc0ss +RZ6qwOQmXCo/lLcDUxJAgG95cPw//sI00tZan75VgsGzSWAOdjQpFM0l4dxvKwHn +tUeT3ZsAgt0JnGqNm2Bkz81kG4A2hSyFZTFA8vZGhp+hz+8Q573tAR89y9YJBdYM +zp0FM4zwMNEUwgfRzv1tEVVUEXmoFCyhzonUUw4nE4CFu/sE3ffhjKcXcY//qiSW +xm4erY3XAgMBAAGjgZowgZcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0O +BBYEFO9t7XWuFf2SKLmuijgqR4sGDlRsMC4GA1UdEQQnMCWBI3NhbXVlbC53aWxs +aWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MC4GA1UdEgQnMCWBI3NhbXVlbC53aWxs +aWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MA0GCSqGSIb3DQEBCwUAA4IBgQB5sxkE +cBsSYwK6fYpM+hA5B5yZY2+L0Z+27jF1pWGgbhPH8/FjjBLVn+VFok3CDpRqwXCl +xCO40JEkKdznNy2avOMra6PFiQyOE74kCtv7P+Fdc+FhgqI5lMon6tt9rNeXmnW/ +c1NaMRdxy999hmRGzUSFjozcCwxpy/LwabxtdXwXgSay4mQ32EDjqR1TixS1+smp +8C/NCWgpIfzpHGJsjvmH2wAfKtTTqB9CVKLCWEnCHyCaRVuKkrKjqhYCdmMBqCws +JkxfQWC+jBVeG9ZtPhQgZpfhvh+6hMhraUYRQ6XGyvBqEUe+yo6DKIT3MtGE2+CP +eX9i9ZWBydWb8/rvmwmX2kkcBbX0hZS1rcR593hGc61JR6lvkGYQ2MYskBveyaxt +Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8 +voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg= -----END CERTIFICATE----- diff --git a/spec/localhost/authority_spec.rb b/spec/localhost/authority_spec.rb deleted file mode 100644 index ec2bd7c..0000000 --- a/spec/localhost/authority_spec.rb +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright, 2018, by Samuel G. D. Williams. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -require 'localhost/authority' - -require 'async/io/host_endpoint' -require 'async/io/ssl_endpoint' - -require 'async/process' -require 'fileutils' - -RSpec.describe Localhost::Authority do - it "can generate key and certificate" do - FileUtils.mkdir_p("ssl") - subject.save("ssl") - - expect(File).to be_exist("ssl/localhost.lock") - expect(File).to be_exist("ssl/localhost.crt") - expect(File).to be_exist("ssl/localhost.key") - end - - it "have correct key and certificate path" do - subject.save(subject.class.path) - expect(File).to be_exist(subject.certificate_path) - expect(File).to be_exist(subject.key_path) - - expect(subject.key_path).to eq(File.join(File.expand_path("~/.localhost"), "localhost.key")) - expect(subject.certificate_path).to eq(File.join(File.expand_path("~/.localhost"), "localhost.crt")) - end - - describe '#store' do - it "can verify certificate" do - expect(subject.store.verify(subject.certificate)).to be true - end - end - - describe '#server_context' do - it "can generate appropriate ssl context" do - expect(subject.server_context).to be_a OpenSSL::SSL::SSLContext - end - end - - context 'client/server' do - include_context Async::RSpec::Reactor - - let(:endpoint) {Async::IO::Endpoint.tcp("localhost", 4040)} - let!(:server_endpoint) {Async::IO::SSLEndpoint.new(endpoint, ssl_context: subject.server_context)} - let!(:client_endpoint) {Async::IO::SSLEndpoint.new(endpoint, ssl_context: subject.client_context)} - - let(:client) {client_endpoint.connect} - - it "can verify peer" do - server_task = reactor.async do - server_endpoint.accept do |peer| - peer.write("Hello World!") - peer.close - end - end - - expect(client.read(12)).to be == "Hello World!" - - client.close - server_task.stop - end - end -end diff --git a/spec/localhost/protocol_spec.rb b/spec/localhost/protocol_spec.rb deleted file mode 100644 index fd22d49..0000000 --- a/spec/localhost/protocol_spec.rb +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright, 2018, by Samuel G. D. Williams. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -require 'localhost/authority' - -require 'async/io/host_endpoint' -require 'async/io/ssl_endpoint' - -require 'async/process' -require 'fileutils' - -RSpec.shared_examples_for "valid protocol" do |protocol, openssl_options, curl_options| - it "can connect using #{protocol}" do - status = Async::Process.spawn("openssl", "s_client", "-connect", "localhost:4040", *openssl_options) - - expect(status).to be_success - - server_task.stop - end - - it "can connect using HTTP over #{protocol}" do - status = Async::Process.spawn("curl", "--verbose", "--insecure", "https://localhost:4040", *curl_options) - - expect(status).to be_success - - server_task.stop - end -end - -RSpec.shared_examples_for "invalid protocol" do |protocol, openssl_options, curl_options| - it "can't connect using #{protocol}" do - status = Async::Process.spawn("openssl", "s_client", "-connect", "localhost:4040", *openssl_options) - - expect(status).to_not be_success - - server_task.stop - end - - it "can't connect using HTTP over #{protocol}" do - status = Async::Process.spawn("curl", "--verbose", "--insecure", "https://localhost:4040", *curl_options) - - expect(status).to_not be_success - - server_task.stop - end -end - -RSpec.describe Localhost::Authority do - include_context Async::RSpec::Reactor - - let(:endpoint) {Async::IO::Endpoint.tcp("localhost", 4040)} - let!(:server_endpoint) {Async::IO::SSLEndpoint.new(endpoint, ssl_context: subject.server_context)} - let!(:client_endpoint) {Async::IO::SSLEndpoint.new(endpoint, ssl_context: subject.client_context)} - - let(:client) {client_endpoint.connect} - - let!(:server_task) do - reactor.async do - server_endpoint.accept do |peer| - peer.write("HTTP/1.1 200 Okay\r\n") - peer.write("Connection: close\r\nContent-Length: 0\r\n\r\n") - peer.flush - peer.close - end - end - end - - # Curl no longer supports this. - # it_behaves_like "invalid protocol", "SSLv3", ["-ssl3"], ["--sslv3"] - - # Most modern browsers have removed support for these: - # it_behaves_like "valid protocol", "TLSv1", ["-tls1"], ["--tlsv1"] - # it_behaves_like "valid protocol", "TLSv1.1", ["-tls1_1"], ["--tlsv1.1"] - - it_behaves_like "valid protocol", "TLSv1.2", ["-tls1_2"], ["--tlsv1.2"] - - it_behaves_like "valid protocol", "default", [], [] -end diff --git a/spec/localhost_spec.rb b/spec/localhost_spec.rb deleted file mode 100644 index 4c5e433..0000000 --- a/spec/localhost_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright, 2018, by Samuel G. D. Williams. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -require 'localhost' - -RSpec.describe Localhost do - it "has a version number" do - expect(Localhost::VERSION).not_to be nil - end -end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb deleted file mode 100644 index a6109ee..0000000 --- a/spec/spec_helper.rb +++ /dev/null @@ -1,20 +0,0 @@ - -require 'covered/rspec' - -require 'async/rspec' - -RSpec.configure do |config| - # Enable flags like --only-failures and --next-failure - config.example_status_persistence_file_path = ".rspec_status" - - # Disable RSpec exposing methods globally on `Module` and `main` - config.disable_monkey_patching! - - config.expect_with :rspec do |c| - c.syntax = :expect - end - - config.before(:all) do - FileUtils.rm_rf("ssl") - end -end diff --git a/ssl/localhost.crt b/ssl/localhost.crt new file mode 100644 index 0000000..d8e9c6b --- /dev/null +++ b/ssl/localhost.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDcDCCAligAwIBAgIEY+LPWDANBgkqhkiG9w0BAQsFADAqMRQwEgYDVQQKDAtE +ZXZlbG9wbWVudDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIzMDIwNzIyMjMyMFoX +DTMzMDIwNDIyMjMyMFowKjEUMBIGA1UECgwLRGV2ZWxvcG1lbnQxEjAQBgNVBAMM +CWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMGBhAye +aCOP76IZfxKLM3mYn8tUt0U8RXetmKbTSrusy4KyaT5g7JATbvNRQI5Ld28X7b3E +DjBohCXO9XHBZ+6IbhPwA93lIxMbIc+l7k+Me/5ClrBd2UtKc0FXe1+bDwHh2SvL +7sFVTb9lOuk4IB2Vn5o3CvVZIvR0jQTKmnbXab3e1r2AHxCNgHwAm+VgCKvuMJ3X +lAeOw51n9rW/l92OQYSawI+6i2GMGd1YXJz8kMwWqeAsfHBidvwfVyg98UoXyojK +IvTYZN9uHdCb7GJsgcquC8+yFPi+B1T9/nbVnG6DlJR/La0sc1o3yK+Ldon/Ud7V +MEA7ARXYHJRtwk0CAwEAAaOBnTCBmjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTv +XSXTCOUN1+RR5/h4e20ZxJ+0wzBVBgNVHSMETjBMgBTvXSXTCOUN1+RR5/h4e20Z +xJ+0w6EupCwwKjEUMBIGA1UECgwLRGV2ZWxvcG1lbnQxEjAQBgNVBAMMCWxvY2Fs +aG9zdIIEY+LPWDAUBgNVHREEDTALgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQAD +ggEBAJafdbNzb+mUszfhNkW1pYBf/QVObGDsMcRn6NWGfQ7qV1/11wpZq/H0dazZ +Bw08AE5YwtPiJEMRXOG0clwH3xLFPbkQ90pMKcMTa7oN5AU7NR1POcuubGpnYEsM +/y3d+EiR3G6Fazlvl/EIPh17U4WB+ED7W5MXSmhueWyx/EisjPGNCt2lg39JeUBV +S3OlS/E/E3X1Lp3yzBahax9fyLCgOYnwJVfAqplxcAH3lyPj5/caxETUlrfDSES2 +TrfEQpChsOtkgv1Q7YkImn4m3MFi2/G0DhVjJjxol5og3FY6KdVcwif98zQGIXPR +Xgah1uu2CvoQBuxpI087DTKg3GY= +-----END CERTIFICATE----- diff --git a/ssl/localhost.key b/ssl/localhost.key new file mode 100644 index 0000000..6c69fc2 --- /dev/null +++ b/ssl/localhost.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAwYGEDJ5oI4/vohl/EoszeZify1S3RTxFd62YptNKu6zLgrJp +PmDskBNu81FAjkt3bxftvcQOMGiEJc71ccFn7ohuE/AD3eUjExshz6XuT4x7/kKW +sF3ZS0pzQVd7X5sPAeHZK8vuwVVNv2U66TggHZWfmjcK9Vki9HSNBMqadtdpvd7W +vYAfEI2AfACb5WAIq+4wndeUB47DnWf2tb+X3Y5BhJrAj7qLYYwZ3VhcnPyQzBap +4Cx8cGJ2/B9XKD3xShfKiMoi9Nhk324d0JvsYmyByq4Lz7IU+L4HVP3+dtWcboOU +lH8trSxzWjfIr4t2if9R3tUwQDsBFdgclG3CTQIDAQABAoIBAA5JaF0gz5eF569p +f9RNVWjuN9NkrH3+y9zg2EXDkTT3YQnZRPlHYVqR1L3qNdX2WcRorojgPMaeMNjf +Gt1h5jEvqXuXW5xlGoiClvskc8qJGMPWWWx+wVhUZYYMK3O3mGK522A8bPhL5V2d +imfwWOQA9AkIH1WrVcVZWuq2UAk4urdepg56ouGZJ3LhIItmE+4720R5PRHQ6G/z +weGxtKc6Kxmq7OzzrIyS0dpNE034gDB27H1yGt6a6iQLNdSognNaMSjSh/vAw0w9 +1hcAMhNe/ohlLTGw+iY9654mQcDcs3nOoO9YBw9V5L4P+lJnSuL17Vi5T2IqPVam +7h6olRECgYEA7IgoGIBkFEpPyGgs3+UKZT1Cgw3YUpHOwvYLPHu/kVwrOxWno7cj +XuuI+TMJRSGsUk7HCTgfI4XOLjlrEYZ1NQrfOb85TiRrcFBzBJwonm4EUfSOgc13 +hXeM0A/7/KbltiRvWcu+SjWfdo2ae49hDaTqQI57kgRzqsyHNuonZ5sCgYEA0W7I +BW1lDXFOPcEe0owVDn/3AkRZL83A3vWVfOsnr/h0d5fB4K3zb1KQA67zcTEu53WH +GCLxCv/b/KEf9llIiRxWuxg8xartiNtjqSN4QY/luRMWbO81WUxsKXCBD1UiG7Ld +afGL/sz/i4KBoM3350JMARb/z7Y5yKjjKYOLgDcCgYAfqMnVHbpHjPrI1EjNXxbZ +Hi385KmDw8htCAnQ+q9VgYS3z9o0a5rsZZJb6JzhB/TMv4ackUp5srs6LK1MFzcw +9leSnynIb8+BpQMAJva43fjuD1HTxfCtiKbsYndUBfLRQmc1GbRKsoq5j5KR30sa +TGyeX3Piw33H6sBedVD46QKBgEePW8cG9wVd1schCqAUf0liDgt3QSYlXqaQMVDq +pLfq5BjNAND9fvVlt5GaoNHnZUhvDwb/QW9pt0gd4ebx4OgAh94LzRAZdGpT1DzB +wuBcA7l2PS5hmc/2XerW5zJO+4WNWzxM7XHVp+eKYzKHzhH1xDSHIEdf02St2Fih ++vOHAoGAEbqPUbY+mNV75Th049F9dd5X7QSemKpjwF0Tw/Hrqc+XT2GpNhX9fFhb +AF+J8eqJmVbuOY/s2coJlLcw6fa+QAp3Ruyl6t2+P1Hzqbb76fm5SBih0n1tq54X +AUKov9ICxP6Pszed1D8hwYngTKa9T/cdPVc2DVGVGjxMkg7O8SU= +-----END RSA PRIVATE KEY----- diff --git a/ssl/localhost.lock b/ssl/localhost.lock new file mode 100644 index 0000000..e69de29 diff --git a/test/localhost.rb b/test/localhost.rb new file mode 100644 index 0000000..d82aa25 --- /dev/null +++ b/test/localhost.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2023, by Samuel Williams. + +require 'localhost' + +describe Localhost do + it "has a version number" do + expect(Localhost::VERSION).to be =~ /\d+\.\d+\.\d+/ + end +end diff --git a/test/localhost/authority.rb b/test/localhost/authority.rb new file mode 100644 index 0000000..7a92287 --- /dev/null +++ b/test/localhost/authority.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2023, by Samuel Williams. + +require 'localhost/authority' + +require 'sus/fixtures/async/reactor_context' +require 'async/io/host_endpoint' +require 'async/io/ssl_endpoint' +require 'async/io/shared_endpoint' + +require 'async/process' +require 'fileutils' + +describe Localhost::Authority do + let(:authority) {subject.new} + + it "can generate key and certificate" do + FileUtils.mkdir_p("ssl") + authority.save("ssl") + + expect(File).to be(:exist?, "ssl/localhost.lock") + expect(File).to be(:exist?, "ssl/localhost.crt") + expect(File).to be(:exist?, "ssl/localhost.key") + end + + it "have correct key and certificate path" do + authority.save(authority.class.path) + expect(File).to be(:exist?, authority.certificate_path) + expect(File).to be(:exist?, authority.key_path) + + expect(authority.key_path).to be == File.join(File.expand_path("~/.localhost"), "localhost.key") + expect(authority.certificate_path).to be == File.join(File.expand_path("~/.localhost"), "localhost.crt") + end + + with '#store' do + it "can verify certificate" do + expect(authority.store.verify(authority.certificate)).to be == true + end + end + + with '#server_context' do + it "can generate appropriate ssl context" do + expect(authority.server_context).to be_a OpenSSL::SSL::SSLContext + end + end + + with 'client/server' do + include Sus::Fixtures::Async::ReactorContext + + let(:endpoint) {Async::IO::Endpoint.tcp("localhost", 4040)} + let(:server_endpoint) {Async::IO::SSLEndpoint.new(endpoint, ssl_context: authority.server_context)} + let(:client_endpoint) {Async::IO::SSLEndpoint.new(endpoint, ssl_context: authority.client_context)} + + let(:client) {client_endpoint.connect} + + def before + @bound_endpoint = Async::IO::SharedEndpoint.bound(server_endpoint) + + @server_task = reactor.async do + @bound_endpoint.accept do |peer| + peer.write("Hello World!") + peer.close + end + end + + super + end + + def after + @server_task&.stop + @bound_endpoint&.close + + super + end + + it "can verify peer" do + expect(client.read(12)).to be == "Hello World!" + + client.close + end + end +end diff --git a/test/localhost/protocol.rb b/test/localhost/protocol.rb new file mode 100644 index 0000000..9a4752e --- /dev/null +++ b/test/localhost/protocol.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2023, by Samuel Williams. + +require 'localhost/authority' + +require 'sus/fixtures/async/reactor_context' +require 'async/io/host_endpoint' +require 'async/io/ssl_endpoint' +require 'async/io/shared_endpoint' + +require 'async/process' +require 'fileutils' + +AValidProtocol = Sus::Shared("valid protocol") do |protocol, openssl_options, curl_options| + it "can connect using #{protocol} using openssl" do + status = Async::Process.spawn("openssl", "s_client", "-connect", "localhost:4040", *openssl_options) + + expect(status).to be(:success?) + end + + it "can connect using HTTP over #{protocol} using curl" do + status = Async::Process.spawn("curl", "--verbose", "--insecure", "https://localhost:4040", *curl_options) + + expect(status).to be(:success?) + end +end + +AnInvalidProtocol = Sus::Shared("invalid protocol") do |protocol, openssl_options, curl_options| + it "can't connect using #{protocol}" do + status = Async::Process.spawn("openssl", "s_client", "-connect", "localhost:4040", *openssl_options) + + expect(status).to_not be(:success?) + end + + it "can't connect using HTTP over #{protocol}" do + status = Async::Process.spawn("curl", "--verbose", "--insecure", "https://localhost:4040", *curl_options) + + expect(status).to_not be(:success?) + end +end + +describe Localhost::Authority do + let(:authority) {subject.new} + + include Sus::Fixtures::Async::ReactorContext + + let(:endpoint) {Async::IO::Endpoint.tcp("localhost", 4040)} + let(:server_endpoint) {Async::IO::SSLEndpoint.new(endpoint, ssl_context: authority.server_context)} + let(:client_endpoint) {Async::IO::SSLEndpoint.new(endpoint, ssl_context: authority.client_context)} + + let(:client) {client_endpoint.connect} + + def before + @bound_endpoint = Async::IO::SharedEndpoint.bound(server_endpoint) + + @server_task = reactor.async do + @bound_endpoint.accept do |peer| + peer.write("HTTP/1.1 200 Okay\r\n") + peer.write("Connection: close\r\nContent-Length: 0\r\n\r\n") + sleep 0.2 + peer.flush + peer.close + end + end + + super + end + + def after + @server_task&.stop + @bound_endpoint&.close + + super + end + + # Curl no longer supports this. + # it_behaves_like "invalid protocol", "SSLv3", ["-ssl3"], ["--sslv3"] + + # Most modern browsers have removed support for these: + # it_behaves_like "valid protocol", "TLSv1", ["-tls1"], ["--tlsv1"] + # it_behaves_like "valid protocol", "TLSv1.1", ["-tls1_1"], ["--tlsv1.1"] + + it_behaves_like AValidProtocol, "TLSv1.2", ["-tls1_2"], ["--tlsv1.2"] + it_behaves_like AValidProtocol, "default", [], [] +end From 5f6a27d849a1e19b6e9a12f94ab12ce7659f6734 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Wed, 8 Feb 2023 22:25:22 +1300 Subject: [PATCH 2/4] Add external tests. --- config/external.yaml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 config/external.yaml diff --git a/config/external.yaml b/config/external.yaml new file mode 100644 index 0000000..21bcc9b --- /dev/null +++ b/config/external.yaml @@ -0,0 +1,3 @@ +falcon: + url: https://github.com/socketry/falcon + command: bundle exec rspec From 04aca07757709356064ab2cf9c11e92db3dda219 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Wed, 8 Feb 2023 22:26:45 +1300 Subject: [PATCH 3/4] Fix tests. --- gems.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gems.rb b/gems.rb index 7961d88..c35914c 100644 --- a/gems.rb +++ b/gems.rb @@ -14,9 +14,10 @@ gem "utopia-project" end -group :development do - gem 'async-io' - gem 'async-rspec' +group :test do + gem "bake-test" + gem "bake-test-external" + gem 'async-io' gem 'async-process' end From 0086ffb659d33d7a6f33afbeb36109bf96577833 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Wed, 8 Feb 2023 22:28:04 +1300 Subject: [PATCH 4/4] Code coverage. --- config/sus.rb | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 config/sus.rb diff --git a/config/sus.rb b/config/sus.rb new file mode 100644 index 0000000..bb035bd --- /dev/null +++ b/config/sus.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2023, by Samuel Williams. + +require 'covered/sus' +include Covered::Sus