From a9d6d821da2f74f57cf6d53037fbc5798605e905 Mon Sep 17 00:00:00 2001 From: alex-sig <143193681+alex-sig@users.noreply.github.com> Date: Thu, 10 Oct 2024 15:55:56 +0530 Subject: [PATCH] OTWO-7311 Remove Firebase phone auth (#1802) * OTWO-7311 Relax Github oauth restrictions * OTWO-7311 Remove Firebase phone auth --- .env | 4 - .env.test | 4 - app/assets/javascripts/accounts.js.coffee | 9 +- app/assets/javascripts/firebase.coffee | 42 --- app/assets/stylesheets/account.sass | 9 +- app/assets/stylesheets/static_forms.sass | 23 -- app/controllers/accounts_controller.rb | 4 +- app/controllers/application_controller.rb | 2 +- app/controllers/authentications_controller.rb | 22 +- app/models/account.rb | 2 +- app/models/account/access.rb | 4 +- app/models/firebase_verification.rb | 19 +- app/models/github_api.rb | 16 - app/models/github_verification.rb | 2 + app/models/manual_verification.rb | 2 +- app/models/reverification_tracker.rb | 2 +- app/models/verification.rb | 3 +- app/services/firebase_service.rb | 101 ------ app/views/accounts/_fields.html.haml | 14 - app/views/accounts/new.html.haml | 12 +- app/views/authentications/_fields.html.haml | 15 - app/views/layouts/application.html.haml | 4 - .../layouts/partials/_js_scripts.html.haml | 7 +- .../initializers/content_security_policy.rb | 2 +- config/locales/accounts.en.yml | 2 - config/locales/en.yml | 1 - config/routes.rb | 1 - features/sign_up_and_verify.feature | 8 +- features/steps/sign_up_and_verify.rb | 12 +- .../GithubVerificationSpammer.yml | 304 ------------------ test/controllers/accounts_controller_test.rb | 18 +- .../authentications_controller_test.rb | 75 ----- test/controllers/spam_controller_test.rb | 15 +- .../ruby/active_record_migrator_patch_test.rb | 11 + test/factories/verifications.rb | 5 +- test/lib/email_obfuscation_test.rb | 13 + test/mailers/account_mailer_test.rb | 8 + test/models/account/access_test.rb | 11 + test/models/firebase_verification_test.rb | 41 --- test/models/github_api_test.rb | 32 -- test/models/github_verification_test.rb | 8 + test/models/manual_verification_test.rb | 13 + test/models/reverification_tracker_test.rb | 4 +- test/services/firebase_service_test.rb | 51 --- test/test_helper.rb | 16 - 45 files changed, 119 insertions(+), 854 deletions(-) delete mode 100644 app/assets/javascripts/firebase.coffee delete mode 100644 app/services/firebase_service.rb delete mode 100644 fixtures/vcr_cassettes/GithubVerificationSpammer.yml create mode 100644 test/core_extensions/ruby/active_record_migrator_patch_test.rb create mode 100644 test/lib/email_obfuscation_test.rb delete mode 100644 test/models/firebase_verification_test.rb create mode 100644 test/models/manual_verification_test.rb delete mode 100644 test/services/firebase_service_test.rb diff --git a/.env b/.env index 1e6c0c9b1..3aff95c46 100644 --- a/.env +++ b/.env @@ -60,10 +60,6 @@ TRAVIS_API_BASE_URL = 'https://api.travis-ci.org/' CII_API_BASE_URL = 'https://bestpractices.coreinfrastructure.org/' CII_PROJECTS_EMAIL_RECEIPIENT = 'ohteam@blackduck.com' -FIREBASE_API_KEY = -FIREBASE_PROJECT_ID = -FIREBASE_AUTH_DOMAIN = - CODE_SUBDOMAIN = 'code' FISBOT_CLIENT_REGISTRATION_ID = diff --git a/.env.test b/.env.test index 0dcb60a24..6dabe78ce 100644 --- a/.env.test +++ b/.env.test @@ -19,13 +19,9 @@ KB_PROJECT_SEARCH_URL = 'https://www.vcrlocalhost.org/kb?' KB_AUTH_KEY = 'dummy_test_key' OHLOH_CIPHER_KEY = 'ohlohuiapplicationcipherkeyforminitestcases' -FIREBASE_API_KEY = 'dummy_firebase_api_key' GITHUB_CLIENT_ID = 'dummy_github_client_id' GITHUB_CLIENT_SECRET = 'dummy_github_client_secret' -FIREBASE_PROJECT_ID = "openhub-test" -FIREBASE_AUTH_DOMAIN = "openhub-test.firebaseapp.com" - GITHUB_REDIRECT_URI = "http://lvh.me:3000/authentications/github_callback" FISBOT_API_URL = 'http://vcrlocalhost.org:4004' diff --git a/app/assets/javascripts/accounts.js.coffee b/app/assets/javascripts/accounts.js.coffee index 49ee30564..4b00c808f 100644 --- a/app/assets/javascripts/accounts.js.coffee +++ b/app/assets/javascripts/accounts.js.coffee @@ -2,7 +2,7 @@ $(document).on 'page:change', -> if $('#account_affiliation_type').length new App.OrganizationSelector('account') - + $('.show-more-2').click -> if $('.text-2').hasClass('show-more-height-2') $(this).text 'Show Less' @@ -15,4 +15,9 @@ $(document).on 'page:change', -> $(this).text 'Show Less' else $(this).text 'Show More' - $('.text-1').toggleClass 'show-more-height-1' \ No newline at end of file + $('.text-1').toggleClass 'show-more-height-1' + + if $('#email-sign-up').length + $('#email-sign-up').click -> + $('#sign-up-options').remove() + $('#sign-up-fields').show() diff --git a/app/assets/javascripts/firebase.coffee b/app/assets/javascripts/firebase.coffee deleted file mode 100644 index f8d05a2f7..000000000 --- a/app/assets/javascripts/firebase.coffee +++ /dev/null @@ -1,42 +0,0 @@ -uiConfig = -> - 'signInSuccessUrl': '/' - 'callbacks': - 'signInSuccessWithAuthResult': (authResult) -> - user = authResult.user - user.getIdToken().then (idToken) -> - $('#credentials').val idToken - $('#hidden-verified-label').show() - $('.phone-verification-form').submit() - false - 'signInFlow': 'popup' - 'signInOptions': [ { - provider: firebase.auth.PhoneAuthProvider.PROVIDER_ID - recaptchaParameters: size: 'invisible' - } ] - 'tosUrl': 'https://community.blackduck.com/s/article/Black-Duck-Open-Hub-Terms-of-Use' - 'privacyPolicyUrl': -> - window.location.assign 'https://community.blackduck.com/s/article/Black-Duck-Open-Hub-Open-Hub-Privacy-Policy' - -initializeFirebase = -> - firebase.initializeApp( - apiKey: $('[name=firebase-consumer-key]').attr('content') - authDomain: $('[name=firebase-app-url]').attr('content') - projectId: $('[name=firebase-app-id]').attr('content') - ) - -displayUI = -> - ui = new firebaseui.auth.AuthUI(firebase.auth()) - ui.start '#firebaseui-auth-container', uiConfig() - -startFirebase = -> - initializeFirebase() - displayUI() - -$(document).on 'page:change', -> - if $('#digits-sign-up').length - $('#digits-sign-up').click -> - $('#sign-up-options').remove() - $('#sign-up-fields').show() - startFirebase() - else if $('#firebaseui-auth-container').length - setTimeout(startFirebase, 1000) diff --git a/app/assets/stylesheets/account.sass b/app/assets/stylesheets/account.sass index aed0b4fdf..cbdaa6d07 100644 --- a/app/assets/stylesheets/account.sass +++ b/app/assets/stylesheets/account.sass @@ -132,7 +132,7 @@ margin-left: auto margin-right: auto text-align: center - #digits-sign-up + #email-sign-up width: 200px .github-oauth width: 200px @@ -140,13 +140,6 @@ #accounts_unsubscribe_emails_page padding: 0 30px 0 20px !important -#hidden-verified-label - display: none - -.verified - display: block - margin-bottom: 10px - .grecaptcha-badge display: none @media only all and (min-width: 768px) and (max-width: 1024px) diff --git a/app/assets/stylesheets/static_forms.sass b/app/assets/stylesheets/static_forms.sass index 787de9051..3c5734cd8 100644 --- a/app/assets/stylesheets/static_forms.sass +++ b/app/assets/stylesheets/static_forms.sass @@ -697,26 +697,3 @@ span.add-on -moz-box-sizing: content-box -ms-box-sizing: content-box box-sizing: content-box - -@media (min-width: 768px) and (max-width: 1024px) - #firebaseui-auth-container - width: 115% - margin-left: -10px - - .firebaseui-country-selector - width: 65px - - .firebaseui-flag - width: 15px - - .firebaseui-button - width: 60px - padding: 0px 10px !important - margin-left: -15px !important - - .firebaseui-title - font-size: 15px - -@media (min-width: 320px) and (max-width: 480px) - .firebaseui-title - font-size: 15px diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 6f5c9420a..7855a8277 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -18,11 +18,11 @@ class AccountsController < ApplicationController def new @account = Account.new - @account.build_firebase_verification end def create @account = Account.new(account_params) + @account.build_manual_verification if @account.save clearance_session.sign_in @account @@ -114,7 +114,7 @@ def account_params params.require(:account).permit( :login, :email, :password, :name, :country_code, :location, :latitude, :longitude, :twitter_account, :organization_id, :organization_name, :affiliation_type, :invite_code, - :about_raw, :url, firebase_verification_attributes: [:credentials] + :about_raw, :url ) end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 7435d549e..12bc0256f 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -307,7 +307,7 @@ def redirect_for_email_activation end def redirect_for_spammer_verification - return if current_user && !current_user.access.disabled? && current_user.access.mobile_or_oauth_verified? + return if current_user && !current_user.access.disabled? && current_user.access.manual_or_oauth_verified? redirect_to new_authentication_path end diff --git a/app/controllers/authentications_controller.rb b/app/controllers/authentications_controller.rb index dd7d4b989..40c5acef2 100644 --- a/app/controllers/authentications_controller.rb +++ b/app/controllers/authentications_controller.rb @@ -2,14 +2,12 @@ class AuthenticationsController < ApplicationController skip_before_action :store_location - before_action :session_required, only: %i[new firebase_callback] - before_action :redirect_invalid_github_account, only: :github_callback, unless: :github_api_account_is_verified? + before_action :session_required, only: :new before_action :redirect_matching_account, only: :github_callback, unless: -> { current_user.present? } before_action :redirect_if_current_user_verified def new @account = current_user - @account.build_firebase_verification render partial: 'fields' if request.xhr? end @@ -18,11 +16,6 @@ def github_callback create(github_verification_params) end - def firebase_callback - statsd_increment('Openhub.Account.Signup.firebase') - create(firebase_verification_params) - end - private def create(auth_params) @@ -54,10 +47,6 @@ def create_account_using_github(auth_params) end end - def firebase_verification_params - params.require(:account).permit(firebase_verification_attributes: [:credentials]) - end - def github_verification_params { github_verification_attributes: { unique_id: github_api.login, token: github_api.access_token } } end @@ -113,14 +102,7 @@ def github_api def redirect_if_current_user_verified return if current_user.nil? - redirect_to root_path if current_user.access.mobile_or_oauth_verified? - end - - def redirect_invalid_github_account - return if github_api.created_at < ENV['GITHUB_REPO_AGE_LIMIT'].to_i.days.ago && github_api.repository_has_language? - - redirect_path = current_user.present? ? new_authentication_path : new_account_path - redirect_to redirect_path, notice: t('.invalid_github_account') + redirect_to root_path if current_user.access.manual_or_oauth_verified? end def github_api_account_is_verified? diff --git a/app/models/account.rb b/app/models/account.rb index d69711c9b..5a0896175 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -18,7 +18,7 @@ class Account < ApplicationRecord serialize :reset_password_tokens, Hash - accepts_nested_attributes_for :github_verification, :firebase_verification + accepts_nested_attributes_for :github_verification, :manual_verification def anonymous? login == AnonymousAccount::LOGIN diff --git a/app/models/account/access.rb b/app/models/account/access.rb index c61b04aef..85beb863e 100644 --- a/app/models/account/access.rb +++ b/app/models/account/access.rb @@ -59,13 +59,13 @@ def bot! account.update!(level: BOT) end - def mobile_or_oauth_verified? + def manual_or_oauth_verified? return if account.nil? account.verifications.exists? end def verified? - mobile_or_oauth_verified? && email_verified? + manual_or_oauth_verified? && email_verified? end end diff --git a/app/models/firebase_verification.rb b/app/models/firebase_verification.rb index ecc39dc8b..3ef788554 100644 --- a/app/models/firebase_verification.rb +++ b/app/models/firebase_verification.rb @@ -1,22 +1,5 @@ # frozen_string_literal: true +# Retained for backwards compatibility with existing DB records. class FirebaseVerification < Verification - attr_accessor :credentials - - validates :credentials, presence: true - - before_validation :generate_token, on: :create - - private - - def generate_token - firebase = FirebaseService.new(ENV['FIREBASE_PROJECT_ID']) - decoded_token = firebase.decode(credentials) - if decoded_token - self.token = decoded_token[0]['user_id'] - self.unique_id = token - else - errors.add(:unique_id, 'Phone Verification failed please try again') - end - end end diff --git a/app/models/github_api.rb b/app/models/github_api.rb index 5775ca5db..09bc0d94c 100644 --- a/app/models/github_api.rb +++ b/app/models/github_api.rb @@ -19,16 +19,6 @@ def email fetch_private_email end - def created_at - Time.zone.parse(user_response['created_at']) - end - - def repository_has_language? - repositories_response.any? do |repository_hash| - repository_hash['language'].present? - end - end - def access_token return @access_token if @access_token @@ -63,12 +53,6 @@ def user_response @user_response = get_response_using_token(user_uri) end - def repositories_response - params = { type: :owner, sort: :pushed, per_page: REPO_LIMIT } - repositories_uri = URI(GITHUB_USER_URI + "/repos?#{params.to_query}") - get_response_using_token(repositories_uri) - end - def config CGI.unescape({ code: @code, client_id: ENV['GITHUB_CLIENT_ID'], client_secret: ENV['GITHUB_CLIENT_SECRET'], redirect_uri: ENV['GITHUB_REDIRECT_URI'] }.to_query) diff --git a/app/models/github_verification.rb b/app/models/github_verification.rb index 4b4692535..fa1dc4e8f 100644 --- a/app/models/github_verification.rb +++ b/app/models/github_verification.rb @@ -2,4 +2,6 @@ class GithubVerification < Verification validates :token, presence: true + + validates :unique_id, presence: true, uniqueness: true end diff --git a/app/models/manual_verification.rb b/app/models/manual_verification.rb index 68078010a..85769418e 100644 --- a/app/models/manual_verification.rb +++ b/app/models/manual_verification.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true class ManualVerification < Verification - belongs_to :account, optional: true + belongs_to :account end diff --git a/app/models/reverification_tracker.rb b/app/models/reverification_tracker.rb index f9ed7905a..7ddd77e8f 100644 --- a/app/models/reverification_tracker.rb +++ b/app/models/reverification_tracker.rb @@ -91,7 +91,7 @@ def remove_reverification_trackers_for_verified_accounts next unless rev_tracker.account rev_tracker.account.update!(level: 0) if rev_tracker.account.level == -10 - rev_tracker.destroy if rev_tracker.account.access.mobile_or_oauth_verified? + rev_tracker.destroy if rev_tracker.account.access.manual_or_oauth_verified? end end diff --git a/app/models/verification.rb b/app/models/verification.rb index 345f339c1..04df72f6d 100644 --- a/app/models/verification.rb +++ b/app/models/verification.rb @@ -3,6 +3,5 @@ class Verification < ApplicationRecord belongs_to :account, optional: true - validates :unique_id, :type, presence: true - validates :unique_id, uniqueness: { scope: :type } + validates :type, presence: true end diff --git a/app/services/firebase_service.rb b/app/services/firebase_service.rb deleted file mode 100644 index b119437eb..000000000 --- a/app/services/firebase_service.rb +++ /dev/null @@ -1,101 +0,0 @@ -# frozen_string_literal: true - -require 'jwt' -require 'net/http' - -class FirebaseService - VALID_JWT_PUBLIC_KEYS_RESPONSE_CACHE_KEY = 'firebase_phone_jwt_public_keys_cache_key' - JWT_ALGORITHM = 'RS256' - - def initialize(firebase_project_id) - @firebase_project_id = firebase_project_id - end - - def decode(id_token) - decoded_token = FirebaseService.decode_jwt_token(id_token, @firebase_project_id, nil) - return nil unless decoded_token - - valid_public_keys = FirebaseService.retrieve_and_cache_jwt_valid_public_keys - return nil unless check_validations(decoded_token, valid_public_keys.keys) - - kid = decoded_token[1]['kid'] - public_key = OpenSSL::X509::Certificate.new(valid_public_keys[kid]).public_key - FirebaseService.decode_jwt_token(id_token, @firebase_project_id, public_key) - end - - def check_validations(token, valid_public_keys) - payload = token[0] - headers = token[1] - valid_algorithm?(headers['alg']) && valid_kid_key?(headers['kid'], valid_public_keys) && valid_sub?(payload['sub']) - end - - def valid_algorithm?(alg) - flag = true - if alg != JWT_ALGORITHM - Rails.logger.info("Invalid access token 'alg' header (#{alg}). Must be '#{JWT_ALGORITHM}'.") - flag = false - end - flag - end - - def valid_kid_key?(kid, valid_keys) - flag = true - unless valid_keys.include?(kid) - Rails.logger.info("Invalid access token 'kid' header, do not correspond to valid public keys.") - flag = false - end - flag - end - - def valid_sub?(sub) - flag = true - if sub.blank? - Rails.logger.info("Invalid access token. 'Subject' (sub) must be a non-empty string.") - flag = false - end - flag - end - - def self.get_custom_options(firebase_project_id) - { verify_iat: true, - verify_aud: true, aud: firebase_project_id, - verify_iss: true, - iss: "https://securetoken.google.com/#{firebase_project_id}" } - end - - def self.decode_jwt_token(firebase_jwt_token, firebase_project_id, public_key) - custom_options = get_custom_options(firebase_project_id) - custom_options[:algorithm] = JWT_ALGORITHM unless public_key.nil? - begin - decoded_token = JWT.decode(firebase_jwt_token, public_key, !public_key.nil?, custom_options) - rescue StandardError => e - Rails.logger.info("#{e.class} message: #{e.message}") - return nil - end - decoded_token - end - - def self.retrieve_and_cache_jwt_valid_public_keys - valid_public_keys = Rails.cache.read(VALID_JWT_PUBLIC_KEYS_RESPONSE_CACHE_KEY) - if valid_public_keys.nil? - response = fetch_keys - valid_public_keys = response[0] - cc = response[1]['cache-control'] - max_age = cc[/max-age=(\d+?),/m, 1] - - Rails.cache.write(VALID_JWT_PUBLIC_KEYS_RESPONSE_CACHE_KEY, valid_public_keys, expires_in: max_age.to_i) - end - valid_public_keys - end - - def self.fetch_keys - uri = URI('https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com') - https = Net::HTTP.new(uri.host, uri.port) - https.use_ssl = true - req = Net::HTTP::Get.new(uri.path) - response = https.request(req) - raise "Something went wrong: can't obtain valid JWT public keys from Google." if response.code != '200' - - [JSON.parse(response.body), response] - end -end diff --git a/app/views/accounts/_fields.html.haml b/app/views/accounts/_fields.html.haml index a4246ae53..1bcf7f4e4 100644 --- a/app/views/accounts/_fields.html.haml +++ b/app/views/accounts/_fields.html.haml @@ -1,6 +1,4 @@ = form_for @account, html: { id: :account_form, class: 'well' } do |f| - = f.fields_for :firebase_verification do |firebase_form| - = firebase_form.hidden_field :credentials, id: :credentials %fieldset %legend= t('.new_account') .controls @@ -28,17 +26,5 @@ - error_tag(@account, :password) %p.help-block= t('.password_help') - - firebase_attribute = 'firebase_verification.unique_id' - - verified = @account.firebase_verification.try(:unique_id?) && @account.errors[firebase_attribute].empty? - .label.label-info.verified{ id: ('hidden-verified-label' unless verified) } - = t('.phone_number_verified') - - unless verified - .control-group - #firebaseui-auth-container - - error_tag(@account, firebase_attribute) - - %p.help-block - = t('.phone_disclaimer') - .actions %input.btn.btn-primary{ type: :submit, value: t('.sign_up') } diff --git a/app/views/accounts/new.html.haml b/app/views/accounts/new.html.haml index 83e81a3b3..b7043a73d 100644 --- a/app/views/accounts/new.html.haml +++ b/app/views/accounts/new.html.haml @@ -24,17 +24,17 @@ = t('.github_disclaimer') -if only_device? .col-xs-3.pull-right#sign-up-email - = link_to 'javascript:', id: 'digits-sign-up', class: 'btn btn-primary' do + = link_to 'javascript:', id: 'email-sign-up', class: 'btn btn-primary' do = t('.sign_up_with') %br - %i.fa.fa-mobile - Phone & Email + %i.fa.fa-envelope-o + Email -else - = link_to 'javascript:', id: 'digits-sign-up', class: 'btn btn-primary btn-block' do + = link_to 'javascript:', id: 'email-sign-up', class: 'btn btn-primary btn-block' do = t('.sign_up_with') %br - %i.fa.fa-mobile - Phone & Email + %i.fa.fa-envelope-o + Email .col-xs-12.col-sm-5.no_right_padding{ id: ('sign-up-fields' if @account.errors.none?) } - if flash[:message] diff --git a/app/views/authentications/_fields.html.haml b/app/views/authentications/_fields.html.haml index 72eee6abc..ca3ce88db 100644 --- a/app/views/authentications/_fields.html.haml +++ b/app/views/authentications/_fields.html.haml @@ -1,21 +1,6 @@ .row-fluid .well.well-large.col-md-8.col-md-offset-2.margin_top_20 - %p - = t('.mobile_verification_hint') - .verification-buttons-container - %button.btn.btn-primary#digits-sign-up - %i.fa.fa-twitter - = t('.verify_using_phone_number') - -   (OR)   - = link_to 'javascript:', { class: 'btn btn-primary github-oauth' }.merge(github_data_attributes) do %i.fa.fa-github = t('.verify_using_github') -#firebaseui-auth-container - -- html_options = { method: 'POST', class: 'phone-verification-form' } -= form_for @account, url: firebase_callback_authentications_path, html: html_options do |f| - = f.fields_for :firebase_verification do |firebase_form| - = firebase_form.hidden_field :credentials, id: :credentials diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 80f56322e..7c5f3dbe8 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -8,11 +8,7 @@ %meta{ name: 'viewport', content: 'width=device-width, initial-scale=1.0' } %meta{ name: 'description', content: page_context[:description] } %meta{ name: 'keywords', content: page_context[:keywords] } - %meta{ name: 'firebase-consumer-key', content: ENV['FIREBASE_API_KEY'] } - %meta{ name: 'firebase-app-id', content: ENV['FIREBASE_PROJECT_ID'] } - %meta{ name: 'firebase-app-url', content: ENV['FIREBASE_AUTH_DOMAIN'] } %meta{ name: 'google-site-verification', content: 'jKkWeVQ0tB1bffJYg7xXAtcIM-nrjjVxhP3ohb8UH2A' } - %link{ href: 'https://cdn.firebase.com/libs/firebaseui/3.4.0/firebaseui.css', rel: 'stylesheet', type: 'text/css' }/ = render partial: 'layouts/partials/otwo_head_info' diff --git a/app/views/layouts/partials/_js_scripts.html.haml b/app/views/layouts/partials/_js_scripts.html.haml index 43cd68c08..b0b4f0087 100644 --- a/app/views/layouts/partials/_js_scripts.html.haml +++ b/app/views/layouts/partials/_js_scripts.html.haml @@ -1,8 +1,3 @@ = yield(:javascript) if content_for?(:javascript) -%script{ src: 'https://cdn.firebase.com/libs/firebaseui/3.4.0/firebaseui.js' } %script{ src: 'https://www.google.com/recaptcha/api.js', async: '', defer: '' } -= javascript_include_tag 'application', - 'https://www.gstatic.com/firebasejs/5.4.1/firebase-app.js', - 'https://www.gstatic.com/firebasejs/5.4.1/firebase-auth.js', - cache: 'cached_js_files', - async: true += javascript_include_tag 'application', cache: 'cached_js_files', async: true diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index b75d9b275..dc37b33a5 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -allowed_script_sources = %w[www.google.com cdn.firebase.com www.gstatic.com s7.addthis.com cdnjs.cloudflare.com] +allowed_script_sources = %w[www.google.com www.gstatic.com s7.addthis.com cdnjs.cloudflare.com] Rails.application.config.content_security_policy do |policy| policy.default_src :self, :https diff --git a/config/locales/accounts.en.yml b/config/locales/accounts.en.yml index d27ab2779..e1d437232 100644 --- a/config/locales/accounts.en.yml +++ b/config/locales/accounts.en.yml @@ -235,5 +235,3 @@ en: verify_password: 'Verify Password' password_help: 'Password must be at least 5 characters long' verify_password_help: 'Verify Password must be at least 5 characters long' - phone_disclaimer: OpenHub will not store your mobile number. - phone_number_verified: Your phone number has been verified diff --git a/config/locales/en.yml b/config/locales/en.yml index 9ef05a476..403d2f936 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -424,7 +424,6 @@ en: create: error: There seems to be an issue with the mobile verification. Please try again later. github_callback: - invalid_github_account: This github account is insufficient for signing up at the Open Hub. email_mismatch: You have successfully logged in, however your Open Hub email address and GitHub email address do not match. You can update your Open Hub email address in your Settings page copyright: start_year : Copyright 2014 - diff --git a/config/routes.rb b/config/routes.rb index 34780ec23..c523d24fe 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -135,7 +135,6 @@ resources :authentications, only: [:new] do collection do get :github_callback - post :firebase_callback end end diff --git a/features/sign_up_and_verify.feature b/features/sign_up_and_verify.feature index bec820e1e..1ae671f30 100644 --- a/features/sign_up_and_verify.feature +++ b/features/sign_up_and_verify.feature @@ -1,10 +1,10 @@ Feature: Sign up and verify In order to use OpenHub As a new user - I must be able to sign up using Github/Phone + I must be able to sign up using Github/Email @javascript - Scenario: Signup for OpenHub using phone number + Scenario: Signup for OpenHub using email Given I am on the OpenHub sign up page - When I select Phone & Email - Then I should see a form to enter my phone number + When I select Email + Then I should see a form to enter my email diff --git a/features/steps/sign_up_and_verify.rb b/features/steps/sign_up_and_verify.rb index 26b51877f..bd27a2322 100644 --- a/features/steps/sign_up_and_verify.rb +++ b/features/steps/sign_up_and_verify.rb @@ -4,16 +4,16 @@ class Spinach::Features::SignUpAndVerify < Spinach::FeatureSteps step 'I am on the OpenHub sign up page' do visit new_account_path page.must_have_content 'Github' - page.must_have_content 'Phone & Email' - page.must_have_selector(:css, 'a#digits-sign-up') + page.must_have_content 'Email' + page.must_have_selector(:css, 'a#email-sign-up') end - step 'I select Phone & Email' do - click_on 'Phone & Email' + step 'I select Email' do + click_on 'Email' end - step 'I should see a form to enter my phone number' do + step 'I should see a form to enter my email address' do sleep 1 - page.must_have_content 'Enter your phone number' + page.must_have_content 'Email Address' end end diff --git a/fixtures/vcr_cassettes/GithubVerificationSpammer.yml b/fixtures/vcr_cassettes/GithubVerificationSpammer.yml deleted file mode 100644 index 6c176d4d2..000000000 --- a/fixtures/vcr_cassettes/GithubVerificationSpammer.yml +++ /dev/null @@ -1,304 +0,0 @@ ---- -http_interactions: -- request: - method: post - uri: https://github.com/login/oauth/access_token - body: - encoding: UTF-8 - string: client_id=fake_client_id&client_secret=fake_client_secret&code=663a92c0728e35c83176&redirect_uri=http://lvh.me:3000/authentications/github_callback - headers: - Accept-Encoding: - - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 - Accept: - - "*/*" - User-Agent: - - Ruby - response: - status: - code: 200 - message: OK - headers: - Date: - - Wed, 18 Oct 2017 10:43:56 GMT - Content-Type: - - application/x-www-form-urlencoded; charset=utf-8 - Transfer-Encoding: - - chunked - Server: - - GitHub.com - Status: - - 200 OK - Cache-Control: - - no-cache - Vary: - - Accept-Encoding - - X-PJAX - X-Ua-Compatible: - - IE=Edge,chrome=1 - X-Request-Id: - - f8a61c00c5f7912b805d05bb15731c41 - X-Runtime: - - '0.024108' - Expect-Ct: - - max-age=2592000; report-uri="https://api.github.com/_private/browser/errors" - Content-Security-Policy: - - 'default-src ''none''; base-uri ''self''; block-all-mixed-content; child-src - render.githubusercontent.com; connect-src ''self'' uploads.github.com status.github.com - collector.githubapp.com api.github.com www.google-analytics.com github-cloud.s3.amazonaws.com - github-production-repository-file-5c1aeb.s3.amazonaws.com github-production-upload-manifest-file-7fdce7.s3.amazonaws.com - github-production-user-asset-6210df.s3.amazonaws.com wss://live.github.com; - font-src assets-cdn.github.com; form-action ''self'' github.com gist.github.com; - frame-ancestors ''none''; img-src ''self'' data: assets-cdn.github.com identicons.github.com - collector.githubapp.com github-cloud.s3.amazonaws.com *.githubusercontent.com; - media-src ''none''; script-src assets-cdn.github.com; style-src ''unsafe-inline'' - assets-cdn.github.com' - Strict-Transport-Security: - - max-age=31536000; includeSubdomains; preload - Public-Key-Pins: - - max-age=5184000; pin-sha256="WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18="; - pin-sha256="RRM1dGqnDFsCJXBTHky16vi1obOlCgFFn/yOhI/y+ho="; pin-sha256="k2v657xBsOVe1PQRwOsHsw3bsGT2VzIqz5K+59sNQws="; - pin-sha256="K87oWBWM9UZfyddvDfoxL+8lpNyoUB2ptGtn0fv6G2Q="; pin-sha256="IQBnNBEiFuhj+8x6X8XLgh01V9Ic5/V3IRQLNFFc7v4="; - pin-sha256="iie1VXtL7HzAMF+/PVPR9xzT80kQxdZeJ+zduCB3uj0="; pin-sha256="LvRiGEjRqfzurezaWuj8Wie2gyHMrW5Q06LspMnox7A="; - includeSubDomains - X-Content-Type-Options: - - nosniff - X-Frame-Options: - - deny - X-Xss-Protection: - - 1; mode=block - X-Runtime-Rack: - - '0.028451' - X-Github-Request-Id: - - A3AC:15AE5:47A412:6E72DD:59E7306C - body: - encoding: UTF-8 - string: access_token=e068fc1968fakef5c7e7fake6369336fake4bab9&scope=&token_type=bearer - http_version: - recorded_at: Wed, 18 Oct 2017 10:43:57 GMT -- request: - method: get - uri: https://api.github.com/user - body: - encoding: US-ASCII - string: '' - headers: - Authorization: - - token 4l83bx041fd52144bc14622ca97e4123fb5bfake - Accept-Encoding: - - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 - Accept: - - "*/*" - User-Agent: - - Ruby - response: - status: - code: 200 - message: OK - headers: - Server: - - GitHub.com - Date: - - Mon, 25 Dec 2017 04:41:27 GMT - Content-Type: - - application/json; charset=utf-8 - Transfer-Encoding: - - chunked - Status: - - 200 OK - X-Ratelimit-Limit: - - '5000' - X-Ratelimit-Remaining: - - '4992' - X-Ratelimit-Reset: - - '1514178020' - Cache-Control: - - private, max-age=60, s-maxage=60 - Vary: - - Accept, Authorization, Cookie, X-GitHub-OTP - Etag: - - W/"89a30eb7ab731ec15075cff456dd6b20" - Last-Modified: - - Sun, 24 Dec 2017 19:46:30 GMT - X-Oauth-Scopes: - - public_repo, read:user, user:email - X-Accepted-Oauth-Scopes: - - '' - X-Oauth-Client-Id: - - fake_client_id - X-Github-Media-Type: - - github.v3; format=json - Access-Control-Expose-Headers: - - ETag, Link, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, - X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval - Access-Control-Allow-Origin: - - "*" - Content-Security-Policy: - - default-src 'none' - Strict-Transport-Security: - - max-age=31536000; includeSubdomains; preload - X-Content-Type-Options: - - nosniff - X-Frame-Options: - - deny - X-Xss-Protection: - - 1; mode=block - X-Runtime-Rack: - - '0.050602' - X-Github-Request-Id: - - C12C:4195:70C225:DB0DB4:5A408177 - body: - encoding: ASCII-8BIT - string: '{"login":"alex-bds","id":34818342,"avatar_url":"https://avatars3.githubusercontent.com/u/34818342?v=4","gravatar_id":"","url":"https://api.github.com/users/alex-bds","html_url":"https://github.com/alex-bds","followers_url":"https://api.github.com/users/alex-bds/followers","following_url":"https://api.github.com/users/alex-bds/following{/other_user}","gists_url":"https://api.github.com/users/alex-bds/gists{/gist_id}","starred_url":"https://api.github.com/users/alex-bds/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alex-bds/subscriptions","organizations_url":"https://api.github.com/users/alex-bds/orgs","repos_url":"https://api.github.com/users/alex-bds/repos","events_url":"https://api.github.com/users/alex-bds/events{/privacy}","received_events_url":"https://api.github.com/users/alex-bds/received_events","type":"User","site_admin":false,"name":null,"company":null,"blog":"","location":null,"email":null,"hireable":null,"bio":null,"public_repos":1,"public_gists":0,"followers":0,"following":0,"created_at":"2017-12-24T19:46:30Z","updated_at":"2017-12-24T19:46:30Z","private_gists":0,"total_private_repos":0,"owned_private_repos":0,"disk_usage":15,"collaborators":0,"two_factor_authentication":false,"plan":{"name":"free","space":976562499,"collaborators":0,"private_repos":0}}' - http_version: - recorded_at: Mon, 25 Dec 2017 04:41:28 GMT -- request: - method: get - uri: https://api.github.com/user/emails - body: - encoding: US-ASCII - string: '' - headers: - Authorization: - - token 4l83bx041fd52144bc14622ca97e4123fb5bfake - Accept-Encoding: - - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 - Accept: - - "*/*" - User-Agent: - - Ruby - response: - status: - code: 200 - message: OK - headers: - Server: - - GitHub.com - Date: - - Mon, 25 Dec 2017 04:41:31 GMT - Content-Type: - - application/json; charset=utf-8 - Transfer-Encoding: - - chunked - Status: - - 200 OK - X-Ratelimit-Limit: - - '5000' - X-Ratelimit-Remaining: - - '4991' - X-Ratelimit-Reset: - - '1514178020' - Cache-Control: - - private, max-age=60, s-maxage=60 - Vary: - - Accept, Authorization, Cookie, X-GitHub-OTP - Etag: - - W/"d9a6cb7e7ee6a69944a5c94a3713d662" - X-Oauth-Scopes: - - public_repo, read:user, user:email - X-Accepted-Oauth-Scopes: - - user, user:email - X-Oauth-Client-Id: - - fake_client_id - X-Github-Media-Type: - - github.v3; format=json - Access-Control-Expose-Headers: - - ETag, Link, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, - X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval - Access-Control-Allow-Origin: - - "*" - Content-Security-Policy: - - default-src 'none' - Strict-Transport-Security: - - max-age=31536000; includeSubdomains; preload - X-Content-Type-Options: - - nosniff - X-Frame-Options: - - deny - X-Xss-Protection: - - 1; mode=block - X-Runtime-Rack: - - '0.027714' - X-Github-Request-Id: - - C12E:4195:70C2D5:DB0EF7:5A408179 - body: - encoding: ASCII-8BIT - string: '[{"email":"ajohnson@blackducksoftware.com","primary":true,"verified":true,"visibility":"private"},{"email":"34818342+alex-bds@users.noreply.github.com","primary":false,"verified":true,"visibility":null}]' - http_version: - recorded_at: Mon, 25 Dec 2017 04:41:31 GMT -- request: - method: get - uri: https://api.github.com/user/repos?per_page=10&sort=pushed&type=owner - body: - encoding: US-ASCII - string: '' - headers: - Authorization: - - token 4l83bx041fd52144bc14622ca97e4123fb5bfake - Accept-Encoding: - - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 - Accept: - - "*/*" - User-Agent: - - Ruby - response: - status: - code: 200 - message: OK - headers: - Server: - - GitHub.com - Date: - - Mon, 25 Dec 2017 04:41:33 GMT - Content-Type: - - application/json; charset=utf-8 - Transfer-Encoding: - - chunked - Status: - - 200 OK - X-Ratelimit-Limit: - - '5000' - X-Ratelimit-Remaining: - - '4990' - X-Ratelimit-Reset: - - '1514178020' - Cache-Control: - - private, max-age=60, s-maxage=60 - Vary: - - Accept, Authorization, Cookie, X-GitHub-OTP - Etag: - - W/"890450aee07c02a1cd6df00d9a9eb202" - X-Oauth-Scopes: - - public_repo, read:user, user:email - X-Accepted-Oauth-Scopes: - - '' - X-Oauth-Client-Id: - - fake_client_id - X-Github-Media-Type: - - github.v3; format=json - Access-Control-Expose-Headers: - - ETag, Link, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, - X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval - Access-Control-Allow-Origin: - - "*" - Content-Security-Policy: - - default-src 'none' - Strict-Transport-Security: - - max-age=31536000; includeSubdomains; preload - X-Content-Type-Options: - - nosniff - X-Frame-Options: - - deny - X-Xss-Protection: - - 1; mode=block - X-Runtime-Rack: - - '0.042152' - X-Github-Request-Id: - - 8EBA:4193:43BC39:938DD7:5A40817C - body: - encoding: ASCII-8BIT - string: '[{"id":115284624,"name":"repository_1","full_name":"alex-bds/repository_1","owner":{"login":"alex-bds","id":34818342,"avatar_url":"https://avatars3.githubusercontent.com/u/34818342?v=4","gravatar_id":"","url":"https://api.github.com/users/alex-bds","html_url":"https://github.com/alex-bds","followers_url":"https://api.github.com/users/alex-bds/followers","following_url":"https://api.github.com/users/alex-bds/following{/other_user}","gists_url":"https://api.github.com/users/alex-bds/gists{/gist_id}","starred_url":"https://api.github.com/users/alex-bds/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alex-bds/subscriptions","organizations_url":"https://api.github.com/users/alex-bds/orgs","repos_url":"https://api.github.com/users/alex-bds/repos","events_url":"https://api.github.com/users/alex-bds/events{/privacy}","received_events_url":"https://api.github.com/users/alex-bds/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/alex-bds/repository_1","description":"Test - repository","fork":false,"url":"https://api.github.com/repos/alex-bds/repository_1","forks_url":"https://api.github.com/repos/alex-bds/repository_1/forks","keys_url":"https://api.github.com/repos/alex-bds/repository_1/keys{/key_id}","collaborators_url":"https://api.github.com/repos/alex-bds/repository_1/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/alex-bds/repository_1/teams","hooks_url":"https://api.github.com/repos/alex-bds/repository_1/hooks","issue_events_url":"https://api.github.com/repos/alex-bds/repository_1/issues/events{/number}","events_url":"https://api.github.com/repos/alex-bds/repository_1/events","assignees_url":"https://api.github.com/repos/alex-bds/repository_1/assignees{/user}","branches_url":"https://api.github.com/repos/alex-bds/repository_1/branches{/branch}","tags_url":"https://api.github.com/repos/alex-bds/repository_1/tags","blobs_url":"https://api.github.com/repos/alex-bds/repository_1/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/alex-bds/repository_1/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/alex-bds/repository_1/git/refs{/sha}","trees_url":"https://api.github.com/repos/alex-bds/repository_1/git/trees{/sha}","statuses_url":"https://api.github.com/repos/alex-bds/repository_1/statuses/{sha}","languages_url":"https://api.github.com/repos/alex-bds/repository_1/languages","stargazers_url":"https://api.github.com/repos/alex-bds/repository_1/stargazers","contributors_url":"https://api.github.com/repos/alex-bds/repository_1/contributors","subscribers_url":"https://api.github.com/repos/alex-bds/repository_1/subscribers","subscription_url":"https://api.github.com/repos/alex-bds/repository_1/subscription","commits_url":"https://api.github.com/repos/alex-bds/repository_1/commits{/sha}","git_commits_url":"https://api.github.com/repos/alex-bds/repository_1/git/commits{/sha}","comments_url":"https://api.github.com/repos/alex-bds/repository_1/comments{/number}","issue_comment_url":"https://api.github.com/repos/alex-bds/repository_1/issues/comments{/number}","contents_url":"https://api.github.com/repos/alex-bds/repository_1/contents/{+path}","compare_url":"https://api.github.com/repos/alex-bds/repository_1/compare/{base}...{head}","merges_url":"https://api.github.com/repos/alex-bds/repository_1/merges","archive_url":"https://api.github.com/repos/alex-bds/repository_1/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/alex-bds/repository_1/downloads","issues_url":"https://api.github.com/repos/alex-bds/repository_1/issues{/number}","pulls_url":"https://api.github.com/repos/alex-bds/repository_1/pulls{/number}","milestones_url":"https://api.github.com/repos/alex-bds/repository_1/milestones{/number}","notifications_url":"https://api.github.com/repos/alex-bds/repository_1/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/alex-bds/repository_1/labels{/name}","releases_url":"https://api.github.com/repos/alex-bds/repository_1/releases{/id}","deployments_url":"https://api.github.com/repos/alex-bds/repository_1/deployments","created_at":"2017-12-24T20:02:08Z","updated_at":"2017-12-24T20:02:08Z","pushed_at":"2017-12-24T20:02:09Z","git_url":"git://github.com/alex-bds/repository_1.git","ssh_url":"git@github.com:alex-bds/repository_1.git","clone_url":"https://github.com/alex-bds/repository_1.git","svn_url":"https://github.com/alex-bds/repository_1","homepage":null,"size":15,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"gpl-3.0","name":"GNU - General Public License v3.0","spdx_id":"GPL-3.0","url":"https://api.github.com/licenses/gpl-3.0"},"forks":0,"open_issues":0,"watchers":0,"default_branch":"main","permissions":{"admin":true,"push":true,"pull":true}}]' - http_version: - recorded_at: Mon, 25 Dec 2017 04:41:33 GMT -recorded_with: VCR 3.0.3 diff --git a/test/controllers/accounts_controller_test.rb b/test/controllers/accounts_controller_test.rb index 1228eca7d..e5cf77357 100644 --- a/test/controllers/accounts_controller_test.rb +++ b/test/controllers/accounts_controller_test.rb @@ -63,23 +63,17 @@ class AccountsControllerTest < ActionController::TestCase _(assigns(:account).errors.messages[:email]).must_be :present? end - it 'must redirect to accounts page after create' do + it 'must setup manual verification' do post :create, params: account_params - assert_redirected_to Account.last + account = Account.last + _(account.verifications.first).must_be_kind_of ManualVerification end - it 'must return error when phone number is a duplicate' do - existing_account = create(:account) - firebase_token = [{ 'user_id' => Faker::Internet.password }] - FirebaseService.any_instance.stubs(:decode).returns(firebase_token) - create(:firebase_verification, account: existing_account) - - params = account_params[:account].merge(firebase_verification_attributes: { credentials: Faker::Lorem.word }) - post :create, params: { account: params } + it 'must redirect to accounts page after create' do + post :create, params: account_params - _(assigns(:account)).wont_be :valid? - _(assigns(:account).errors['firebase_verification.unique_id']).must_be :present? + assert_redirected_to Account.last end end diff --git a/test/controllers/authentications_controller_test.rb b/test/controllers/authentications_controller_test.rb index 64362c4d2..26ad41525 100644 --- a/test/controllers/authentications_controller_test.rb +++ b/test/controllers/authentications_controller_test.rb @@ -48,7 +48,6 @@ class AuthenticationsControllerTest < ActionController::TestCase assert_response :ok _(assigns(:account)).must_be :present? - _(assigns(:account).firebase_verification).must_be :present? end it 'wont allow access to verified users' do @@ -101,36 +100,6 @@ class AuthenticationsControllerTest < ActionController::TestCase _(account.github_verification).must_be :present? end - it 'must only allow accounts that are atleast a month old' do - VCR.use_cassette('GithubVerificationSpammer') do - GithubApi.any_instance.stubs(:repository_has_language?).returns(true) - - GithubApi.any_instance.stubs(:created_at).returns(20.days.ago) - assert_no_difference('Account.count', 1) do - get :github_callback, params: { code: Faker::Lorem.word } - end - - _(request.env[:clearance].current_user).must_be_nil - assert_redirected_to new_account_path - _(flash[:notice]).must_equal I18n.t('authentications.github_callback.invalid_github_account') - end - end - - it 'must stop accounts that have no repository with valid language' do - VCR.use_cassette('GithubVerificationSpammer') do - login_as account - account.verifications.delete_all - GithubApi.any_instance.stubs(:created_at).returns(2.months.ago) - - assert_no_difference('Account.count', 1) do - get :github_callback, params: { code: Faker::Lorem.word } - end - - assert_redirected_to new_authentication_path - _(flash[:notice]).must_equal I18n.t('authentications.github_callback.invalid_github_account') - end - end - it 'must show errors when github verification fails for logged in user' do login_as account account.verifications.delete_all @@ -231,18 +200,6 @@ class AuthenticationsControllerTest < ActionController::TestCase _(request.env[:clearance].current_user.id).must_equal account.id end - it 'wont sign in a non github verified user which fails github restrictions' do - github_account_stub.stubs(:created_at).returns(Time.current) - @controller.stubs(:github_api).returns(github_account_stub) - account.verifications.delete_all - FirebaseVerification.any_instance.stubs(:generate_token) - create(:firebase_verification, account: account) - - get :github_callback, params: { code: Faker::Lorem.word } - - _(request.env[:clearance].current_user).must_be_nil - end - it 'must create a github verification record for a matching unverified account' do account.github_verification.destroy @controller.stubs(:github_api).returns(github_account_stub) @@ -313,36 +270,4 @@ class AuthenticationsControllerTest < ActionController::TestCase end end end - - describe 'firebase_callback' do - it 'must create verification record for existing account' do - account.verifications.destroy_all - login_as account - firebase_token = [{ 'user_id' => Faker::Internet.password }] - FirebaseService.any_instance.stubs(:decode).returns(firebase_token) - - auth_params = { 'firebase_verification_attributes' => { 'credentials' => Faker::Lorem.word } } - - get :firebase_callback, params: { account: auth_params } - - account.reload - assert_redirected_to account - _(account.firebase_verification).must_be :present? - end - - it 'must handle verification failure for existing record' do - account.verifications.destroy_all - login_as account - firebase_token = [{ 'user_id' => '' }] - FirebaseService.any_instance.stubs(:decode).returns(firebase_token) - - auth_params = { 'firebase_verification_attributes' => { 'credentials' => Faker::Lorem.word } } - - get :firebase_callback, params: { account: auth_params } - - account.reload - assert_redirected_to new_authentication_path - _(flash[:notice]).must_be :present? - end - end end diff --git a/test/controllers/spam_controller_test.rb b/test/controllers/spam_controller_test.rb index e313d89c0..c5926af58 100644 --- a/test/controllers/spam_controller_test.rb +++ b/test/controllers/spam_controller_test.rb @@ -15,16 +15,11 @@ class SpamControllerTest < ActionController::TestCase it 'should redirect to an account if there is one in oh.potential_spammers' do login_as admin - sql = 'SELECT id FROM oh.potential_spammers LIMIT 1;' - result = ActiveRecord::Base.connection.execute(sql) - if result.num_tuples.positive? - account = Account.find(result[0]['id']) - get :redirect_to_first_potential_spammer - assert_redirected_to account_path(account.login) - else - get :redirect_to_first_potential_spammer - assert_redirected_to oh_admin_root_path - end + markup = create(:markup, raw: 'https://foobar') + account.update!(about_markup_id: markup.id) + + get :redirect_to_first_potential_spammer + assert_redirected_to account_path(account.login) end it 'should redirect to admin path if there is nothing in oh.potential_spammers' do diff --git a/test/core_extensions/ruby/active_record_migrator_patch_test.rb b/test/core_extensions/ruby/active_record_migrator_patch_test.rb new file mode 100644 index 000000000..1f54579ff --- /dev/null +++ b/test/core_extensions/ruby/active_record_migrator_patch_test.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require 'test_helper' + +class ActiveRecordMigratorPatchTest < ActiveSupport::TestCase + describe 'any_migrations?' do + it 'must return true' do + _(ActiveRecord::Migrator.any_migrations?).must_equal true + end + end +end diff --git a/test/factories/verifications.rb b/test/factories/verifications.rb index 0196791f2..d2d23eb4c 100644 --- a/test/factories/verifications.rb +++ b/test/factories/verifications.rb @@ -10,8 +10,7 @@ type { 'GithubVerification' } end - factory :firebase_verification, parent: :verification, class: :FirebaseVerification do - type { 'FirebaseVerification' } - credentials { Faker::Internet.password } + factory :manual_verification, parent: :verification, class: :ManualVerification do + type { 'ManualVerification' } end end diff --git a/test/lib/email_obfuscation_test.rb b/test/lib/email_obfuscation_test.rb new file mode 100644 index 000000000..4ac2bee7b --- /dev/null +++ b/test/lib/email_obfuscation_test.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'test_helper' + +class EmailObfuscationTest < ActiveSupport::TestCase + describe 'obfuscate_email' do + it 'must mask email address' do + email = Faker::Internet.email + + _(Commit.new.obfuscate_email(email)).wont_equal email + end + end +end diff --git a/test/mailers/account_mailer_test.rb b/test/mailers/account_mailer_test.rb index 8f2c39d94..54291cd53 100644 --- a/test/mailers/account_mailer_test.rb +++ b/test/mailers/account_mailer_test.rb @@ -43,6 +43,14 @@ end end + describe 'notify_disabled_account_for_login_failure' do + let(:mail) { AccountMailer.notify_disabled_account_for_login_failure(account) } + + it 'should notify disabled account' do + _(mail.to).must_equal [account.email] + end + end + describe '#reset_password' do let(:mail) { AccountMailer.reset_password(account.id) } diff --git a/test/models/account/access_test.rb b/test/models/account/access_test.rb index 4d7e6cdea..941f4f404 100644 --- a/test/models/account/access_test.rb +++ b/test/models/account/access_test.rb @@ -163,4 +163,15 @@ class Account::AccessTest < ActiveSupport::TestCase _(proc { nil_account_access.spam! }).must_raise NoMethodError end end + + describe 'manual_or_oauth_verified' do + it 'must verify old Firebase records' do + account = create(:account) + account.verifications.destroy_all + + _(account.access).wont_be :manual_or_oauth_verified? + FirebaseVerification.create! unique_id: Faker::Internet.password, account: account + _(account.access).must_be :manual_or_oauth_verified? + end + end end diff --git a/test/models/firebase_verification_test.rb b/test/models/firebase_verification_test.rb deleted file mode 100644 index ed0fbec5b..000000000 --- a/test/models/firebase_verification_test.rb +++ /dev/null @@ -1,41 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -class FirebaseVerificationTest < ActiveSupport::TestCase - describe 'generate_token' do - it 'must set token using firebase credentials' do - decoded_val = stub_firebase_verification - JWT.stubs(:decode).returns(decoded_val) - VCR.use_cassette('google_keys') do - firebase_verification = FirebaseVerification.create!( - credentials: Faker::Internet.password - ) - _(firebase_verification.token).must_equal decoded_val[0]['user_id'] - end - end - - it 'Should add error when decoded token is nil' do - VCR.use_cassette('google_keys') do - _(proc { FirebaseVerification.create!(credentials: '') }).must_raise ActiveRecord::RecordInvalid - end - end - end - - it 'must raise appropriate error for uniqueness' do - FirebaseVerification.any_instance.stubs(:generate_token) - verification = create(:firebase_verification) - new_verification = build(:firebase_verification, unique_id: verification.unique_id) - - _(new_verification).wont_be :valid? - message = I18n.t('activerecord.errors.models.firebase_verification.attributes.unique_id.taken') - _(new_verification.errors.messages[:unique_id].first).must_equal message - end - - it 'wont report uniqueness message for blank values' do - FirebaseVerification.any_instance.stubs(:generate_token) - verification = build(:firebase_verification, unique_id: nil, token: nil) - _(verification).wont_be :valid? - _(verification.errors.messages[:unique_id]).must_equal ["can't be blank"] - end -end diff --git a/test/models/github_api_test.rb b/test/models/github_api_test.rb index fcd3917c6..ed4e73c64 100644 --- a/test/models/github_api_test.rb +++ b/test/models/github_api_test.rb @@ -22,36 +22,4 @@ class GithubApiTest < ActiveSupport::TestCase _(github_api.access_token).must_equal 'e068fc1968fakef5c7e7fake6369336fake4bab9' end end - - describe 'created_at' do - it 'must correctly parse github account created at string' do - VCR.use_cassette('GithubVerification') do |cassette| - _(github_api.created_at).must_be :<, relative_time(cassette, months: -1) - end - end - - it 'must correctly parse created at string when it is newer' do - VCR.use_cassette('GithubVerificationSpammer') do |cassette| - _(github_api.created_at).must_be :>, relative_time(cassette, months: -1) - end - end - end - - describe 'repository_has_language?' do - it 'must return true if github account has any repository with language' do - VCR.use_cassette('GithubVerification') do - _(github_api).must_be :repository_has_language? - end - end - - it 'must return false if github account has no repository with language' do - VCR.use_cassette('GithubVerificationSpammer') do - _(github_api).wont_be :repository_has_language? - end - end - end -end - -def relative_time(cassette, months:) - cassette.originally_recorded_at.advance(months: months) end diff --git a/test/models/github_verification_test.rb b/test/models/github_verification_test.rb index dcae73fe9..62e0e5a35 100644 --- a/test/models/github_verification_test.rb +++ b/test/models/github_verification_test.rb @@ -22,4 +22,12 @@ class GithubVerificationTest < ActiveSupport::TestCase message = I18n.t('activerecord.errors.models.github_verification.attributes.unique_id.taken') _(new_verification.errors.messages[:unique_id].first).must_equal message end + + it 'must scope unique_id uniqueness only for current type' do + account = create(:account) + verification = create(:manual_verification, account: account) + new_verification = build(:github_verification, account: account, unique_id: verification.unique_id) + + _(new_verification).must_be :valid? + end end diff --git a/test/models/manual_verification_test.rb b/test/models/manual_verification_test.rb new file mode 100644 index 000000000..b55d29134 --- /dev/null +++ b/test/models/manual_verification_test.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'test_helper' + +class ManualVerificationTest < ActiveSupport::TestCase + it 'must allow duplicate manual verification records' do + account = create(:account) + verification = create(:manual_verification, account: account) + new_verification = build(:manual_verification, account: account, unique_id: verification.unique_id) + + _(new_verification).must_be :valid? + end +end diff --git a/test/models/reverification_tracker_test.rb b/test/models/reverification_tracker_test.rb index 018a53abd..9f8cb5548 100644 --- a/test/models/reverification_tracker_test.rb +++ b/test/models/reverification_tracker_test.rb @@ -283,8 +283,8 @@ class ReverificationTrackerTest < ActiveSupport::TestCase it 'should destroy all reverification trackers if account verified' do verified = create(:reverification_tracker) unverified = create(:initial_rev_tracker) - assert verified.account.access.mobile_or_oauth_verified? - assert_not unverified.account.access.mobile_or_oauth_verified? + assert verified.account.access.manual_or_oauth_verified? + assert_not unverified.account.access.manual_or_oauth_verified? ReverificationTracker.remove_reverification_trackers_for_verified_accounts assert_equal 1, ReverificationTracker.count end diff --git a/test/services/firebase_service_test.rb b/test/services/firebase_service_test.rb deleted file mode 100644 index 8277f65f7..000000000 --- a/test/services/firebase_service_test.rb +++ /dev/null @@ -1,51 +0,0 @@ -# frozen_string_literal: true - -require 'test_helper' - -class FirebaseServiceTest < ActiveSupport::TestCase - describe 'service' do - it 'decode should give correct token' do - firebase = FirebaseService.new('fir-sample-8bb3e') - id_token = 'dfhhdfgyudsgfyugdudygsdu' - decoded_val = stub_firebase_verification - JWT.stubs(:decode).returns(decoded_val) - VCR.use_cassette('google_keys') do - token = firebase.decode(id_token) - _(token).must_equal decoded_val - end - end - - it 'should return nil for invalid kid' do - firebase = FirebaseService.new('fir-sample-8bb3e') - id_token = 'dfhhdfgyudsgfyugdudygsdu' - decoded_val = stub_firebase_verification('123', 'RS256', ' ') - JWT.stubs(:decode).returns(decoded_val) - VCR.use_cassette('google_keys') do - token = firebase.decode(id_token) - _(token).must_be_nil - end - end - - it 'should return nil for invalid algorithm' do - firebase = FirebaseService.new('fir-sample-8bb3e') - id_token = 'dfhhdfgyudsgfyugdudygsdu' - decoded_val = stub_firebase_verification('123', 'invalid_alg') - JWT.stubs(:decode).returns(decoded_val) - VCR.use_cassette('google_keys') do - token = firebase.decode(id_token) - _(token).must_be_nil - end - end - - it 'should return nil for invalid sub' do - firebase = FirebaseService.new('fir-sample-8bb3e') - id_token = 'dfhhdfgyudsgfyugdudygsdu' - decoded_val = stub_firebase_verification('') - JWT.stubs(:decode).returns(decoded_val) - VCR.use_cassette('google_keys') do - token = firebase.decode(id_token) - _(token).must_be_nil - end - end - end -end diff --git a/test/test_helper.rb b/test/test_helper.rb index c12a900a4..dd92f0d59 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -157,22 +157,6 @@ def stub_code_location_subscription_api_call(code_location_id, project_id, metho match_requests_on: %i[host path method], &block) end - def stub_firebase_verification(sub = '123', alg = 'RS256', kid = '745c7128cba10e251b9fe712aed52613388a6699') - [{ 'iss' => 'https://securetoken.google.com/fir-sample-8bb3e', - 'aud' => 'fir-sample-8bb3e', - 'auth_time' => 1_505_737_344, - 'user_id' => '123', - 'sub' => sub, - 'iat' => 1_505_737_344, - 'exp' => 1_505_740_944, - 'phone_number' => '+919999999999', - 'firebase' => { 'identities' => { 'phone' => ['+919999999999'] }, - 'sign_in_provider' => 'phone' } }, - { 'alg' => alg, - 'kid' => kid }, - nil] - end - def assert_response(code) assert_response(code) end