Skip to content
Draft
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ PATH
mobility (>= 1.0.1, < 2.0)
mobility-actiontext (~> 1.1)
noticed
octokit
omniauth
omniauth-github (~> 2.0.0)
omniauth-rails_csrf_protection
premailer-rails
public_activity
pundit (>= 2.1, < 2.6)
Expand Down Expand Up @@ -472,6 +476,8 @@ GEM
mobility (~> 1.2)
msgpack (1.8.0)
multi_json (1.17.0)
multi_xml (0.7.1)
bigdecimal (~> 3.1)
multipart-post (2.4.1)
net-http (0.6.0)
uri
Expand All @@ -493,6 +499,29 @@ GEM
racc (~> 1.4)
noticed (2.8.1)
rails (>= 6.1.0)
oauth2 (2.0.9)
faraday (>= 0.17.3, < 3.0)
jwt (>= 1.0, < 3.0)
multi_xml (~> 0.5)
rack (>= 1.2, < 4)
snaky_hash (~> 2.0)
version_gem (~> 1.1)
octokit (9.1.0)
faraday (>= 1, < 3)
sawyer (~> 0.9)
omniauth (2.1.2)
hashie (>= 3.4.6)
rack (>= 2.2.3)
rack-protection
omniauth-github (2.0.1)
omniauth (~> 2.0)
omniauth-oauth2 (~> 1.8)
omniauth-oauth2 (1.8.0)
oauth2 (>= 1.4, < 3)
omniauth (~> 2.0)
omniauth-rails_csrf_protection (1.0.2)
actionpack (>= 4.2)
omniauth (~> 2.0)
optimist (3.2.1)
orm_adapter (0.5.0)
parallel (1.27.0)
Expand Down Expand Up @@ -722,6 +751,9 @@ GEM
ffi (~> 1.9)
sassc-embedded (1.80.4)
sass-embedded (~> 1.80)
sawyer (0.9.2)
addressable (>= 2.3.5)
faraday (>= 0.17.3, < 3)
securerandom (0.4.1)
selenium-webdriver (4.35.0)
base64 (~> 0.2)
Expand Down Expand Up @@ -756,6 +788,9 @@ GEM
simplecov_json_formatter (~> 0.1)
simplecov-html (0.13.1)
simplecov_json_formatter (0.1.4)
snaky_hash (2.0.1)
hashie
version_gem (~> 1.1, >= 1.1.1)
spring (4.4.0)
spring-watcher-listen (2.1.0)
listen (>= 2.7, < 4.0)
Expand Down Expand Up @@ -801,6 +836,7 @@ GEM
unicode-emoji (4.0.4)
uri (1.0.3)
useragent (0.16.11)
version_gem (1.1.4)
virtus (2.0.0)
axiom-types (~> 0.1)
coercible (~> 1.0)
Expand Down
86 changes: 86 additions & 0 deletions app/builders/better_together/external_platform_builder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# frozen_string_literal: true

# app/builders/better_together/external_platform_builder.rb

module BetterTogether
# Builder to create external OAuth provider platforms
class ExternalPlatformBuilder < Builder
OAUTH_PROVIDERS = [
{
name: 'GitHub',
url: 'https://github.com',
identifier: 'github',
description: 'GitHub OAuth Provider',
time_zone: 'UTC'
},
{
name: 'Google',
url: 'https://accounts.google.com',
identifier: 'google',
description: 'Google OAuth Provider',
time_zone: 'UTC'
},
{
name: 'Facebook',
url: 'https://www.facebook.com',
identifier: 'facebook',
description: 'Facebook OAuth Provider',
time_zone: 'UTC'
},
{
name: 'LinkedIn',
url: 'https://linkedin.com',
identifier: 'linkedin',
description: 'LinkedIn OAuth Provider',
time_zone: 'UTC'
}
].freeze

class << self
def seed_data
puts "Creating #{OAUTH_PROVIDERS.length} external OAuth provider platforms..."

OAUTH_PROVIDERS.each do |provider_attrs|
create_external_platform(provider_attrs)
end

