From d4813ab278aa87c5a7aecb2ed411153aa115bed1 Mon Sep 17 00:00:00 2001 From: Peter Boling Date: Wed, 26 Feb 2025 00:48:11 +0700 Subject: [PATCH 01/46] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20s=20=3D>=20spec?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- masq.gemspec | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/masq.gemspec b/masq.gemspec index e341b9e..db487c4 100644 --- a/masq.gemspec +++ b/masq.gemspec @@ -6,24 +6,24 @@ gem_version = Masq::Version::VERSION Masq::Version.send(:remove_const, :VERSION) # Describe your gem and declare its dependencies: -Gem::Specification.new do |s| - s.name = "masq2" - s.version = gem_version - s.authors = ["Peter Boling", "Dennis Reimann", "Bardoe Besselaar","Nikita Vasiliev"] - s.email = ["peter.boling@gmail.com"] - s.homepage = "https://github.com/oauth-xx/masq2" - s.summary = "Mountable Rails engine that provides OpenID 2.0 server/identity provider functionality" - s.description = "Masq2 supports OpenID 2.0 and supports SReg, AX (fetch and store requests) and PAPE as well as some custom additions like multi-factor authentication using a yubikey" +Gem::Specification.new do |spec| + spec.name = "masq2" + spec.version = gem_version + spec.authors = ["Peter Boling", "Dennis Reimann", "Bardoe Besselaar","Nikita Vasiliev"] + spec.email = ["peter.boling@gmail.com"] + spec.homepage = "https://github.com/oauth-xx/masq2" + spec.summary = "Mountable Rails engine that provides OpenID 2.0 server/identity provider functionality" + spec.description = "Masq2 supports OpenID 2.0 and supports SReg, AX (fetch and store requests) and PAPE as well as some custom additions like multi-factor authentication using a yubikey" - s.files = Dir["{app,config,db,lib}/**/*"] + ["MIT-LICENSE", "Rakefile", "README.md"] - s.test_files = Dir["test/**/*"] + spec.files = Dir["{app,config,db,lib}/**/*"] + ["MIT-LICENSE", "Rakefile", "README.md"] + spec.test_files = Dir["test/**/*"] - s.add_dependency "version_gem", "~> 1.1", ">= 1.1.6" - s.add_dependency "rails", ">= 5.2.8.1" - s.add_dependency "erb" - s.add_dependency "rails-controller-testing" - s.add_dependency "ruby-openid2", "~> 3.1" - s.add_dependency "ruby-yadis" - s.add_dependency "yubikey" - s.add_dependency "i18n_data" + spec.add_dependency "version_gem", "~> 1.1", ">= 1.1.6" + spec.add_dependency "rails", ">= 5.2.8.1" + spec.add_dependency "erb" + spec.add_dependency "rails-controller-testing" + spec.add_dependency "ruby-openid2", "~> 3.1" + spec.add_dependency "ruby-yadis" + spec.add_dependency "yubikey" + spec.add_dependency "i18n_data" end From ae66274214808e7784629136c345712d11195622 Mon Sep 17 00:00:00 2001 From: Peter Boling Date: Wed, 26 Feb 2025 00:54:35 +0700 Subject: [PATCH 02/46] =?UTF-8?q?=F0=9F=94=92=EF=B8=8F=20Optionally=20sign?= =?UTF-8?q?=20gem=20releases?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- masq.gemspec | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/masq.gemspec b/masq.gemspec index db487c4..963e321 100644 --- a/masq.gemspec +++ b/masq.gemspec @@ -7,6 +7,22 @@ Masq::Version.send(:remove_const, :VERSION) # Describe your gem and declare its dependencies: Gem::Specification.new do |spec| + # Linux distros may package ruby gems differently, + # and securely certify them independently via alternate package management systemspec. + # Ref: https://gitlab.com/oauth-xx/version_gem/-/issues/3 + # Hence, only enable signing if the cert_file is present. + # See CONTRIBUTING.md + default_user_cert = "certs/#{ENV.fetch("GEM_CERT_USER", ENV["USER"])}.pem" + default_user_cert_path = File.join(__dir__, default_user_cert) + cert_file_path = ENV.fetch("GEM_CERT_PATH", default_user_cert_path) + cert_chain = cert_file_path.split(",") + if cert_file_path && cert_chain.map { |fp| File.exist?(fp) } + spec.cert_chain = cert_chain + if $PROGRAM_NAME.end_with?("gem", "rake") && ARGV[0] == "build" + spec.signing_key = File.expand_path("~/.ssh/gem-private_key.pem") + end + end + spec.name = "masq2" spec.version = gem_version spec.authors = ["Peter Boling", "Dennis Reimann", "Bardoe Besselaar","Nikita Vasiliev"] From 1eee1979611a009c9f11cdfb258a6291dbc13d33 Mon Sep 17 00:00:00 2001 From: Peter Boling Date: Wed, 26 Feb 2025 00:55:11 +0700 Subject: [PATCH 03/46] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Upgrade=20deps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Gemfile.lock | 202 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 130 insertions(+), 72 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 4f42034..292e2dd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -14,68 +14,113 @@ PATH GEM remote: https://rubygems.org/ specs: - actioncable (5.2.8.1) - actionpack (= 5.2.8.1) + actioncable (7.1.5.1) + actionpack (= 7.1.5.1) + activesupport (= 7.1.5.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailer (5.2.8.1) - actionpack (= 5.2.8.1) - actionview (= 5.2.8.1) - activejob (= 5.2.8.1) + zeitwerk (~> 2.6) + actionmailbox (7.1.5.1) + actionpack (= 7.1.5.1) + activejob (= 7.1.5.1) + activerecord (= 7.1.5.1) + activestorage (= 7.1.5.1) + activesupport (= 7.1.5.1) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.1.5.1) + actionpack (= 7.1.5.1) + actionview (= 7.1.5.1) + activejob (= 7.1.5.1) + activesupport (= 7.1.5.1) mail (~> 2.5, >= 2.5.4) - rails-dom-testing (~> 2.0) - actionpack (5.2.8.1) - actionview (= 5.2.8.1) - activesupport (= 5.2.8.1) - rack (~> 2.0, >= 2.0.8) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.2) + actionpack (7.1.5.1) + actionview (= 7.1.5.1) + activesupport (= 7.1.5.1) + nokogiri (>= 1.8.5) + racc + rack (>= 2.2.4) + rack-session (>= 1.0.1) rack-test (>= 0.6.3) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.2.8.1) - activesupport (= 5.2.8.1) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + actiontext (7.1.5.1) + actionpack (= 7.1.5.1) + activerecord (= 7.1.5.1) + activestorage (= 7.1.5.1) + activesupport (= 7.1.5.1) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.1.5.1) + activesupport (= 7.1.5.1) builder (~> 3.1) - erubi (~> 1.4) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (5.2.8.1) - activesupport (= 5.2.8.1) + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + activejob (7.1.5.1) + activesupport (= 7.1.5.1) globalid (>= 0.3.6) - activemodel (5.2.8.1) - activesupport (= 5.2.8.1) - activerecord (5.2.8.1) - activemodel (= 5.2.8.1) - activesupport (= 5.2.8.1) - arel (>= 9.0) - activestorage (5.2.8.1) - actionpack (= 5.2.8.1) - activerecord (= 5.2.8.1) - marcel (~> 1.0.0) - activesupport (5.2.8.1) + activemodel (7.1.5.1) + activesupport (= 7.1.5.1) + activerecord (7.1.5.1) + activemodel (= 7.1.5.1) + activesupport (= 7.1.5.1) + timeout (>= 0.4.0) + activestorage (7.1.5.1) + actionpack (= 7.1.5.1) + activejob (= 7.1.5.1) + activerecord (= 7.1.5.1) + activesupport (= 7.1.5.1) + marcel (~> 1.0) + activesupport (7.1.5.1) + base64 + benchmark (>= 0.3) + bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - arel (9.0.0) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + logger (>= 1.4.2) + minitest (>= 5.1) + mutex_m + securerandom (>= 0.3) + tzinfo (~> 2.0) base64 (0.2.0) + benchmark (0.4.0) + bigdecimal (3.1.9) builder (3.3.0) byebug (11.1.3) cgi (0.4.1) - concurrent-ruby (1.3.4) + concurrent-ruby (1.3.5) + connection_pool (2.5.0) crass (1.0.6) date (3.4.1) + drb (2.2.1) erb (4.0.4) cgi (>= 0.3.3) erubi (1.13.1) - globalid (1.1.0) - activesupport (>= 5.0) + globalid (1.2.1) + activesupport (>= 6.1) guard-compat (1.2.1) guard-minitest (2.4.6) guard-compat (~> 1.2) minitest (>= 3.0) - i18n (1.14.6) + i18n (1.14.7) concurrent-ruby (~> 1.0) i18n_data (0.17.1) simple_po_parser (~> 1.1) + io-console (0.8.0) + irb (1.15.1) + pp (>= 0.6.0) + rdoc (>= 4.0.0) + reline (>= 0.4.2) + logger (1.6.6) loofah (2.24.0) crass (~> 1.0.2) nokogiri (>= 1.12.0) @@ -85,44 +130,56 @@ GEM net-pop net-smtp marcel (1.0.4) - method_source (1.1.0) mini_mime (1.1.5) mini_portile2 (2.8.8) minitest (5.25.4) mocha (2.7.1) ruby2_keywords (>= 0.0.5) + mutex_m (0.3.0) mysql2 (0.5.6) - net-imap (0.4.18) + net-imap (0.4.19) date net-protocol net-pop (0.1.2) net-protocol net-protocol (0.2.2) timeout - net-smtp (0.5.0) + net-smtp (0.5.1) net-protocol nio4r (2.7.4) nokogiri (1.15.7-arm64-darwin) racc (~> 1.4) pg (1.5.9) power_assert (2.0.5) + pp (0.6.2) + prettyprint + prettyprint (0.2.0) + psych (5.2.3) + date + stringio racc (1.8.1) - rack (2.2.10) + rack (3.1.10) + rack-session (2.1.0) + base64 (>= 0.1.0) + rack (>= 3.0.0) rack-test (2.2.0) rack (>= 1.3) - rails (5.2.8.1) - actioncable (= 5.2.8.1) - actionmailer (= 5.2.8.1) - actionpack (= 5.2.8.1) - actionview (= 5.2.8.1) - activejob (= 5.2.8.1) - activemodel (= 5.2.8.1) - activerecord (= 5.2.8.1) - activestorage (= 5.2.8.1) - activesupport (= 5.2.8.1) - bundler (>= 1.3.0) - railties (= 5.2.8.1) - sprockets-rails (>= 2.0.0) + rackup (2.2.1) + rack (>= 3) + rails (7.1.5.1) + actioncable (= 7.1.5.1) + actionmailbox (= 7.1.5.1) + actionmailer (= 7.1.5.1) + actionpack (= 7.1.5.1) + actiontext (= 7.1.5.1) + actionview (= 7.1.5.1) + activejob (= 7.1.5.1) + activemodel (= 7.1.5.1) + activerecord (= 7.1.5.1) + activestorage (= 7.1.5.1) + activesupport (= 7.1.5.1) + bundler (>= 1.15.0) + railties (= 7.1.5.1) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) @@ -134,42 +191,43 @@ GEM rails-html-sanitizer (1.6.2) loofah (~> 2.21) nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) - railties (5.2.8.1) - actionpack (= 5.2.8.1) - activesupport (= 5.2.8.1) - method_source - rake (>= 0.8.7) - thor (>= 0.19.0, < 2.0) + railties (7.1.5.1) + actionpack (= 7.1.5.1) + activesupport (= 7.1.5.1) + irb + rackup (>= 1.0.0) + rake (>= 12.2) + thor (~> 1.0, >= 1.2.2) + zeitwerk (~> 2.6) rake (13.2.1) rb-fsevent (0.11.2) + rdoc (6.12.0) + psych (>= 4.0.0) + reline (0.6.0) + io-console (~> 0.5) ruby-openid2 (3.1.0) version_gem (~> 1.1, >= 1.1.4) ruby-yadis (0.3.4) ruby2_keywords (0.0.5) ruby_gntp (0.3.4) + securerandom (0.3.2) simple_po_parser (1.1.6) - sprockets (4.2.1) - concurrent-ruby (~> 1.0) - rack (>= 2.2.4, < 4) - sprockets-rails (3.4.2) - actionpack (>= 5.2) - activesupport (>= 5.2) - sprockets (>= 3.0.0) sqlite3 (1.7.3) mini_portile2 (~> 2.8.0) + stringio (3.1.5) test-unit (3.6.7) power_assert thor (1.3.2) - thread_safe (0.3.6) timeout (0.4.3) - tzinfo (1.2.11) - thread_safe (~> 0.1) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) version_gem (1.1.6) websocket-driver (0.7.7) base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) yubikey (1.4.1) + zeitwerk (2.6.18) PLATFORMS arm64-darwin-22 From 58ed492a551e520423dee542d0718ccce1871ce2 Mon Sep 17 00:00:00 2001 From: Peter Boling Date: Wed, 26 Feb 2025 01:16:45 +0700 Subject: [PATCH 04/46] =?UTF-8?q?=F0=9F=9A=9A=20LICENSE.txt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MIT-LICENSE => LICENSE.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename MIT-LICENSE => LICENSE.txt (100%) diff --git a/MIT-LICENSE b/LICENSE.txt similarity index 100% rename from MIT-LICENSE rename to LICENSE.txt From d580db495ffbb7feaf946b4b27cc8ebbe530c2de Mon Sep 17 00:00:00 2001 From: Peter Boling Date: Wed, 26 Feb 2025 01:21:43 +0700 Subject: [PATCH 05/46] =?UTF-8?q?=F0=9F=93=9D=20CODE=5FOF=5FCONDUCT.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CODE_OF_CONDUCT.md | 135 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..6be4700 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,135 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official email address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +[![Contact BDFL][🚂bdfl-contact-img]][🚂bdfl-contact]. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations +[🚂bdfl-contact]: http://www.railsbling.com/contact +[🚂bdfl-contact-img]: https://img.shields.io/badge/Contact-BDFL-0093D0.svg?style=flat&logo=rubyonrails&logoColor=red From 2e7e13b6ec97bc5db3b1ec8bc11d9d94e1e18033 Mon Sep 17 00:00:00 2001 From: Peter Boling Date: Wed, 26 Feb 2025 01:24:00 +0700 Subject: [PATCH 06/46] =?UTF-8?q?=F0=9F=93=9D=20CONTRIBUTING.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTING.md | 131 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..30ea1b7 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,131 @@ +# Contributing + +Bug reports and pull requests are welcome on GitLab at [https://gitlab.com/oauth-xx/masq2][🚎src-main] +. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to +the [code of conduct][🤝conduct]. + +To submit a patch, please fork the project and create a patch with tests. +Once you're happy with it send a pull request. + +We [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you make changes, remember to update it. + +## You can help! + +Simply follow these instructions: + +1. Fork the repository +2. Create your feature branch (`git checkout -b my-new-feature`) +3. Make some fixes. +4. Commit your changes (`git commit -am 'Added some feature'`) +5. Push to the branch (`git push origin my-new-feature`) +6. Make sure to add tests for it. This is important, so it doesn't break in a future release. +7. Create new Pull Request. + +## Appraisals + +From time to time the appraisal gemfiles in `gemfiles/` will need to be updated. +They are created and updated with the commands: + +NOTE: We run on a [fork][🚎appraisal-fork] of Appraisal. + +Please upvote the PR for `eval_gemfile` [support][🚎appraisal-eval-gemfile-pr] + +```shell +BUNDLE_GEMFILE=Appraisal.root.gemfile bundle +BUNDLE_GEMFILE=Appraisal.root.gemfile bundle exec appraisal update +``` + +When adding an appraisal to CI check the [runner tool cache][🏃‍♂️runner-tool-cache] to see which runner to use. + +## The Reek List + +Take a look at the `reek` list which is the file called `REEK` and find something to improve. + +To refresh the `reek` list: + +```bash +bundle exec reek > REEK +``` + +## Run Tests + +To run all tests + +```bash +bundle exec rake test +``` + +## Lint It + +Run all the default tasks, which includes running the gradually autocorrecting linter, `rubocop-gradual`. + +```bash +bundle exec rake +``` + +Or just run the linter. + +```bash +bundle exec rake rubocop_gradual:autocorrect +``` + +## Contributors + +Your picture could be here! + +[![Contributors][🖐contributors-img]][🖐contributors] + +Made with [contributors-img][🖐contrib-rocks]. + +Also see GitLab Contributors: [https://gitlab.com/oauth-xx/masq2/-/graphs/main][🚎contributors-gl] + +## For Maintainers + +### One-time, Per-maintainer, Setup + +**IMPORTANT**: Your public key for signing gems will need to be picked up by the line in the +`gemspec` defining the `spec.cert_chain` (check the relevant ENV variables there), +in order to sign the new release. +See: [RubyGems Security Guide][🔒️rubygems-security-guide] + +### To release a new version: + +1. Run `bin/setup && bin/rake` as a tests, coverage, & linting sanity check +2. Update the version number in `version.rb`, and ensure `CHANGELOG.md` reflects changes +3. Run `bin/setup && bin/rake` again as a secondary check, and to update `Gemfile.lock` +4. Run `git commit -am "🔖 Prepare release v"` to commit the changes +5. Run `git push` to trigger the final CI pipeline before release, & merge PRs + - NOTE: Remember to [check the build][🧪build]! +6. Run `export GIT_TRUNK_BRANCH_NAME="$(git remote show origin | grep 'HEAD branch' | cut -d ' ' -f5)" && echo $GIT_TRUNK_BRANCH_NAME` +7. Run `git checkout $GIT_TRUNK_BRANCH_NAME` +8. Run `git pull origin $GIT_TRUNK_BRANCH_NAME` to ensure you will release the latest trunk code +9. Set `SOURCE_DATE_EPOCH` so `rake build` and `rake release` use same timestamp, and generate same checksums + - Run `export SOURCE_DATE_EPOCH=$EPOCHSECONDS && echo $SOURCE_DATE_EPOCH` + - If the echo above has no output, then it didn't work. + - Note that you'll need the `zsh/datetime` module, if running `zsh`. + - In `bash` you can use `date +%s` instead, i.e. `export SOURCE_DATE_EPOCH=$(date +%s) && echo $SOURCE_DATE_EPOCH` +10. Run `bundle exec rake build` +11. Run `bin/gem_checksums` (more context [1][🔒️rubygems-checksums-pr] and [2][🔒️rubygems-guides-pr]) + to create SHA-256 and SHA-512 checksums + - Checksums will be committed automatically by the script, but not pushed +12. Run `bundle exec rake release` which will create a git tag for the version, + push git commits and tags, and push the `.gem` file to [rubygems.org][💎rubygems] + +[🚎src-main]: https://gitlab.com/oauth-xx/masq2 +[🧪build]: https://github.com/oauth-xx/masq2/actions +[🤝conduct]: https://gitlab.com/oauth-xx/masq2/-/blob/main/CODE_OF_CONDUCT.md +[🖐contrib-rocks]: https://contrib.rocks +[🖐contributors]: https://github.com/oauth-xx/masq2/graphs/contributors +[🚎contributors-gl]: https://gitlab.com/oauth-xx/masq2/-/graphs/main +[🖐contributors-img]: https://contrib.rocks/image?repo=oauth-xx/masq2 +[💎rubygems]: https://rubygems.org +[🔒️rubygems-security-guide]: https://guides.rubygems.org/security/#building-gems +[🔒️rubygems-checksums-pr]: https://github.com/rubygems/rubygems/pull/6022 +[🔒️rubygems-guides-pr]: https://github.com/rubygems/guides/pull/325 +[📗keep-changelog]: https://keepachangelog.com/en/1.0.0/ +[📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-FFDD67.svg?style=flat +[📌semver-breaking]: https://github.com/semver/semver/issues/716#issuecomment-869336139 +[📌major-versions-not-sacred]: https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html +[🚎appraisal-eval-gemfile-pr]: https://github.com/thoughtbot/appraisal/pull/248 +[🚎appraisal-fork]: https://github.com/pboling/appraisal/tree/galtzo +[🏃‍♂️runner-tool-cache]: https://github.com/ruby/ruby-builder/releases/tag/toolcache From 104cc7059fc9880518b9e5efcc0054eaaa4617e0 Mon Sep 17 00:00:00 2001 From: Peter Boling Date: Wed, 26 Feb 2025 01:25:00 +0700 Subject: [PATCH 07/46] =?UTF-8?q?=F0=9F=93=9D=20SECURITY.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SECURITY.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..91cf09e --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,22 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +|------------|-----------| +| 1.0.latest | ✅ | +| 0.x | ❌ | + +## Security contact information + +To report a security vulnerability, please use the +[Tidelift security contact](https://tidelift.com/security). +Tidelift will coordinate the fix and disclosure. + +## Additional Support + +If you are interested in support for versions older than the latest release, +please consider sponsoring the project / maintainer @ https://liberapay.com/pboling/donate, +or find other sponsorship links in the [README]. + +[README]: README.md From b817b969c5289fd177cb433c8bb173f588a3c339 Mon Sep 17 00:00:00 2001 From: Peter Boling Date: Wed, 26 Feb 2025 01:52:37 +0700 Subject: [PATCH 08/46] =?UTF-8?q?=F0=9F=94=A8=20dotfiles?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .envrc | 37 +++++++++++++++++++++++++++++++++++++ .gitignore | 51 ++++++++++++++++++++++++++++----------------------- .rspec | 4 ++++ .rubocop.yml | 2 ++ .simplecov | 3 +++ .yardopts | 1 + 6 files changed, 75 insertions(+), 23 deletions(-) create mode 100644 .envrc create mode 100644 .rspec create mode 100644 .rubocop.yml create mode 100644 .simplecov create mode 100644 .yardopts diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..b4dbbdc --- /dev/null +++ b/.envrc @@ -0,0 +1,37 @@ +# Run any command in this library's bin/ without the bin/ prefix! +PATH_add bin + +# Only add things to this file that should be shared with the team. + +# **dotenv** (See end of file for .env.local integration) +# .env would override anything in this file, if enabled. +# .env is a DOCKER standard, and if we use it, it would be in deployed, or DOCKER, environments. +# Override and customize anything below in your own .env.local +# If you are using dotenv and not direnv, +# copy the following `export` statements to your own .env file. + +### General Ruby ### +# Turn off Ruby Warnings about deprecated code +# export RUBYOPT="-W0" + +### External Testing Controls +export K_SOUP_COV_DO=true # Means you want code coverage +# Available formats are html, xml, rcov, lcov, json, tty +export K_SOUP_COV_COMMAND_NAME="RSpec Coverage" +export K_SOUP_COV_FORMATTERS="html,tty" +export K_SOUP_COV_MIN_BRANCH=100 # Means you want to enforce X% branch coverage +export K_SOUP_COV_MIN_LINE=100 # Means you want to enforce X% line coverage +export K_SOUP_COV_MIN_HARD=true # Means you want the build to fail if the coverage thresholds are not met +export K_SOUP_COV_MULTI_FORMATTERS=true +export MAX_ROWS=1 # Setting for simplecov-console gem for tty output, limits to the worst N rows of bad coverage + +# Internal Debugging Controls +export DEBUG=false # do not allow byebug statements (override in .env.local) + +# .env would override anything in this file, if `dotenv` is uncommented below. +# .env is a DOCKER standard, and if we use it, it would be in deployed, or DOCKER, environments, +# and that is why we generally want to leave it commented out. +# dotenv + +# .env.local will override anything in this file. +dotenv_if_exists .env.local diff --git a/.gitignore b/.gitignore index f435572..3dd4f85 100644 --- a/.gitignore +++ b/.gitignore @@ -1,25 +1,30 @@ -.bundle -.DS_Store -.loadpath -.project -.ruby-version -.rvmrc -Capfile -Thumbs.db -db/*.sqlite3 -doc/* -log/*.log -pkg/ -public/cache/**/* -run_tests.sh -test/dummy/db/*.sqlite3 -test/dummy/log/*.log -test/dummy/tmp -test/dummy/.sass-cache -tmp -vendor/ruby +/.bundle/ +/.yardoc +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/tmp/ -# Ignore uploaded files in development, if ever there are any from ActiveStorage -/storage/* +# rspec failure tracking +.rspec_status -/public/assets +# IDEs +/.idea/ + +# Packaging Artifacts +*.gem +gemfiles/*.gemfile.lock +Appraisal.*.gemfile.lock + +# Engine stuff +/db/*.sqlite3 +/log/*.log +/public/cache/**/* +/vendor/ + +# Dummy Rails App +/test/dummy/db/*.sqlite3 +/test/dummy/log/*.log +/test/dummy/tmp +/test/dummy/.sass-cache diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..b95daa8 --- /dev/null +++ b/.rspec @@ -0,0 +1,4 @@ +--format documentation +--color +--require spec_helper +--warnings diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..8273e09 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,2 @@ +inherit_gem: + rubocop-lts: config/rubygem.yml diff --git a/.simplecov b/.simplecov new file mode 100644 index 0000000..bfe90c0 --- /dev/null +++ b/.simplecov @@ -0,0 +1,3 @@ +require "kettle/soup/cover/config" + +SimpleCov.start diff --git a/.yardopts b/.yardopts new file mode 100644 index 0000000..f9cf06c --- /dev/null +++ b/.yardopts @@ -0,0 +1 @@ +--plugin junk From c71afbca703946060b9dfe95d126681e3833f1d2 Mon Sep 17 00:00:00 2001 From: Peter Boling Date: Wed, 26 Feb 2025 03:21:31 +0700 Subject: [PATCH 09/46] =?UTF-8?q?=F0=9F=94=A5=20Remove=20Rails=203=20scrip?= =?UTF-8?q?t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script/rails | 8 -------- 1 file changed, 8 deletions(-) delete mode 100755 script/rails diff --git a/script/rails b/script/rails deleted file mode 100755 index e2b69d5..0000000 --- a/script/rails +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env ruby -# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. - -ENGINE_ROOT = File.expand_path('../..', __FILE__) -ENGINE_PATH = File.expand_path('../../lib/masq/engine', __FILE__) - -require 'rails/all' -require 'rails/engine/commands' From 97e00300dae50245221c073dc11143c86f6895e3 Mon Sep 17 00:00:00 2001 From: Peter Boling Date: Tue, 18 Mar 2025 17:16:32 -0600 Subject: [PATCH 10/46] =?UTF-8?q?=F0=9F=90=9B=20Fixed=20Rails=208=20compat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .envrc | 4 +- .rubocop_gradual.lock | 65 +++ .tool-versions | 2 +- Appraisal.root.gemfile | 14 + Appraisals | 66 ++++ CHANGELOG.md | 39 +- Gemfile | 58 ++- Gemfile.lock | 369 +++++++++++++----- Guardfile | 16 +- README.md | 10 +- Rakefile | 102 +++-- app/controllers/masq/accounts_controller.rb | 55 ++- app/controllers/masq/base_controller.rb | 27 +- app/controllers/masq/consumer_controller.rb | 89 ++--- app/controllers/masq/info_controller.rb | 8 +- app/controllers/masq/passwords_controller.rb | 28 +- app/controllers/masq/personas_controller.rb | 21 +- app/controllers/masq/server_controller.rb | 34 +- app/controllers/masq/sessions_controller.rb | 29 +- app/controllers/masq/sites_controller.rb | 10 +- .../masq/yubikey_associations_controller.rb | 4 +- app/helpers/masq/application_helper.rb | 13 +- app/helpers/masq/personas_helper.rb | 6 +- app/mailers/masq/account_mailer.rb | 10 +- app/models/masq/account.rb | 93 +++-- app/models/masq/open_id_request.rb | 20 +- app/models/masq/persona.rb | 17 +- app/models/masq/release_policy.rb | 4 +- app/models/masq/signup.rb | 11 +- app/models/masq/site.rb | 16 +- app/views/layouts/masq/consumer.html.erb | 2 +- app/views/masq/accounts/show.xrds.builder | 64 +-- app/views/masq/server/index.xrds.builder | 28 +- .../masq/server/seatbelt_config.xml.builder | 42 +- .../server/seatbelt_login_state.xml.builder | 6 +- .../masq/shared/_error_messages.html.erb | 10 +- config.ru | 9 + config/initializers/configuration.rb | 2 +- config/initializers/mime_types.rb | 2 +- config/initializers/requires.rb | 12 +- config/routes.rb | 10 +- db/migrate/20120312120000_masq_schema.rb | 200 +++++----- ...enticated_with_yubikey_on_masq_accounts.rb | 2 +- ..._first_and_lastname_columns_to_personas.rb | 4 +- ..._id_associations_server_url_column_type.rb | 8 +- gemfiles/modular/audit.gemfile | 14 + gemfiles/modular/coverage.gemfile | 6 + gemfiles/modular/db_adapters.gemfile | 11 + gemfiles/modular/debug.gemfile | 20 + gemfiles/modular/documentation.gemfile | 8 + gemfiles/modular/mini_testing.gemfile | 7 + gemfiles/modular/style.gemfile | 13 + lib/masq.rb | 28 +- .../active_record_openid_store/association.rb | 9 +- lib/masq/active_record_openid_store/nonce.rb | 6 +- .../openid_ar_store.rb | 38 +- lib/masq/authenticated_system.rb | 25 +- lib/masq/engine.rb | 2 + lib/masq/openid_server_system.rb | 14 +- lib/masq2.rb | 2 +- lib/tasks/masq_tasks.rake | 28 +- masq.gemspec | 81 +++- spec/internal/app/assets/config/manifest.js | 0 spec/internal/config/database.yml | 3 + spec/internal/config/routes.rb | 5 + spec/internal/config/storage.yml | 3 + spec/internal/db/schema.rb | 6 + spec/internal/log/.gitignore | 1 + spec/internal/public/favicon.ico | 0 test/config/debug.rb | 12 + test/dummy/Rakefile | 2 +- test/dummy/bin/bundle | 4 +- test/dummy/bin/rails | 6 +- test/dummy/bin/rake | 4 +- test/dummy/bin/setup | 18 +- test/dummy/bin/update | 18 +- test/dummy/config.ru | 2 +- test/dummy/config/application.rb | 10 +- test/dummy/config/boot.rb | 4 +- test/dummy/config/environment.rb | 2 +- test/dummy/config/environments/development.rb | 4 +- test/dummy/config/environments/production.rb | 4 +- test/dummy/config/environments/test.rb | 7 +- .../initializers/new_framework_defaults.rb | 1 - .../dummy/config/initializers/secret_token.rb | 2 +- .../config/initializers/session_store.rb | 2 +- test/dummy/config/puma.rb | 2 +- test/dummy/config/routes.rb | 2 +- test/dummy/db/schema.rb | 169 ++++---- test/dummy/script/rails | 6 +- test/fixtures/accounts.yml | 10 +- .../masq/accounts_controller_test.rb | 132 +++---- test/functional/masq/info_controller_test.rb | 70 ++-- .../masq/passwords_controller_test.rb | 101 ++--- .../masq/personas_controller_test.rb | 50 ++- .../functional/masq/server_controller_test.rb | 105 ++--- .../masq/sessions_controller_test.rb | 117 +++--- test/functional/masq/sites_controller_test.rb | 39 +- .../yubikey_associations_controller_test.rb | 19 +- test/integration/openid_user_stories_test.rb | 287 ++++++++------ test/internal/Rakefile | 5 + test/internal/app/assets/config/manifest.js | 0 .../app/assets/stylesheets/application.css | 13 + .../app/controllers/application_controller.rb | 3 + .../app/helpers/application_helper.rb | 2 + .../app/mailers/application_mailer.rb | 4 + test/internal/app/mailers/hello_mailer.rb | 9 + test/internal/app/models/.gitkeep | 0 .../app/views/hello_mailer/bonjour.text.erb | 3 + .../app/views/layouts/application.html.erb | 13 + .../app/views/layouts/mailer.text.erb | 1 + test/internal/config/database.yml | 3 + test/internal/config/environments/test.rb | 10 + test/internal/config/masq.yml | 133 +++++++ test/internal/config/routes.rb | 7 + test/internal/config/storage.yml | 3 + test/internal/db/combustion_test.sqlite | Bin 0 -> 86016 bytes test/internal/db/combustion_test.sqlite3 | Bin 0 -> 86016 bytes test/internal/db/schema.rb | 129 ++++++ test/internal/log/.gitignore | 1 + test/internal/public/404.html | 26 ++ test/internal/public/422.html | 26 ++ test/internal/public/500.html | 25 ++ test/internal/public/favicon.ico | 0 test/support/active_support/test_case.rb | 12 +- test/test_helper.rb | 189 +++++---- test/unit/masq/account_mailer_test.rb | 28 +- test/unit/masq/account_test.rb | 193 +++++---- test/unit/masq/open_id_request_test.rb | 24 +- test/unit/masq/persona_test.rb | 9 +- test/unit/masq/release_policy_test.rb | 7 +- test/unit/masq/signup_test.rb | 48 ++- test/unit/masq/site_test.rb | 15 +- 133 files changed, 2610 insertions(+), 1513 deletions(-) create mode 100644 .rubocop_gradual.lock create mode 100644 Appraisal.root.gemfile create mode 100644 Appraisals create mode 100644 config.ru create mode 100644 gemfiles/modular/audit.gemfile create mode 100644 gemfiles/modular/coverage.gemfile create mode 100644 gemfiles/modular/db_adapters.gemfile create mode 100644 gemfiles/modular/debug.gemfile create mode 100644 gemfiles/modular/documentation.gemfile create mode 100644 gemfiles/modular/mini_testing.gemfile create mode 100644 gemfiles/modular/style.gemfile create mode 100644 spec/internal/app/assets/config/manifest.js create mode 100644 spec/internal/config/database.yml create mode 100644 spec/internal/config/routes.rb create mode 100644 spec/internal/config/storage.yml create mode 100644 spec/internal/db/schema.rb create mode 100644 spec/internal/log/.gitignore create mode 100644 spec/internal/public/favicon.ico create mode 100644 test/config/debug.rb create mode 100644 test/internal/Rakefile create mode 100644 test/internal/app/assets/config/manifest.js create mode 100644 test/internal/app/assets/stylesheets/application.css create mode 100644 test/internal/app/controllers/application_controller.rb create mode 100644 test/internal/app/helpers/application_helper.rb create mode 100644 test/internal/app/mailers/application_mailer.rb create mode 100644 test/internal/app/mailers/hello_mailer.rb create mode 100644 test/internal/app/models/.gitkeep create mode 100644 test/internal/app/views/hello_mailer/bonjour.text.erb create mode 100644 test/internal/app/views/layouts/application.html.erb create mode 100644 test/internal/app/views/layouts/mailer.text.erb create mode 100644 test/internal/config/database.yml create mode 100644 test/internal/config/environments/test.rb create mode 100644 test/internal/config/masq.yml create mode 100644 test/internal/config/routes.rb create mode 100644 test/internal/config/storage.yml create mode 100644 test/internal/db/combustion_test.sqlite create mode 100644 test/internal/db/combustion_test.sqlite3 create mode 100644 test/internal/db/schema.rb create mode 100644 test/internal/log/.gitignore create mode 100644 test/internal/public/404.html create mode 100644 test/internal/public/422.html create mode 100644 test/internal/public/500.html create mode 100644 test/internal/public/favicon.ico diff --git a/.envrc b/.envrc index b4dbbdc..33e7843 100644 --- a/.envrc +++ b/.envrc @@ -19,8 +19,8 @@ export K_SOUP_COV_DO=true # Means you want code coverage # Available formats are html, xml, rcov, lcov, json, tty export K_SOUP_COV_COMMAND_NAME="RSpec Coverage" export K_SOUP_COV_FORMATTERS="html,tty" -export K_SOUP_COV_MIN_BRANCH=100 # Means you want to enforce X% branch coverage -export K_SOUP_COV_MIN_LINE=100 # Means you want to enforce X% line coverage +export K_SOUP_COV_MIN_BRANCH=2 # Means you want to enforce X% branch coverage +export K_SOUP_COV_MIN_LINE=46 # Means you want to enforce X% line coverage export K_SOUP_COV_MIN_HARD=true # Means you want the build to fail if the coverage thresholds are not met export K_SOUP_COV_MULTI_FORMATTERS=true export MAX_ROWS=1 # Setting for simplecov-console gem for tty output, limits to the worst N rows of bad coverage diff --git a/.rubocop_gradual.lock b/.rubocop_gradual.lock new file mode 100644 index 0000000..1a67a96 --- /dev/null +++ b/.rubocop_gradual.lock @@ -0,0 +1,65 @@ +{ + "app/controllers/masq/info_controller.rb:3069306562": [ + [13, 65, 2, "Style/AndOr: Use `||` instead of `or`.", 5861240] + ], + "app/controllers/masq/passwords_controller.rb:4013562638": [ + [8, 18, 1, "Lint/AssignmentInCondition: Wrap assignment in parentheses if intentional", 177560] + ], + "app/controllers/masq/server_controller.rb:4249946322": [ + [47, 16, 1, "Lint/AssignmentInCondition: Wrap assignment in parentheses if intentional", 177560], + [89, 25, 1, "Lint/AssignmentInCondition: Wrap assignment in parentheses if intentional", 177560] + ], + "app/controllers/masq/sessions_controller.rb:2546607075": [ + [39, 21, 3, "Style/AndOr: Use `&&` instead of `and`.", 193409806], + [49, 20, 1, "Lint/AssignmentInCondition: Wrap assignment in parentheses if intentional", 177560] + ], + "app/models/masq/account.rb:3431296046": [ + [43, 5, 298, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 2464945722], + [80, 5, 1035, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 2286399262], + [82, 17, 3, "Style/AndOr: Use `&&` instead of `and`.", 193409806], + [98, 18, 3, "Style/AndOr: Use `&&` instead of `and`.", 193409806], + [98, 32, 3, "Style/AndOr: Use `&&` instead of `and`.", 193409806], + [99, 39, 2, "Style/AndOr: Use `||` instead of `or`.", 5861240], + [99, 88, 3, "Style/AndOr: Use `&&` instead of `and`.", 193409806], + [108, 5, 97, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 4218748683], + [220, 5, 3, "Lint/IneffectiveAccessModifier: `private` (on line 216) does not make singleton methods private. Use `private_class_method` or `private` inside a `class << self` block instead.", 193404514], + [220, 5, 85, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 115756650], + [226, 5, 3, "Lint/IneffectiveAccessModifier: `private` (on line 216) does not make singleton methods private. Use `private_class_method` or `private` inside a `class << self` block instead.", 193404514], + [226, 5, 181, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 3702657420], + [234, 5, 3, "Lint/IneffectiveAccessModifier: `private` (on line 216) does not make singleton methods private. Use `private_class_method` or `private` inside a `class << self` block instead.", 193404514], + [234, 5, 135, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 4139970307] + ], + "app/models/masq/open_id_request.rb:3145306176": [ + [27, 7, 159, "Style/SafeNavigation: Use safe navigation (`&.`) instead of checking if an object exists before calling the method.", 474907089] + ], + "app/models/masq/persona.rb:3585878101": [ + [14, 5, 55, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 1041090622], + [18, 5, 142, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 3038409932], + [55, 5, 3, "Lint/IneffectiveAccessModifier: `private` (on line 52) does not make singleton methods private. Use `private_class_method` or `private` inside a `class << self` block instead.", 193404514], + [55, 5, 78, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 2563415249] + ], + "app/models/masq/signup.rb:1186383472": [ + [7, 5, 126, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 1071524745] + ], + "lib/masq/authenticated_system.rb:2956957840": [ + [95, 5, 3, "Lint/IneffectiveAccessModifier: `protected` (on line 3) does not make singleton methods protected. Use `protected` inside a `class << self` block instead.", 193404514], + [95, 5, 111, "Style/ClassMethodsDefinitions: Use `class << self` to define a class method.", 4258707989], + [127, 10, 34, "Style/SafeNavigation: Use safe navigation (`&.`) instead of checking if an object exists before calling the method.", 631550519] + ], + "lib/masq/openid_server_system.rb:2879462441": [ + [106, 26, 41, "Style/SafeNavigation: Use safe navigation (`&.`) instead of checking if an object exists before calling the method.", 3858462676] + ], + "lib/tasks/masq_tasks.rake:1483017689": [ + [39, 21, 42, "Style/SafeNavigation: Use safe navigation (`&.`) instead of checking if an object exists before calling the method.", 4054527944] + ], + "masq.gemspec:1107948888": [ + [72, 3, 26, "Gemspec/DependencyVersion: Dependency version specification is required.", 1260806891], + [73, 3, 32, "Gemspec/DependencyVersion: Dependency version specification is required.", 855136127], + [76, 3, 33, "Gemspec/DependencyVersion: Dependency version specification is required.", 3159729161], + [78, 3, 30, "Gemspec/DependencyVersion: Dependency version specification is required.", 2010339150], + [89, 3, 72, "Gemspec/DependencyVersion: Dependency version specification is required.", 2491072344] + ], + "test/test_helper.rb:2707756256": [ + [194, 45, 1, "Lint/AssignmentInCondition: Wrap assignment in parentheses if intentional", 177560] + ] +} diff --git a/.tool-versions b/.tool-versions index 59511e1..ae5ecdb 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -ruby 2.7.8 +ruby 3.4.2 diff --git a/Appraisal.root.gemfile b/Appraisal.root.gemfile new file mode 100644 index 0000000..3d53a93 --- /dev/null +++ b/Appraisal.root.gemfile @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } + +source "https://rubygems.org" + +# Appraisal Root Gemfile is for running appraisal to generate the Appraisal Gemfiles +# in gemfiles/*gemfile. +# On CI, we use it for the Appraisal-based builds. +# We do not load the standard Gemfile, as it is tailored for local development. + +gemspec + +gem "appraisal", github: "pboling/appraisal", branch: "galtzo" diff --git a/Appraisals b/Appraisals new file mode 100644 index 0000000..04d2e6d --- /dev/null +++ b/Appraisals @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +# Compat: Ruby >= 2.2.2 +# Test Matrix: +# - Ruby 2.3 +# - Ruby 2.4 +# - Ruby 2.5 +# - Ruby 2.6 +# - Ruby 2.7 +appraise "rails-5-2" do + # Load order is very important with combustion! + gem "combustion", "~> 1.5" + + gem "rails", "~> 5.2.8.1" + gem "nokogiri" +end + +# Compat: Ruby >= 2.5 +# Test Matrix: +# - Ruby 2.5 +# - Ruby 2.6 +# - Ruby 2.7 +appraise "rails-6-0" do + # Load order is very important with combustion! + gem "combustion", "~> 1.5" + + gem "rails", "~> 6.0.6.1" +end + +# Compat: Ruby >= 2.5 +# Test Matrix: +# - Ruby 2.5 +# - Ruby 2.6 +# - Ruby 2.7 +# - Ruby 3.0 +appraise "rails-6-1" do + # Load order is very important with combustion! + gem "combustion", "~> 1.5" + + gem "rails", "~> 6.1.7.7" +end + +# Compat: Ruby >= 2.7 +# Test Matrix: +# - Ruby 2.7 +# - Ruby 3.0 +# - Ruby 3.1 +appraise "rails-7-0" do + # Load order is very important with combustion! + gem "combustion", "~> 1.5" + + gem "rails", "~> 7.0.8.1" +end + +# Compat: Ruby >= 2.7 +# Test Matrix: +# - Ruby 2.7 +# - Ruby 3.0 +# - Ruby 3.1 +# - Ruby 3.2 +appraise "rails-7-1" do + # Load order is very important with combustion! + gem "combustion", "~> 1.5" + + gem "rails", "~> 7.1.3.2" +end diff --git a/CHANGELOG.md b/CHANGELOG.md index 44d19c9..142abb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,37 @@ -# CHANGELOG +# Changelog + +[![SemVer 2.0.0][📌semver-img]][📌semver] [![Keep-A-Changelog 1.0.0][📗keep-changelog-img]][📗keep-changelog] + +All notable changes to this project will be documented in this file. + +Since version 1.0, the format is based on [Keep a Changelog][📗keep-changelog], +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html), +and [yes][📌major-versions-not-sacred], platform and engine support are part of the [public API][📌semver-breaking]. +Please file a bug if you notice a violation of semantic versioning. + +[📌semver]: https://semver.org/spec/v2.0.0.html +[📌semver-img]: https://img.shields.io/badge/semver-2.0.0-FFDD67.svg?style=flat +[📌semver-breaking]: https://github.com/semver/semver/issues/716#issuecomment-869336139 +[📌major-versions-not-sacred]: https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html +[📗keep-changelog]: https://keepachangelog.com/en/1.0.0/ +[📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-FFDD67.svg?style=flat + +## [Unreleased] +### Added +### Changed +### Fixed +### Removed + +## [1.0.0] - 2025-02-25 ([tag][1.0.0t]) +- COVERAGE: 98.44% -- 63/64 lines in 6 files +- BRANCH COVERAGE: 94.44% -- 17/18 branches in 6 files +- 63.64% documented +### Added +- Compatibility with Rails v5.2, v6.x, 7.x, 8.0 +- Compatibility with Ruby 2.7.8, 3.x +### Removed +- Dropped compatibility with Rails < 5.2 +- Dropped compatibility with Ruby < 2.7.8 ## v0.3.4 @@ -42,3 +75,7 @@ ## v0.2.5 * [Security] Updated Rails to version 3.2.11 + +[Unreleased]: https://github.com/oauth-xx/masq2/compare/v0.1.7...HEAD +[0.1.7]: https://github.com/oauth-xx/masq2/compare/v0.1.16...v0.1.7 +[0.1.7t]: https://github.com/oauth-xx/masq2/tags/v0.1.6 diff --git a/Gemfile b/Gemfile index 49f7560..d8e9903 100644 --- a/Gemfile +++ b/Gemfile @@ -1,22 +1,44 @@ source "https://rubygems.org" -group :development, :test do - platforms :ruby, :mswin, :mingw do - gem 'sqlite3' - gem 'mysql2' - gem 'pg' - gem 'byebug' - #gem 'activerecord-oracle_enhanced-adapter' - #gem 'ruby-plsql' - #gem 'ruby-oci8' - end - gem 'minitest' - gem 'rails-controller-testing' - gem 'test-unit', '~> 3.0' - gem 'mocha' - gem 'ruby_gntp' - gem 'guard-minitest' - gem 'rb-fsevent', :require => false -end +git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } +git_source(:gitlab) { |repo_name| "https://gitlab.com/#{repo_name}" } +#### IMPORTANT ####################################################### +# Gemfile is for local development ONLY; Gemfile is NOT loaded in CI # +####################################################### IMPORTANT #### + +# Load order it important for combustion, so make sure it loads first! +gem "combustion", "~> 1.5" + +# Include dependencies from .gemspec gemspec + +# Security Audit +eval_gemfile "gemfiles/modular/audit.gemfile" + +# Debugging +eval_gemfile "gemfiles/modular/debug.gemfile" + +# Code Coverage +eval_gemfile "gemfiles/modular/coverage.gemfile" + +# Linting +eval_gemfile "gemfiles/modular/style.gemfile" + +# Documentation +eval_gemfile "gemfiles/modular/documentation.gemfile" + +# DB Adapters +eval_gemfile "gemfiles/modular/db_adapters.gemfile" + +# Testing +eval_gemfile "gemfiles/modular/mini_testing.gemfile" + +# Local Testing (not applicable to CI) +# gem "guard-minitest" + +gem "appraisal", github: "pboling/appraisal", branch: "galtzo" + +# For local testing we'll use Rails v8.0 +# In CI we'll use `combustion` and `appraisal` to test other versions +gem "rails", "~> 8.0", ">= 8.0.1" diff --git a/Gemfile.lock b/Gemfile.lock index 292e2dd..735f969 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,24 @@ +GIT + remote: https://github.com/VitalConnectInc/yard-junk + revision: 709571e184f14d72e67fbfbe4fb65a5b62e1786e + branch: next + specs: + yard-junk (0.0.10) + backports (>= 3.18) + ostruct + rainbow + yard + +GIT + remote: https://github.com/pboling/appraisal + revision: a3a3e4b7db67d9b085f96b2ffddd2b51bd8a1196 + branch: galtzo + specs: + appraisal (3.0.0.rc1) + bundler (>= 1.17.3) + rake (>= 10) + thor (>= 0.14) + PATH remote: . specs: @@ -5,7 +26,6 @@ PATH erb i18n_data rails (>= 5.2.8.1) - rails-controller-testing ruby-openid2 (~> 3.1) ruby-yadis version_gem (~> 1.1, >= 1.1.6) @@ -14,112 +34,159 @@ PATH GEM remote: https://rubygems.org/ specs: - actioncable (7.1.5.1) - actionpack (= 7.1.5.1) - activesupport (= 7.1.5.1) + actioncable (8.0.2) + actionpack (= 8.0.2) + activesupport (= 8.0.2) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.1.5.1) - actionpack (= 7.1.5.1) - activejob (= 7.1.5.1) - activerecord (= 7.1.5.1) - activestorage (= 7.1.5.1) - activesupport (= 7.1.5.1) - mail (>= 2.7.1) - net-imap - net-pop - net-smtp - actionmailer (7.1.5.1) - actionpack (= 7.1.5.1) - actionview (= 7.1.5.1) - activejob (= 7.1.5.1) - activesupport (= 7.1.5.1) - mail (~> 2.5, >= 2.5.4) - net-imap - net-pop - net-smtp + actionmailbox (8.0.2) + actionpack (= 8.0.2) + activejob (= 8.0.2) + activerecord (= 8.0.2) + activestorage (= 8.0.2) + activesupport (= 8.0.2) + mail (>= 2.8.0) + actionmailer (8.0.2) + actionpack (= 8.0.2) + actionview (= 8.0.2) + activejob (= 8.0.2) + activesupport (= 8.0.2) + mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (7.1.5.1) - actionview (= 7.1.5.1) - activesupport (= 7.1.5.1) + actionpack (8.0.2) + actionview (= 8.0.2) + activesupport (= 8.0.2) nokogiri (>= 1.8.5) - racc rack (>= 2.2.4) rack-session (>= 1.0.1) rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - actiontext (7.1.5.1) - actionpack (= 7.1.5.1) - activerecord (= 7.1.5.1) - activestorage (= 7.1.5.1) - activesupport (= 7.1.5.1) + useragent (~> 0.16) + actiontext (8.0.2) + actionpack (= 8.0.2) + activerecord (= 8.0.2) + activestorage (= 8.0.2) + activesupport (= 8.0.2) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.1.5.1) - activesupport (= 7.1.5.1) + actionview (8.0.2) + activesupport (= 8.0.2) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (7.1.5.1) - activesupport (= 7.1.5.1) + activejob (8.0.2) + activesupport (= 8.0.2) globalid (>= 0.3.6) - activemodel (7.1.5.1) - activesupport (= 7.1.5.1) - activerecord (7.1.5.1) - activemodel (= 7.1.5.1) - activesupport (= 7.1.5.1) + activemodel (8.0.2) + activesupport (= 8.0.2) + activerecord (8.0.2) + activemodel (= 8.0.2) + activesupport (= 8.0.2) timeout (>= 0.4.0) - activestorage (7.1.5.1) - actionpack (= 7.1.5.1) - activejob (= 7.1.5.1) - activerecord (= 7.1.5.1) - activesupport (= 7.1.5.1) + activestorage (8.0.2) + actionpack (= 8.0.2) + activejob (= 8.0.2) + activerecord (= 8.0.2) + activesupport (= 8.0.2) marcel (~> 1.0) - activesupport (7.1.5.1) + activesupport (8.0.2) base64 benchmark (>= 0.3) bigdecimal - concurrent-ruby (~> 1.0, >= 1.0.2) + concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) logger (>= 1.4.2) minitest (>= 5.1) - mutex_m securerandom (>= 0.3) - tzinfo (~> 2.0) + tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) + ansi (1.5.0) + ast (2.4.3) + backports (3.25.0) base64 (0.2.0) benchmark (0.4.0) bigdecimal (3.1.9) builder (3.3.0) - byebug (11.1.3) - cgi (0.4.1) + bundler-audit (0.9.2) + bundler (>= 1.2.0, < 3) + thor (~> 1.0) + cgi (0.4.2) + coderay (1.1.3) + combustion (1.5.0) + activesupport (>= 3.0.0) + railties (>= 3.0.0) + thor (>= 0.14.6) concurrent-ruby (1.3.5) connection_pool (2.5.0) crass (1.0.6) date (3.4.1) + debug (1.10.0) + irb (~> 1.10) + reline (>= 0.3.8) + diff-lcs (1.6.0) + diffy (3.4.3) + docile (1.4.1) drb (2.2.1) + dry-configurable (1.3.0) + dry-core (~> 1.1) + zeitwerk (~> 2.6) + dry-core (1.1.0) + concurrent-ruby (~> 1.0) + logger + zeitwerk (~> 2.6) + dry-inflector (1.2.0) + dry-initializer (3.2.0) + dry-logic (1.6.0) + bigdecimal + concurrent-ruby (~> 1.0) + dry-core (~> 1.1) + zeitwerk (~> 2.6) + dry-schema (1.13.4) + concurrent-ruby (~> 1.0) + dry-configurable (~> 1.0, >= 1.0.1) + dry-core (~> 1.0, < 2) + dry-initializer (~> 3.0) + dry-logic (>= 1.4, < 2) + dry-types (>= 1.7, < 2) + zeitwerk (~> 2.6) + dry-types (1.8.2) + bigdecimal (~> 3.0) + concurrent-ruby (~> 1.0) + dry-core (~> 1.0) + dry-inflector (~> 1.0) + dry-logic (~> 1.4) + zeitwerk (~> 2.6) erb (4.0.4) cgi (>= 0.3.3) erubi (1.13.1) globalid (1.2.1) activesupport (>= 6.1) - guard-compat (1.2.1) - guard-minitest (2.4.6) - guard-compat (~> 1.2) - minitest (>= 3.0) i18n (1.14.7) concurrent-ruby (~> 1.0) - i18n_data (0.17.1) + i18n_data (1.1.0) simple_po_parser (~> 1.1) io-console (0.8.0) irb (1.15.1) pp (>= 0.6.0) rdoc (>= 4.0.0) reline (>= 0.4.2) + json (2.10.2) + kettle-soup-cover (1.0.4) + simplecov (~> 0.22) + simplecov-cobertura (~> 2.1) + simplecov-console (~> 0.9, >= 0.9.1) + simplecov-html (~> 0.12) + simplecov-lcov (~> 0.8) + simplecov-rcov (~> 0.3, >= 0.3.3) + simplecov_json_formatter (~> 0.1, >= 0.1.4) + version_gem (~> 1.1, >= 1.1.4) + language_server-protocol (3.17.0.4) + lint_roller (1.1.0) logger (1.6.6) loofah (2.24.0) crass (~> 1.0.2) @@ -130,14 +197,13 @@ GEM net-pop net-smtp marcel (1.0.4) + method_source (1.1.0) mini_mime (1.1.5) - mini_portile2 (2.8.8) - minitest (5.25.4) + minitest (5.25.5) mocha (2.7.1) ruby2_keywords (>= 0.0.5) - mutex_m (0.3.0) mysql2 (0.5.6) - net-imap (0.4.19) + net-imap (0.5.6) date net-protocol net-pop (0.1.2) @@ -147,18 +213,26 @@ GEM net-smtp (0.5.1) net-protocol nio4r (2.7.4) - nokogiri (1.15.7-arm64-darwin) + nokogiri (1.18.5-arm64-darwin) racc (~> 1.4) + ostruct (0.6.1) + parallel (1.26.3) + parser (3.3.7.1) + ast (~> 2.4.1) + racc pg (1.5.9) power_assert (2.0.5) pp (0.6.2) prettyprint prettyprint (0.2.0) + pry (0.15.2) + coderay (~> 1.1) + method_source (~> 1.0) psych (5.2.3) date stringio racc (1.8.1) - rack (3.1.10) + rack (3.1.12) rack-session (2.1.0) base64 (>= 0.1.0) rack (>= 3.0.0) @@ -166,20 +240,20 @@ GEM rack (>= 1.3) rackup (2.2.1) rack (>= 3) - rails (7.1.5.1) - actioncable (= 7.1.5.1) - actionmailbox (= 7.1.5.1) - actionmailer (= 7.1.5.1) - actionpack (= 7.1.5.1) - actiontext (= 7.1.5.1) - actionview (= 7.1.5.1) - activejob (= 7.1.5.1) - activemodel (= 7.1.5.1) - activerecord (= 7.1.5.1) - activestorage (= 7.1.5.1) - activesupport (= 7.1.5.1) + rails (8.0.2) + actioncable (= 8.0.2) + actionmailbox (= 8.0.2) + actionmailer (= 8.0.2) + actionpack (= 8.0.2) + actiontext (= 8.0.2) + actionview (= 8.0.2) + activejob (= 8.0.2) + activemodel (= 8.0.2) + activerecord (= 8.0.2) + activestorage (= 8.0.2) + activesupport (= 8.0.2) bundler (>= 1.15.0) - railties (= 7.1.5.1) + railties (= 8.0.2) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) @@ -191,60 +265,173 @@ GEM rails-html-sanitizer (1.6.2) loofah (~> 2.21) nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) - railties (7.1.5.1) - actionpack (= 7.1.5.1) - activesupport (= 7.1.5.1) - irb + railties (8.0.2) + actionpack (= 8.0.2) + activesupport (= 8.0.2) + irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) thor (~> 1.0, >= 1.2.2) zeitwerk (~> 2.6) + rainbow (3.1.1) rake (13.2.1) - rb-fsevent (0.11.2) rdoc (6.12.0) psych (>= 4.0.0) + reek (6.4.0) + dry-schema (~> 1.13.0) + logger (~> 1.6) + parser (~> 3.3.0) + rainbow (>= 2.0, < 4.0) + rexml (~> 3.1) + regexp_parser (2.10.0) reline (0.6.0) io-console (~> 0.5) + require_bench (1.0.4) + version_gem (>= 1.1.3, < 4) + rexml (3.4.1) + rspec-block_is_expected (1.0.6) + rubocop (1.73.2) + json (~> 2.3) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) + parallel (~> 1.10) + parser (>= 3.3.0.2) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.38.0, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.40.0) + parser (>= 3.3.1.0) + rubocop-gradual (0.3.6) + diff-lcs (>= 1.2.0, < 2.0) + diffy (~> 3.0) + parallel (~> 1.10) + rainbow (>= 2.2.2, < 4.0) + rubocop (~> 1.0) + rubocop-lts (18.2.1) + rubocop-ruby2_7 (>= 2.0.4, < 3) + standard-rubocop-lts (>= 1.0.3, < 3) + version_gem (>= 1.1.2, < 3) + rubocop-md (1.2.4) + rubocop (>= 1.45) + rubocop-packaging (0.5.2) + rubocop (>= 1.33, < 2.0) + rubocop-performance (1.24.0) + lint_roller (~> 1.1) + rubocop (>= 1.72.1, < 2.0) + rubocop-ast (>= 1.38.0, < 2.0) + rubocop-rake (0.7.1) + lint_roller (~> 1.1) + rubocop (>= 1.72.1) + rubocop-ruby2_7 (2.0.6) + rubocop-gradual (~> 0.3, >= 0.3.1) + rubocop-md (~> 1.2) + rubocop-rake (~> 0.6) + rubocop-shopify (~> 2.14) + rubocop-thread_safety (~> 0.5, >= 0.5.1) + standard-rubocop-lts (~> 1.0, >= 1.0.7) + version_gem (>= 1.1.3, < 3) + rubocop-shopify (2.16.0) + rubocop (~> 1.62) + rubocop-thread_safety (0.7.2) + lint_roller (~> 1.1) + rubocop (~> 1.72, >= 1.72.1) ruby-openid2 (3.1.0) version_gem (~> 1.1, >= 1.1.4) + ruby-progressbar (1.13.0) ruby-yadis (0.3.4) ruby2_keywords (0.0.5) - ruby_gntp (0.3.4) - securerandom (0.3.2) + securerandom (0.4.1) simple_po_parser (1.1.6) - sqlite3 (1.7.3) - mini_portile2 (~> 2.8.0) + simplecov (0.22.0) + docile (~> 1.1) + simplecov-html (~> 0.11) + simplecov_json_formatter (~> 0.1) + simplecov-cobertura (2.1.0) + rexml + simplecov (~> 0.19) + simplecov-console (0.9.3) + ansi + simplecov + terminal-table + simplecov-html (0.13.1) + simplecov-lcov (0.8.0) + simplecov-rcov (0.3.7) + simplecov (>= 0.4.1) + simplecov_json_formatter (0.1.4) + sqlite3 (2.6.0-arm64-darwin) + standard (1.47.0) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.0) + rubocop (~> 1.73.0) + standard-custom (~> 1.0.0) + standard-performance (~> 1.7) + standard-custom (1.0.2) + lint_roller (~> 1.0) + rubocop (~> 1.50) + standard-performance (1.7.0) + lint_roller (~> 1.1) + rubocop-performance (~> 1.24.0) + standard-rubocop-lts (1.0.10) + rspec-block_is_expected (~> 1.0, >= 1.0.5) + standard (>= 1.35.1, < 2) + standard-custom (>= 1.0.2, < 2) + standard-performance (>= 1.3.1, < 2) + version_gem (>= 1.1.4, < 3) stringio (3.1.5) + terminal-table (4.0.0) + unicode-display_width (>= 1.1.1, < 4) test-unit (3.6.7) power_assert thor (1.3.2) timeout (0.4.3) tzinfo (2.0.6) concurrent-ruby (~> 1.0) + unicode-display_width (3.1.4) + unicode-emoji (~> 4.0, >= 4.0.4) + unicode-emoji (4.0.4) + uri (1.0.3) + useragent (0.16.11) version_gem (1.1.6) websocket-driver (0.7.7) base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) + yard (0.9.37) yubikey (1.4.1) - zeitwerk (2.6.18) + zeitwerk (2.7.2) PLATFORMS arm64-darwin-22 + arm64-darwin-24 DEPENDENCIES - byebug - guard-minitest + appraisal! + benchmark (~> 0.4) + bundler-audit (~> 0.9.2) + combustion (~> 1.5) + debug (>= 1.0.0) + kettle-soup-cover (~> 1.0, >= 1.0.4) masq2! minitest mocha mysql2 pg + pry (~> 0.14) + rails (~> 8.0, >= 8.0.1) rails-controller-testing - rb-fsevent - ruby_gntp + rake (~> 13.0) + rdoc (~> 6.11) + reek (~> 6.4) + require_bench + rubocop-lts (~> 18.2, >= 18.2.1) + rubocop-packaging (~> 0.5, >= 0.5.2) sqlite3 + standard (>= 1.35.1, != 1.42.0, != 1.41.1) test-unit (~> 3.0) + yard (~> 0.9, >= 0.9.37) + yard-junk (~> 0.0, >= 0.0.10)! BUNDLED WITH - 2.4.22 + 2.6.5 diff --git a/Guardfile b/Guardfile index ed7ca8d..090c29a 100644 --- a/Guardfile +++ b/Guardfile @@ -1,15 +1,15 @@ -guard 'minitest' do +guard "minitest" do # with Minitest::Unit watch(%r|^test/(.*)\/?(.*)_test\.rb|) - watch(%r|^lib/masq.*\.rb|) { "test" } - watch(%r|^test/test_helper\.rb|) { "test" } + watch(%r|^lib/masq.*\.rb|) { "test" } + watch(%r|^test/test_helper\.rb|) { "test" } # Rails watch(%r|^app/controllers/(.*)/application_controller\.rb|) { |m| "test/functional" } watch(%r|^app/controllers/(.*)/(.*)\.rb|) { |m| "test/functional/#{m[1]}/#{m[2]}_test.rb" } - watch(%r|^app/helpers/(.*)/(.*)\.rb|) { |m| "test/helpers/#{m[1]}/#{m[2]}_test.rb" } - watch(%r|^app/models/(.*)/(.*)\.rb|) { |m| "test/unit/#{m[1]}/#{m[2]}_test.rb" } - watch(%r|^app/mailers/(.*)/(.*)\.rb|) { |m| "test/unit/#{m[1]}/#{m[2]}_test.rb" } - watch(%r|^app/views/(.*)/(.*)|) { |m| "test/integration" } - watch(%r|^config/routes\.rb|) { |m| "test/integration" } + watch(%r|^app/helpers/(.*)/(.*)\.rb|) { |m| "test/helpers/#{m[1]}/#{m[2]}_test.rb" } + watch(%r|^app/models/(.*)/(.*)\.rb|) { |m| "test/unit/#{m[1]}/#{m[2]}_test.rb" } + watch(%r|^app/mailers/(.*)/(.*)\.rb|) { |m| "test/unit/#{m[1]}/#{m[2]}_test.rb" } + watch(%r|^app/views/(.*)/(.*)|) { |m| "test/integration" } + watch(%r|^config/routes\.rb|) { |m| "test/integration" } end diff --git a/README.md b/README.md index 3b8629a..d025206 100644 --- a/README.md +++ b/README.md @@ -58,16 +58,16 @@ client-server communication (like requesting simple registration data). ### Introduction -`masq2` adds ORACLE database support, as well as support for +`masq2` adds ORACLE database support, as well as support for Rails 5.2, 6.0, 6.1, 7.0, 7.1, 7.2, 8.0, -which `masq` never had. +which `masq` never had. The main functionality is in the server controller, which is the endpoint for incoming OpenID requests. The server controller is supposed to only interact with relying parties a.k.a. consumer websites. It includes the OpenidServerSystem module, which provides some handy methods to access and answer OpenID requests. -#### v1 Release Breaking Change +#### v1 Release Breaking Change \[📒Also Rails 5.2+ / Serialization / Psych Caveats\] @@ -106,13 +106,13 @@ In addition, one of the following is also needed. 1. Simple, but insecure fix, which reverts to previous unpatched behavior is: ```ruby - Rails.application.config.active_record.use_yaml_unsafe_load = true +Rails.application.config.active_record.use_yaml_unsafe_load = true ``` 2. More complex, and a bit less insecure fix, is to explicitly list the allowed classes to serialize: ```ruby - Rails.application.config.active_record.yaml_column_permitted_classes = [Symbol, Date, Time, HashWithIndifferentAccess] +Rails.application.config.active_record.yaml_column_permitted_classes = [Symbol, Date, Time, HashWithIndifferentAccess] ``` ### Testing diff --git a/Rakefile b/Rakefile index cf31198..80ad2dc 100644 --- a/Rakefile +++ b/Rakefile @@ -1,39 +1,80 @@ -#!/usr/bin/env rake +# frozen_string_literal: true + +require "bundler/gem_tasks" + +Bundler.require :default, :development +Combustion.path = "test/internal" +Combustion.initialize!(:all) + +APP_RAKEFILE = File.expand_path("../test/internal/Rakefile", __FILE__) +load "rails/tasks/engine.rake" + +# APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__) +# load "rails/tasks/engine.rake" +# require "masq2" + +# Setup Reek begin - require 'bundler' - require 'bundler/setup' - Bundler::GemHelper.install_tasks + require "reek/rake/task" + + Reek::Rake::Task.new do |t| + t.fail_on_error = true + t.verbose = false + t.source_files = "{app,config,db,lib,test}/**/*.rb" + end rescue LoadError - puts 'You must `gem install bundler` and `bundle install` to run rake tasks' + task(:reek) do + warn("reek is disabled") + end end +# Setup Yard begin - require 'rdoc/task' + require "yard" + + YARD::Rake::YardocTask.new(:yard) rescue LoadError - require 'rdoc/rdoc' - require 'rake/rdoctask' - RDoc::Task = Rake::RDocTask + task(:yard) do + warn("yard is disabled") + end end -RDoc::Task.new(:rdoc) do |rdoc| - rdoc.rdoc_dir = 'rdoc' - rdoc.title = 'Masq' - rdoc.options << '--line-numbers' - rdoc.rdoc_files.include('lib/**/*.rb') +# Setup RuboCop-LTS +begin + require "rubocop/lts" + Rubocop::Lts.install_tasks +rescue LoadError + task(:rubocop_gradual) do + warn("RuboCop (Gradual) is disabled") + end end -APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__) -load 'rails/tasks/engine.rake' +# Setup Kettle Soup Cover +begin + require "kettle-soup-cover" + Kettle::Soup::Cover.install_tasks +rescue LoadError + desc("alias coverage task to test (coverage unavailable)") + task(coverage: :test) +end -Bundler::GemHelper.install_tasks +# Setup stone_checksums +begin + require "stone_checksums" + GemChecksums.install_tasks +rescue LoadError + task("build:generate_checksums") do + warn("gem_checksums is not available") + end +end -require 'rake/testtask' +require "rake/testtask" namespace :test do |ns| desc "Prepare tests" task :prepare do - Rails.env = 'test' - Rake::Task['db:setup'].invoke + # Rails.env = "test" + Rake::Task["db:reset"].invoke end tests = %w(unit functional integration) @@ -41,28 +82,31 @@ namespace :test do |ns| tests.each do |type| desc "Run #{type} tests" Rake::TestTask.new(type) do |t| - t.libs << 'lib' - t.libs << 'test' + t.libs << "lib" + t.libs << "test" t.test_files = FileList["test/#{type}/**/*_test.rb"] t.verbose = false end end desc "Run all tests" - Rake::TestTask.new('all') do |t| + Rake::TestTask.new("all") do |t| files = [] tests.each { |type| files += FileList["test/#{type}/**/*_test.rb"] } - t.libs << 'lib' - t.libs << 'test' + t.libs << "lib" + t.libs << "test" t.test_files = files t.verbose = false end - end -Rake::Task['test'].clear +test_tasks = %w[test:prepare test:all] +test_tasks.push("coverage") unless ENV.fetch("CI", "").casecmp?("true") + +Rake::Task["test"].clear desc "Run tests" -task :test => %w[test:prepare test:all] +task test: test_tasks -task :default => :test \ No newline at end of file +# coverage task will open coverage in browser locally +task default: %i[coverage rubocop_gradual:autocorrect yard reek] diff --git a/app/controllers/masq/accounts_controller.rb b/app/controllers/masq/accounts_controller.rb index 9c8dad2..7160d10 100644 --- a/app/controllers/masq/accounts_controller.rb +++ b/app/controllers/masq/accounts_controller.rb @@ -1,8 +1,8 @@ module Masq class AccountsController < BaseController - before_action :check_disabled_registration, :only => [:new, :create] - before_action :login_required, :except => [:show, :new, :create, :activate, :resend_activation_email] - before_action :detect_xrds, :only => :show + before_action :check_disabled_registration, only: [:new, :create] + before_action :login_required, except: [:show, :new, :create, :activate, :resend_activation_email] + before_action :detect_xrds, only: :show def show @account = @@ -16,7 +16,7 @@ def show respond_to do |format| format.html do - response.headers['X-XRDS-Location'] = identity_url(:account => @account, :format => :xrds, :protocol => scheme) + response.headers["X-XRDS-Location"] = identity_url(account: @account, format: :xrds, protocol: scheme) end format.xrds end @@ -27,16 +27,16 @@ def new end def create - cookies.delete :auth_token + cookies.delete(:auth_token) account_params[:login] = account_params[:email] if email_as_login? signup = Signup.create_account!(account_params) if signup.succeeded? - redirect_to login_path, :notice => signup.send_activation_email? ? + redirect_to(login_path, notice: signup.send_activation_email? ? t(:thanks_for_signing_up_activation_link) : - t(:thanks_for_signing_up) + t(:thanks_for_signing_up)) else @account = signup.account - render :action => 'new' + render(action: "new") end end @@ -44,58 +44,58 @@ def update account_params.delete(:email) if email_as_login? account_params.delete(:login) - if current_account.update_attributes(account_params) - redirect_to edit_account_path(:account => current_account), :notice => t(:profile_updated) + if current_account.update(account_params) + redirect_to(edit_account_path(account: current_account), notice: t(:profile_updated)) else - render :action => 'edit' + render(action: "edit") end end def destroy - return render_404 unless Masq::Engine.config.masq['can_disable_account'] + return render_404 unless Masq::Engine.config.masq["can_disable_account"] if current_account.authenticated?(params[:confirmation_password]) current_account.disable! current_account.forget_me - cookies.delete :auth_token + cookies.delete(:auth_token) reset_session - redirect_to root_path, :notice => t(:account_disabled) + redirect_to(root_path, notice: t(:account_disabled)) else - redirect_to edit_account_path, :alert => t(:entered_password_is_wrong) + redirect_to(edit_account_path, alert: t(:entered_password_is_wrong)) end end def activate - return render_404 unless Masq::Engine.config.masq['send_activation_mail'] + return render_404 unless Masq::Engine.config.masq["send_activation_mail"] begin Account.find_and_activate!(params[:activation_code]) - redirect_to login_path, :notice => t(:account_activated_login_now) + redirect_to(login_path, notice: t(:account_activated_login_now)) rescue ArgumentError, Account::ActivationCodeNotFound - redirect_to new_account_path, :alert => t(:couldnt_find_account_with_code_create_new_one) + redirect_to(new_account_path, alert: t(:couldnt_find_account_with_code_create_new_one)) rescue Account::AlreadyActivated - redirect_to login_path, :alert => t(:account_already_activated_please_login) + redirect_to(login_path, alert: t(:account_already_activated_please_login)) end end def change_password - return render_404 unless Masq::Engine.config.masq['can_change_password'] + return render_404 unless Masq::Engine.config.masq["can_change_password"] if Account.authenticate(current_account.login, params[:old_password]) - if ((params[:password] == params[:password_confirmation]) && !params[:password_confirmation].blank?) + if (params[:password] == params[:password_confirmation]) && !params[:password_confirmation].blank? current_account.password_confirmation = params[:password_confirmation] current_account.password = params[:password] if current_account.save - redirect_to edit_account_path(:account => current_account), :notice => t(:password_has_been_changed) + redirect_to(edit_account_path(account: current_account), notice: t(:password_has_been_changed)) else - redirect_to edit_account_path, :alert => t(:sorry_password_couldnt_be_changed) + redirect_to(edit_account_path, alert: t(:sorry_password_couldnt_be_changed)) end else @old_password = params[:old_password] - redirect_to edit_account_path, :alert => t(:confirmation_of_new_password_invalid) + redirect_to(edit_account_path, alert: t(:confirmation_of_new_password_invalid)) end else - redirect_to edit_account_path, :alert => t(:old_password_incorrect) + redirect_to(edit_account_path, alert: t(:old_password_incorrect)) end end @@ -109,13 +109,13 @@ def resend_activation_email flash[:alert] = t(:account_already_activated_or_missing) end - redirect_to login_path + redirect_to(login_path) end protected def check_disabled_registration - render_404 if Masq::Engine.config.masq['disable_registration'] + render_404 if Masq::Engine.config.masq["disable_registration"] end def detect_xrds @@ -128,6 +128,5 @@ def detect_xrds def account_params @account_params ||= params.require(:account).permit(:login, :email, :password, :password_confirmation, :public_persona_id, :yubikey_mandatory) end - end end diff --git a/app/controllers/masq/base_controller.rb b/app/controllers/masq/base_controller.rb index bd46b45..22e35ce 100644 --- a/app/controllers/masq/base_controller.rb +++ b/app/controllers/masq/base_controller.rb @@ -5,21 +5,26 @@ class BaseController < ActionController::Base protect_from_forgery - rescue_from ::ActiveRecord::RecordNotFound, :with => :render_404 - rescue_from ::ActionController::InvalidAuthenticityToken, :with => :render_422 + rescue_from ::ActiveRecord::RecordNotFound, with: :render_404 + rescue_from ::ActionController::InvalidAuthenticityToken, with: :render_422 - helper_method :extract_host, :extract_login_from_identifier, :checkid_request, - :identifier, :endpoint_url, :scheme, :email_as_login? + helper_method :extract_host, + :extract_login_from_identifier, + :checkid_request, + :identifier, + :endpoint_url, + :scheme, + :email_as_login? protected def endpoint_url - server_url(:protocol => scheme) + server_url(protocol: scheme) end # Returns the OpenID identifier for an account def identifier(account) - identity_url(:account => account, :protocol => scheme) + identity_url(account: account, protocol: scheme) end # Extracts the hostname from the given url, which is used to @@ -29,11 +34,11 @@ def extract_host(u) end def extract_login_from_identifier(openid_url) - openid_url.gsub(/^https?:\/\/.*\//, '') + openid_url.gsub(/^https?:\/\/.*\//, "") end def checkid_request - unless (@checkid_request||=nil) + unless @checkid_request ||= nil req = openid_server.decode_request(current_openid_request.parameters) if current_openid_request @checkid_request = req.is_a?(OpenID::Server::CheckIDRequest) ? req : false end @@ -57,17 +62,17 @@ def render_500 end def render_error(status_code) - render :file => "#{Rails.root}/public/#{status_code}", :formats => [:html], :status => status_code, :layout => false + render(file: "#{Rails.root}/public/#{status_code}.html", formats: [:html], status: status_code, layout: false) end private def scheme - Masq::Engine.config.masq['use_ssl'] ? 'https' : 'http' + Masq::Engine.config.masq["use_ssl"] ? "https" : "http" end def email_as_login? - Masq::Engine.config.masq['email_as_login'] + Masq::Engine.config.masq["email_as_login"] end end end diff --git a/app/controllers/masq/consumer_controller.rb b/app/controllers/masq/consumer_controller.rb index a770440..901d013 100644 --- a/app/controllers/masq/consumer_controller.rb +++ b/app/controllers/masq/consumer_controller.rb @@ -1,67 +1,68 @@ module Masq class ConsumerController < BaseController - skip_before_action :verify_authenticity_token def start begin oidreq = openid_consumer.begin(params[:openid_identifier]) rescue OpenID::OpenIDError => e - redirect_to consumer_path, :alert => "Discovery failed for #{params[:openid_identifier]}: #{e}" + redirect_to(consumer_path, alert: "Discovery failed for #{params[:openid_identifier]}: #{e}") return end if params[:use_sreg] sregreq = OpenID::SReg::Request.new - sregreq.policy_url = 'http://www.policy-url.com' - sregreq.request_fields(['nickname', 'email'], true) # required - sregreq.request_fields(['fullname', 'dob'], false) # optional + sregreq.policy_url = "http://www.policy-url.com" + sregreq.request_fields(["nickname", "email"], true) # required + sregreq.request_fields(["fullname", "dob"], false) # optional oidreq.add_extension(sregreq) - oidreq.return_to_args['did_sreg'] = 'y' + oidreq.return_to_args["did_sreg"] = "y" end if params[:use_ax_fetch] axreq = OpenID::AX::FetchRequest.new - requested_attrs = [['https://openid.tzi.de/spec/schema', 'uid', true], - ['http://axschema.org/namePerson/friendly', 'nickname', true], - ['http://axschema.org/contact/email', 'email', true], - ['http://axschema.org/namePerson', 'fullname'], - ['http://axschema.org/contact/web/default', 'website', false, 2], - ['http://axschema.org/contact/postalCode/home', 'postcode'], - ['http://axschema.org/person/gender', 'gender'], - ['http://axschema.org/birthDate', 'birth_date'], - ['http://axschema.org/contact/country/home', 'country'], - ['http://axschema.org/pref/language', 'language'], - ['http://axschema.org/pref/timezone', 'timezone']] + requested_attrs = [ + ["https://openid.tzi.de/spec/schema", "uid", true], + ["http://axschema.org/namePerson/friendly", "nickname", true], + ["http://axschema.org/contact/email", "email", true], + ["http://axschema.org/namePerson", "fullname"], + ["http://axschema.org/contact/web/default", "website", false, 2], + ["http://axschema.org/contact/postalCode/home", "postcode"], + ["http://axschema.org/person/gender", "gender"], + ["http://axschema.org/birthDate", "birth_date"], + ["http://axschema.org/contact/country/home", "country"], + ["http://axschema.org/pref/language", "language"], + ["http://axschema.org/pref/timezone", "timezone"], + ] requested_attrs.each { |a| axreq.add(OpenID::AX::AttrInfo.new(a[0], a[1], a[2] || false, a[3] || 1)) } oidreq.add_extension(axreq) - oidreq.return_to_args['did_ax_fetch'] = 'y' + oidreq.return_to_args["did_ax_fetch"] = "y" end if params[:use_ax_store] ax_store_req = OpenID::AX::StoreRequest.new - ax_store_req.set_values('http://axschema.org/contact/email', %w(email@example.com)) - ax_store_req.set_values('http://axschema.org/birthDate', %w(1976-08-07)) - ax_store_req.set_values('http://axschema.org/customValueThatIsNotSupported', %w(unsupported)) + ax_store_req.set_values("http://axschema.org/contact/email", %w(email@example.com)) + ax_store_req.set_values("http://axschema.org/birthDate", %w(1976-08-07)) + ax_store_req.set_values("http://axschema.org/customValueThatIsNotSupported", %w(unsupported)) oidreq.add_extension(ax_store_req) - oidreq.return_to_args['did_ax_store'] = 'y' + oidreq.return_to_args["did_ax_store"] = "y" end if params[:use_pape] papereq = OpenID::PAPE::Request.new papereq.add_policy_uri(OpenID::PAPE::AUTH_PHISHING_RESISTANT) papereq.max_auth_age = 60 oidreq.add_extension(papereq) - oidreq.return_to_args['did_pape'] = 'y' + oidreq.return_to_args["did_pape"] = "y" end if params[:force_post] - oidreq.return_to_args['force_post'] = 'x' * 2048 + oidreq.return_to_args["force_post"] = "x" * 2048 end if oidreq.send_redirect?(consumer_url, consumer_complete_url, params[:immediate]) - redirect_to oidreq.redirect_url(consumer_url, consumer_complete_url, params[:immediate]) + redirect_to(oidreq.redirect_url(consumer_url, consumer_complete_url, params[:immediate])) else - @form_text = oidreq.form_markup(consumer_url, consumer_complete_url, params[:immediate], { 'id' => 'checkid_form' }) + @form_text = oidreq.form_markup(consumer_url, consumer_complete_url, params[:immediate], {"id" => "checkid_form"}) end end def complete - parameters = params.to_unsafe_h.reject{ |k,v| request.path_parameters[k.to_sym] } + parameters = params.to_unsafe_h.reject { |k, v| request.path_parameters[k.to_sym] } oidresp = openid_consumer.complete(parameters, url_for({})) case oidresp.status when OpenID::Consumer::SETUP_NEEDED @@ -70,10 +71,10 @@ def complete flash[:alert] = t(:openid_transaction_cancelled) when OpenID::Consumer::FAILURE flash[:alert] = oidresp.display_identifier ? - t(:verification_of_identifier_failed, :identifier => oidresp.display_identifier, :message => oidresp.message) : - t(:verification_failed_message, :message => oidresp.message) + t(:verification_of_identifier_failed, identifier: oidresp.display_identifier, message: oidresp.message) : + t(:verification_failed_message, message: oidresp.message) when OpenID::Consumer::SUCCESS - flash[:notice] = t(:verification_of_identifier_succeeded, :identifier => oidresp.display_identifier) + flash[:notice] = t(:verification_of_identifier_succeeded, identifier: oidresp.display_identifier) if params[:did_sreg] sreg_resp = OpenID::SReg::Response.from_success_response(oidresp) sreg_message = "\n\n" + t(:simple_registration_data_requested) @@ -81,50 +82,50 @@ def complete sreg_message << ", " + t(:but_none_was_returned) else sreg_message << ". " + t(:the_following_data_were_sent) + "\n" - sreg_resp.data.each { |k,v| sreg_message << "#{k}: #{v}\n" } + sreg_resp.data.each { |k, v| sreg_message << "#{k}: #{v}\n" } end flash[:notice] += sreg_message end if params[:did_ax_fetch] ax_fetch_resp = OpenID::AX::FetchResponse.from_success_response(oidresp) ax_fetch_message = "\n\n" + t(:attribute_exchange_data_requested) - unless ax_fetch_resp - ax_fetch_message << ", " + t(:but_none_was_returned) - else + if ax_fetch_resp ax_fetch_message << ". " + t(:the_following_data_were_sent) + "\n" - ax_fetch_resp.data.each { |k,v| ax_fetch_message << "#{k}: #{v}\n" } + ax_fetch_resp.data.each { |k, v| ax_fetch_message << "#{k}: #{v}\n" } + else + ax_fetch_message << ", " + t(:but_none_was_returned) end flash[:notice] += ax_fetch_message end if params[:did_ax_store] ax_store_resp = OpenID::AX::StoreResponse.from_success_response(oidresp) ax_store_message = "\n\n" + t(:attribute_exchange_store_requested) - unless ax_store_resp - ax_store_message << ", " + t(:but_got_no_response) - else + ax_store_message << if ax_store_resp if ax_store_resp.succeeded? - ax_store_message << " " + t(:and_saved_at_the_identity_provider) + " " + t(:and_saved_at_the_identity_provider) else - ax_store_message << ", " + t(:but_an_error_occured, :error_message => ax_store_resp.error_message) + ", " + t(:but_an_error_occured, error_message: ax_store_resp.error_message) end + else + ", " + t(:but_got_no_response) end flash[:notice] += ax_store_message end if params[:did_pape] pape_resp = OpenID::PAPE::Response.from_success_response(oidresp) pape_message = "\n\n" + t(:authentication_policies_requested) - unless pape_resp.auth_policies.empty? + if pape_resp.auth_policies.empty? + pape_message << ", " + t(:but_the_server_did_not_report_one) + else pape_message << ", " + t(:and_server_reported_the_following) + "\n" pape_resp.auth_policies.each { |p| pape_message << "#{p}\n" } - else - pape_message << ", " + t(:but_the_server_did_not_report_one) end pape_message << "\n" + t(:authentication_time) + ": #{pape_resp.auth_time}" if pape_resp.auth_time pape_message << "\nNIST Auth Level: #{pape_resp.nist_auth_level}" if pape_resp.nist_auth_level flash[:notice] += pape_message end end - redirect_to :action => 'index' + redirect_to(action: "index") end private diff --git a/app/controllers/masq/info_controller.rb b/app/controllers/masq/info_controller.rb index 17f8afc..e00d65b 100644 --- a/app/controllers/masq/info_controller.rb +++ b/app/controllers/masq/info_controller.rb @@ -3,17 +3,17 @@ class InfoController < BaseController # The yadis discovery header tells incoming OpenID # requests where to find the server endpoint. def index - response.headers['X-XRDS-Location'] = server_url(:format => :xrds, :protocol => scheme) + response.headers["X-XRDS-Location"] = server_url(format: :xrds, protocol: scheme) end # This page is to prevent phishing attacks. It should # not contain any links, the user has to navigate to # the right login page manually. def safe_login - if not Masq::Engine.config.masq.include? 'protect_phishing' or Masq::Engine.config.masq['protect_phishing'] - render :layout => false + if !Masq::Engine.config.masq.include?("protect_phishing") or Masq::Engine.config.masq["protect_phishing"] + render(layout: false) else - redirect_to login_url + redirect_to(login_url) end end diff --git a/app/controllers/masq/passwords_controller.rb b/app/controllers/masq/passwords_controller.rb index 77b4f84..0560158 100644 --- a/app/controllers/masq/passwords_controller.rb +++ b/app/controllers/masq/passwords_controller.rb @@ -1,31 +1,29 @@ module Masq class PasswordsController < BaseController - before_action :check_can_change_password, :only => [:create, :edit, :update] - before_action :find_account_by_reset_code, :only => [:edit, :update] + before_action :check_can_change_password, only: [:create, :edit, :update] + before_action :find_account_by_reset_code, only: [:edit, :update] # Forgot password def create if account = Account.find_by(email: params[:email], activation_code: nil) account.forgot_password! - redirect_to login_path, :notice => t(:password_reset_link_has_been_sent) + redirect_to(login_path, notice: t(:password_reset_link_has_been_sent)) else flash[:alert] = t(:could_not_find_user_with_email_address) - render :action => 'new' + render(action: "new") end end # Reset password def update - unless params[:password].blank? - if @account.update_attributes(:password => params[:password], :password_confirmation => params[:password_confirmation]) - redirect_to login_path, :notice => t(:password_reset) - else - flash[:alert] = t(:password_mismatch) - render :action => 'edit' - end - else + if params[:password].blank? flash[:alert] = t(:password_cannot_be_blank) - render :action => 'edit' + render(action: "edit") + elsif @account.update(password: params[:password], password_confirmation: params[:password_confirmation]) + redirect_to(login_path, notice: t(:password_reset)) + else + flash[:alert] = t(:password_mismatch) + render(action: "edit") end end @@ -34,11 +32,11 @@ def update def find_account_by_reset_code @reset_code = params[:id] @account = @reset_code.blank? ? nil : Account.find_by(password_reset_code: @reset_code) - redirect_to(forgot_password_path, :alert => t(:reset_code_invalid_try_again)) unless @account + redirect_to(forgot_password_path, alert: t(:reset_code_invalid_try_again)) unless @account end def check_can_change_password - render_404 unless Masq::Engine.config.masq['can_change_password'] + render_404 unless Masq::Engine.config.masq["can_change_password"] end end end diff --git a/app/controllers/masq/personas_controller.rb b/app/controllers/masq/personas_controller.rb index 341dc69..8514800 100644 --- a/app/controllers/masq/personas_controller.rb +++ b/app/controllers/masq/personas_controller.rb @@ -1,7 +1,7 @@ module Masq class PersonasController < BaseController before_action :login_required - before_action :store_return_url, :only => [:new, :edit] + before_action :store_return_url, only: [:new, :edit] helper_method :persona @@ -17,25 +17,24 @@ def new @persona = current_account.personas.new end - def create respond_to do |format| if persona.save! flash[:notice] = t(:persona_successfully_created) - format.html { redirect_back_or_default account_personas_path } + format.html { redirect_back_or_default(account_personas_path) } else - format.html { render :action => "new" } + format.html { render(action: "new") } end end end def update respond_to do |format| - if persona.update_attributes(persona_params) + if persona.update(persona_params) flash[:notice] = t(:persona_updated) - format.html { redirect_back_or_default account_personas_path } + format.html { redirect_back_or_default(account_personas_path) } else - format.html { render :action => "edit" } + format.html { render(action: "edit") } end end end @@ -45,7 +44,7 @@ def destroy unless persona.destroy flash[:alert] = t(:persona_cannot_be_deleted) end - format.html { redirect_to account_personas_path } + format.html { redirect_to(account_personas_path) } end end @@ -60,12 +59,12 @@ def persona def persona_params rejected_keys = [:created_at, :updated_at, :account_id, :deletable] params.require(:persona).permit!.except(rejected_keys) - end + end def redirect_back_or_default(default) case session[:return_to] - when decide_path then redirect_to decide_path(:persona_id => persona.id) - else super(default) + when decide_path then redirect_to(decide_path(persona_id: persona.id)) + else super end end diff --git a/app/controllers/masq/server_controller.rb b/app/controllers/masq/server_controller.rb index b6d5965..9895255 100644 --- a/app/controllers/masq/server_controller.rb +++ b/app/controllers/masq/server_controller.rb @@ -26,7 +26,7 @@ def index elsif openid_request handle_non_checkid_request else - render :plain => t(:this_is_openid_not_a_human_ressource) + render(plain: t(:this_is_openid_not_a_human_ressource)) end end format.xrds @@ -55,7 +55,7 @@ def proceed elsif checkid_request.immediate render_response(checkid_request.answer(true, nil, identity)) else - redirect_to decide_path + redirect_to(decide_path) end end @@ -76,7 +76,7 @@ def complete resp = checkid_request.answer(true, nil, identifier(current_account)) if params[:always] @site = current_account.sites.where(persona_id: params[:site][:persona_id], url: params[:site][:url]).first_or_create - @site.update_attributes(site_params) + @site.update(site_params) elsif sreg_request || ax_fetch_request @site = current_account.sites.where(persona_id: params[:site][:persona_id], url: params[:site][:url]).first_or_create @site.attributes = site_params @@ -111,7 +111,7 @@ def complete # Cancels the current OpenID request def cancel if checkid_request - redirect_to checkid_request.cancel_url + redirect_to(checkid_request.cancel_url) else reset_session redirect_to(login_path) @@ -128,7 +128,7 @@ def cancel def handle_checkid_request if allow_verification? save_checkid_request - redirect_to proceed_path + redirect_to(proceed_path) elsif openid_request.immediate render_response(openid_request.answer(false)) else @@ -152,7 +152,7 @@ def save_checkid_request # Deletes the old request when a new one comes in. def clear_checkid_request unless session[:request_token].blank? - OpenIdRequest.where(:token => session[:request_token]).destroy_all + OpenIdRequest.where(token: session[:request_token]).destroy_all session[:request_token] = nil end end @@ -164,13 +164,13 @@ def clear_checkid_request def ensure_valid_checkid_request self.openid_request = checkid_request if !openid_request.is_a?(OpenID::Server::CheckIDRequest) - redirect_to root_path, alert: t(:identity_verification_request_invalid) + redirect_to(root_path, alert: t(:identity_verification_request_invalid)) elsif !allow_verification? - flash[:notice] = logged_in? && !pape_requirements_met?(auth_time) ? + flash[:notice] = (logged_in? && !pape_requirements_met?(auth_time)) ? t(:service_provider_requires_reauthentication_last_login_too_long_ago) : t(:login_to_verify_identity) session[:return_to] = proceed_path - redirect_to login_path + redirect_to(login_path) end end @@ -184,7 +184,7 @@ def allow_verification? # must be logged in, so that we know his identifier or the identifier # has to be selected by the server (id_select). def correct_identifier? - (openid_request.identity == identifier(current_account) || openid_request.id_select) + openid_request.identity == identifier(current_account) || openid_request.id_select end # Clears the stored request and answers @@ -197,9 +197,9 @@ def render_response(resp) def transform_ax_data(parameters) data = {} parameters.each_pair do |key, details| - if details['value'] - data["type.#{key}"] = details['type'] - data["value.#{key}"] = details['value'] + if details["value"] + data["type.#{key}"] = details["type"] + data["value.#{key}"] = details["value"] end end data @@ -208,10 +208,10 @@ def transform_ax_data(parameters) # Renders the exception message as text output def render_openid_error(exception) error = case exception - when OpenID::Server::MalformedTrustRoot then "Malformed trust root '#{exception}'" - else exception.to_s + when OpenID::Server::MalformedTrustRoot then "Malformed trust root '#{exception}'" + else exception.to_s end - render plain: "Invalid OpenID request: #{error}", status: 500 + render(plain: "Invalid OpenID request: #{error}", status: 500) end private @@ -219,7 +219,7 @@ def render_openid_error(exception) # The NIST Assurance Level, see: # http://openid.net/specs/openid-provider-authentication-policy-extension-1_0-01.html#anchor12 def auth_level - if Masq::Engine.config.masq['use_ssl'] + if Masq::Engine.config.masq["use_ssl"] current_account.last_authenticated_by_yubikey? ? 3 : 2 else 0 diff --git a/app/controllers/masq/sessions_controller.rb b/app/controllers/masq/sessions_controller.rb index 769d84a..038f41c 100644 --- a/app/controllers/masq/sessions_controller.rb +++ b/app/controllers/masq/sessions_controller.rb @@ -1,7 +1,7 @@ module Masq class SessionsController < BaseController - before_action :login_required, :only => :destroy - after_action :set_login_cookie, :only => :create + before_action :login_required, only: :destroy + after_action :set_login_cookie, only: :create def new redirect_after_login if logged_in? @@ -15,41 +15,42 @@ def create else a = Account.find_by(login: params[:login]) if a.nil? - redirect_to login_path, :alert => t(:login_incorrect) + redirect_to(login_path, alert: t(:login_incorrect)) elsif a.active? && a.enabled? - redirect_to login_path, :alert => t(:password_incorrect) - elsif not a.enabled? - redirect_to login_path, :alert => t(:account_deactivated) + redirect_to(login_path, alert: t(:password_incorrect)) + elsif !a.enabled? + redirect_to(login_path, alert: t(:account_deactivated)) else - redirect_to login_path(:resend_activation_for => params[:login]), :alert => t(:account_not_yet_activated) + redirect_to(login_path(resend_activation_for: params[:login]), alert: t(:account_not_yet_activated)) end end end def destroy current_account.forget_me - cookies.delete :auth_token + cookies.delete(:auth_token) reset_session - redirect_to root_path, :notice => t(:you_are_now_logged_out) + redirect_to(root_path, notice: t(:you_are_now_logged_out)) end private def set_login_cookie - if logged_in? and params[:remember_me] == '1' + if logged_in? and params[:remember_me] == "1" current_account.remember_me cookies[:auth_token] = { - :value => current_account.remember_token, - :expires => current_account.remember_token_expires_at } + value: current_account.remember_token, + expires: current_account.remember_token_expires_at, + } end end def redirect_after_login if return_to = session[:return_to] session[:return_to] = nil - redirect_to return_to + redirect_to(return_to) else - redirect_to identifier(current_account) + redirect_to(identifier(current_account)) end end end diff --git a/app/controllers/masq/sites_controller.rb b/app/controllers/masq/sites_controller.rb index 88961b3..e949658 100644 --- a/app/controllers/masq/sites_controller.rb +++ b/app/controllers/masq/sites_controller.rb @@ -1,7 +1,7 @@ module Masq class SitesController < BaseController before_action :login_required - before_action :find_personas, :only => [:create, :edit, :update] + before_action :find_personas, only: [:create, :edit, :update] helper_method :site, :persona @@ -19,11 +19,11 @@ def edit def update respond_to do |format| - if site.update_attributes(site_params) + if site.update(site_params) flash[:notice] = t(:release_policy_for_site_updated) - format.html { redirect_to edit_account_site_path(site) } + format.html { redirect_to(edit_account_site_path(site)) } else - format.html { render :action => 'edit' } + format.html { render(action: "edit") } end end end @@ -32,7 +32,7 @@ def destroy site.destroy respond_to do |format| - format.html { redirect_to account_sites_path } + format.html { redirect_to(account_sites_path) } end end diff --git a/app/controllers/masq/yubikey_associations_controller.rb b/app/controllers/masq/yubikey_associations_controller.rb index 24ac314..6aa64ca 100644 --- a/app/controllers/masq/yubikey_associations_controller.rb +++ b/app/controllers/masq/yubikey_associations_controller.rb @@ -9,7 +9,7 @@ def create flash[:alert] = t(:sorry_yubico_one_time_password_incorrect) end respond_to do |format| - format.html { redirect_to edit_account_path } + format.html { redirect_to(edit_account_path) } end end @@ -18,7 +18,7 @@ def destroy current_account.save respond_to do |format| - format.html { redirect_to edit_account_path, :notice => t(:account_disassociated_from_yubico_identity) } + format.html { redirect_to(edit_account_path, notice: t(:account_disassociated_from_yubico_identity)) } end end end diff --git a/app/helpers/masq/application_helper.rb b/app/helpers/masq/application_helper.rb index 6e7941a..9050f45 100644 --- a/app/helpers/masq/application_helper.rb +++ b/app/helpers/masq/application_helper.rb @@ -1,28 +1,27 @@ module Masq - module ApplicationHelper def page_title - (@page_title||=nil) ? "#{@page_title} | #{Masq::Engine.config.masq['name']}" : Masq::Engine.config.masq['name'] + (@page_title ||= nil) ? "#{@page_title} | #{Masq::Engine.config.masq["name"]}" : Masq::Engine.config.masq["name"] end def label_tag(field, text = nil, options = {}) - content_tag :label, text ? text : field.to_s.humanize, options.reverse_merge(:for => field.to_s) + content_tag(:label, text ? text : field.to_s.humanize, options.reverse_merge(for: field.to_s)) end def error_messages_for(*objects) - render "masq/shared/error_messages", :objects => objects.flatten + render("masq/shared/error_messages", objects: objects.flatten) end # Is the current page an identity page? This is used to display # further information (like the endoint url) in the def identity_page? - active_page? 'accounts' => ['show'] + active_page?("accounts" => ["show"]) end # Is the current page the home page? This is used to display # further information (like the endoint url) in the def home_page? - active_page? 'info' => ['index'] + active_page?("info" => ["index"]) end # Custom label names for request properties (like SReg data) @@ -43,7 +42,7 @@ def property_label_text_for_type_uri(type_uri) # Renders a navigation element and marks it as active where # appropriate. See active_page? for details def nav(name, url, pages = nil, active = false) - content_tag :li, link_to(name, url), :class => (active || (pages && active_page?(pages)) ? 'act' : nil) + content_tag(:li, link_to(name, url), class: ((active || (pages && active_page?(pages))) ? "act" : nil)) end # Takes a hash with pages and tells whether the current page is among them. diff --git a/app/helpers/masq/personas_helper.rb b/app/helpers/masq/personas_helper.rb index 2291fa5..f93302b 100644 --- a/app/helpers/masq/personas_helper.rb +++ b/app/helpers/masq/personas_helper.rb @@ -1,15 +1,15 @@ -require 'i18n_data' +require "i18n_data" module Masq module PersonasHelper # get list of codes and names sorted by country name def countries_for_select - ::I18nData.countries.map{|pair| pair.reverse}.sort{|x,y| x.first <=> y.first} + ::I18nData.countries.map { |pair| pair.reverse }.sort_by(&:first) end # get list of codes and names sorted by language name def languages_for_select - ::I18nData.languages.map{|pair| pair.reverse}.sort{|x,y| x.first <=> y.first} + ::I18nData.languages.map { |pair| pair.reverse }.sort_by(&:first) end end end diff --git a/app/mailers/masq/account_mailer.rb b/app/mailers/masq/account_mailer.rb index 05ce898..2ad9db2 100644 --- a/app/mailers/masq/account_mailer.rb +++ b/app/mailers/masq/account_mailer.rb @@ -1,17 +1,17 @@ module Masq class AccountMailer < ActionMailer::Base - default :from => Masq::Engine.config.masq['email'] - default_url_options[:host] = Masq::Engine.config.masq['host'] + default from: Masq::Engine.config.masq["email"] + default_url_options[:host] = Masq::Engine.config.masq["host"] def signup_notification(account) - raise "send_activation_mail deactivated" unless Masq::Engine.config.masq['send_activation_mail'] + raise "send_activation_mail deactivated" unless Masq::Engine.config.masq["send_activation_mail"] @account = account - mail :to => account.email, :subject => I18n.t(:please_activate_your_account) + mail(to: account.email, subject: I18n.t(:please_activate_your_account)) end def forgot_password(account) @account = account - mail :to => account.email, :subject => I18n.t(:your_request_for_a_new_password) + mail(to: account.email, subject: I18n.t(:your_request_for_a_new_password)) end end end diff --git a/app/models/masq/account.rb b/app/models/masq/account.rb index 71f293b..7a4fb75 100644 --- a/app/models/masq/account.rb +++ b/app/models/masq/account.rb @@ -1,35 +1,36 @@ -require 'digest/sha1' +require "digest/sha1" module Masq class Account < ActiveRecord::Base - has_many :personas, ->(){order(:id)}, :dependent => :delete_all - has_many :sites, :dependent => :destroy - belongs_to :public_persona, :class_name => "Persona", optional: true + has_many :personas, ->() { order(:id) }, dependent: :delete_all + has_many :sites, dependent: :destroy + belongs_to :public_persona, class_name: "Persona", optional: true validates_presence_of :login - validates_length_of :login, :within => 3..254 - validates_uniqueness_of :login, :case_sensitive => false - validates_format_of :login, :with => /\A[A-Za-z0-9_@.-]+\z/ + validates_length_of :login, within: 3..254 + validates_uniqueness_of :login, case_sensitive: false + validates_format_of :login, with: /\A[A-Za-z0-9_@.-]+\z/ validates_presence_of :email - validates_uniqueness_of :email, :case_sensitive => false - validates_format_of :email, :with => /(\A([^@\s]+)@((?:[-_a-z0-9]+\.)+[a-z]{2,})\z)/i, :allow_blank => true - validates_presence_of :password, :if => :password_required? - validates_presence_of :password_confirmation, :if => :password_required? - validates_length_of :password, :within => 6..40, :if => :password_required? - validates_confirmation_of :password, :if => :password_required? + validates_uniqueness_of :email, case_sensitive: false + validates_format_of :email, with: /(\A([^@\s]+)@((?:[-_a-z0-9]+\.)+[a-z]{2,})\z)/i, allow_blank: true + validates_presence_of :password, if: :password_required? + validates_presence_of :password_confirmation, if: :password_required? + validates_length_of :password, within: 6..40, if: :password_required? + validates_confirmation_of :password, if: :password_required? # check `rake routes' for whether this list is still complete when routes are changed - validates_exclusion_of :login, :in => %w[account session password help safe-login forgot_password reset_password login logout server consumer] + validates_exclusion_of :login, in: %w[account session password help safe-login forgot_password reset_password login logout server consumer] - before_save :encrypt_password - after_save :deliver_forgot_password + before_save :encrypt_password + after_save :deliver_forgot_password - #attr_accessible :login, :email, :password, :password_confirmation, :public_persona_id, :yubikey_mandatory + # attr_accessible :login, :email, :password, :password_confirmation, :public_persona_id, :yubikey_mandatory attr_accessor :password class ActivationCodeNotFound < StandardError; end + class AlreadyActivated < StandardError attr_reader :user, :message - def initialize(account, message=nil) + def initialize(account, message = nil) @message, @account = message, account end end @@ -61,7 +62,7 @@ def activate! @activated = true self.activated_at = Time.now.utc self.activation_code = nil - self.save + save end # True if the user has just been activated @@ -76,28 +77,29 @@ def has_otp_device? # Authenticates a user by their login name and password. # Returns the user or nil. - def self.authenticate(login, password, basic_auth_used=false) + def self.authenticate(login, password, basic_auth_used = false) a = Account.find_by(login: login) - if a.nil? and Masq::Engine.config.masq['create_auth_ondemand']['enabled'] + if a.nil? and Masq::Engine.config.masq["create_auth_ondemand"]["enabled"] # Need to set some password - but is never used - if Masq::Engine.config.masq['create_auth_ondemand']['random_password'] - pw = SecureRandom.hex(13) + pw = if Masq::Engine.config.masq["create_auth_ondemand"]["random_password"] + SecureRandom.hex(13) else - pw = password + password end signup = Signup.create_account!( - :login => login, - :password => pw, - :password_confirmation => pw, - :email => "#{login}@#{Masq::Engine.config.masq['create_auth_ondemand']['default_mail_domain']}") + login: login, + password: pw, + password_confirmation: pw, + email: "#{login}@#{Masq::Engine.config.masq["create_auth_ondemand"]["default_mail_domain"]}", + ) a = signup.account if signup.succeeded? end - if not a.nil? and a.active? and a.enabled - if a.authenticated?(password) or (Masq::Engine.config.masq['trust_basic_auth'] and basic_auth_used) + if !a.nil? and a.active? and a.enabled + if a.authenticated?(password) or (Masq::Engine.config.masq["trust_basic_auth"] and basic_auth_used) a.last_authenticated_at, a.last_authenticated_by_yubikey = Time.now, a.authenticated_with_yubikey? - a.save(:validate => false) - return a + a.save(validate: false) + a end end end @@ -114,10 +116,10 @@ def encrypt(password) def authenticated?(password) if password.nil? - return false + false elsif password.length < 50 && !(yubico_identity? && yubikey_mandatory?) encrypt(password) == crypted_password - elsif Masq::Engine.config.masq['can_use_yubikey'] + elsif Masq::Engine.config.masq["can_use_yubikey"] password, yubico_otp = Account.split_password_and_yubico_otp(password) encrypt(password) == crypted_password && @authenticated_with_yubikey = yubikey_authenticated?(yubico_otp) end @@ -139,7 +141,7 @@ def authenticated_with_yubikey? def associate_with_yubikey(otp) if Account.verify_yubico_otp(otp) self.yubico_identity = Account.extract_yubico_identity_from_otp(otp) - save(:validate => false) + save(validate: false) else false end @@ -151,23 +153,23 @@ def remember_token? # These create and unset the fields required for remembering users between browser closes def remember_me - remember_me_for 2.weeks + remember_me_for(2.weeks) end def remember_me_for(time) - remember_me_until time.from_now.utc + remember_me_until(time.from_now.utc) end def remember_me_until(time) self.remember_token_expires_at = time self.remember_token = encrypt("#{email}--#{remember_token_expires_at}") - save(:validate => false) + save(validate: false) end def forget_me self.remember_token_expires_at = nil self.remember_token = nil - save(:validate => false) + save(validate: false) end def forgot_password! @@ -199,7 +201,7 @@ def disable! def encrypt_password return if password.blank? - self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record? + self.salt = Digest::SHA1.hexdigest("--#{Time.now}--#{login}--") if new_record? self.crypted_password = encrypt(password) end @@ -208,7 +210,7 @@ def password_required? end def make_password_reset_code - self.password_reset_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join ) + self.password_reset_code = Digest::SHA1.hexdigest(Time.now.to_s.split("").sort_by { rand }.join) end private @@ -230,16 +232,13 @@ def self.split_password_and_yubico_otp(token) # Utilizes the Yubico library to verify an one time password def self.verify_yubico_otp(otp) - begin - Yubikey::OTP::Verify.new(otp).valid? - rescue Yubikey::OTP::InvalidOTPError - false - end + Yubikey::OTP::Verify.new(otp).valid? + rescue Yubikey::OTP::InvalidOTPError + false end def deliver_forgot_password AccountMailer.forgot_password(self).deliver_now if recently_forgot_password? end - end end diff --git a/app/models/masq/open_id_request.rb b/app/models/masq/open_id_request.rb index ba39c85..f964e94 100644 --- a/app/models/masq/open_id_request.rb +++ b/app/models/masq/open_id_request.rb @@ -2,39 +2,37 @@ module Masq class OpenIdRequest < ActiveRecord::Base validates_presence_of :token, :parameters - before_validation :make_token, :on => :create + before_validation :make_token, on: :create - #attr_accessible :parameters - serialize :parameters, JSON + serialize :parameters, type: Hash, coder: JSON def parameters self[:parameters] end + def parameters=(params) self[:parameters] = case params # arbitrary params passed as Hash when Hash - params.delete_if { |k,v| k.index('openid.') != 0 } + params.delete_if { |k, v| k.index("openid.") != 0 } # params from ActionController (does not inherit directly from HashWithIndifferentAccess after Rails 4.2) when ActionController::Parameters - params.to_unsafe_h.delete_if { |k,v| k.index('openid.') != 0 } - else - nil + params.to_unsafe_h.delete_if { |k, v| k.index("openid.") != 0 } end end def from_trusted_domain? - host = URI.parse(parameters['openid.realm'] || parameters['openid.trust_root']).host - unless Masq::Engine.config.masq['trusted_domains'].nil? - Masq::Engine.config.masq['trusted_domains'].find { |domain| host.ends_with? domain } + host = URI.parse(parameters["openid.realm"] || parameters["openid.trust_root"]).host + unless Masq::Engine.config.masq["trusted_domains"].nil? + Masq::Engine.config.masq["trusted_domains"].find { |domain| host.ends_with?(domain) } end end private def make_token - self.token = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join ) + self.token = Digest::SHA1.hexdigest(Time.now.to_s.split("").sort_by { rand }.join) end end end diff --git a/app/models/masq/persona.rb b/app/models/masq/persona.rb index 07b87a8..5cbe41e 100644 --- a/app/models/masq/persona.rb +++ b/app/models/masq/persona.rb @@ -1,15 +1,15 @@ module Masq class Persona < ActiveRecord::Base belongs_to :account - has_many :sites, :dependent => :destroy + has_many :sites, dependent: :destroy validates_presence_of :account validates_presence_of :title - validates_uniqueness_of :title, :scope => :account_id + validates_uniqueness_of :title, scope: :account_id before_destroy :check_deletable! - #attr_protected :account_id, :deletable + # attr_protected :account_id, :deletable def self.properties Persona.mappings.keys @@ -23,16 +23,16 @@ def self.attribute_name_for_type_uri(type_uri) # Returns the personas attribute for the given SReg name or AX Type URI def property(type) prop = Persona.mappings.detect { |i| i[1].include?(type) } - prop ? self.send(prop[0]).to_s : nil + prop ? send(prop[0]).to_s : nil end def date_of_birth - "#{dob_year? ? dob_year : '0000'}-#{dob_month? ? dob_month.to_s.rjust(2, '0') : '00'}-#{dob_day? ? dob_day.to_s.rjust(2, '0') : '00'}" + "#{dob_year? ? dob_year : "0000"}-#{dob_month? ? dob_month.to_s.rjust(2, "0") : "00"}-#{dob_day? ? dob_day.to_s.rjust(2, "0") : "00"}" end def fullname=(name) - self.firstname, self.surname = name.to_s.split(' ') - self.surname ||= self.firstname + self.firstname, self.surname = name.to_s.split(" ") + self.surname ||= firstname self[:fullname] = name end @@ -41,7 +41,6 @@ def date_of_birth=(dob) self.dob_year = res[0] self.dob_month = res[1] self.dob_day = res[2] - dob end protected @@ -54,7 +53,7 @@ def check_deletable! # Mappings for SReg names and AX Type URIs to attributes def self.mappings - Masq::Engine.config.masq['attribute_mappings'] + Masq::Engine.config.masq["attribute_mappings"] end end end diff --git a/app/models/masq/release_policy.rb b/app/models/masq/release_policy.rb index f6b758e..a228b2a 100644 --- a/app/models/masq/release_policy.rb +++ b/app/models/masq/release_policy.rb @@ -4,8 +4,8 @@ class ReleasePolicy < ActiveRecord::Base validates_presence_of :site validates_presence_of :property - validates_uniqueness_of :property, :scope => [:site_id, :type_identifier] + validates_uniqueness_of :property, scope: [:site_id, :type_identifier] - #attr_accessible :property, :type_identifier + # attr_accessible :property, :type_identifier end end diff --git a/app/models/masq/signup.rb b/app/models/masq/signup.rb index 7fc54ad..70d86df 100644 --- a/app/models/masq/signup.rb +++ b/app/models/masq/signup.rb @@ -1,11 +1,11 @@ -require 'digest/sha1' +require "digest/sha1" module Masq class Signup attr_accessor :account def self.create_account!(attrs = {}) - signup = Signup.new attrs + signup = Signup.new(attrs) signup.send(:create_account!) signup end @@ -15,7 +15,7 @@ def succeeded? end def send_activation_email? - Masq::Engine.config.masq['send_activation_mail'] + Masq::Engine.config.masq["send_activation_mail"] end protected @@ -38,14 +38,13 @@ def create_account! end def make_activation_code - account.activation_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join ) + account.activation_code = Digest::SHA1.hexdigest(Time.now.to_s.split("").sort_by { rand }.join) end def make_default_persona - account.public_persona = account.personas.build(:title => "Standard", :email => account.email) + account.public_persona = account.personas.build(title: "Standard", email: account.email) account.public_persona.deletable = false account.public_persona.save! end - end end diff --git a/app/models/masq/site.rb b/app/models/masq/site.rb index 103cb2a..a37e397 100644 --- a/app/models/masq/site.rb +++ b/app/models/masq/site.rb @@ -2,11 +2,11 @@ module Masq class Site < ActiveRecord::Base belongs_to :account belongs_to :persona - has_many :release_policies, :dependent => :destroy + has_many :release_policies, dependent: :destroy validates_presence_of :url, :persona, :account - validates_uniqueness_of :url, :scope => :account_id - #attr_accessible :url, :persona_id, :properties, :ax_fetch, :sreg + validates_uniqueness_of :url, scope: :account_id + # attr_accessible :url, :persona_id, :properties, :ax_fetch, :sreg # Sets the release policies by first deleting the old ones and # then appending a new one for every given sreg and ax property. @@ -19,7 +19,7 @@ class Site < ActiveRecord::Base def properties=(props) release_policies.destroy_all props.each_pair do |property, details| - release_policies.build(:property => property, :type_identifier => details['type']) if details['value'] + release_policies.build(property: property, type_identifier: details["type"]) if details["value"] end end @@ -28,7 +28,7 @@ def properties=(props) # to set the attributes recieved from the decision form. def ax_fetch=(props) props.each_pair do |property, details| - release_policies.build(:property => property, :type_identifier => details['type']) if details['value'] + release_policies.build(property: property, type_identifier: details["type"]) if details["value"] end end @@ -37,7 +37,7 @@ def ax_fetch=(props) # to set the attributes recieved from the decision form. def sreg=(props) props.each_key do |property| - release_policies.build(:property => property, :type_identifier => property) + release_policies.build(property: property, type_identifier: property) end end @@ -57,9 +57,9 @@ def sreg_properties def ax_properties props = {} release_policies.each do |rp| - if rp.type_identifier.match("://") + if rp.type_identifier.match?("://") props["type.#{rp.property}"] = rp.type_identifier - props["value.#{rp.property}"] = persona.property(rp.type_identifier ) + props["value.#{rp.property}"] = persona.property(rp.type_identifier) end end props diff --git a/app/views/layouts/masq/consumer.html.erb b/app/views/layouts/masq/consumer.html.erb index 69ad620..ce08590 100644 --- a/app/views/layouts/masq/consumer.html.erb +++ b/app/views/layouts/masq/consumer.html.erb @@ -21,7 +21,7 @@