Skip to content

Commit

Permalink
add github oauth (#191)
Browse files Browse the repository at this point in the history
* add github oauth

* bundle lock --add-platform x86_64-linux

* fix schema

* remove system tests

* add another test

* amin stuffs

* fix Github user name

* make redirect to configurable

* fix test
  • Loading branch information
adrienpoly committed Sep 10, 2024
1 parent ac9c7e8 commit 7f98bd5
Show file tree
Hide file tree
Showing 29 changed files with 447 additions and 112 deletions.
7 changes: 7 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -130,5 +130,12 @@ gem "country_select", "~> 8.0"
gem "avo", "~> 3.11"
gem "frozen_record", "~> 0.27.2"

# Use OmniAuth to support multi-provider authentication [https://github.com/omniauth/omniauth]
gem "omniauth"
gem "omniauth-github"

# Provides a mitigation against CVE-2015-9284 [https://github.com/cookpad/omniauth-rails_csrf_protection]
gem "omniauth-rails_csrf_protection"

# silence Ruby 3.4 warnings
gem "ostruct"
59 changes: 36 additions & 23 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -202,21 +202,16 @@ GEM
raabro (~> 1.4)
globalid (1.2.1)
activesupport (>= 6.1)
google-protobuf (4.28.0-aarch64-linux)
bigdecimal
rake (>= 13)
google-protobuf (4.28.0-arm64-darwin)
bigdecimal
rake (>= 13)
google-protobuf (4.28.0-x86_64-darwin)
bigdecimal
rake (>= 13)
google-protobuf (4.28.0-x86_64-linux)
bigdecimal
rake (>= 13)
groupdate (6.4.0)
activesupport (>= 6.1)
hashdiff (1.1.1)
hashie (5.0.0)
httparty (0.22.0)
csv
mini_mime (>= 1.0.0)
Expand All @@ -240,18 +235,14 @@ GEM
activesupport (>= 5.0.0)
json (2.7.2)
json-repair (0.2.0)
jwt (2.8.2)
base64
language_server-protocol (3.17.0.3)
lint_roller (1.1.0)
literal (0.2.1)
litestream (0.10.5)
logfmt (>= 0.0.10)
sqlite3
litestream (0.10.5-arm64-darwin)
logfmt (>= 0.0.10)
sqlite3
litestream (0.10.5-x86_64-darwin)
logfmt (>= 0.0.10)
sqlite3
litestream (0.10.5-x86_64-linux)
logfmt (>= 0.0.10)
sqlite3
Expand Down Expand Up @@ -298,18 +289,34 @@ GEM
net-smtp (0.5.0)
net-protocol
nio4r (2.7.3)
nokogiri (1.16.7-aarch64-linux)
racc (~> 1.4)
nokogiri (1.16.7-arm64-darwin)
racc (~> 1.4)
nokogiri (1.16.7-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.16.7-x86_64-linux)
racc (~> 1.4)
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)
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)
ostruct (0.6.0)
pagy (9.0.8)
parallel (1.26.3)
parser (3.3.5.0)
pagy (9.0.5)
parallel (1.25.1)
parser (3.3.4.0)
ast (~> 2.4.1)
racc
prism (1.0.0)
Expand All @@ -326,6 +333,9 @@ GEM
raabro (1.4.0)
racc (1.8.1)
rack (3.1.7)
rack-protection (4.0.0)
base64 (>= 0.1.0)
rack (>= 3.0.0, < 4)
rack-proxy (0.7.7)
rack
rack-session (2.0.0)
Expand Down Expand Up @@ -423,6 +433,9 @@ GEM
sitemap_generator (6.3.0)
builder (~> 3.0)
smart_properties (1.17.0)
snaky_hash (2.0.1)
hashie
version_gem (~> 1.1, >= 1.1.1)
solid_cache (1.0.5)
activejob (>= 7.2)
activerecord (>= 7.2)
Expand All @@ -435,9 +448,7 @@ GEM
railties (>= 7.1)
thor (~> 1.3.1)
sorbet-runtime (0.5.11558)
sqlite3 (2.0.4-aarch64-linux-gnu)
sqlite3 (2.0.4-arm64-darwin)
sqlite3 (2.0.4-x86_64-darwin)
sqlite3 (2.0.4-x86_64-linux-gnu)
standard (1.40.0)
language_server-protocol (~> 3.17.0.2)
Expand Down Expand Up @@ -472,6 +483,7 @@ GEM
useragent (0.16.10)
vcr (6.3.1)
base64
version_gem (1.1.4)
view_component (3.14.0)
activesupport (>= 5.2.0, < 8.0)
concurrent-ruby (~> 1.0)
Expand Down Expand Up @@ -502,9 +514,7 @@ GEM
zeitwerk (2.6.18)