puts '✓ Successfully processed all OAuth providers'
end

# Clear existing external platforms - Use with caution!
def clear_existing
count = Platform.external.count
Platform.external.delete_all
puts "✓ Cleared #{count} existing external platforms"
end

private

def create_external_platform(provider_attrs)
platform = Platform.find_or_initialize_by(
identifier: provider_attrs[:identifier],
external: true
)

if platform.new_record?
platform.assign_attributes(
name: provider_attrs[:name],
url: provider_attrs[:url],
description: provider_attrs[:description],
time_zone: provider_attrs[:time_zone],
external: true,
host: false,
privacy: 'public'
)

platform.save!
puts " ✓ Created external platform: #{platform.name}"
else
puts " - External platform already exists: #{platform.name}"
end

platform
end
end
end
end
59 changes: 59 additions & 0 deletions app/controllers/better_together/omniauth_callbacks_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
class BetterTogether::OmniauthCallbacksController < Devise::OmniauthCallbacksController
# See https://github.com/omniauth/omniauth/wiki/FAQ#rails-session-is-clobbered-after-callback-on-developer-strategy
skip_before_action :verify_authenticity_token, only: %i[github]

Check failure

Code scanning / CodeQL

CSRF protection weakened or disabled High

Potential CSRF vulnerability due to forgery protection being disabled or weakened.

Copilot Autofix

AI 27 days ago

To fix this issue, re-enable CSRF protection for the github callback by removing or altering the line that skips CSRF verification for it. The best, most minimal fix is to delete or comment out the skip_before_action :verify_authenticity_token, only: %i[github] line (line 3 in the given code). This restores Rails' default (and secure) behaviour: requests made to the github callback will require the authenticity token, mitigating CSRF risk. No additional code or imports are needed—just remove that single line.

Suggested changeset 1
app/controllers/better_together/omniauth_callbacks_controller.rb

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/app/controllers/better_together/omniauth_callbacks_controller.rb b/app/controllers/better_together/omniauth_callbacks_controller.rb
--- a/app/controllers/better_together/omniauth_callbacks_controller.rb
+++ b/app/controllers/better_together/omniauth_callbacks_controller.rb
@@ -1,6 +1,5 @@
 class BetterTogether::OmniauthCallbacksController < Devise::OmniauthCallbacksController
   # See https://github.com/omniauth/omniauth/wiki/FAQ#rails-session-is-clobbered-after-callback-on-developer-strategy
-  skip_before_action :verify_authenticity_token, only: %i[github]
 
   before_action :set_person_platform_integration, except: [:failure]
   before_action :set_user, except: [:failure]
EOF
@@ -1,6 +1,5 @@
class BetterTogether::OmniauthCallbacksController < Devise::OmniauthCallbacksController
# See https://github.com/omniauth/omniauth/wiki/FAQ#rails-session-is-clobbered-after-callback-on-developer-strategy
skip_before_action :verify_authenticity_token, only: %i[github]

before_action :set_person_platform_integration, except: [:failure]
before_action :set_user, except: [:failure]
Copilot is powered by AI and may make mistakes. Always verify output.

before_action :set_person_platform_integration, except: [:failure]
before_action :set_user, except: [:failure]

attr_reader :person_platform_integration, :user

# def facebook
# handle_auth "Facebook"
# end

def github
handle_auth 'Github'
end

private

def handle_auth(kind)
if user.present?
flash[:success] = t 'devise_omniauth_callbacks.success', kind: kind if is_navigational_format?
sign_in_and_redirect user, event: :authentication # This handles the redirect
else
flash[:alert] =
t 'devise_omniauth_callbacks.failure', kind:, reason: "#{auth.info.email} is not authorized"
redirect_to new_user_registration_path
end
end

def auth
request.env['omniauth.auth']
end

def set_person_platform_integration
@person_platform_integration = BetterTogether::PersonPlatformIntegration.find_by(provider: auth.provider,
uid: auth.uid)
end

def set_user
@user = ::BetterTogether.user_class.from_omniauth(person_platform_integration:, auth:, current_user:)
end

