├── .github ├── actions │ ├── setup-ruby-1.71.0 │ │ ├── .gitattributes │ │ ├── .github │ │ │ ├── ISSUE_TEMPLATE │ │ │ │ └── bug_report.md │ │ │ └── workflows │ │ │ │ ├── release.yml │ │ │ │ └── test.yml │ │ ├── .gitignore │ │ ├── .ruby-version │ │ ├── .tool-versions │ │ ├── CONTRIBUTING.md │ │ ├── Gemfile │ │ ├── LICENSE │ │ ├── README.md │ │ ├── action.yml │ │ ├── bundler.js │ │ ├── common.js │ │ ├── dist │ │ │ └── index.js │ │ ├── gemfiles │ │ │ ├── bundler1.gemfile │ │ │ ├── nokogiri.gemfile │ │ │ ├── rails5.gemfile │ │ │ └── rails6.gemfile │ │ ├── generate-windows-versions.rb │ │ ├── index.js │ │ ├── package.json │ │ ├── pre-commit │ │ ├── ruby-builder-versions.js │ │ ├── ruby-builder.js │ │ ├── test_subprocess.rb │ │ ├── versions-strings-for-builder.rb │ │ ├── windows-versions.js │ │ ├── windows.js │ │ └── yarn.lock │ └── v1.71.0.zip └── workflows │ └── source-test.yml ├── .gitignore ├── .rspec ├── CONTRIBUTING.md ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── bin └── c7decrypt ├── c7decrypt.gemspec ├── certs └── claudijd.pem ├── fuzz └── fuzz_decrypt.rb ├── images └── cisco.jpeg ├── lib ├── c7decrypt.rb └── c7decrypt │ ├── type5 │ ├── constants.rb │ └── type5.rb │ ├── type7 │ ├── constants.rb │ ├── exceptions.rb │ └── type7.rb │ └── version.rb └── spec ├── example_configs ├── bad_canned_example.txt ├── empty_example.txt └── simple_canned_example.txt ├── spec_helper.rb ├── type5_spec.rb └── type7_spec.rb /.github/actions/setup-ruby-1.71.0/.gitattributes: -------------------------------------------------------------------------------- 1 | /dist/index.js linguist-generated 2 | /package-lock.json linguist-generated 3 | /yarn.lock linguist-generated 4 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 22 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Update the v1 branch when a release is published 2 | on: 3 | release: 4 | types: [published] 5 | jobs: 6 | release: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | with: 11 | fetch-depth: 0 12 | - run: git push origin HEAD:v1 13 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test this action 2 | on: 3 | pull_request: 4 | push: 5 | branches-ignore: 6 | - v1 7 | tags-ignore: 8 | - '*' 9 | paths-ignore: 10 | - README.md 11 | schedule: 12 | - cron: '0 7 * * SUN' 13 | jobs: 14 | test: 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | os: [ ubuntu-18.04, ubuntu-20.04, macos-10.15, macos-11.0, windows-2016, windows-2019 ] 19 | ruby: [ 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, '3.0', ruby-head, jruby, jruby-head, truffleruby, truffleruby-head ] 20 | include: 21 | - { os: windows-2016, ruby: mingw } 22 | - { os: windows-2019, ruby: mingw } 23 | - { os: windows-2019, ruby: mswin } 24 | exclude: 25 | - { os: windows-2016, ruby: debug } 26 | - { os: windows-2016, ruby: truffleruby } 27 | - { os: windows-2016, ruby: truffleruby-head } 28 | - { os: windows-2019, ruby: debug } 29 | - { os: windows-2019, ruby: truffleruby } 30 | - { os: windows-2019, ruby: truffleruby-head } 31 | 32 | name: ${{ matrix.os }} ${{ matrix.ruby }} 33 | runs-on: ${{ matrix.os }} 34 | steps: 35 | - uses: actions/checkout@v2 36 | 37 | - uses: ./ 38 | with: 39 | ruby-version: ${{ matrix.ruby }} 40 | bundler-cache: true 41 | - run: ruby -v 42 | - name: PATH 43 | shell: bash 44 | run: echo $PATH 45 | 46 | - name: build compiler 47 | run: | 48 | ruby -e "puts 'build compiler: ' + RbConfig::CONFIG.fetch('CC_VERSION_MESSAGE', 'unknown').lines.first" 49 | - name: gcc and ridk version (mingw) 50 | if: startsWith(matrix.os, 'windows') 51 | run: | 52 | $abi, $plat = $(ruby -e "STDOUT.write RbConfig::CONFIG['ruby_version'] + ' ' + RUBY_PLATFORM").split(' ') 53 | if ($plat.Contains('mingw')) { 54 | gcc --version 55 | if ($abi -ge '2.4') { 56 | ridk version 57 | } else { 58 | echo 'ridk is unavailable' 59 | } 60 | } 61 | - name: RbConfig::CONFIG 62 | run: ruby -rrbconfig -rpp -e 'pp RbConfig::CONFIG' 63 | - name: RbConfig::MAKEFILE_CONFIG 64 | run: ruby -rrbconfig -rpp -e 'pp RbConfig::MAKEFILE_CONFIG' 65 | 66 | - name: Subprocess test 67 | run: ruby test_subprocess.rb 68 | - name: OpenSSL version 69 | run: ruby -ropenssl -e 'puts OpenSSL::OPENSSL_LIBRARY_VERSION' 70 | - name: OpenSSL test 71 | run: ruby -ropen-uri -e 'puts URI.send(:open, %{https://rubygems.org/}) { |f| f.read(1024) }' 72 | 73 | - name: C extension test 74 | run: gem install json:2.2.0 --no-document 75 | - run: bundle --version 76 | # This step is redundant with `bundler-cache: true` but is there to check a redundant `bundle install` still works 77 | - run: bundle install 78 | - run: bundle exec rake --version 79 | 80 | - name: which ruby, rake 81 | if: "!startsWith(matrix.os, 'windows')" 82 | run: which -a ruby rake 83 | - name: where ruby, rake 84 | if: startsWith(matrix.os, 'windows') 85 | run: | 86 | $ErrorActionPreference = 'Continue' 87 | $where = 'ruby', 'rake' 88 | foreach ($e in $where) { 89 | $rslt = where.exe $e 2>&1 | Out-String 90 | if ($rslt.contains($e)) { echo $rslt.Trim() } 91 | else { echo "Can't find $e" } 92 | echo '' 93 | } 94 | - name: bash test 95 | shell: bash 96 | run: echo ~ 97 | # Disabled until https://github.com/jruby/jruby/issues/6648 is fixed 98 | # - name: Windows JRuby 99 | # if: startsWith(matrix.os, 'windows') && startsWith(matrix.ruby, 'jruby') 100 | # run: gem install sassc -N 101 | 102 | testExactBundlerVersion: 103 | name: "Test with an exact Bundler version" 104 | runs-on: ubuntu-latest 105 | steps: 106 | - uses: actions/checkout@v2 107 | - uses: ./ 108 | with: 109 | ruby-version: 2.6 110 | bundler: 2.2.3 111 | - run: bundle --version | grep -F "Bundler version 2.2.3" 112 | 113 | testDependencyOnBundler1: 114 | name: "Test gemfile depending on Bundler 1" 115 | runs-on: ubuntu-latest 116 | env: 117 | BUNDLE_GEMFILE: gemfiles/bundler1.gemfile 118 | steps: 119 | - uses: actions/checkout@v2 120 | - uses: ./ 121 | with: 122 | ruby-version: 2.7 123 | bundler: 1 124 | bundler-cache: true 125 | - run: bundle --version | grep -F "Bundler version 1." 126 | 127 | testGemfileMatrix: 128 | strategy: 129 | fail-fast: false 130 | matrix: 131 | gemfile: [ rails5, rails6 ] 132 | name: "Test with ${{ matrix.gemfile }} gemfile" 133 | runs-on: ubuntu-latest 134 | env: 135 | BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile 136 | steps: 137 | - uses: actions/checkout@v2 138 | - uses: ./ 139 | with: 140 | ruby-version: 2.6 141 | bundler-cache: true 142 | - run: bundle exec rails --version 143 | 144 | testTruffleRubyNokogiri: 145 | name: "Test installing a Gemfile with nokogiri on TruffleRuby" 146 | runs-on: ubuntu-latest 147 | env: 148 | BUNDLE_GEMFILE: gemfiles/nokogiri.gemfile 149 | steps: 150 | - uses: actions/checkout@v2 151 | - uses: ./ 152 | with: 153 | ruby-version: truffleruby-head 154 | bundler-cache: true 155 | - run: bundle list | grep nokogiri 156 | 157 | lint: 158 | runs-on: ubuntu-20.04 159 | steps: 160 | - uses: actions/checkout@v2 161 | - run: yarn install 162 | - run: yarn run package 163 | - name: Check generated files are up to date 164 | run: git diff --exit-code 165 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | 3 | # Editors 4 | .vscode 5 | 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Other Dependency directories 41 | jspm_packages/ 42 | 43 | # TypeScript v1 declaration files 44 | typings/ 45 | 46 | # Optional npm cache directory 47 | .npm 48 | 49 | # Optional eslint cache 50 | .eslintcache 51 | 52 | # Optional REPL history 53 | .node_repl_history 54 | 55 | # Output of 'npm pack' 56 | *.tgz 57 | 58 | # Yarn Integrity file 59 | .yarn-integrity 60 | 61 | # dotenv environment variables file 62 | .env 63 | 64 | # next.js build output 65 | .next 66 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/.ruby-version: -------------------------------------------------------------------------------- 1 | ruby-2.6.5 2 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/.tool-versions: -------------------------------------------------------------------------------- 1 | nodejs 12.0.0 2 | ruby 2.7.0 3 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Installing dependencies 4 | 5 | ```bash 6 | $ yarn install 7 | ``` 8 | 9 | `npm` doesn't install the correct dependencies for `eslint` so we use `yarn`. 10 | 11 | ## Regenerating dist/index.js 12 | 13 | ```bash 14 | $ yarn run package 15 | ``` 16 | 17 | It is recommended to add this as a `git` `pre-commit` hook: 18 | 19 | ```bash 20 | $ cp pre-commit .git/hooks/pre-commit 21 | ``` 22 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/Gemfile: -------------------------------------------------------------------------------- 1 | # Used for testing 2 | source 'https://rubygems.org' 3 | 4 | gem "rake" 5 | gem "path" 6 | gem "json", ">= 2.3.0" -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Benoit Daloze 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/README.md: -------------------------------------------------------------------------------- 1 | # setup-ruby 2 | 3 | This action downloads a prebuilt ruby and adds it to the `PATH`. 4 | 5 | It is very efficient and takes about 5 seconds to download, extract and add the given Ruby to the `PATH`. 6 | No extra packages need to be installed. 7 | 8 | Compared to [actions/setup-ruby](https://github.com/actions/setup-ruby), 9 | this actions supports many more versions and features. 10 | 11 | ### Supported Versions 12 | 13 | This action currently supports these versions of MRI, JRuby and TruffleRuby: 14 | 15 | | Interpreter | Versions | 16 | | ----------- | -------- | 17 | | `ruby` | 2.1.9, 2.2, all versions from 2.3.0 until 3.0.1, head, debug, mingw, mswin | 18 | | `jruby` | 9.1.17.0, 9.2.9.0 - 9.2.17.0, head | 19 | | `truffleruby` | 19.3.0 - 21.1.0, head | 20 | 21 | `ruby-debug` is the same as `ruby-head` but with assertions enabled (`-DRUBY_DEBUG=1`). 22 | On Windows, `mingw` and `mswin` are `ruby-head` builds using the MSYS2/MinGW and the MSVC toolchains respectively. 23 | 24 | Preview and RC versions of Ruby might be available too on Ubuntu and macOS (not on Windows). 25 | However, it is recommended to test against `ruby-head` rather than previews, 26 | as it provides more useful feedback for the Ruby core team and for upcoming changes. 27 | 28 | Only versions published by [RubyInstaller](https://rubyinstaller.org/downloads/archives/) are available on Windows. 29 | Due to that, Ruby 2.2 resolves to 2.2.6 on Windows and 2.2.10 on other platforms. 30 | And Ruby 2.3 on Windows only has builds for 2.3.0, 2.3.1 and 2.3.3. 31 | 32 | Note that Ruby ≤ 2.4 and the OpenSSL version it needs (1.0.2) are both end-of-life, 33 | which means Ruby ≤ 2.4 is unmaintained and considered insecure. 34 | 35 | ### Supported Platforms 36 | 37 | The action works for all [GitHub-hosted runners](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/virtual-environments-for-github-hosted-runners). 38 | 39 | | Operating System | Recommended | Other Supported Versions | 40 | | ----------- | -------- | -------- | 41 | | Ubuntu | `ubuntu-latest` (= `ubuntu-20.04`) | `ubuntu-18.04`, `ubuntu-16.04` | 42 | | macOS | `macos-latest` (= `macos-10.15`) | `macos-11.0` | 43 | | Windows | `windows-latest` (= `windows-2019`) | `windows-2016` | 44 | 45 | The prebuilt releases are generated by [ruby-builder](https://github.com/ruby/ruby-builder) 46 | and on Windows by [RubyInstaller2](https://github.com/oneclick/rubyinstaller2). 47 | `mingw` and `mswin` builds are generated by [ruby-loco](https://github.com/MSP-Greg/ruby-loco). 48 | `ruby-head` is generated by [ruby-dev-builder](https://github.com/ruby/ruby-dev-builder), 49 | `jruby-head` is generated by [jruby-dev-builder](https://github.com/ruby/jruby-dev-builder) 50 | and `truffleruby-head` is generated by [truffleruby-dev-builder](https://github.com/ruby/truffleruby-dev-builder). 51 | The full list of available Ruby versions can be seen in [ruby-builder-versions.js](ruby-builder-versions.js) 52 | for Ubuntu and macOS and in [windows-versions.js](windows-versions.js) for Windows. 53 | 54 | ## Usage 55 | 56 | ### Single Job 57 | 58 | ```yaml 59 | name: My workflow 60 | on: [push, pull_request] 61 | jobs: 62 | test: 63 | runs-on: ubuntu-latest 64 | steps: 65 | - uses: actions/checkout@v2 66 | - uses: ruby/setup-ruby@v1 67 | with: 68 | ruby-version: 2.6 # Not needed with a .ruby-version file 69 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically 70 | - run: bundle exec rake 71 | ``` 72 | 73 | ### Matrix of Ruby Versions 74 | 75 | This matrix tests all stable releases and `head` versions of MRI, JRuby and TruffleRuby on Ubuntu and macOS. 76 | 77 | ```yaml 78 | name: My workflow 79 | on: [push, pull_request] 80 | jobs: 81 | test: 82 | strategy: 83 | fail-fast: false 84 | matrix: 85 | os: [ubuntu-latest, macos-latest] 86 | # Due to https://github.com/actions/runner/issues/849, we have to use quotes for '3.0' 87 | ruby: [2.5, 2.6, 2.7, '3.0', head, jruby, jruby-head, truffleruby, truffleruby-head] 88 | runs-on: ${{ matrix.os }} 89 | steps: 90 | - uses: actions/checkout@v2 91 | - uses: ruby/setup-ruby@v1 92 | with: 93 | ruby-version: ${{ matrix.ruby }} 94 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically 95 | - run: bundle exec rake 96 | ``` 97 | 98 | ### Matrix of Gemfiles 99 | 100 | ```yaml 101 | name: My workflow 102 | on: [push, pull_request] 103 | jobs: 104 | test: 105 | strategy: 106 | fail-fast: false 107 | matrix: 108 | gemfile: [ rails5, rails6 ] 109 | runs-on: ubuntu-latest 110 | env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps 111 | BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile 112 | steps: 113 | - uses: actions/checkout@v2 114 | - uses: ruby/setup-ruby@v1 115 | with: 116 | ruby-version: 2.6 117 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically 118 | - run: bundle exec rake 119 | ``` 120 | 121 | See the GitHub Actions documentation for more details about the 122 | [workflow syntax](https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions) 123 | and the [condition and expression syntax](https://help.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions). 124 | 125 | ### Supported Version Syntax 126 | 127 | * engine-version like `ruby-2.6.5` and `truffleruby-19.3.0` 128 | * short version like `2.6`, automatically using the latest release matching that version (`2.6.5`) 129 | * version only like `2.6.5`, assumes MRI for the engine 130 | * engine only like `truffleruby`, uses the latest stable release of that implementation 131 | * `.ruby-version` reads from the project's `.ruby-version` file 132 | * `.tool-versions` reads from the project's `.tool-versions` file 133 | * If the `ruby-version` input is not specified, `.ruby-version` is tried first, followed by `.tool-versions` 134 | 135 | ### Working Directory 136 | 137 | The `working-directory` input can be set to resolve `.ruby-version`, `.tool-versions` and `Gemfile.lock` 138 | if they are not at the root of the repository, see [action.yml](action.yml) for details. 139 | 140 | ### Bundler 141 | 142 | By default, if there is a `Gemfile.lock` file (or `$BUNDLE_GEMFILE.lock` or `gems.locked`) with a `BUNDLED WITH` section, 143 | that version of Bundler will be installed and used. 144 | Otherwise, the latest compatible Bundler version is installed (Bundler 2 on Ruby >= 2.4, Bundler 1 on Ruby < 2.4). 145 | 146 | This behavior can be customized, see [action.yml](action.yml) for more details about the `bundler` input. 147 | 148 | ### Caching `bundle install` automatically 149 | 150 | This action provides a way to automatically run `bundle install` and cache the result: 151 | ```yaml 152 | - uses: ruby/setup-ruby@v1 153 | with: 154 | bundler-cache: true 155 | ``` 156 | 157 | Note that any step doing `bundle install` (for the root `Gemfile`) or `gem install bundler` can be removed with `bundler-cache: true`. 158 | 159 | This caching speeds up installing gems significantly and avoids too many requests to RubyGems.org. 160 | It needs a `Gemfile` (or `$BUNDLE_GEMFILE` or `gems.rb`) under the [`working-directory`](#working-directory). 161 | If there is a `Gemfile.lock` (or `$BUNDLE_GEMFILE.lock` or `gems.locked`), `bundle config --local deployment true` is used. 162 | 163 | To use a `Gemfile` which is not at the root or has a different name, set `BUNDLE_GEMFILE` in the `env` at the job level 164 | as shown in the [example](#matrix-of-gemfiles). 165 | 166 | #### bundle config 167 | 168 | When using `bundler-cache: true` you might notice there is no good place to run `bundle config ...` commands. 169 | These can be replaced by `BUNDLE_*` environment variables, which are also faster. 170 | They should be set in the `env` at the job level as shown in the [example](#matrix-of-gemfiles). 171 | To find the correct the environment variable name, see the [Bundler docs](https://bundler.io/man/bundle-config.1.html) or look at `.bundle/config` after running `bundle config --local KEY VALUE` locally. 172 | You might need to `"`-quote the environment variable name in YAML if it has unusual characters like `/`. 173 | 174 | To perform caching, this action will use `bundle config --local path $PWD/vendor/bundle`. 175 | Therefore, the Bundler `path` should not be changed in your workflow for the cache to work (no `bundle config path`). 176 | 177 | #### How it Works 178 | 179 | When there is no lockfile, one is generated with `bundle lock`, which is the same as `bundle install` would do first before actually fetching any gem. 180 | In other words, it works exactly like `bundle install`. 181 | The hash of the generated lockfile is then used for caching, which is the only correct approach. 182 | 183 | #### Dealing with a corrupted cache 184 | 185 | In some rare scenarios (like using gems with C extensions whose functionality depends on libraries found on the system 186 | at the time of the gem's build) it may be necessary to ignore contents of the cache and get and build all the gems anew. 187 | In order to achieve this, set the `cache-version` option to any value other than `0` (or change it to a new unique value 188 | if you have already used it before.) 189 | 190 | ```yaml 191 | - uses: ruby/setup-ruby@v1 192 | with: 193 | bundler-cache: true 194 | cache-version: 1 195 | ``` 196 | 197 | #### Caching `bundle install` manually 198 | 199 | It is also possible to cache gems manually, but this is not recommended because it is verbose and *very difficult* to do correctly. 200 | There are many concerns which means using `actions/cache` is never enough for caching gems (e.g., incomplete cache key, cleaning old gems when restoring from another key, correctly hashing the lockfile if not checked in, OS versions, ABI compatibility for `ruby-head`, etc). 201 | So, please use `bundler-cache: true` instead and report any issue. 202 | 203 | ## Windows 204 | 205 | Note that running CI on Windows can be quite challenging if you are not very familiar with Windows. 206 | It is recommended to first get your build working on Ubuntu and macOS before trying Windows. 207 | 208 | * The default shell on Windows is not Bash but [PowerShell](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#using-a-specific-shell). 209 | This can lead issues such as multi-line scripts [not working as expected](https://github.com/ruby/setup-ruby/issues/13). 210 | * The `PATH` contains [multiple compiler toolchains](https://github.com/ruby/setup-ruby/issues/19). Use `where.exe` to debug which tool is used. 211 | * For Ruby ≥ 2.4, MSYS2 is prepended to the `Path`, similar to what RubyInstaller2 does. 212 | * For Ruby < 2.4, the DevKit MSYS tools are installed and prepended to the `Path`. 213 | * JRuby on Windows has a known bug that `bundle exec rake` [fails](https://github.com/ruby/setup-ruby/issues/18). 214 | 215 | ## Versioning 216 | 217 | It is highly recommended to use `ruby/setup-ruby@v1` for the version of this action. 218 | This will provide the best experience by automatically getting bug fixes, new Ruby versions and new features. 219 | 220 | If you instead choose a specific version (v1.2.3) or a commit sha, there will be no automatic bug fixes and 221 | it will be your responsibility to update every time the action no longer works. 222 | Make sure to always use the latest release before reporting an issue on GitHub. 223 | 224 | This action follows semantic versioning with a moving `v1` branch. 225 | This follows the [recommendations](https://github.com/actions/toolkit/blob/master/docs/action-versioning.md) of GitHub Actions. 226 | 227 | ## Using self-hosted runners 228 | 229 | This action might work with [self-hosted runners](https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners) 230 | if the [virtual environment](https://github.com/actions/virtual-environments) is very similar to the ones used by GitHub runners. Notably: 231 | 232 | * Make sure to use the same operating system and version. 233 | * Set the environment variable `ImageOS` on the runner to the corresponding value on GitHub-hosted runners (e.g. `ubuntu18`/`macos1015`/`win19`). This is necessary to detect the operating system and version. 234 | * Make sure to use the same version of libssl. 235 | * Make sure that the operating system has `libyaml-0` installed 236 | * The default tool cache directory (`/opt/hostedtoolcache` on Linux, `/Users/runner/hostedtoolcache` on macOS, 237 | `C:/hostedtoolcache/windows` on Windows) must be writable by the `runner` user. 238 | This is necessary since the Ruby builds embed the install path when built and cannot be moved around. 239 | * `/home/runner` must be writable by the `runner` user. 240 | 241 | In other cases, please use a system Ruby or [install Ruby manually](https://github.com/postmodern/chruby/wiki#installing-rubies) instead. 242 | 243 | ## History 244 | 245 | This action used to be at `eregon/use-ruby-action` and was moved to the `ruby` organization. 246 | Please [update](https://github.com/ruby/setup-ruby/releases/tag/v1.13.0) if you are using `eregon/use-ruby-action`. 247 | 248 | ## Credits 249 | 250 | The current maintainer of this action is @eregon. 251 | Most of the Windows logic is based on work by MSP-Greg. 252 | Many thanks to MSP-Greg and Lars Kanis for the help with Ruby Installer. 253 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Setup Ruby, JRuby and TruffleRuby' 2 | description: 'Download a prebuilt Ruby and add it to the PATH in 5 seconds' 3 | author: 'Benoit Daloze' 4 | branding: 5 | color: red 6 | icon: download 7 | inputs: 8 | ruby-version: 9 | description: 'Engine and version to use, see the syntax in the README. Reads from .ruby-version or .tool-versions if unset.' 10 | required: false 11 | default: 'default' 12 | bundler: 13 | description: | 14 | The version of Bundler to install. Either 'none', 'latest', 'Gemfile.lock', or a version number (e.g., 1, 2, 2.1.4). 15 | For 'Gemfile.lock', the version is determined based on the BUNDLED WITH section from the file Gemfile.lock, $BUNDLE_GEMFILE.lock or gems.locked. 16 | Defaults to 'Gemfile.lock' if the file exists and 'latest' otherwise. 17 | required: false 18 | default: 'default' 19 | bundler-cache: 20 | description: 'Run "bundle install", and cache the result automatically. Either true or false.' 21 | required: false 22 | default: 'false' 23 | working-directory: 24 | description: 'The working directory to use for resolving paths for .ruby-version, .tool-versions and Gemfile.lock.' 25 | required: false 26 | default: '.' 27 | cache-version: 28 | description: | 29 | Arbitrary string that will be added to the cache key of the bundler cache. Set or change it if you need 30 | to invalidate the cache. 31 | required: false 32 | default: '0' 33 | outputs: 34 | ruby-prefix: 35 | description: 'The prefix of the installed ruby' 36 | runs: 37 | using: 'node12' 38 | main: 'dist/index.js' 39 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/bundler.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const core = require('@actions/core') 4 | const exec = require('@actions/exec') 5 | const cache = require('@actions/cache') 6 | const common = require('./common') 7 | 8 | export const DEFAULT_CACHE_VERSION = '0' 9 | 10 | // The returned gemfile is guaranteed to exist, the lockfile might not exist 11 | export function detectGemfiles() { 12 | const gemfilePath = process.env['BUNDLE_GEMFILE'] || 'Gemfile' 13 | if (fs.existsSync(gemfilePath)) { 14 | return [gemfilePath, `${gemfilePath}.lock`] 15 | } else if (process.env['BUNDLE_GEMFILE']) { 16 | throw new Error(`$BUNDLE_GEMFILE is set to ${gemfilePath} but does not exist`) 17 | } 18 | 19 | if (fs.existsSync("gems.rb")) { 20 | return ["gems.rb", "gems.locked"] 21 | } 22 | 23 | return [null, null] 24 | } 25 | 26 | function readBundledWithFromGemfileLock(lockFile) { 27 | if (lockFile !== null && fs.existsSync(lockFile)) { 28 | const contents = fs.readFileSync(lockFile, 'utf8') 29 | const lines = contents.split(/\r?\n/) 30 | const bundledWithLine = lines.findIndex(line => /^BUNDLED WITH$/.test(line.trim())) 31 | if (bundledWithLine !== -1) { 32 | const nextLine = lines[bundledWithLine+1] 33 | if (nextLine && /^\d+/.test(nextLine.trim())) { 34 | const bundlerVersion = nextLine.trim() 35 | console.log(`Using Bundler ${bundlerVersion} from ${lockFile} BUNDLED WITH ${bundlerVersion}`) 36 | return bundlerVersion 37 | } 38 | } 39 | } 40 | return null 41 | } 42 | 43 | async function afterLockFile(lockFile, platform, engine) { 44 | if (engine === 'truffleruby' && platform.startsWith('ubuntu-')) { 45 | const contents = fs.readFileSync(lockFile, 'utf8') 46 | if (contents.includes('nokogiri')) { 47 | await common.measure('Installing libxml2-dev libxslt-dev, required to install nokogiri on TruffleRuby', async () => 48 | exec.exec('sudo', ['apt-get', '-yqq', 'install', 'libxml2-dev', 'libxslt-dev'], { silent: true })) 49 | } 50 | } 51 | } 52 | 53 | export async function installBundler(bundlerVersionInput, lockFile, platform, rubyPrefix, engine, rubyVersion) { 54 | let bundlerVersion = bundlerVersionInput 55 | 56 | if (bundlerVersion === 'default' || bundlerVersion === 'Gemfile.lock') { 57 | bundlerVersion = readBundledWithFromGemfileLock(lockFile) 58 | 59 | if (!bundlerVersion) { 60 | bundlerVersion = 'latest' 61 | } 62 | } 63 | 64 | if (bundlerVersion === 'latest') { 65 | bundlerVersion = '2' 66 | } 67 | 68 | if (/^\d+/.test(bundlerVersion)) { 69 | // OK 70 | } else { 71 | throw new Error(`Cannot parse bundler input: ${bundlerVersion}`) 72 | } 73 | 74 | if (engine === 'ruby' && rubyVersion.match(/^2\.[012]/)) { 75 | console.log('Bundler 2 requires Ruby 2.3+, using Bundler 1 on Ruby <= 2.2') 76 | bundlerVersion = '1' 77 | } else if (engine === 'ruby' && rubyVersion.match(/^2\.3\.[01]/)) { 78 | console.log('Ruby 2.3.0 and 2.3.1 have shipped with an old rubygems that only works with Bundler 1') 79 | bundlerVersion = '1' 80 | } else if (engine === 'jruby' && rubyVersion.startsWith('9.1')) { // JRuby 9.1 targets Ruby 2.3, treat it the same 81 | console.log('JRuby 9.1 has a bug with Bundler 2 (https://github.com/ruby/setup-ruby/issues/108), using Bundler 1 instead on JRuby 9.1') 82 | bundlerVersion = '1' 83 | } 84 | 85 | if (common.isHeadVersion(rubyVersion) && common.isBundler2Default(engine, rubyVersion) && bundlerVersion.startsWith('2')) { 86 | // Avoid installing a newer Bundler version for head versions as it might not work. 87 | // For releases, even if they ship with Bundler 2 we install the latest Bundler. 88 | console.log(`Using Bundler 2 shipped with ${engine}-${rubyVersion}`) 89 | } else if (engine === 'truffleruby' && !common.isHeadVersion(rubyVersion) && bundlerVersion.startsWith('1')) { 90 | console.log(`Using Bundler 1 shipped with ${engine}`) 91 | } else { 92 | const gem = path.join(rubyPrefix, 'bin', 'gem') 93 | const bundlerVersionConstraint = bundlerVersion.match(/^\d+\.\d+\.\d+/) ? bundlerVersion : `~> ${bundlerVersion}` 94 | await exec.exec(gem, ['install', 'bundler', '-v', bundlerVersionConstraint, '--no-document']) 95 | } 96 | 97 | return bundlerVersion 98 | } 99 | 100 | export async function bundleInstall(gemfile, lockFile, platform, engine, rubyVersion, bundlerVersion, cacheVersion) { 101 | if (gemfile === null) { 102 | console.log('Could not determine gemfile path, skipping "bundle install" and caching') 103 | return false 104 | } 105 | 106 | let envOptions = {} 107 | if (bundlerVersion.startsWith('1') && common.isBundler2Default(engine, rubyVersion)) { 108 | // If Bundler 1 is specified on Rubies which ship with Bundler 2, 109 | // we need to specify which Bundler version to use explicitly until the lockfile exists. 110 | console.log(`Setting BUNDLER_VERSION=${bundlerVersion} for "bundle config|lock" commands below to ensure Bundler 1 is used`) 111 | envOptions = { env: { ...process.env, BUNDLER_VERSION: bundlerVersion } } 112 | } 113 | 114 | // config 115 | const cachePath = 'vendor/bundle' 116 | // An absolute path, so it is reliably under $PWD/vendor/bundle, and not relative to the gemfile's directory 117 | const bundleCachePath = path.join(process.cwd(), cachePath) 118 | 119 | await exec.exec('bundle', ['config', '--local', 'path', bundleCachePath], envOptions) 120 | 121 | if (fs.existsSync(lockFile)) { 122 | await exec.exec('bundle', ['config', '--local', 'deployment', 'true'], envOptions) 123 | } else { 124 | // Generate the lockfile so we can use it to compute the cache key. 125 | // This will also automatically pick up the latest gem versions compatible with the Gemfile. 126 | await exec.exec('bundle', ['lock'], envOptions) 127 | } 128 | 129 | await afterLockFile(lockFile, platform, engine) 130 | 131 | // cache key 132 | const paths = [cachePath] 133 | const baseKey = await computeBaseKey(platform, engine, rubyVersion, lockFile, cacheVersion) 134 | const key = `${baseKey}-${await common.hashFile(lockFile)}` 135 | // If only Gemfile.lock changes we can reuse part of the cache, and clean old gem versions below 136 | const restoreKeys = [`${baseKey}-`] 137 | console.log(`Cache key: ${key}`) 138 | 139 | // restore cache & install 140 | let cachedKey = null 141 | try { 142 | cachedKey = await cache.restoreCache(paths, key, restoreKeys) 143 | } catch (error) { 144 | if (error.name === cache.ValidationError.name) { 145 | throw error; 146 | } else { 147 | core.info(`[warning] There was an error restoring the cache ${error.message}`) 148 | } 149 | } 150 | 151 | if (cachedKey) { 152 | console.log(`Found cache for key: ${cachedKey}`) 153 | } 154 | 155 | // Always run 'bundle install' to list the gems 156 | await exec.exec('bundle', ['install', '--jobs', '4']) 157 | 158 | // @actions/cache only allows to save for non-existing keys 159 | if (cachedKey !== key) { 160 | if (cachedKey) { // existing cache but Gemfile.lock differs, clean old gems 161 | await exec.exec('bundle', ['clean']) 162 | } 163 | 164 | // Error handling from https://github.com/actions/cache/blob/master/src/save.ts 165 | console.log('Saving cache') 166 | try { 167 | await cache.saveCache(paths, key) 168 | } catch (error) { 169 | if (error.name === cache.ValidationError.name) { 170 | throw error; 171 | } else if (error.name === cache.ReserveCacheError.name) { 172 | core.info(error.message); 173 | } else { 174 | core.info(`[warning]${error.message}`) 175 | } 176 | } 177 | } 178 | 179 | return true 180 | } 181 | 182 | async function computeBaseKey(platform, engine, version, lockFile, cacheVersion) { 183 | const cacheVersionSuffix = DEFAULT_CACHE_VERSION === cacheVersion ? '' : `-cachever:${cacheVersion}` 184 | let key = `setup-ruby-bundler-cache-v3-${platform}-${engine}-${version}${cacheVersionSuffix}` 185 | 186 | if (engine !== 'jruby' && common.isHeadVersion(version)) { 187 | let revision = ''; 188 | await exec.exec('ruby', ['-e', 'print RUBY_REVISION'], { 189 | silent: true, 190 | listeners: { 191 | stdout: (data) => { 192 | revision += data.toString(); 193 | } 194 | } 195 | }); 196 | key += `-revision-${revision}` 197 | } 198 | 199 | key += `-${lockFile}` 200 | return key 201 | } 202 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/common.js: -------------------------------------------------------------------------------- 1 | const os = require('os') 2 | const path = require('path') 3 | const fs = require('fs') 4 | const util = require('util') 5 | const stream = require('stream') 6 | const crypto = require('crypto') 7 | const core = require('@actions/core') 8 | const { performance } = require('perf_hooks') 9 | 10 | export const windows = (os.platform() === 'win32') 11 | // Extract to SSD on Windows, see https://github.com/ruby/setup-ruby/pull/14 12 | export const drive = (windows ? (process.env['GITHUB_WORKSPACE'] || 'C')[0] : undefined) 13 | 14 | export function partition(string, separator) { 15 | const i = string.indexOf(separator) 16 | if (i === -1) { 17 | throw new Error(`No separator ${separator} in string ${string}`) 18 | } 19 | return [string.slice(0, i), string.slice(i + separator.length, string.length)] 20 | } 21 | 22 | let inGroup = false 23 | 24 | export async function measure(name, block) { 25 | const body = async () => { 26 | const start = performance.now() 27 | try { 28 | return await block() 29 | } finally { 30 | const end = performance.now() 31 | const duration = (end - start) / 1000.0 32 | console.log(`Took ${duration.toFixed(2).padStart(6)} seconds`) 33 | } 34 | } 35 | 36 | if (inGroup) { 37 | // Nested groups are not yet supported on GitHub Actions 38 | console.log(`> ${name}`) 39 | return await body() 40 | } else { 41 | inGroup = true 42 | try { 43 | return await core.group(name, body) 44 | } finally { 45 | inGroup = false 46 | } 47 | } 48 | } 49 | 50 | export function isHeadVersion(rubyVersion) { 51 | return rubyVersion === 'head' || rubyVersion === 'debug' || rubyVersion === 'mingw' || rubyVersion === 'mswin' 52 | } 53 | 54 | export function isStableVersion(rubyVersion) { 55 | return /^\d+(\.\d+)*$/.test(rubyVersion) 56 | } 57 | 58 | export function isBundler2Default(engine, rubyVersion) { 59 | if (engine === 'ruby') { 60 | return isHeadVersion(rubyVersion) || floatVersion(rubyVersion) >= 2.7 61 | } else if (engine === 'truffleruby') { 62 | return isHeadVersion(rubyVersion) || floatVersion(rubyVersion) >= 21.0 63 | } else if (engine === 'jruby') { 64 | return isHeadVersion(rubyVersion) || floatVersion(rubyVersion) >= 9.3 65 | } else { 66 | return false 67 | } 68 | } 69 | 70 | export function floatVersion(rubyVersion) { 71 | const match = rubyVersion.match(/^\d+\.\d+/) 72 | if (match) { 73 | return parseFloat(match[0]) 74 | } else { 75 | return 0.0 76 | } 77 | } 78 | 79 | export async function hashFile(file) { 80 | // See https://github.com/actions/runner/blob/master/src/Misc/expressionFunc/hashFiles/src/hashFiles.ts 81 | const hash = crypto.createHash('sha256') 82 | const pipeline = util.promisify(stream.pipeline) 83 | await pipeline(fs.createReadStream(file), hash) 84 | return hash.digest('hex') 85 | } 86 | 87 | function getImageOS() { 88 | const imageOS = process.env['ImageOS'] 89 | if (!imageOS) { 90 | throw new Error('The environment variable ImageOS must be set') 91 | } 92 | return imageOS 93 | } 94 | 95 | export function getVirtualEnvironmentName() { 96 | const imageOS = getImageOS() 97 | 98 | let match = imageOS.match(/^ubuntu(\d+)/) // e.g. ubuntu18 99 | if (match) { 100 | return `ubuntu-${match[1]}.04` 101 | } 102 | 103 | match = imageOS.match(/^macos(\d{2})(\d+)?/) // e.g. macos1015, macos11 104 | if (match) { 105 | return `macos-${match[1]}.${match[2] || '0'}` 106 | } 107 | 108 | match = imageOS.match(/^win(\d+)/) // e.g. win19 109 | if (match) { 110 | return `windows-20${match[1]}` 111 | } 112 | 113 | throw new Error(`Unknown ImageOS ${imageOS}`) 114 | } 115 | 116 | export function shouldUseToolCache(engine, version) { 117 | return engine === 'ruby' && !isHeadVersion(version) 118 | } 119 | 120 | function getPlatformToolCache(platform) { 121 | // Hardcode paths rather than using $RUNNER_TOOL_CACHE because the prebuilt Rubies cannot be moved anyway 122 | if (platform.startsWith('ubuntu-')) { 123 | return '/opt/hostedtoolcache' 124 | } else if (platform.startsWith('macos-')) { 125 | return '/Users/runner/hostedtoolcache' 126 | } else if (platform.startsWith('windows-')) { 127 | return 'C:/hostedtoolcache/windows' 128 | } else { 129 | throw new Error('Unknown platform') 130 | } 131 | } 132 | 133 | export function getToolCacheRubyPrefix(platform, version) { 134 | const toolCache = getPlatformToolCache(platform) 135 | return path.join(toolCache, 'Ruby', version, 'x64') 136 | } 137 | 138 | export function createToolCacheCompleteFile(toolCacheRubyPrefix) { 139 | const completeFile = `${toolCacheRubyPrefix}.complete` 140 | fs.writeFileSync(completeFile, '') 141 | } 142 | 143 | // convert windows path like C:\Users\runneradmin to /c/Users/runneradmin 144 | export function win2nix(path) { 145 | if (/^[A-Z]:/i.test(path)) { 146 | // path starts with drive 147 | path = `/${path[0].toLowerCase()}${partition(path, ':')[1]}` 148 | } 149 | return path.replace(/\\/g, '/').replace(/ /g, '\\ ') 150 | } 151 | 152 | export function setupPath(newPathEntries) { 153 | const envPath = windows ? 'Path' : 'PATH' 154 | const originalPath = process.env[envPath].split(path.delimiter) 155 | let cleanPath = originalPath.filter(entry => !/\bruby\b/i.test(entry)) 156 | 157 | // First remove the conflicting path entries 158 | if (cleanPath.length !== originalPath.length) { 159 | core.startGroup(`Cleaning ${envPath}`) 160 | console.log(`Entries removed from ${envPath} to avoid conflicts with Ruby:`) 161 | for (const entry of originalPath) { 162 | if (!cleanPath.includes(entry)) { 163 | console.log(` ${entry}`) 164 | } 165 | } 166 | core.exportVariable(envPath, cleanPath.join(path.delimiter)) 167 | core.endGroup() 168 | } 169 | 170 | // Then add new path entries using core.addPath() 171 | let newPath 172 | if (windows) { 173 | // add MSYS2 in path for all Rubies on Windows, as it provides a better bash shell and a native toolchain 174 | const msys2 = ['C:\\msys64\\mingw64\\bin', 'C:\\msys64\\usr\\bin'] 175 | newPath = [...newPathEntries, ...msys2] 176 | } else { 177 | newPath = newPathEntries 178 | } 179 | core.addPath(newPath.join(path.delimiter)) 180 | } 181 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/gemfiles/bundler1.gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem "bundler", "~> 1.0" 4 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/gemfiles/nokogiri.gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "nokogiri" 4 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/gemfiles/rails5.gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "rails", "~> 5.2.0" 4 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/gemfiles/rails6.gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "rails", "~> 6.0.0" 4 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/generate-windows-versions.rb: -------------------------------------------------------------------------------- 1 | require 'net/http' 2 | require 'yaml' 3 | require 'json' 4 | 5 | min_requirements = ['~> 2.1.9', '>= 2.2.6'].map { |req| Gem::Requirement.new(req) } 6 | 7 | url = 'https://raw.githubusercontent.com/oneclick/rubyinstaller.org-website/master/_data/downloads.yaml' 8 | entries = YAML.load(Net::HTTP.get(URI(url)), symbolize_names: true) 9 | 10 | versions = entries.select { |entry| 11 | entry[:filetype] == 'rubyinstaller7z' and 12 | entry[:name].include?('(x64)') 13 | }.group_by { |entry| 14 | entry[:name][/Ruby (\d+\.\d+\.\d+)/, 1] 15 | }.map { |version, builds| 16 | unless builds.sort_by { |build| build[:name] } == builds.reverse 17 | raise "not sorted as expected for #{version}" 18 | end 19 | [version, builds.first] 20 | }.sort_by { |version, entry| 21 | Gem::Version.new(version) 22 | }.select { |version, entry| 23 | min_requirements.any? { |req| req.satisfied_by?(Gem::Version.new(version)) } 24 | }.map { |version, entry| 25 | [version, entry[:href]] 26 | }.to_h 27 | 28 | versions['head'] = 'https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-head/rubyinstaller-head-x64.7z' 29 | versions['mingw'] = 'https://github.com/MSP-Greg/ruby-loco/releases/download/ruby-master/ruby-mingw.7z' 30 | versions['mswin'] = 'https://github.com/MSP-Greg/ruby-loco/releases/download/ruby-master/ruby-mswin.7z' 31 | 32 | js = "export const versions = #{JSON.pretty_generate(versions)}\n" 33 | File.binwrite 'windows-versions.js', js 34 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/index.js: -------------------------------------------------------------------------------- 1 | const os = require('os') 2 | const fs = require('fs') 3 | const path = require('path') 4 | const core = require('@actions/core') 5 | const common = require('./common') 6 | const bundler = require('./bundler') 7 | 8 | const windows = common.windows 9 | 10 | const inputDefaults = { 11 | 'ruby-version': 'default', 12 | 'bundler': 'default', 13 | 'bundler-cache': 'true', 14 | 'working-directory': '.', 15 | 'cache-version': bundler.DEFAULT_CACHE_VERSION, 16 | } 17 | 18 | // entry point when this action is run on its own 19 | export async function run() { 20 | try { 21 | await setupRuby() 22 | } catch (error) { 23 | core.setFailed(error.message) 24 | } 25 | } 26 | 27 | // entry point when this action is run from other actions 28 | export async function setupRuby(options = {}) { 29 | const inputs = { ...options } 30 | for (const key in inputDefaults) { 31 | if (!Object.prototype.hasOwnProperty.call(inputs, key)) { 32 | inputs[key] = core.getInput(key) || inputDefaults[key] 33 | } 34 | } 35 | 36 | process.chdir(inputs['working-directory']) 37 | 38 | const platform = common.getVirtualEnvironmentName() 39 | const [engine, parsedVersion] = parseRubyEngineAndVersion(inputs['ruby-version']) 40 | 41 | let installer 42 | if (platform.startsWith('windows-') && engine !== 'jruby') { 43 | installer = require('./windows') 44 | } else { 45 | installer = require('./ruby-builder') 46 | } 47 | 48 | const engineVersions = installer.getAvailableVersions(platform, engine) 49 | const version = validateRubyEngineAndVersion(platform, engineVersions, engine, parsedVersion) 50 | 51 | createGemRC() 52 | envPreInstall() 53 | 54 | const rubyPrefix = await installer.install(platform, engine, version) 55 | 56 | // When setup-ruby is used by other actions, this allows code in them to run 57 | // before 'bundle install'. Installed dependencies may require additional 58 | // libraries & headers, build tools, etc. 59 | if (inputs['afterSetupPathHook'] instanceof Function) { 60 | await inputs['afterSetupPathHook']({ platform, rubyPrefix, engine, version }) 61 | } 62 | 63 | if (inputs['bundler'] !== 'none') { 64 | const [gemfile, lockFile] = bundler.detectGemfiles() 65 | 66 | const bundlerVersion = await common.measure('Installing Bundler', async () => 67 | bundler.installBundler(inputs['bundler'], lockFile, platform, rubyPrefix, engine, version)) 68 | 69 | if (inputs['bundler-cache'] === 'true') { 70 | await common.measure('bundle install', async () => 71 | bundler.bundleInstall(gemfile, lockFile, platform, engine, version, bundlerVersion, inputs['cache-version'])) 72 | } 73 | } 74 | 75 | core.setOutput('ruby-prefix', rubyPrefix) 76 | } 77 | 78 | function parseRubyEngineAndVersion(rubyVersion) { 79 | if (rubyVersion === 'default') { 80 | if (fs.existsSync('.ruby-version')) { 81 | rubyVersion = '.ruby-version' 82 | } else if (fs.existsSync('.tool-versions')) { 83 | rubyVersion = '.tool-versions' 84 | } else { 85 | throw new Error('input ruby-version needs to be specified if no .ruby-version or .tool-versions file exists') 86 | } 87 | } 88 | 89 | if (rubyVersion === '.ruby-version') { // Read from .ruby-version 90 | rubyVersion = fs.readFileSync('.ruby-version', 'utf8').trim() 91 | console.log(`Using ${rubyVersion} as input from file .ruby-version`) 92 | } else if (rubyVersion === '.tool-versions') { // Read from .tool-versions 93 | const toolVersions = fs.readFileSync('.tool-versions', 'utf8').trim() 94 | const rubyLine = toolVersions.split(/\r?\n/).filter(e => e.match(/^ruby\s/))[0] 95 | rubyVersion = rubyLine.match(/^ruby\s+(.+)$/)[1] 96 | console.log(`Using ${rubyVersion} as input from file .tool-versions`) 97 | } 98 | 99 | let engine, version 100 | if (rubyVersion.match(/^(\d+)/) || common.isHeadVersion(rubyVersion)) { // X.Y.Z => ruby-X.Y.Z 101 | engine = 'ruby' 102 | version = rubyVersion 103 | } else if (!rubyVersion.includes('-')) { // myruby -> myruby-stableVersion 104 | engine = rubyVersion 105 | version = '' // Let the logic in validateRubyEngineAndVersion() find the version 106 | } else { // engine-X.Y.Z 107 | [engine, version] = common.partition(rubyVersion, '-') 108 | } 109 | 110 | return [engine, version] 111 | } 112 | 113 | function validateRubyEngineAndVersion(platform, engineVersions, engine, parsedVersion) { 114 | if (!engineVersions) { 115 | throw new Error(`Unknown engine ${engine} on ${platform}`) 116 | } 117 | 118 | let version = parsedVersion 119 | if (!engineVersions.includes(parsedVersion)) { 120 | const latestToFirstVersion = engineVersions.slice().reverse() 121 | // Try to match stable versions first, so an empty version (engine-only) matches the latest stable version 122 | let found = latestToFirstVersion.find(v => common.isStableVersion(v) && v.startsWith(parsedVersion)) 123 | if (!found) { 124 | // Exclude head versions, they must be exact matches 125 | found = latestToFirstVersion.find(v => !common.isHeadVersion(v) && v.startsWith(parsedVersion)) 126 | } 127 | 128 | if (found) { 129 | version = found 130 | } else { 131 | throw new Error(`Unknown version ${parsedVersion} for ${engine} on ${platform} 132 | available versions for ${engine} on ${platform}: ${engineVersions.join(', ')} 133 | Make sure you use the latest version of the action with - uses: ruby/setup-ruby@v1 134 | File an issue at https://github.com/ruby/setup-ruby/issues if would like support for a new version`) 135 | } 136 | } 137 | 138 | return version 139 | } 140 | 141 | function createGemRC() { 142 | const gemrc = path.join(os.homedir(), '.gemrc') 143 | if (!fs.existsSync(gemrc)) { 144 | fs.writeFileSync(gemrc, `gem: --no-document${os.EOL}`) 145 | } 146 | } 147 | 148 | // sets up ENV variables 149 | // currently only used on Windows runners 150 | function envPreInstall() { 151 | const ENV = process.env 152 | if (windows) { 153 | // puts normal Ruby temp folder on SSD 154 | core.exportVariable('TMPDIR', ENV['RUNNER_TEMP']) 155 | // bash - sets home to match native windows, normally C:\Users\ 156 | core.exportVariable('HOME', ENV['HOMEDRIVE'] + ENV['HOMEPATH']) 157 | // bash - needed to maintain Path from Windows 158 | core.exportVariable('MSYS2_PATH_TYPE', 'inherit') 159 | } 160 | } 161 | 162 | if (__filename.endsWith('index.js')) { run() } 163 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "setup-ruby", 3 | "version": "0.1.0", 4 | "description": "Download a prebuilt Ruby and add it to the PATH in 5 seconds", 5 | "main": "index.js", 6 | "scripts": { 7 | "package": "ncc build index.js -o dist" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/ruby/setup-ruby.git" 12 | }, 13 | "keywords": [ 14 | "GitHub", 15 | "Actions", 16 | "Ruby" 17 | ], 18 | "author": "Benoit Daloze", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/ruby/setup-ruby/issues" 22 | }, 23 | "homepage": "https://github.com/ruby/setup-ruby", 24 | "dependencies": { 25 | "@actions/cache": "^1.0.5", 26 | "@actions/core": "^1.2.6", 27 | "@actions/exec": "^1.0.3", 28 | "@actions/io": "^1.0.2", 29 | "@actions/tool-cache": "^1.3.4" 30 | }, 31 | "devDependencies": { 32 | "@vercel/ncc": "^0.23.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/sh 2 | set -e 3 | yarn install 4 | yarn run package 5 | exec git add dist/index.js 6 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/ruby-builder-versions.js: -------------------------------------------------------------------------------- 1 | export function getVersions(platform) { 2 | const versions = { 3 | "ruby": [ 4 | "2.1.9", 5 | "2.2.10", 6 | "2.3.0", "2.3.1", "2.3.2", "2.3.3", "2.3.4", "2.3.5", "2.3.6", "2.3.7", "2.3.8", 7 | "2.4.0", "2.4.1", "2.4.2", "2.4.3", "2.4.4", "2.4.5", "2.4.6", "2.4.7", "2.4.9", "2.4.10", 8 | "2.5.0", "2.5.1", "2.5.2", "2.5.3", "2.5.4", "2.5.5", "2.5.6", "2.5.7", "2.5.8", "2.5.9", 9 | "2.6.0", "2.6.1", "2.6.2", "2.6.3", "2.6.4", "2.6.5", "2.6.6", "2.6.7", 10 | "2.7.0", "2.7.1", "2.7.2", "2.7.3", 11 | "3.0.0-preview1", "3.0.0-preview2", "3.0.0-rc1", "3.0.0", "3.0.1", 12 | "head", "debug", 13 | ], 14 | "jruby": [ 15 | "9.1.17.0", 16 | "9.2.9.0", "9.2.10.0", "9.2.11.0", "9.2.11.1", "9.2.12.0", "9.2.13.0", "9.2.14.0", "9.2.15.0", "9.2.16.0", "9.2.17.0", 17 | "head" 18 | ], 19 | "truffleruby": [ 20 | "19.3.0", "19.3.1", 21 | "20.0.0", "20.1.0", "20.2.0", "20.3.0", 22 | "21.0.0", "21.1.0", 23 | "head" 24 | ] 25 | } 26 | 27 | return versions 28 | } 29 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/ruby-builder.js: -------------------------------------------------------------------------------- 1 | const os = require('os') 2 | const path = require('path') 3 | const exec = require('@actions/exec') 4 | const io = require('@actions/io') 5 | const tc = require('@actions/tool-cache') 6 | const common = require('./common') 7 | const rubyBuilderVersions = require('./ruby-builder-versions') 8 | 9 | const builderReleaseTag = 'toolcache' 10 | const releasesURL = 'https://github.com/ruby/ruby-builder/releases' 11 | 12 | const windows = common.windows 13 | 14 | export function getAvailableVersions(platform, engine) { 15 | return rubyBuilderVersions.getVersions(platform)[engine] 16 | } 17 | 18 | export async function install(platform, engine, version) { 19 | let rubyPrefix, inToolCache 20 | if (common.shouldUseToolCache(engine, version)) { 21 | inToolCache = tc.find('Ruby', version) 22 | if (inToolCache) { 23 | rubyPrefix = inToolCache 24 | } else { 25 | rubyPrefix = common.getToolCacheRubyPrefix(platform, version) 26 | } 27 | } else if (windows) { 28 | rubyPrefix = path.join(`${common.drive}:`, `${engine}-${version}`) 29 | } else { 30 | rubyPrefix = path.join(os.homedir(), '.rubies', `${engine}-${version}`) 31 | } 32 | 33 | // Set the PATH now, so the MSYS2 'tar' is in Path on Windows 34 | common.setupPath([path.join(rubyPrefix, 'bin')]) 35 | 36 | if (!inToolCache) { 37 | await downloadAndExtract(platform, engine, version, rubyPrefix); 38 | } 39 | 40 | return rubyPrefix 41 | } 42 | 43 | async function downloadAndExtract(platform, engine, version, rubyPrefix) { 44 | const parentDir = path.dirname(rubyPrefix) 45 | 46 | await io.rmRF(rubyPrefix) 47 | await io.mkdirP(parentDir) 48 | 49 | const downloadPath = await common.measure('Downloading Ruby', async () => { 50 | const url = getDownloadURL(platform, engine, version) 51 | console.log(url) 52 | return await tc.downloadTool(url) 53 | }) 54 | 55 | await common.measure('Extracting Ruby', async () => { 56 | if (windows) { 57 | // Windows 2016 doesn't have system tar, use MSYS2's, it needs unix style paths 58 | await exec.exec('tar', ['-xz', '-C', common.win2nix(parentDir), '-f', common.win2nix(downloadPath)]) 59 | } else { 60 | await exec.exec('tar', ['-xz', '-C', parentDir, '-f', downloadPath]) 61 | } 62 | }) 63 | 64 | if (common.shouldUseToolCache(engine, version)) { 65 | common.createToolCacheCompleteFile(rubyPrefix) 66 | } 67 | } 68 | 69 | function getDownloadURL(platform, engine, version) { 70 | let builderPlatform = platform 71 | if (platform.startsWith('windows-')) { 72 | builderPlatform = 'windows-latest' 73 | } else if (platform.startsWith('macos-')) { 74 | builderPlatform = 'macos-latest' 75 | } 76 | 77 | if (common.isHeadVersion(version)) { 78 | return getLatestHeadBuildURL(builderPlatform, engine, version) 79 | } else { 80 | return `${releasesURL}/download/${builderReleaseTag}/${engine}-${version}-${builderPlatform}.tar.gz` 81 | } 82 | } 83 | 84 | function getLatestHeadBuildURL(platform, engine, version) { 85 | return `https://github.com/ruby/${engine}-dev-builder/releases/latest/download/${engine}-${version}-${platform}.tar.gz` 86 | } 87 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/test_subprocess.rb: -------------------------------------------------------------------------------- 1 | require 'rbconfig' 2 | require 'stringio' 3 | 4 | puts "CPPFLAGS: #{RbConfig::CONFIG["CPPFLAGS"]}" 5 | 6 | $stderr = StringIO.new 7 | begin 8 | system RbConfig.ruby, "-e", "p :OK" 9 | out = $stderr.string 10 | ensure 11 | $stderr = STDERR 12 | end 13 | abort out unless out.empty? 14 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/versions-strings-for-builder.rb: -------------------------------------------------------------------------------- 1 | hash = File.read('ruby-builder-versions.js')[/\bversions = {[^}]+}/] 2 | versions = eval hash 3 | 4 | by_minor = versions[:ruby].group_by { |v| v[/^\d\.\d/] } 5 | 6 | (1..7).each do |minor| 7 | p by_minor["2.#{minor}"].map { |v| "ruby-#{v}" } 8 | end 9 | 10 | puts 11 | p (versions[:truffleruby] - %w[head]).map { |v| "truffleruby-#{v}" } 12 | 13 | puts 14 | p (versions[:jruby] - %w[head]).map { |v| "jruby-#{v}" } 15 | 16 | (versions[:jruby] - %w[head]).each do |v| 17 | puts "- { os: windows-latest, jruby-version: #{v}, ruby: jruby-#{v} }" 18 | end 19 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/windows-versions.js: -------------------------------------------------------------------------------- 1 | export const versions = { 2 | "2.1.9": "https://github.com/oneclick/rubyinstaller/releases/download/ruby-2.1.9/ruby-2.1.9-x64-mingw32.7z", 3 | "2.2.6": "https://github.com/oneclick/rubyinstaller/releases/download/ruby-2.2.6/ruby-2.2.6-x64-mingw32.7z", 4 | "2.3.0": "https://github.com/oneclick/rubyinstaller/releases/download/ruby-2.3.0/ruby-2.3.0-x64-mingw32.7z", 5 | "2.3.1": "https://github.com/oneclick/rubyinstaller/releases/download/ruby-2.3.1/ruby-2.3.1-x64-mingw32.7z", 6 | "2.3.3": "https://github.com/oneclick/rubyinstaller/releases/download/ruby-2.3.3/ruby-2.3.3-x64-mingw32.7z", 7 | "2.4.1": "https://github.com/oneclick/rubyinstaller2/releases/download/2.4.1-2/rubyinstaller-2.4.1-2-x64.7z", 8 | "2.4.2": "https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-2.4.2-2/rubyinstaller-2.4.2-2-x64.7z", 9 | "2.4.3": "https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-2.4.3-2/rubyinstaller-2.4.3-2-x64.7z", 10 | "2.4.4": "https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-2.4.4-2/rubyinstaller-2.4.4-2-x64.7z", 11 | "2.4.5": "https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-2.4.5-1/rubyinstaller-2.4.5-1-x64.7z", 12 | "2.4.6": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.4.6-1/rubyinstaller-2.4.6-1-x64.7z", 13 | "2.4.7": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.4.7-1/rubyinstaller-2.4.7-1-x64.7z", 14 | "2.4.9": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.4.9-1/rubyinstaller-2.4.9-1-x64.7z", 15 | "2.4.10": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.4.10-1/rubyinstaller-2.4.10-1-x64.7z", 16 | "2.5.0": "https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-2.5.0-2/rubyinstaller-2.5.0-2-x64.7z", 17 | "2.5.1": "https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-2.5.1-2/rubyinstaller-2.5.1-2-x64.7z", 18 | "2.5.3": "https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-2.5.3-1/rubyinstaller-2.5.3-1-x64.7z", 19 | "2.5.5": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.5.5-1/rubyinstaller-2.5.5-1-x64.7z", 20 | "2.5.6": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.5.6-1/rubyinstaller-2.5.6-1-x64.7z", 21 | "2.5.7": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.5.7-1/rubyinstaller-2.5.7-1-x64.7z", 22 | "2.5.8": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.5.8-2/rubyinstaller-2.5.8-2-x64.7z", 23 | "2.5.9": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.5.9-1/rubyinstaller-2.5.9-1-x64.7z", 24 | "2.6.0": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.6.0-1/rubyinstaller-2.6.0-1-x64.7z", 25 | "2.6.1": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.6.1-1/rubyinstaller-2.6.1-1-x64.7z", 26 | "2.6.2": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.6.2-1/rubyinstaller-2.6.2-1-x64.7z", 27 | "2.6.3": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.6.3-1/rubyinstaller-2.6.3-1-x64.7z", 28 | "2.6.4": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.6.4-1/rubyinstaller-2.6.4-1-x64.7z", 29 | "2.6.5": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.6.5-1/rubyinstaller-2.6.5-1-x64.7z", 30 | "2.6.6": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.6.6-2/rubyinstaller-2.6.6-2-x64.7z", 31 | "2.6.7": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.6.7-1/rubyinstaller-2.6.7-1-x64.7z", 32 | "2.7.0": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.7.0-1/rubyinstaller-2.7.0-1-x64.7z", 33 | "2.7.1": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.7.1-1/rubyinstaller-2.7.1-1-x64.7z", 34 | "2.7.2": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.7.2-1/rubyinstaller-2.7.2-1-x64.7z", 35 | "2.7.3": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-2.7.3-1/rubyinstaller-2.7.3-1-x64.7z", 36 | "3.0.0": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-3.0.0-1/rubyinstaller-3.0.0-1-x64.7z", 37 | "3.0.1": "https://github.com/oneclick/rubyinstaller2/releases/download/RubyInstaller-3.0.1-1/rubyinstaller-3.0.1-1-x64.7z", 38 | "head": "https://github.com/oneclick/rubyinstaller2/releases/download/rubyinstaller-head/rubyinstaller-head-x64.7z", 39 | "mingw": "https://github.com/MSP-Greg/ruby-loco/releases/download/ruby-master/ruby-mingw.7z", 40 | "mswin": "https://github.com/MSP-Greg/ruby-loco/releases/download/ruby-master/ruby-mswin.7z" 41 | } 42 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/windows.js: -------------------------------------------------------------------------------- 1 | // Most of this logic is from 2 | // https://github.com/MSP-Greg/actions-ruby/blob/master/lib/main.js 3 | 4 | const fs = require('fs') 5 | const path = require('path') 6 | const cp = require('child_process') 7 | const core = require('@actions/core') 8 | const exec = require('@actions/exec') 9 | const io = require('@actions/io') 10 | const tc = require('@actions/tool-cache') 11 | const common = require('./common') 12 | const rubyInstallerVersions = require('./windows-versions').versions 13 | 14 | const drive = common.drive 15 | 16 | // needed for 2.1, 2.2, 2.3, and mswin, cert file used by Git for Windows 17 | const certFile = 'C:\\Program Files\\Git\\mingw64\\ssl\\cert.pem' 18 | 19 | // location & path for old RubyInstaller DevKit (MSYS), Ruby 2.1, 2.2 and 2.3 20 | const msys = `${drive}:\\DevKit64` 21 | const msysPathEntries = [`${msys}\\mingw\\x86_64-w64-mingw32\\bin`, `${msys}\\mingw\\bin`, `${msys}\\bin`] 22 | 23 | export function getAvailableVersions(platform, engine) { 24 | if (engine === 'ruby') { 25 | return Object.keys(rubyInstallerVersions) 26 | } else { 27 | return undefined 28 | } 29 | } 30 | 31 | export async function install(platform, engine, version) { 32 | const url = rubyInstallerVersions[version] 33 | 34 | if (!url.endsWith('.7z')) { 35 | throw new Error(`URL should end in .7z: ${url}`) 36 | } 37 | const base = url.slice(url.lastIndexOf('/') + 1, url.length - '.7z'.length) 38 | 39 | let rubyPrefix, inToolCache 40 | if (common.shouldUseToolCache(engine, version)) { 41 | inToolCache = tc.find('Ruby', version) 42 | if (inToolCache) { 43 | rubyPrefix = inToolCache 44 | } else { 45 | rubyPrefix = common.getToolCacheRubyPrefix(platform, version) 46 | } 47 | } else { 48 | rubyPrefix = `${drive}:\\${base}` 49 | } 50 | 51 | let toolchainPaths = (version === 'mswin') ? await setupMSWin() : await setupMingw(version) 52 | 53 | common.setupPath([`${rubyPrefix}\\bin`, ...toolchainPaths]) 54 | 55 | if (!inToolCache) { 56 | await downloadAndExtract(engine, version, url, base, rubyPrefix); 57 | } 58 | 59 | return rubyPrefix 60 | } 61 | 62 | async function downloadAndExtract(engine, version, url, base, rubyPrefix) { 63 | const parentDir = path.dirname(rubyPrefix) 64 | 65 | const downloadPath = await common.measure('Downloading Ruby', async () => { 66 | console.log(url) 67 | return await tc.downloadTool(url) 68 | }) 69 | 70 | await common.measure('Extracting Ruby', async () => 71 | exec.exec('7z', ['x', downloadPath, `-xr!${base}\\share\\doc`, `-o${parentDir}`], { silent: true })) 72 | 73 | if (base !== path.basename(rubyPrefix)) { 74 | await io.mv(path.join(parentDir, base), rubyPrefix) 75 | } 76 | 77 | if (common.shouldUseToolCache(engine, version)) { 78 | common.createToolCacheCompleteFile(rubyPrefix) 79 | } 80 | } 81 | 82 | async function setupMingw(version) { 83 | core.exportVariable('MAKE', 'make.exe') 84 | 85 | if (version.match(/^2\.[123]/)) { 86 | core.exportVariable('SSL_CERT_FILE', certFile) 87 | await common.measure('Installing MSYS', async () => installMSYS(version)) 88 | return msysPathEntries 89 | } else { 90 | return [] 91 | } 92 | } 93 | 94 | // Ruby 2.1, 2.2 and 2.3 95 | async function installMSYS(version) { 96 | const url = 'https://github.com/oneclick/rubyinstaller/releases/download/devkit-4.7.2/DevKit-mingw64-64-4.7.2-20130224-1432-sfx.exe' 97 | const downloadPath = await tc.downloadTool(url) 98 | await exec.exec('7z', ['x', downloadPath, `-o${msys}`], { silent: true }) 99 | 100 | // below are set in the old devkit.rb file ? 101 | core.exportVariable('RI_DEVKIT', msys) 102 | core.exportVariable('CC' , 'gcc') 103 | core.exportVariable('CXX', 'g++') 104 | core.exportVariable('CPP', 'cpp') 105 | core.info(`Installed RubyInstaller DevKit for Ruby ${version}`) 106 | } 107 | 108 | async function setupMSWin() { 109 | core.exportVariable('MAKE', 'nmake.exe') 110 | 111 | // All standard MSVC OpenSSL builds use C:\Program Files\Common Files\SSL 112 | const certsDir = 'C:\\Program Files\\Common Files\\SSL\\certs' 113 | if (!fs.existsSync(certsDir)) { 114 | fs.mkdirSync(certsDir) 115 | } 116 | 117 | // cert.pem location is hard-coded by OpenSSL msvc builds 118 | const cert = 'C:\\Program Files\\Common Files\\SSL\\cert.pem' 119 | if (!fs.existsSync(cert)) { 120 | fs.copyFileSync(certFile, cert) 121 | } 122 | 123 | return await common.measure('Setting up MSVC environment', async () => addVCVARSEnv()) 124 | } 125 | 126 | /* Sets MSVC environment for use in Actions 127 | * allows steps to run without running vcvars*.bat, also for PowerShell 128 | * adds a convenience VCVARS environment variable 129 | * this assumes a single Visual Studio version being available in the windows-latest image */ 130 | export function addVCVARSEnv() { 131 | const vcVars = '"C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\VC\\Auxiliary\\Build\\vcvars64.bat"' 132 | core.exportVariable('VCVARS', vcVars) 133 | 134 | let newEnv = new Map() 135 | let cmd = `cmd.exe /c "${vcVars} && set"` 136 | let newSet = cp.execSync(cmd).toString().trim().split(/\r?\n/) 137 | newSet = newSet.filter(line => line.match(/\S=\S/)) 138 | newSet.forEach(s => { 139 | let [k,v] = common.partition(s, '=') 140 | newEnv.set(k,v) 141 | }) 142 | 143 | let newPathEntries = undefined 144 | for (let [k, v] of newEnv) { 145 | if (process.env[k] !== v) { 146 | if (/^Path$/i.test(k)) { 147 | const newPathStr = v.replace(`${path.delimiter}${process.env['Path']}`, '') 148 | newPathEntries = newPathStr.split(path.delimiter) 149 | } else { 150 | core.exportVariable(k, v) 151 | } 152 | } 153 | } 154 | return newPathEntries 155 | } 156 | -------------------------------------------------------------------------------- /.github/actions/setup-ruby-1.71.0/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@actions/cache@^1.0.5": 6 | version "1.0.5" 7 | resolved "https://registry.yarnpkg.com/@actions/cache/-/cache-1.0.5.tgz#ba98725d38611b5426fc57a2f00bd8b0d9202f36" 8 | integrity sha512-TcvJOduwsPP27KLmIa5cqXsQYFK2GzILcEpnhvYmhGwi1aYx9XwhKmp6Im8X6DJMBxbvupKPsOntG6f6sSkIPA== 9 | dependencies: 10 | "@actions/core" "^1.2.6" 11 | "@actions/exec" "^1.0.1" 12 | "@actions/glob" "^0.1.0" 13 | "@actions/http-client" "^1.0.9" 14 | "@actions/io" "^1.0.1" 15 | "@azure/ms-rest-js" "^2.0.7" 16 | "@azure/storage-blob" "^12.1.2" 17 | semver "^6.1.0" 18 | uuid "^3.3.3" 19 | 20 | "@actions/core@^1.2.0", "@actions/core@^1.2.3", "@actions/core@^1.2.6": 21 | version "1.2.6" 22 | resolved "https://registry.yarnpkg.com/@actions/core/-/core-1.2.6.tgz#a78d49f41a4def18e88ce47c2cac615d5694bf09" 23 | integrity sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA== 24 | 25 | "@actions/exec@^1.0.0", "@actions/exec@^1.0.1", "@actions/exec@^1.0.3": 26 | version "1.0.4" 27 | resolved "https://registry.yarnpkg.com/@actions/exec/-/exec-1.0.4.tgz#99d75310e62e59fc37d2ee6dcff6d4bffadd3a5d" 28 | integrity sha512-4DPChWow9yc9W3WqEbUj8Nr86xkpyE29ZzWjXucHItclLbEW6jr80Zx4nqv18QL6KK65+cifiQZXvnqgTV6oHw== 29 | dependencies: 30 | "@actions/io" "^1.0.1" 31 | 32 | "@actions/glob@^0.1.0": 33 | version "0.1.0" 34 | resolved "https://registry.yarnpkg.com/@actions/glob/-/glob-0.1.0.tgz#969ceda7e089c39343bca3306329f41799732e40" 35 | integrity sha512-lx8SzyQ2FE9+UUvjqY1f28QbTJv+w8qP7kHHbfQRhphrlcx0Mdmm1tZdGJzfxv1jxREa/sLW4Oy8CbGQKCJySA== 36 | dependencies: 37 | "@actions/core" "^1.2.0" 38 | minimatch "^3.0.4" 39 | 40 | "@actions/http-client@^1.0.8": 41 | version "1.0.8" 42 | resolved "https://registry.yarnpkg.com/@actions/http-client/-/http-client-1.0.8.tgz#8bd76e8eca89dc8bcf619aa128eba85f7a39af45" 43 | integrity sha512-G4JjJ6f9Hb3Zvejj+ewLLKLf99ZC+9v+yCxoYf9vSyH+WkzPLB2LuUtRMGNkooMqdugGBFStIKXOuvH1W+EctA== 44 | dependencies: 45 | tunnel "0.0.6" 46 | 47 | "@actions/http-client@^1.0.9": 48 | version "1.0.9" 49 | resolved "https://registry.yarnpkg.com/@actions/http-client/-/http-client-1.0.9.tgz#af1947d020043dbc6a3b4c5918892095c30ffb52" 50 | integrity sha512-0O4SsJ7q+MK0ycvXPl2e6bMXV7dxAXOGjrXS1eTF9s2S401Tp6c/P3c3Joz04QefC1J6Gt942Wl2jbm3f4mLcg== 51 | dependencies: 52 | tunnel "0.0.6" 53 | 54 | "@actions/io@^1.0.1", "@actions/io@^1.0.2": 55 | version "1.0.2" 56 | resolved "https://registry.yarnpkg.com/@actions/io/-/io-1.0.2.tgz#2f614b6e69ce14d191180451eb38e6576a6e6b27" 57 | integrity sha512-J8KuFqVPr3p6U8W93DOXlXW6zFvrQAJANdS+vw0YhusLIq+bszW8zmK2Fh1C2kDPX8FMvwIl1OUcFgvJoXLbAg== 58 | 59 | "@actions/tool-cache@^1.3.4": 60 | version "1.6.0" 61 | resolved "https://registry.yarnpkg.com/@actions/tool-cache/-/tool-cache-1.6.0.tgz#5b425db2d642df65dd0d6bcec0d84dcdbca3f80d" 62 | integrity sha512-+fyEBImPD3m5I0o6DflCO0NHY180LPoX8Lo6y4Iez+V17kO8kfkH0VHxb8mUdmD6hn9dWA9Ch1JA20fXoIYUeQ== 63 | dependencies: 64 | "@actions/core" "^1.2.3" 65 | "@actions/exec" "^1.0.0" 66 | "@actions/http-client" "^1.0.8" 67 | "@actions/io" "^1.0.1" 68 | semver "^6.1.0" 69 | uuid "^3.3.2" 70 | 71 | "@azure/abort-controller@^1.0.0": 72 | version "1.0.1" 73 | resolved "https://registry.yarnpkg.com/@azure/abort-controller/-/abort-controller-1.0.1.tgz#8510935b25ac051e58920300e9d7b511ca6e656a" 74 | integrity sha512-wP2Jw6uPp8DEDy0n4KNidvwzDjyVV2xnycEIq7nPzj1rHyb/r+t3OPeNT1INZePP2wy5ZqlwyuyOMTi0ePyY1A== 75 | dependencies: 76 | tslib "^1.9.3" 77 | 78 | "@azure/core-asynciterator-polyfill@^1.0.0": 79 | version "1.0.0" 80 | resolved "https://registry.yarnpkg.com/@azure/core-asynciterator-polyfill/-/core-asynciterator-polyfill-1.0.0.tgz#dcccebb88406e5c76e0e1d52e8cc4c43a68b3ee7" 81 | integrity sha512-kmv8CGrPfN9SwMwrkiBK9VTQYxdFQEGe0BmQk+M8io56P9KNzpAxcWE/1fxJj7uouwN4kXF0BHW8DNlgx+wtCg== 82 | 83 | "@azure/core-auth@^1.1.3": 84 | version "1.1.3" 85 | resolved "https://registry.yarnpkg.com/@azure/core-auth/-/core-auth-1.1.3.tgz#94e7bbc207010e7a2fdba61565443e4e1cf1e131" 86 | integrity sha512-A4xigW0YZZpkj1zK7dKuzbBpGwnhEcRk6WWuIshdHC32raR3EQ1j6VA9XZqE+RFsUgH6OAmIK5BWIz+mZjnd6Q== 87 | dependencies: 88 | "@azure/abort-controller" "^1.0.0" 89 | "@azure/core-tracing" "1.0.0-preview.8" 90 | "@opentelemetry/api" "^0.6.1" 91 | tslib "^2.0.0" 92 | 93 | "@azure/core-http@^1.1.1": 94 | version "1.1.6" 95 | resolved "https://registry.yarnpkg.com/@azure/core-http/-/core-http-1.1.6.tgz#9d76bc569c9907e3224bd09c09b4ac08bde9faf8" 96 | integrity sha512-/C+qNzhwlLKt0F6SjaBEyY2pwZvwL2LviyS5PHlCh77qWuTF1sETmYAINM88BCN+kke+UlECK4YOQaAjJwyHvQ== 97 | dependencies: 98 | "@azure/abort-controller" "^1.0.0" 99 | "@azure/core-auth" "^1.1.3" 100 | "@azure/core-tracing" "1.0.0-preview.9" 101 | "@azure/logger" "^1.0.0" 102 | "@opentelemetry/api" "^0.10.2" 103 | "@types/node-fetch" "^2.5.0" 104 | "@types/tunnel" "^0.0.1" 105 | form-data "^3.0.0" 106 | node-fetch "^2.6.0" 107 | process "^0.11.10" 108 | tough-cookie "^4.0.0" 109 | tslib "^2.0.0" 110 | tunnel "^0.0.6" 111 | uuid "^8.1.0" 112 | xml2js "^0.4.19" 113 | 114 | "@azure/core-lro@^1.0.2": 115 | version "1.0.2" 116 | resolved "https://registry.yarnpkg.com/@azure/core-lro/-/core-lro-1.0.2.tgz#b7b51ff7b84910b7eb152a706b0531d020864f31" 117 | integrity sha512-Yr0JD7GKryOmbcb5wHCQoQ4KCcH5QJWRNorofid+UvudLaxnbCfvKh/cUfQsGUqRjO9L/Bw4X7FP824DcHdMxw== 118 | dependencies: 119 | "@azure/abort-controller" "^1.0.0" 120 | "@azure/core-http" "^1.1.1" 121 | events "^3.0.0" 122 | tslib "^1.10.0" 123 | 124 | "@azure/core-paging@^1.1.1": 125 | version "1.1.1" 126 | resolved "https://registry.yarnpkg.com/@azure/core-paging/-/core-paging-1.1.1.tgz#9639d2d5b6631d481d81040504e0e26c003f47b1" 127 | integrity sha512-hqEJBEGKan4YdOaL9ZG/GRG6PXaFd/Wb3SSjQW4LWotZzgl6xqG00h6wmkrpd2NNkbBkD1erLHBO3lPHApv+iQ== 128 | dependencies: 129 | "@azure/core-asynciterator-polyfill" "^1.0.0" 130 | 131 | "@azure/core-tracing@1.0.0-preview.8": 132 | version "1.0.0-preview.8" 133 | resolved "https://registry.yarnpkg.com/@azure/core-tracing/-/core-tracing-1.0.0-preview.8.tgz#1e0ff857e855edb774ffd33476003c27b5bb2705" 134 | integrity sha512-ZKUpCd7Dlyfn7bdc+/zC/sf0aRIaNQMDuSj2RhYRFe3p70hVAnYGp3TX4cnG2yoEALp/LTj/XnZGQ8Xzf6Ja/Q== 135 | dependencies: 136 | "@opencensus/web-types" "0.0.7" 137 | "@opentelemetry/api" "^0.6.1" 138 | tslib "^1.10.0" 139 | 140 | "@azure/core-tracing@1.0.0-preview.9": 141 | version "1.0.0-preview.9" 142 | resolved "https://registry.yarnpkg.com/@azure/core-tracing/-/core-tracing-1.0.0-preview.9.tgz#84f3b85572013f9d9b85e1e5d89787aa180787eb" 143 | integrity sha512-zczolCLJ5QG42AEPQ+Qg9SRYNUyB+yZ5dzof4YEc+dyWczO9G2sBqbAjLB7IqrsdHN2apkiB2oXeDKCsq48jug== 144 | dependencies: 145 | "@opencensus/web-types" "0.0.7" 146 | "@opentelemetry/api" "^0.10.2" 147 | tslib "^2.0.0" 148 | 149 | "@azure/logger@^1.0.0": 150 | version "1.0.0" 151 | resolved "https://registry.yarnpkg.com/@azure/logger/-/logger-1.0.0.tgz#48b371dfb34288c8797e5c104f6c4fb45bf1772c" 152 | integrity sha512-g2qLDgvmhyIxR3JVS8N67CyIOeFRKQlX/llxYJQr1OSGQqM3HTpVP8MjmjcEKbL/OIt2N9C9UFaNQuKOw1laOA== 153 | dependencies: 154 | tslib "^1.9.3" 155 | 156 | "@azure/ms-rest-js@^2.0.7": 157 | version "2.0.8" 158 | resolved "https://registry.yarnpkg.com/@azure/ms-rest-js/-/ms-rest-js-2.0.8.tgz#f84304fba29e699fc7a391ce47af2824af4f585e" 159 | integrity sha512-PO4pnYaF66IAB/RWbhrTprGyhOzDzsgcbT7z8k3O38JKlwifbrhW+8M0fzx0ScZnaacP8rZyBazYMUF9P12c0g== 160 | dependencies: 161 | "@types/node-fetch" "^2.3.7" 162 | "@types/tunnel" "0.0.1" 163 | abort-controller "^3.0.0" 164 | form-data "^2.5.0" 165 | node-fetch "^2.6.0" 166 | tough-cookie "^3.0.1" 167 | tslib "^1.10.0" 168 | tunnel "0.0.6" 169 | uuid "^3.3.2" 170 | xml2js "^0.4.19" 171 | 172 | "@azure/storage-blob@^12.1.2": 173 | version "12.1.2" 174 | resolved "https://registry.yarnpkg.com/@azure/storage-blob/-/storage-blob-12.1.2.tgz#046d146a3bd2622b61d6bdc5708955893a5b4f04" 175 | integrity sha512-PCHgG4r3xLt5FaFj+uiMqrRpuzD3TD17cvxCeA1JKK2bJEf8b07H3QRLQVf0DM1MmvYY8FgQagkWZTp+jr9yew== 176 | dependencies: 177 | "@azure/abort-controller" "^1.0.0" 178 | "@azure/core-http" "^1.1.1" 179 | "@azure/core-lro" "^1.0.2" 180 | "@azure/core-paging" "^1.1.1" 181 | "@azure/core-tracing" "1.0.0-preview.8" 182 | "@azure/logger" "^1.0.0" 183 | "@opentelemetry/api" "^0.6.1" 184 | events "^3.0.0" 185 | tslib "^1.10.0" 186 | 187 | "@opencensus/web-types@0.0.7": 188 | version "0.0.7" 189 | resolved "https://registry.yarnpkg.com/@opencensus/web-types/-/web-types-0.0.7.tgz#4426de1fe5aa8f624db395d2152b902874f0570a" 190 | integrity sha512-xB+w7ZDAu3YBzqH44rCmG9/RlrOmFuDPt/bpf17eJr8eZSrLt7nc7LnWdxM9Mmoj/YKMHpxRg28txu3TcpiL+g== 191 | 192 | "@opentelemetry/api@^0.10.2": 193 | version "0.10.2" 194 | resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-0.10.2.tgz#9647b881f3e1654089ff7ea59d587b2d35060654" 195 | integrity sha512-GtpMGd6vkzDMYcpu2t9LlhEgMy/SzBwRnz48EejlRArYqZzqSzAsKmegUK7zHgl+EOIaK9mKHhnRaQu3qw20cA== 196 | dependencies: 197 | "@opentelemetry/context-base" "^0.10.2" 198 | 199 | "@opentelemetry/api@^0.6.1": 200 | version "0.6.1" 201 | resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-0.6.1.tgz#a00b504801f408230b9ad719716fe91ad888c642" 202 | integrity sha512-wpufGZa7tTxw7eAsjXJtiyIQ42IWQdX9iUQp7ACJcKo1hCtuhLU+K2Nv1U6oRwT1oAlZTE6m4CgWKZBhOiau3Q== 203 | dependencies: 204 | "@opentelemetry/context-base" "^0.6.1" 205 | 206 | "@opentelemetry/context-base@^0.10.2": 207 | version "0.10.2" 208 | resolved "https://registry.yarnpkg.com/@opentelemetry/context-base/-/context-base-0.10.2.tgz#55bea904b2b91aa8a8675df9eaba5961bddb1def" 209 | integrity sha512-hZNKjKOYsckoOEgBziGMnBcX0M7EtstnCmwz5jZUOUYwlZ+/xxX6z3jPu1XVO2Jivk0eLfuP9GP+vFD49CMetw== 210 | 211 | "@opentelemetry/context-base@^0.6.1": 212 | version "0.6.1" 213 | resolved "https://registry.yarnpkg.com/@opentelemetry/context-base/-/context-base-0.6.1.tgz#b260e454ee4f9635ea024fc83be225e397f15363" 214 | integrity sha512-5bHhlTBBq82ti3qPT15TRxkYTFPPQWbnkkQkmHPtqiS1XcTB69cEKd3Jm7Cfi/vkPoyxapmePE9tyA7EzLt8SQ== 215 | 216 | "@types/node-fetch@^2.3.7", "@types/node-fetch@^2.5.0": 217 | version "2.5.7" 218 | resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c" 219 | integrity sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw== 220 | dependencies: 221 | "@types/node" "*" 222 | form-data "^3.0.0" 223 | 224 | "@types/node@*": 225 | version "14.6.0" 226 | resolved "https://registry.yarnpkg.com/@types/node/-/node-14.6.0.tgz#7d4411bf5157339337d7cff864d9ff45f177b499" 227 | integrity sha512-mikldZQitV94akrc4sCcSjtJfsTKt4p+e/s0AGscVA6XArQ9kFclP+ZiYUMnq987rc6QlYxXv/EivqlfSLxpKA== 228 | 229 | "@types/tunnel@0.0.1", "@types/tunnel@^0.0.1": 230 | version "0.0.1" 231 | resolved "https://registry.yarnpkg.com/@types/tunnel/-/tunnel-0.0.1.tgz#0d72774768b73df26f25df9184273a42da72b19c" 232 | integrity sha512-AOqu6bQu5MSWwYvehMXLukFHnupHrpZ8nvgae5Ggie9UwzDR1CCwoXgSSWNZJuyOlCdfdsWMA5F2LlmvyoTv8A== 233 | dependencies: 234 | "@types/node" "*" 235 | 236 | "@vercel/ncc@^0.23.0": 237 | version "0.23.0" 238 | resolved "https://registry.yarnpkg.com/@vercel/ncc/-/ncc-0.23.0.tgz#628f293f8ae2038d004378f864396ad8fc14380c" 239 | integrity sha512-Fcr1qlG9t54X4X9qbo/+jr1+t5Qc6H3TgIRBXmKkF/WDs6YFulAN6ilq2Ehx38RbgIOFxaZnjlAQ50GyexnMpQ== 240 | 241 | abort-controller@^3.0.0: 242 | version "3.0.0" 243 | resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" 244 | integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== 245 | dependencies: 246 | event-target-shim "^5.0.0" 247 | 248 | asynckit@^0.4.0: 249 | version "0.4.0" 250 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 251 | integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= 252 | 253 | balanced-match@^1.0.0: 254 | version "1.0.0" 255 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 256 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 257 | 258 | brace-expansion@^1.1.7: 259 | version "1.1.11" 260 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 261 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 262 | dependencies: 263 | balanced-match "^1.0.0" 264 | concat-map "0.0.1" 265 | 266 | combined-stream@^1.0.6, combined-stream@^1.0.8: 267 | version "1.0.8" 268 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" 269 | integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== 270 | dependencies: 271 | delayed-stream "~1.0.0" 272 | 273 | concat-map@0.0.1: 274 | version "0.0.1" 275 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 276 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 277 | 278 | delayed-stream@~1.0.0: 279 | version "1.0.0" 280 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 281 | integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= 282 | 283 | event-target-shim@^5.0.0: 284 | version "5.0.1" 285 | resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" 286 | integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== 287 | 288 | events@^3.0.0: 289 | version "3.2.0" 290 | resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379" 291 | integrity sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg== 292 | 293 | form-data@^2.5.0: 294 | version "2.5.1" 295 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" 296 | integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== 297 | dependencies: 298 | asynckit "^0.4.0" 299 | combined-stream "^1.0.6" 300 | mime-types "^2.1.12" 301 | 302 | form-data@^3.0.0: 303 | version "3.0.0" 304 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682" 305 | integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg== 306 | dependencies: 307 | asynckit "^0.4.0" 308 | combined-stream "^1.0.8" 309 | mime-types "^2.1.12" 310 | 311 | ip-regex@^2.1.0: 312 | version "2.1.0" 313 | resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" 314 | integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= 315 | 316 | mime-db@1.44.0: 317 | version "1.44.0" 318 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" 319 | integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== 320 | 321 | mime-types@^2.1.12: 322 | version "2.1.27" 323 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" 324 | integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== 325 | dependencies: 326 | mime-db "1.44.0" 327 | 328 | minimatch@^3.0.4: 329 | version "3.0.4" 330 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 331 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 332 | dependencies: 333 | brace-expansion "^1.1.7" 334 | 335 | node-fetch@^2.6.0: 336 | version "2.6.1" 337 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" 338 | integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== 339 | 340 | process@^0.11.10: 341 | version "0.11.10" 342 | resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" 343 | integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= 344 | 345 | psl@^1.1.28, psl@^1.1.33: 346 | version "1.8.0" 347 | resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" 348 | integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== 349 | 350 | punycode@^2.1.1: 351 | version "2.1.1" 352 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" 353 | integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== 354 | 355 | sax@>=0.6.0: 356 | version "1.2.4" 357 | resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" 358 | integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== 359 | 360 | semver@^6.1.0: 361 | version "6.3.0" 362 | resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" 363 | integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== 364 | 365 | tough-cookie@^3.0.1: 366 | version "3.0.1" 367 | resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2" 368 | integrity sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg== 369 | dependencies: 370 | ip-regex "^2.1.0" 371 | psl "^1.1.28" 372 | punycode "^2.1.1" 373 | 374 | tough-cookie@^4.0.0: 375 | version "4.0.0" 376 | resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" 377 | integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== 378 | dependencies: 379 | psl "^1.1.33" 380 | punycode "^2.1.1" 381 | universalify "^0.1.2" 382 | 383 | tslib@^1.10.0, tslib@^1.9.3: 384 | version "1.13.0" 385 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" 386 | integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== 387 | 388 | tslib@^2.0.0: 389 | version "2.0.1" 390 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.1.tgz#410eb0d113e5b6356490eec749603725b021b43e" 391 | integrity sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ== 392 | 393 | tunnel@0.0.6, tunnel@^0.0.6: 394 | version "0.0.6" 395 | resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" 396 | integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== 397 | 398 | universalify@^0.1.2: 399 | version "0.1.2" 400 | resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" 401 | integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== 402 | 403 | uuid@^3.3.2, uuid@^3.3.3: 404 | version "3.4.0" 405 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" 406 | integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== 407 | 408 | uuid@^8.1.0: 409 | version "8.3.0" 410 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.0.tgz#ab738085ca22dc9a8c92725e459b1d507df5d6ea" 411 | integrity sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ== 412 | 413 | xml2js@^0.4.19: 414 | version "0.4.23" 415 | resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" 416 | integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== 417 | dependencies: 418 | sax ">=0.6.0" 419 | xmlbuilder "~11.0.0" 420 | 421 | xmlbuilder@~11.0.0: 422 | version "11.0.1" 423 | resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" 424 | integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== 425 | -------------------------------------------------------------------------------- /.github/actions/v1.71.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudijd/c7decrypt/c515ba062c16e22ffffba9926f32600b8c958e72/.github/actions/v1.71.0.zip -------------------------------------------------------------------------------- /.github/workflows/source-test.yml: -------------------------------------------------------------------------------- 1 | name: Source 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | unit-tests: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | ruby-version: ['2.6', '2.7', '3.0'] 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Set up Ruby 14 | uses: ./.github/actions/setup-ruby-1.71.0 15 | with: 16 | ruby-version: ${{ matrix.ruby-version }} 17 | bundler-cache: true 18 | - name: Setup dependancies 19 | run: bundle install 20 | - name: Run unit tests 21 | run: bundle exec rake -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | *.bundle 19 | *.so 20 | *.o 21 | *.a 22 | mkmf.log 23 | bugs 24 | .rvmrc -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --colour 2 | --format documentation 3 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to C7Decrypt 2 | 3 | Thanks for your interest in contributing to C7Decrypt. 4 | 5 | If you could follow the following guidelines, you will make it much easier for 6 | us to give feedback, help you find whatever problem you have and fix it. 7 | 8 | ## Issues 9 | 10 | If you have questions of any kind, or are unsure of how something works, please 11 | [create an issue](https://github.com/claudijd/c7decrypt/issues/new). 12 | 13 | Please try to answer the following questions in your issue: 14 | 15 | - What did you do? 16 | - What did you expect to happen? 17 | - What happened instead? 18 | 19 | If you have identified a bug, it would be very helpful if you could include a 20 | way to replicate the bug. Ideally a failing test would be perfect, but even a 21 | simple script demonstrating the error would suffice. 22 | 23 | Feature requests are great and if submitted they will be considered for 24 | inclusion, but sending a pull request is much more awesome. 25 | 26 | ## Pull Requests 27 | 28 | If you want your pull requests to be accepted, please follow the following guidelines: 29 | 30 | - [**Add tests!**](http://rspec.info/) Your patch won't be accepted (or will be delayed) if it doesn't have tests. 31 | 32 | - [**Document any change in behaviour**](http://yardoc.org/) Make sure the README and any other 33 | relevant documentation are kept up-to-date. 34 | 35 | - [**Create topic branches**](https://github.com/dchelimsky/rspec/wiki/Topic-Branches) Don't ask us to pull from your master branch. 36 | 37 | - [**One pull request per feature**](https://help.github.com/articles/using-pull-requests) If you want to do more than one thing, send 38 | multiple pull requests. 39 | 40 | - [**Send coherent history**](http://stackoverflow.com/questions/6934752/git-combining-multiple-commits-before-pushing) Make sure each individual commit in your pull 41 | request is meaningful. If you had to make multiple intermediate commits while 42 | developing, please squash them before sending them to us. 43 | 44 | - [**Follow coding conventions**](https://github.com/styleguide/ruby) The standard Ruby stuff, two spaces indent, 45 | don't omit parens unless you have a good reason. 46 | 47 | Thank you so much for contributing! 48 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gemspec -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Jonathan Claudius 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of Jonathan Claudius nor the 13 | names of its contributors may be used to endorse or promote products 14 | derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY JONTHAN CLAUDIUS ''AS IS'' AND ANY 17 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL JONATHAN CLAUDIUS BE LIABLE FOR ANY 20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Cisco Logo](https://github.com/claudijd/c7decrypt/blob/master/images/cisco.jpeg?raw=true) 2 | 3 | # C7Decrypt 4 | 5 | A Ruby-based implementation of a Cisco Type-7 Password Encryptor/Decryptor 6 | 7 | ## Key Benefits 8 | 9 | - **Written in Ruby** - First and only Cisco Type-7 implementation in Ruby that I know of. 10 | - **Minimal/No Dependancies** - Uses native Ruby to do it's work, no heavy dependancies. 11 | - **Not Just a Script** - Implementation is portable for use in another project or for automation of tasks. 12 | - **Simple** - It is a small project so the interfaces are simple and easy to use. 13 | - **Encrypt & Decrypt** - Supports both encryption (with seed control) and decryption operations. 14 | 15 | ## Setup 16 | 17 | To install, type 18 | 19 | ```bash 20 | gem install c7decrypt 21 | ``` 22 | 23 | To install w/ "HighSecurity", type 24 | 25 | ```bash 26 | gem cert --add <(curl -Ls https://raw.github.com/claudijd/c7decrypt/master/certs/claudijd.pem) 27 | gem install c7decrypt -P HighSecurity 28 | ``` 29 | 30 | ## Example Command-Line Usage 31 | 32 | Run `c7decrypt -h` to get this 33 | 34 | Usage: c7decrypt [option] [hash/file] 35 | -s, --string [HASH] A single encrypted hash string 36 | -f, --file [FILE] A file containing multiple hashes 37 | -h, --help Show this message 38 | 39 | Example: c7decrypt -s 04480E051A33490E 40 | Example: c7decrypt -f config.txt 41 | 42 | ## Example Library Usage(s) 43 | 44 | To use, just require 45 | 46 | ```ruby 47 | require 'c7decrypt' 48 | ``` 49 | 50 | Decrypt Cisco Type-7 Password 51 | 52 | ```ruby 53 | >> C7Decrypt::Type7.decrypt("060506324F41") 54 | => "cisco" 55 | ``` 56 | Encrypt Cisco Type-7 Password 57 | 58 | ```ruby 59 | >> C7Decrypt::Type7.encrypt("cisco") 60 | => "02050D480809" 61 | ``` 62 | 63 | Encrypt Cisco Type-5 Password 64 | 65 | ```ruby 66 | >> C7Decrypt::Type5.encrypt("cisco") 67 | => "$1$CQk2$d62sxZKKAp7PHXWq4mOPF." 68 | ``` 69 | 70 | ## Rubies Supported 71 | 72 | This project is integrated with [travis-ci](http://about.travis-ci.org/) and is regularly tested to work with the rubies defined [here](https://github.com/claudijd/c7decrypt/blob/master/.travis.yml). 73 | 74 | To checkout the current build status for these rubies, click [here](https://travis-ci.org/#!/claudijd/c7decrypt). 75 | 76 | ## Contributing 77 | 78 | If you are interested in contributing to this project, please see [CONTRIBUTING.md](https://github.com/claudijd/c7decrypt/blob/master/CONTRIBUTING.md) 79 | 80 | ## Credits 81 | 82 | **Sources of Inspiration for C7Decrypt** 83 | 84 | - [**Daren Matthew**](http://mccltd.net/blog/?p=1034) - For his blog post on the subject aggregating tools and sources that perform the decryption/decoding logic. 85 | - [**m00nie**](http://www.m00nie.com/2011/09/cisco-type-7-password-decryption-and-encryption-with-perl/) - For the blog post on the subject, the source code of type7tool.pl and it's encryption techniques. 86 | - [**Roger Nesbitt (mogest)**](https://github.com/mogest/unix-crypt) - For the unix-crypt Ruby library that demonstrates Unix MD5 hashing schemes. 87 | 88 | **Application(s) that use C7Decrypt** 89 | 90 | - [**Marcus J Carey**](https://www.threatagent.com/c7) - For his web application implementation of this on the ThreatAgent website. Check it out and start decrypting Cisco type-7 passwords right now. 91 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | require 'rubygems' 3 | require 'rake' 4 | require 'rubygems/package_task' 5 | require 'rspec' 6 | require 'rspec/core' 7 | require 'rspec/core/rake_task' 8 | 9 | $:.unshift File.join(File.dirname(__FILE__), "lib") 10 | 11 | require 'c7decrypt' 12 | 13 | task :default => :spec 14 | 15 | desc "Run all specs in spec directory" 16 | RSpec::Core::RakeTask.new(:spec) 17 | 18 | def clean_up 19 | Dir.glob("*.gem").each { |f| File.unlink(f) } 20 | Dir.glob("*.lock").each { |f| File.unlink(f) } 21 | end 22 | 23 | desc "Fuzz C7Decrypt" 24 | task :fuzz do 25 | puts "[+] Fuzzing C7Decrypt" 26 | puts `mkdir bugs` unless File.directory?("bugs") 27 | puts `fuzzbert --bug-dir bugs --limit 10000000 "fuzz/fuzz_**.rb"` 28 | end 29 | 30 | desc "Build the gem" 31 | task :build do 32 | puts "[+] Building C7Decrypt version #{C7Decrypt::VERSION}" 33 | puts `gem build c7decrypt.gemspec` 34 | end 35 | 36 | desc "Publish the gem" 37 | task :publish do 38 | puts "[+] Publishing C7Decrypt version #{C7Decrypt::VERSION}" 39 | Dir.glob("*.gem").each { |f| puts `gem push #{f}`} 40 | end 41 | 42 | desc "Tag the release" 43 | task :tag do 44 | puts "[+] Tagging C7Decrypt version #{C7Decrypt::VERSION}" 45 | `git tag #{C7Decrypt::VERSION}` 46 | `git push --tags` 47 | end 48 | 49 | desc "Bump the Gemspec Version" 50 | task :bump do 51 | puts "[+] Bumping C7Decrypt version #{C7Decrypt::VERSION}" 52 | `git commit -a -m "Bumped Gem version to #{C7Decrypt::VERSION}"` 53 | `git push origin master` 54 | end 55 | 56 | desc "Perform an end-to-end release of the gem" 57 | task :release do 58 | clean_up() # Clean up before we start 59 | Rake::Task[:build].execute 60 | Rake::Task[:bump].execute 61 | Rake::Task[:tag].execute 62 | Rake::Task[:publish].execute 63 | clean_up() # Clean up after we complete 64 | end 65 | -------------------------------------------------------------------------------- /bin/c7decrypt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'optparse' 4 | require 'ostruct' 5 | 6 | $:.unshift File.join(File.dirname(__FILE__), '..', 'lib') 7 | 8 | require 'c7decrypt' 9 | 10 | options = OpenStruct.new 11 | options.string = nil 12 | options.file = nil 13 | 14 | opt_parser = OptionParser.new do |opts| 15 | opts.banner = "Usage: c7decrypt [option] [hash/file]" 16 | 17 | opts.on("-s", "--string [HASH]", "A single encrypted hash string") do |v| 18 | options.string = v 19 | end 20 | 21 | opts.on("-f", "--file [FILE]", "A file containing multiple hashes") do |v| 22 | options.file = v 23 | end 24 | 25 | opts.on_tail("-h", "--help", "Show this message") do 26 | puts "" 27 | puts opts 28 | puts "" 29 | puts "Example: c7decrypt -s 04480E051A33490E" 30 | puts "Example: c7decrypt -f config.txt" 31 | puts "" 32 | exit 33 | end 34 | end 35 | 36 | opt_parser.parse! 37 | 38 | if options.string.nil? && 39 | options.file.nil? 40 | 41 | puts "" 42 | puts opt_parser 43 | puts "" 44 | puts "Example: c7decrypt -s 04480E051A33490E" 45 | puts "Example: c7decrypt -f config.txt" 46 | puts "" 47 | exit 48 | end 49 | 50 | if options.string 51 | puts C7Decrypt::Type7.decrypt(options.string) 52 | end 53 | 54 | if options.file && 55 | File.exists?(options.file) 56 | 57 | C7Decrypt::Type7.decrypt_config(options.file).each {|pw| puts pw } 58 | end 59 | -------------------------------------------------------------------------------- /c7decrypt.gemspec: -------------------------------------------------------------------------------- 1 | $: << "lib" 2 | require 'c7decrypt/version' 3 | require 'date' 4 | 5 | Gem::Specification.new do |s| 6 | s.name = 'c7decrypt' 7 | s.version = C7Decrypt::VERSION 8 | s.authors = ["Jonathan Claudius"] 9 | s.email = 'claudijd@yahoo.com' 10 | s.platform = Gem::Platform::RUBY 11 | s.files = Dir.glob("lib/**/*") + 12 | Dir.glob("bin/**/*") + 13 | [".gitignore", 14 | ".rspec", 15 | ".travis.yml", 16 | "CONTRIBUTING.md", 17 | "Gemfile", 18 | "LICENSE", 19 | "README.md", 20 | "Rakefile", 21 | "c7decrypt.gemspec"] 22 | s.license = "ruby" 23 | s.require_paths = ["lib"] 24 | s.executables = s.files.grep(%r{^bin/[^\/]+$}) { |f| File.basename(f) } 25 | s.summary = 'Ruby based Cisco Password Encryptor/Decryptor' 26 | s.description = 'A library for encrypting/decrypting Cisco passwords' 27 | s.homepage = 'http://rubygems.org/gems/c7decrypt' 28 | s.cert_chain = ['certs/claudijd.pem'] 29 | # s.signing_key = File.expand_path("~/.ssh/gem-private_key.pem") if $0 =~ /gem\z/ 30 | 31 | s.add_development_dependency('fuzzbert', '~> 1.0') 32 | s.add_development_dependency('rspec', '3.7.0') 33 | s.add_development_dependency('rspec-its', '1.2.0') 34 | s.add_development_dependency('rake', '>= 12.3.3') 35 | s.add_development_dependency('coveralls') 36 | end 37 | -------------------------------------------------------------------------------- /certs/claudijd.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDcDCCAligAwIBAgIBATANBgkqhkiG9w0BAQUFADA/MREwDwYDVQQDDAhjbGF1 3 | ZGlqZDEVMBMGCgmSJomT8ixkARkWBXlhaG9vMRMwEQYKCZImiZPyLGQBGRYDY29t 4 | MB4XDTE0MTIxOTE4MzkxOVoXDTE1MTIxOTE4MzkxOVowPzERMA8GA1UEAwwIY2xh 5 | dWRpamQxFTATBgoJkiaJk/IsZAEZFgV5YWhvbzETMBEGCgmSJomT8ixkARkWA2Nv 6 | bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPJYhex3xS5rsgKZnXNK 7 | Bo3/++yub5QJ6e7cNrEpypqL/kh4aKX99779Uiw2vJAQ6E9LH+t53Cip+t6nDWkg 8 | 47FzbH4M7k1ZLKSSKxpWC2qk5mWMAVvyVGvWojM9QGPCIk86pfUGfO2nsOq3whXD 9 | q0FhBF40ZZnYTuIUbiXTkdQnsOor1WMcagLXS8PFVtOrZ/tCghvSy2dIQFiyTBnb 10 | 3cz/hEf/Xq6Cx4IBGPWyqGnvD+3RGvmTK1V4ze4MCLBfyc4gWu6mJVAEN0lleJck 11 | BuiLNW8hs72474B6VKtJaaDA8B/9kTQnoZ7Fa5YJo/GbaYUqItcy6jHSCT0rWJXA 12 | LP8CAwEAAaN3MHUwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFFZi 13 | drho+yUOaenpeDftNILNdfGJMB0GA1UdEQQWMBSBEmNsYXVkaWpkQHlhaG9vLmNv 14 | bTAdBgNVHRIEFjAUgRJjbGF1ZGlqZEB5YWhvby5jb20wDQYJKoZIhvcNAQEFBQAD 15 | ggEBAGPQew4aW3rpPNzen7yJCng88CXjrBHcCZ6NgwV4sFKqGzKMwuP+RiDeSdx7 16 | wdjM9wRtYcgKusVifjUhzmSWNd2O1s/osZY9UWXFKRwhMuk7jtepzx3G+6ptGoFF 17 | 9deFhOXTJ1y6/JEDQDt7ndqcqoEkE4iPVEUlMxuNx5XxnXtaOMMiQDm21l72K+ZQ 18 | jQuNssCu6elWT8ctrme4nmVn2CK74aTVxCsNgtfDMd/1gwHGfnkdWY5Fq+U81uWt 19 | 2Gsrg58uhzB8auXnyQj1csrXR4q84eYMXQFdhGUr/grHSy2kBkyWkzS0iYqwsTzv 20 | ho7/RMjGipku8I9m88xT0YfDq5E= 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /fuzz/fuzz_decrypt.rb: -------------------------------------------------------------------------------- 1 | require 'fuzzbert' 2 | 3 | $:.unshift File.join(File.dirname(__FILE__), '..', 'lib') 4 | require 'c7decrypt' 5 | 6 | fuzz "C7Decrypt::Type7.decrypt" do 7 | deploy do |data| 8 | begin 9 | C7Decrypt::Type7.decrypt(data) 10 | rescue StandardError 11 | #fine, we just want to capture crashes 12 | end 13 | end 14 | 15 | data "completely random" do 16 | FuzzBert::Generators.random 17 | end 18 | end -------------------------------------------------------------------------------- /images/cisco.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudijd/c7decrypt/c515ba062c16e22ffffba9926f32600b8c958e72/images/cisco.jpeg -------------------------------------------------------------------------------- /lib/c7decrypt.rb: -------------------------------------------------------------------------------- 1 | require 'c7decrypt/version' 2 | require 'c7decrypt/type7/type7' 3 | require 'c7decrypt/type5/type5' 4 | -------------------------------------------------------------------------------- /lib/c7decrypt/type5/constants.rb: -------------------------------------------------------------------------------- 1 | module C7Decrypt 2 | module Type5 3 | # Source Reference: 4 | # 5 | # The Ruby logic within this module was adapted 6 | # directly from https://github.com/mogest/unix-crypt 7 | # 8 | # Copyright (c) 2013, Roger Nesbitt 9 | # All rights reserved. 10 | # 11 | module Constants 12 | BYTE_INDEXES = [ 13 | [0, 6, 12], 14 | [1, 7, 13], 15 | [2, 8, 14], 16 | [3, 9, 15], 17 | [4, 10, 5], 18 | [nil, nil, 11] 19 | ] 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/c7decrypt/type5/type5.rb: -------------------------------------------------------------------------------- 1 | require 'digest' 2 | require 'securerandom' 3 | require 'c7decrypt/type5/constants' 4 | 5 | module C7Decrypt 6 | module Type5 7 | 8 | # Source Reference: 9 | # 10 | # The Ruby logic within this module was adapted 11 | # directly from https://github.com/mogest/unix-crypt 12 | # 13 | # Copyright (c) 2013, Roger Nesbitt 14 | # All rights reserved. 15 | # 16 | 17 | # The Encryption Method for Cisco Type-5 Encrypted Strings 18 | # @param [String] password 19 | # @param [String] salt 20 | # @return [String] formatted Type-5 hash 21 | def self.encrypt(password, salt = generate_salt) 22 | password = password.encode("UTF-8") 23 | password.force_encoding("ASCII-8BIT") 24 | 25 | b = Digest::MD5.digest("#{password}#{salt}#{password}") 26 | a_string = "#{password}$1$#{salt}#{b * (password.length/16)}#{b[0...password.length % 16]}" 27 | 28 | password_length = password.length 29 | while password_length > 0 30 | a_string += (password_length & 1 != 0) ? "\x0" : password[0].chr 31 | password_length >>= 1 32 | end 33 | 34 | input = Digest::MD5.digest(a_string) 35 | 36 | 1000.times do |index| 37 | c_string = ((index & 1 != 0) ? password : input) 38 | c_string += salt unless index % 3 == 0 39 | c_string += password unless index % 7 == 0 40 | c_string += ((index & 1 != 0) ? input : password) 41 | input = Digest::MD5.digest(c_string) 42 | end 43 | 44 | return cisco_md5_format(salt, bit_specified_base64encode(input)) 45 | end 46 | 47 | # A helper method for formating Cisco Type-5 hashes 48 | def self.cisco_md5_format(salt, hash) 49 | return "$1$" + salt + "$" + hash 50 | end 51 | 52 | # A helper method for bit specified base64 output (the format Type-5 hashes are in) 53 | # @param [String] input 54 | # @return [String] encoded_input 55 | def self.bit_specified_base64encode(input) 56 | b64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 57 | input = input.bytes.to_a 58 | output = "" 59 | Constants::BYTE_INDEXES.each do |i3, i2, i1| 60 | b1, b2, b3 = i1 && input[i1] || 0, i2 && input[i2] || 0, i3 && input[i3] || 0 61 | output << 62 | b64[ b1 & 0b00111111] << 63 | b64[((b1 & 0b11000000) >> 6) | 64 | ((b2 & 0b00001111) << 2)] << 65 | b64[((b2 & 0b11110000) >> 4) | 66 | ((b3 & 0b00000011) << 4)] << 67 | b64[ (b3 & 0b11111100) >> 2] 68 | end 69 | 70 | remainder = 3 - (16 % 3) 71 | remainder = 0 if remainder == 3 72 | 73 | return output[0..-1-remainder] 74 | end 75 | 76 | # Generates a random salt using the same character set as the base64 encoding 77 | # used by the hash encoder. 78 | # @return [String] salt 79 | def self.generate_salt(size = 4) 80 | SecureRandom.base64((size * 6 / 8.0).ceil).tr("+", ".")[0...size] 81 | end 82 | 83 | end 84 | end 85 | -------------------------------------------------------------------------------- /lib/c7decrypt/type7/constants.rb: -------------------------------------------------------------------------------- 1 | module C7Decrypt 2 | module Type7 3 | module Constants 4 | # Vigenere translation table (these are our key values for decryption) 5 | VT_TABLE = [ 6 | 0x64, 0x73, 0x66, 0x64, 0x3b, 0x6b, 0x66, 0x6f, 0x41, 0x2c, 0x2e, 7 | 0x69, 0x79, 0x65, 0x77, 0x72, 0x6b, 0x6c, 0x64, 0x4a, 0x4b, 0x44, 8 | 0x48, 0x53, 0x55, 0x42, 0x73, 0x67, 0x76, 0x63, 0x61, 0x36, 0x39, 9 | 0x38, 0x33, 0x34, 0x6e, 0x63, 0x78, 0x76, 0x39, 0x38, 0x37, 0x33, 10 | 0x32, 0x35, 0x34, 0x6b, 0x3b, 0x66, 0x67, 0x38, 0x37 11 | ] 12 | 13 | # Regexes for extracting hashes from configs 14 | TYPE_7_REGEXES = [ 15 | /enable password 7 ([A-Z0-9]+)/, 16 | /username [A-Z0-9]+ password 7 ([A-Z0-9]+)/, 17 | /password 7 ([A-Z0-9]+)/ 18 | ] 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/c7decrypt/type7/exceptions.rb: -------------------------------------------------------------------------------- 1 | module C7Decrypt 2 | module Type7 3 | module Exceptions 4 | class InvalidFirstCharacter < StandardError 5 | end 6 | 7 | class InvalidCharacter < StandardError 8 | end 9 | 10 | class OddNumberOfCharacters < StandardError 11 | end 12 | 13 | class InvalidEncryptionSeed < StandardError 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/c7decrypt/type7/type7.rb: -------------------------------------------------------------------------------- 1 | require 'c7decrypt/type7/exceptions' 2 | require 'c7decrypt/type7/constants' 3 | 4 | module C7Decrypt 5 | module Type7 6 | 7 | # The Decryption Method for Cisco Type-7 Encrypted Strings 8 | # @param [String] the Cisco Type-7 Encrypted String 9 | # @raise [Exceptions::InvalidFirstCharacter, 10 | # Exceptions::InvalidCharacter, 11 | # Exceptions::OddNumberOfCharacters] 12 | # @return [String] the Decrypted String 13 | def self.decrypt(e_text) 14 | check_type_7_errors(e_text) 15 | 16 | d_text = "" 17 | seed = nil 18 | 19 | e_text.scan(/../).each_with_index do |char,i| 20 | if i == 0 21 | seed = char.to_i - 1 22 | else 23 | d_text += decrypt_char(char, i, seed) 24 | end 25 | end 26 | 27 | return d_text 28 | end 29 | 30 | # The Encryption Method for Cisco Type-7 Encrypted Strings 31 | # @param [String] the plaintext password 32 | # @param [String] the seed for the encryption used 33 | # @raise [Exceptions::InvalidEncryptionSeed, 34 | # Exceptions::InvalidFirstCharacter, 35 | # Exceptions::InvalidCharacter, 36 | # Exceptions::OddNumberOfCharacters] 37 | # @return [String] the encrypted password 38 | def self.encrypt(d_text, seed = 2) 39 | check_seed(seed) 40 | 41 | e_text = sprintf("%02d", seed) 42 | 43 | d_text.each_char.each_with_index do |d_char,i| 44 | e_text += encrypt_char(d_char, i, seed) 45 | end 46 | 47 | check_type_7_errors(e_text) 48 | 49 | return e_text 50 | end 51 | 52 | # The method for encrypting a single character 53 | # @param [String] the plain text char 54 | # @param [FixNum] the index of the char in plaintext string 55 | # @param [FixNum] the seed used in the encryption process 56 | # @return [String] the string of the encrypted char 57 | def self.encrypt_char(char, i, seed) 58 | sprintf("%02X", char.unpack('C')[0] ^ Constants::VT_TABLE[(i + seed) % 53]) 59 | end 60 | 61 | # The method for decrypting a single character 62 | # @param [String] the encrypted char 63 | # @param [Integer] the index of the char pair in encrypted string 64 | # @param [Integer] the seed used in the decryption process 65 | # @return [String] the string of the decrypted char 66 | def self.decrypt_char(char, i, seed) 67 | (char.hex^Constants::VT_TABLE[(i + seed) % 53]).chr 68 | end 69 | 70 | # A helper method to decrypt an arracy of Cisco Type-7 Encrypted Strings 71 | # @param [Array>String] an array of Cisco Type-7 Encrypted Strings 72 | # @raise [Exceptions::InvalidFirstCharacter, 73 | # Exceptions::InvalidCharacter, 74 | # Exceptions::OddNumberOfCharacters] 75 | # @return [Array>String] an array of Decrypted Strings 76 | def self.decrypt_array(pw_array) 77 | pw_array.collect {|pw| decrypt(pw)} 78 | end 79 | 80 | # A helper method to encrypt an arracy of passwords 81 | # @param [Array>String] an array of plain-text passwords 82 | # @raise [Exceptions::InvalidEncryptionSeed, 83 | # Exceptions::InvalidFirstCharacter, 84 | # Exceptions::InvalidCharacter, 85 | # Exceptions::OddNumberOfCharacters] 86 | # @return [Array>String] an array of encrypted passwords 87 | def self.encrypt_array(pt_array, seed = 2) 88 | pt_array.collect {|pw| encrypt(pw, seed)} 89 | end 90 | 91 | # This method scans a raw config file for type 7 passwords and 92 | # decrypts them 93 | # @param [String] a string of the config file path that contains 94 | # Cisco Type-7 Encrypted Strings 95 | # @raise [Exceptions::InvalidFirstCharacter, 96 | # Exceptions::InvalidCharacter, 97 | # Exceptions::OddNumberOfCharacters] 98 | # @return [Array>String] an array of Decrypted Strings 99 | def self.decrypt_config(file) 100 | f = File.open(file, 'r').to_a 101 | decrypt_array(f.collect {|line| type_7_matches(line)}.flatten) 102 | end 103 | 104 | # This method scans a config line for encrypted type-7 passwords and 105 | # returns an array of results 106 | # @param [String] a line with potential encrypted type-7 passwords 107 | # @return [Array>String] an array of Cisco type-7 encrypted Strings 108 | def self.type_7_matches(string) 109 | Constants::TYPE_7_REGEXES.collect {|regex| string.scan(regex)}.flatten.uniq 110 | end 111 | 112 | # This method determines if an encrypted hash is corrupted/invalid 113 | # and throw a specific exeception 114 | # @param [String] the Cisco Type-7 Encrypted String 115 | # @raise [Exceptions::InvalidFirstCharacter, 116 | # Exceptions::InvalidCharacter, 117 | # Exceptions::OddNumberOfCharacters] 118 | # @return [Nil] 119 | def self.check_type_7_errors(e_text) 120 | 121 | valid_first_chars = (0..15).to_a.collect {|c| sprintf("%02d", c)} 122 | first_char = e_text[0,2] 123 | 124 | # Check for an invalid first character in the has 125 | unless valid_first_chars.include? first_char 126 | raise Exceptions::InvalidFirstCharacter, 127 | "'#{e_text}' hash contains an invalid first chracter (only '00' - '15' allowed)" 128 | end 129 | 130 | # Check for an invalid character in the hash 131 | unless e_text.match(/^[A-Z0-9]+$/) 132 | raise Exceptions::InvalidCharacter, 133 | "'#{e_text}' hash contains an invalid character (only upper-alpha numeric allowed)" 134 | end 135 | 136 | # Check for an odd number of characters in the hash 137 | unless e_text.size % 2 == 0 138 | raise Exceptions::OddNumberOfCharacters, 139 | "'#{e_text}' hash contains odd length of chars (only even number of chars allowed)" 140 | end 141 | 142 | return nil 143 | 144 | end 145 | 146 | # This method determines if an encryption seed is valid or not 147 | # and throw a specific exeception 148 | # @param [FixNum] the seed used in the encryption process 149 | # @raise [Exceptions::InvalidEncryptionSeed] 150 | # @return [Nil] 151 | def self.check_seed(seed) 152 | if seed < 0 || 153 | seed > 15 154 | 155 | raise Exceptions::InvalidEncryptionSeed, 156 | "'#{seed.to_s}' seed is not a valid seed (only 0 - 15 allowed)" 157 | end 158 | 159 | return nil 160 | end 161 | 162 | end 163 | end 164 | -------------------------------------------------------------------------------- /lib/c7decrypt/version.rb: -------------------------------------------------------------------------------- 1 | module C7Decrypt 2 | VERSION = '0.3.3' 3 | end 4 | -------------------------------------------------------------------------------- /spec/example_configs/bad_canned_example.txt: -------------------------------------------------------------------------------- 1 | # Removed "7" 2 | username password 0822455D0A16 3 | # Removed password 4 | username password 7 5 | # changed password to pword 6 | enable pword 7 060506324F41 7 | # changed hash to something weird, but still expect this to "hit" 8 | enable password 7 abc123 9 | R3(config)#do show run | sec vty 10 | line vty 0 4 11 | # again changed hash to something weird, expect this to "hit" but it doesn't ... 12 | password 7 /etc/passwd 13 | login -------------------------------------------------------------------------------- /spec/example_configs/empty_example.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/claudijd/c7decrypt/c515ba062c16e22ffffba9926f32600b8c958e72/spec/example_configs/empty_example.txt -------------------------------------------------------------------------------- /spec/example_configs/simple_canned_example.txt: -------------------------------------------------------------------------------- 1 | username test password 7 0822455D0A16 2 | username test password 7 0822455D0A16 3 | enable password 7 060506324F41 4 | enable password 7 060506324F41 5 | R3(config)#do show run | sec vty 6 | line vty 0 4 7 | password 7 02050D480809 8 | login -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | "no op" -------------------------------------------------------------------------------- /spec/type5_spec.rb: -------------------------------------------------------------------------------- 1 | require 'c7decrypt' 2 | require 'rspec/its' 3 | require 'spec_helper' 4 | 5 | describe C7Decrypt::Type5 do 6 | 7 | context "when encrypting single Cisco Type-5 hash" do 8 | before(:each) do 9 | @password = "SECRETPASSWORD" 10 | @salt = "TMnL" 11 | @hash = C7Decrypt::Type5.encrypt(@password, @salt) 12 | end 13 | 14 | it "should be the right class and value" do 15 | expect(@hash).to be_kind_of(::String) 16 | expect(@hash).to eql("$1$#{@salt}$iAFs16ZXx7x18vR1DeIp6/") 17 | end 18 | end 19 | 20 | context "when encrypting single Cisco Type-5 hash" do 21 | before(:each) do 22 | @password = "Password123" 23 | @salt = "VkQd" 24 | @hash = C7Decrypt::Type5.encrypt(@password, @salt) 25 | end 26 | 27 | it "should be the right class and value" do 28 | expect(@hash).to be_kind_of(::String) 29 | expect(@hash).to eql("$1$#{@salt}$Vma3sR7B1LL.v5lgy1NYc/") 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/type7_spec.rb: -------------------------------------------------------------------------------- 1 | require 'c7decrypt' 2 | require 'rspec/its' 3 | require 'spec_helper' 4 | 5 | describe C7Decrypt::Type7 do 6 | 7 | before(:each) do 8 | @known_values = [ 9 | {:pt => "cisco", :seed => 2, :ph => "02050D480809"}, 10 | {:pt => "cisco", :seed => 3, :ph => "030752180500"}, 11 | {:pt => "cisco", :seed => 4, :ph => "045802150C2E"}, 12 | {:pt => "cisco", :seed => 5, :ph => "05080F1C2243"}, 13 | {:pt => "cisco", :seed => 6, :ph => "060506324F41"}, 14 | {:pt => "cisco", :seed => 7, :ph => "070C285F4D06"}, 15 | {:pt => "cisco", :seed => 8, :ph => "0822455D0A16"}, 16 | {:pt => "cisco", :seed => 9, :ph => "094F471A1A0A"}, 17 | {:pt => "password", :seed => 9, :ph => "095C4F1A0A1218000F"}, 18 | {:pt => "password", :seed => 4, :ph => "044B0A151C36435C0D"} 19 | ] 20 | end 21 | 22 | context "when decrypting single Cisco Type-7 hash using longhand" do 23 | before(:each) do 24 | @encrypted_hash = "060506324F41" 25 | @decrypted_hash = C7Decrypt::Type7.decrypt(@encrypted_hash) 26 | end 27 | 28 | it "should be the right class and value" do 29 | expect(@decrypted_hash).to be_kind_of(::String) 30 | expect(@decrypted_hash).to eql("cisco") 31 | end 32 | end 33 | 34 | context "when decrypting an array of Cisco Type-7 hashes" do 35 | before(:each) do 36 | @encrypted_hashes = [ 37 | "060506324F41", 38 | "0822455D0A16" 39 | ] 40 | @decrypted_hashes = C7Decrypt::Type7.decrypt_array(@encrypted_hashes) 41 | end 42 | 43 | it "should be the right class and values" do 44 | expect(@decrypted_hashes).to be_kind_of(::Array) 45 | expect(@decrypted_hashes.first).to eql("cisco") 46 | expect(@decrypted_hashes.last).to eql("cisco") 47 | expect(@decrypted_hashes.size).to eql(2) 48 | end 49 | end 50 | 51 | context "when decrypting Cisco Type-7 hashes from a config" do 52 | before(:each) do 53 | @config_file = "./spec/example_configs/simple_canned_example.txt" 54 | @decrypted_hashes = C7Decrypt::Type7.decrypt_config(@config_file) 55 | end 56 | 57 | it "should be the right class and values" do 58 | expect(@decrypted_hashes).to be_kind_of(::Array) 59 | expect(@decrypted_hashes.first).to eql("cisco") 60 | expect(@decrypted_hashes.last).to eql("cisco") 61 | expect(@decrypted_hashes.size).to eql(5) 62 | end 63 | end 64 | 65 | context "when decrypting known Cisco Type-7 known value matches" do 66 | before(:each) do 67 | @decrypted_hashes = C7Decrypt::Type7.decrypt_array( 68 | @known_values.map {|known_value| known_value[:ph]} 69 | ) 70 | end 71 | 72 | it "should be the right class and values" do 73 | expect(@decrypted_hashes).to be_kind_of(::Array) 74 | expect(@decrypted_hashes.size).to eql(@known_values.size) 75 | expect(@decrypted_hashes).to eql(@known_values.map {|known_value| known_value[:pt]}) 76 | end 77 | end 78 | 79 | context "when decrypting Cisco Type-7 with a seed greater than 9" do 80 | before(:each) do 81 | @decrypt_hash = C7Decrypt::Type7.decrypt("15000E010723382727") 82 | end 83 | 84 | it "should be the right class and values" do 85 | expect(@decrypt_hash).to be_kind_of(::String) 86 | expect(@decrypt_hash).to eql("remcisco") 87 | end 88 | end 89 | 90 | context "when matchings known Cisco Type-7 known config line matches" do 91 | before(:each) do 92 | @encrypted_hashes = [] 93 | @known_config_lines = { 94 | "username test password 7 0822455D0A16" => "0822455D0A16", 95 | "enable password 7 060506324F41" => "060506324F41", 96 | "password 7 02050D480809" => "02050D480809" 97 | } 98 | 99 | @known_config_lines.keys.each do |k,v| 100 | @encrypted_hashes << C7Decrypt::Type7.type_7_matches(k) 101 | end 102 | @encrypted_hashes.flatten! 103 | end 104 | 105 | it "should be the right class and values" do 106 | expect(@encrypted_hashes).to be_kind_of(::Array) 107 | expect(@encrypted_hashes.size).to eql(@known_config_lines.size) 108 | expect(@encrypted_hashes).to eql(@known_config_lines.values) 109 | end 110 | end 111 | 112 | context "when encrypting single Cisco Type-7 hash" do 113 | before(:each) do 114 | @plaintext_hash = "cisco" 115 | @encrypted_hash = C7Decrypt::Type7.encrypt(@plaintext_hash) 116 | end 117 | 118 | it "should be the right class and values" do 119 | expect(@encrypted_hash).to be_kind_of(::String) 120 | expect(@encrypted_hash).to eql("02050D480809") 121 | end 122 | end 123 | 124 | context "when encrypting single Cisco Type-7 hash with an alternate seed value" do 125 | before(:each) do 126 | @plaintext_hash = "cisco" 127 | @seed = 3 128 | @encrypted_hash = C7Decrypt::Type7.encrypt(@plaintext_hash, @seed) 129 | end 130 | 131 | it "should be the right class and values" do 132 | expect(@encrypted_hash).to be_kind_of(::String) 133 | expect(@encrypted_hash).to eql("030752180500") 134 | expect(C7Decrypt::Type7.decrypt(@encrypted_hash)).to eql(@plaintext_hash) 135 | end 136 | end 137 | 138 | context "when encrypting multiple plaintext passwords with alternate seed values" do 139 | before(:each) do 140 | @plaintext_hash = "cisco" 141 | @seeds = 0..15 142 | @encrypted_hashes = @seeds.map {|seed| C7Decrypt::Type7.encrypt(@plaintext_hash, seed)} 143 | end 144 | 145 | it "should be the right class and values" do 146 | expect(@encrypted_hashes).to be_kind_of(::Array) 147 | @encrypted_hashes.each do |encrypted_hash| 148 | expect(C7Decrypt::Type7.decrypt(encrypted_hash)).to eql(@plaintext_hash) 149 | end 150 | end 151 | end 152 | 153 | context "when encrypting known value matches individually" do 154 | before(:each) do 155 | @encrypted_hashes = [] 156 | @known_values.each do |known_value| 157 | @encrypted_hashes << C7Decrypt::Type7.encrypt(known_value[:pt], known_value[:seed]) 158 | end 159 | end 160 | 161 | it "should be the right class and values" do 162 | expect(@encrypted_hashes).to be_kind_of(::Array) 163 | expect(@encrypted_hashes.size).to eql(@known_values.size) 164 | expect(@encrypted_hashes).to eql(@known_values.map {|known_value| known_value[:ph]}) 165 | end 166 | end 167 | 168 | context "when encrypting known value matches individually as an array" do 169 | before(:each) do 170 | @plaintext_passwords = @known_values.map {|known_value| known_value[:pt]}.uniq 171 | @encrypted_passwords = C7Decrypt::Type7.encrypt_array(@plaintext_passwords) 172 | end 173 | 174 | it "should be the right class and values" do 175 | expect(@encrypted_passwords).to be_kind_of(::Array) 176 | expect(@encrypted_passwords.size).to eql(@plaintext_passwords.size) 177 | expect(@encrypted_passwords).to eql(@plaintext_passwords.map {|plaintext_password| C7Decrypt::Type7.encrypt(plaintext_password)}) 178 | end 179 | end 180 | 181 | context "when encrypting Cisco Type-7" do 182 | before(:each) do 183 | @plaintext_hash = "remcisco" 184 | @encrypted_hash = C7Decrypt::Type7.encrypt(@plaintext_hash) 185 | end 186 | 187 | it "should be the right class and values" do 188 | expect(@encrypted_hash).to be_kind_of(::String) 189 | expect(@encrypted_hash).to eql("02140156080F1C2243") 190 | end 191 | end 192 | 193 | context "when encrypting Cisco Type-7 with a seed of 15" do 194 | before(:each) do 195 | @plaintext_hash = "remcisco" 196 | @seed = 15 197 | @encrypted_hash = C7Decrypt::Type7.encrypt(@plaintext_hash, @seed) 198 | end 199 | 200 | it "should be the right class and values" do 201 | expect(@encrypted_hash).to be_kind_of(::String) 202 | expect(@encrypted_hash).to eql("15000E010723382727") 203 | end 204 | end 205 | 206 | context "when trying to decrypt a hash with an invalid first character" do 207 | it "should raise an InvalidFirstCharacter Exception" do 208 | expect { 209 | C7Decrypt::Type7.decrypt("AA000E010723382727") 210 | }.to raise_error(C7Decrypt::Type7::Exceptions::InvalidFirstCharacter) 211 | end 212 | end 213 | 214 | context "when trying to decrypt a hash with an invalid character" do 215 | it "should raise an InvalidFirstCharacter Exception" do 216 | expect { 217 | C7Decrypt::Type7.decrypt("06000**E010723382727") 218 | }.to raise_error(C7Decrypt::Type7::Exceptions::InvalidCharacter) 219 | end 220 | end 221 | 222 | context "when trying to decrypt a hash with an odd number of characters" do 223 | it "should raise an InvalidFirstCharacter Exception" do 224 | expect { 225 | C7Decrypt::Type7.decrypt("06000E01723382727") 226 | }.to raise_error(C7Decrypt::Type7::Exceptions::OddNumberOfCharacters) 227 | end 228 | end 229 | 230 | context "when trying to encrypt a hash with an invalid high encryption seed" do 231 | it "should raise an InvalidFirstCharacter Exception" do 232 | expect { 233 | C7Decrypt::Type7.encrypt("bananas", 16) 234 | }.to raise_error(C7Decrypt::Type7::Exceptions::InvalidEncryptionSeed) 235 | end 236 | end 237 | 238 | context "when trying to encrypt a hash with an invalid low encryption seed" do 239 | it "should raise an InvalidFirstCharacter Exception" do 240 | expect { 241 | C7Decrypt::Type7.encrypt("bananas", -1) 242 | }.to raise_error(C7Decrypt::Type7::Exceptions::InvalidEncryptionSeed) 243 | end 244 | end 245 | 246 | end 247 | --------------------------------------------------------------------------------