PLATFORMS
aarch64-linux
arm64-darwin-23
x86_64-darwin-23
x86_64-linux

DEPENDENCIES
Expand Down Expand Up @@ -541,6 +551,9 @@ DEPENDENCIES
meta-tags (~> 2.18)
mission_control-jobs
net-http (~> 0.3.2)
omniauth
omniauth-github
omniauth-rails_csrf_protection
ostruct
pagy
propshaft
Expand Down
29 changes: 29 additions & 0 deletions app/avo/resources/connected_account.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# id :integer
# uid :string
# provider :string
# username :string
# user_id :integer
# access_token :string
# expires_at :datetime
# created_at :datetime
# updated_at :datetime

class Avo::Resources::ConnectedAccount < Avo::BaseResource
# self.includes = []
# self.attachments = []
self.search = {
query: -> { query.ransack(id_eq: params[:q], uid_cont: params[:q], m: "or").result(distinct: false) }
}

def fields
field :id, as: :id
field :uid, as: :text
field :provider, as: :text, sortable: true
field :username, as: :text, sortable: true
field :user_id, as: :text, sortable: true, hide_on: [:index]
field :access_token, as: :text, hide_on: [:index]
field :expires_at, as: :date_time, hide_on: [:index]
field :created_at, as: :date_time, hide_on: [:index]
field :updated_at, as: :date_time, hide_on: [:index]
end
end
1 change: 1 addition & 0 deletions app/avo/resources/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ def fields
field :admin, as: :boolean
# field :sessions, as: :has_many, use_resource: Avo::Resources::Session
field :sessions, as: :has_many
field :connected_accounts, as: :has_many
end
end
4 changes: 4 additions & 0 deletions app/controllers/avo/connected_accounts_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# This controller has been generated to enable Rails' resource routes.
# More information on https://docs.avohq.io/3.0/controllers.html
class Avo::ConnectedAccountsController < Avo::ResourcesController
end
14 changes: 14 additions & 0 deletions app/controllers/concerns/authenticable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ module Authenticable
included do
before_action :set_current_request_details
before_action :authenticate_user!

helper_method :signed_in?, :signed_in, :signed_out
end

def signed_in?
Current.user.present?
end

def signed_in(&block)
yield if block && signed_in?
end

def signed_out(&block)
yield if block && !signed_in?
end

private
Expand Down
53 changes: 53 additions & 0 deletions app/controllers/sessions/omniauth_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
class Sessions::OmniauthController < ApplicationController
skip_before_action :verify_authenticity_token
skip_before_action :authenticate_user!

def create
connected_account = ConnectedAccount.find_or_initialize_by(provider: omniauth.provider, uid: omniauth.uid)

if connected_account.new_record?
@user = User.create_with(user_params).find_or_create_by(email: omniauth.info.email)
connected_account.user = @user
connected_account.access_token = omniauth.credentials&.try(:token)
connected_account.username = omniauth.info&.try(:nickname)
connected_account.save!
else
@user = connected_account.user
end

if @user.persisted?
session_record = @user.sessions.create!
cookies.signed.permanent[:session_token] = {value: session_record.id, httponly: true}

redirect_to redirect_to_path, notice: "Signed in successfully"
else
redirect_to sign_in_path, alert: "Authentication failed"
end
end

def failure
redirect_to sign_in_path, alert: params[:message]
end

private

def redirect_to_path
query_params["redirect_to"] || root_path
end

def user_params
{email: omniauth.info.email, password: SecureRandom.base58, verified: true}
end