# def github
# @user = ::BetterTogether.user_class.from_omniauth(request.env['omniauth.auth'])
# if @user.persisted?
# sign_in_and_redirect @user
# set_flash_message(:notice, :success, kind: 'Github') if is_navigational_format?
# else
# flash[:error] = 'There was a problem signing you in through Github. Please register or try signing in later.'
# redirect_to new_user_registration_url
# end
# end

def failure
flash[:error] = 'There was a problem signing you in. Please register or try signing in later.'
redirect_to helpers.base_url
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# frozen_string_literal: true

module BetterTogether
class PersonPlatformIntegrationsController < ApplicationController
before_action :set_person_platform_integration, only: %i[show edit update destroy]

# GET /better_together/person_platform_integrations
def index
@person_platform_integrations = BetterTogether::PersonPlatformIntegration.all
end

# GET /better_together/person_platform_integrations/1
def show; end

# GET /better_together/person_platform_integrations/new
def new
@person_platform_integration = BetterTogether::PersonPlatformIntegration.new
end

# GET /better_together/person_platform_integrations/1/edit
def edit; end

# POST /better_together/person_platform_integrations
def create
@better_together_person_platform_integration = BetterTogether::PersonPlatformIntegration.new(person_platform_integration_params)

if @person_platform_integration.save
redirect_to @person_platform_integration, notice: 'PersonPlatformIntegration was successfully created.'
else
render :new, status: :unprocessable_entity
end
end

# PATCH/PUT /better_together/person_platform_integrations/1
def update
if @person_platform_integration.update(person_platform_integration_params)
redirect_to @person_platform_integration, notice: 'PersonPlatformIntegration was successfully updated.',
status: :see_other
else
render :edit, status: :unprocessable_entity
end
end

# DELETE /better_together/person_platform_integrations/1
def destroy
@person_platform_integration.destroy!
redirect_to person_platform_integrations_url, notice: 'PersonPlatformIntegration was successfully destroyed.',
status: :see_other
end

private

# Use callbacks to share common setup or constraints between actions.
def set_person_platform_integration
@person_platform_integration = BetterTogether::PersonPlatformIntegration.find(params[:id])
end

# Only allow a list of trusted parameters through.
def person_platform_integration_params
params.require(:person_platform_integration).permit(:provider, :uid, :token, :secret, :profile_url, :user_id)
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

module BetterTogether
module Users
class OmniauthCallbacksController < ::Devise::OmniauthCallbacksController # rubocop:todo Style/Documentation
class OmniauthCallbacksController < BetterTogether::OmniauthCallbacksController # rubocop:todo Style/Documentation
include DeviseLocales

skip_before_action :check_platform_privacy
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true

module BetterTogether
module PersonPlatformIntegrationsHelper
end
end
30 changes: 30 additions & 0 deletions app/integrations/better_together/github.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# frozen_string_literal: true

require 'octokit'

module BetterTogether
class Github
def access_token
Octokit::Client.new(bearer_token: jwt).create_app_installation_access_token(Rails.application.credentials.dig(
:github, :installation_id
))[:token]
end

def jwt
payload = {
iat: Time.now.to_i - 60, # issued at time
exp: Time.now.to_i + (10 * 60),
iss: Rails.application.credentials.dig(:github, :app_id)
}
JWT.encode(payload, private_key, 'RS256')
end

def private_key
@private_key ||= OpenSSL::PKey::RSA.new(private_pem)
end

def private_pem
@private_pem ||= Rails.application.credentials.dig(:github, :private_pem)
end
end
end
2 changes: 2 additions & 0 deletions app/models/better_together/person.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ def self.primary_community_delegation_attrs
has_many :agreement_participants, class_name: 'BetterTogether::AgreementParticipant', dependent: :destroy
has_many :agreements, through: :agreement_participants

has_many :person_platform_integrations, dependent: :destroy

has_many :calendars, foreign_key: :creator_id, class_name: 'BetterTogether::Calendar', dependent: :destroy

has_many :event_attendances, class_name: 'BetterTogether::EventAttendance', dependent: :destroy
Expand Down
Loading
Loading