def omniauth_params
{provider: omniauth.provider, uid: omniauth.uid, username: omniauth.info.try(:nickname)}.compact_blank
end

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

def query_params
request.env["omniauth.params"]
end
end
6 changes: 3 additions & 3 deletions app/helpers/icon_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ def heroicon(icon_name, size: :md, variant: :outline, **options)
inline_svg_tag "icons/heroicons/#{variant}/#{icon_name.to_s.tr("_", "-")}.svg", class: classes
end

def icon(icon_name, size: :md, **)
classes = SIZE_CLASSES[size]
inline_svg_tag("icons/icn-#{icon_name}.svg", class: classes, **)
def icon(icon_name, size: :md, **options)
classes = class_names(SIZE_CLASSES[size], options.delete(:class))
inline_svg_tag("icons/icn-#{icon_name}.svg", class: classes, **options)
end
end
19 changes: 19 additions & 0 deletions app/models/connected_account.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# rubocop:disable Layout/LineLength
# == Schema Information
#
# Table name: connected_accounts
#
# id :integer not null, primary key
# uid :string
# provider :string
# username :string
# user_id :integer not null
# access_token :string
# expires_at :datetime
# created_at :datetime not null
# updated_at :datetime not null
#
# rubocop:enable Layout/LineLength
class ConnectedAccount < ApplicationRecord
belongs_to :user
end
4 changes: 2 additions & 2 deletions app/models/talk.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
# date :date
# like_count :integer
# view_count :integer
# raw_transcript :text default(#<Transcript:0x0000000126897d68 @cues=[]>), not null
# enhanced_transcript :text default(#<Transcript:0x0000000126897c78 @cues=[]>), not null
# raw_transcript :text default(#<Transcript:0x00000001645d16b8 @cues=[]>), not null
# enhanced_transcript :text default(#<Transcript:0x00000001645d15c8 @cues=[]>), not null
# summary :text default(""), not null
# language :string default("en"), not null
#
Expand Down
1 change: 1 addition & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class User < ApplicationRecord
has_many :email_verification_tokens, dependent: :destroy
has_many :password_reset_tokens, dependent: :destroy
has_many :sessions, dependent: :destroy, inverse_of: :user
has_many :connected_accounts, dependent: :destroy
has_many :watch_lists, dependent: :destroy

validates :email, presence: true, uniqueness: true, format: {with: URI::MailTo::EMAIL_REGEXP}
Expand Down
48 changes: 23 additions & 25 deletions app/views/sessions/new.html.erb
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
<p style="color: green"><%= notice %></p>
<p style="color: red"><%= alert %></p>
<% redirect_to_path = params.delete(:redirect_to) || root_path %>

<h1>Sign in</h1>
<div class="flex items-center justify-center py-24 px-4 sm:px-6 lg:px-8">
<div class="max-w-md w-full space-y-8">
<div>
<h1 class="mt-6 text-center text-3xl font-semibold text-neutral">
Sign in to your account
</h1>
</div>
<div class="mt-8 space-y-6">
<div>
<%= button_to "/auth/github?redirect_to=#{redirect_to_path}", method: :post, data: {turbo: false}, class: "btn w-full btn-neutral" do %>
<%= icon "github", size: :sm, class: "mr-2" %>
Sign in with GitHub
<% end %>
</div>

<%= form_with(url: sign_in_path) do |form| %>
<div>
<%= form.label :email, style: "display: block" %>
<%= form.email_field :email, value: params[:email_hint], required: true, autofocus: true, autocomplete: "email" %>
<% if Rails.env.development? %>
<div>
<%= button_to "/auth/developer", method: :post, data: {turbo: false}, class: "btn w-full btn-accent" do %>
Sign in with OmniAuth (Development)
<% end %>
</div>
<% end %>
</div>
</div>

<div>
<%= form.label :password, style: "display: block" %>
<%= form.password_field :password, required: true, autocomplete: "current-password" %>
</div>

<div>
<%= form.submit "Sign in" %>
</div>
<% end %>

<br>

<br>

<div>
<%= link_to "Sign up", sign_up_path %> |
<%= link_to "Forgot your password?", new_identity_password_reset_path %>
</div>
Loading

0 comments on commit 7f98bd5

Please sign in to comment.