Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ ENCRYPTION_DETERMINISTIC_KEY=32characterrandomstring12345678902
ENCRYPTION_KEY_DERIVATION_SALT=16charssalt1234
```

Visit <https://hca.dinosaurbbq.org>, log in with an email address, then enable Developer Mode in HCA settings. After that, navigate to the "Developers' Corner" and "app yourself up", specifying a callback URL of `http://localhost:3000/auth/hca/callback` and minimum scopes of `email`, `slack_id`, and `verification_status`.
Visit <https://hca.dinosaurbbq.org>, log in with an email address, then enable Developer Mode in HCA settings. After that, navigate to the "Developers' Corner" and "app yourself up", specifying a callback URL of `http://localhost:3000/auth/hca/callback` and minimum scopes of `openid`, `email`, and `slack_id`.

Then, fill out the following fields in your `.env` file:

```env
# Hack Club Account
HCA_CLIENT_ID=<hca_client_id>
HCA_CLIENT_SECRET=<hca_client_secret>
# Optional when PUBLIC_URL is set; must exactly match the callback registered in HCA.
HCA_REDIRECT_URI=http://localhost:3000/auth/hca/callback
```

Start the containers:
Expand Down
4 changes: 3 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ gem "ruby-vips", "~> 2.3", require: false
gem "dotenv-rails"

# Authentication
# gem "oauth2"
gem "omniauth", "~> 2.1"
gem "omniauth_openid_connect", "~> 0.8"
gem "omniauth-rails_csrf_protection", "~> 1.0"

# Added from the code block
gem "http"
Expand Down
67 changes: 67 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ GEM
uri (>= 0.13.1)
addressable (2.9.0)
public_suffix (>= 2.0.2, < 8.0)
aes_key_wrap (1.1.0)
ast (2.4.3)
attr_required (1.0.2)
autotuner (1.1.0)
aws-eventstream (1.4.0)
aws-partitions (1.1274.0)
Expand Down Expand Up @@ -110,6 +112,7 @@ GEM
parser (>= 2.4)
smart_properties
bigdecimal (4.1.2)
bindata (3.0.0)
bindex (0.8.1)
bootsnap (1.24.6)
msgpack (~> 1.2)
Expand Down Expand Up @@ -175,6 +178,14 @@ GEM
tzinfo
faker (3.8.0)
i18n (>= 1.8.11, < 2)
faraday (2.14.3)
faraday-net_http (>= 2.0, < 3.5)
json
logger
faraday-follow_redirects (0.5.0)
faraday (>= 1, < 3)
faraday-net_http (3.4.4)
net-http (~> 0.5)
ffi (1.17.4-aarch64-linux-gnu)
ffi (1.17.4-aarch64-linux-musl)
ffi (1.17.4-arm-linux-gnu)
Expand Down Expand Up @@ -211,6 +222,8 @@ GEM
railties (>= 6.1.0)
thor (>= 1.0.0)
hashdiff (1.2.1)
hashie (5.1.0)
logger
htmlentities (4.4.2)
http (6.0.4)
http-cookie (~> 1.0)
Expand Down Expand Up @@ -241,6 +254,13 @@ GEM
js_from_routes (4.0.2)
railties (>= 5.1, < 9)
json (2.21.1)
json-jwt (1.17.2)
activesupport (>= 4.2)
aes_key_wrap
base64
bindata
faraday (~> 2.0)
faraday-follow_redirects
json-schema (6.2.0)
addressable (~> 2.8)
bigdecimal (>= 3.1, < 5)
Expand Down Expand Up @@ -291,6 +311,8 @@ GEM
prism (~> 1.5)
msgpack (1.8.4)
mutex_m (0.3.0)
net-http (0.9.1)
uri (>= 0.11.1)
net-imap (0.6.6)
date
net-protocol
Expand Down Expand Up @@ -318,6 +340,29 @@ GEM
oj (3.17.4)
bigdecimal (>= 3.0)
ostruct (>= 0.2)
omniauth (2.1.4)
hashie (>= 3.4.6)
logger
rack (>= 2.2.3)
rack-protection
omniauth-rails_csrf_protection (1.0.2)
actionpack (>= 4.2)
omniauth (~> 2.0)
omniauth_openid_connect (0.8.0)
omniauth (>= 1.9, < 3)
openid_connect (~> 2.2)
openid_connect (2.5.0)
activemodel
attr_required (>= 1.0.0)
faraday (~> 2.0)
faraday-follow_redirects
json-jwt (>= 1.16)
mail
rack-oauth2 (~> 2.2)
swd (~> 2.0)
tzinfo
validate_url
webfinger (~> 2.0)
ostruct (0.6.3)
paper_trail (17.0.0)
activerecord (>= 7.1)
Expand Down Expand Up @@ -364,6 +409,13 @@ GEM
rack (>= 3.0.14)
rack-mini-profiler (4.0.1)
rack (>= 1.2.0)
rack-oauth2 (2.3.0)
activesupport
attr_required
faraday (~> 2.0)
faraday-follow_redirects
json-jwt (>= 1.11.0)
rack (>= 2.1.0)
rack-protection (4.2.1)
base64 (>= 0.1.0)
logger (>= 1.6.0)
Expand Down Expand Up @@ -515,6 +567,11 @@ GEM
stackprof (0.2.28)
stimulus-rails (1.3.4)
railties (>= 6.0.0)
swd (2.0.3)
activesupport (>= 3)
attr_required (>= 0.0.5)
faraday (~> 2.0)
faraday-follow_redirects
thor (1.5.0)
thruster (0.1.23)
thruster (0.1.23-aarch64-linux)
Expand All @@ -534,6 +591,9 @@ GEM
uniform_notifier (1.18.0)
uri (1.1.1)
useragent (0.16.11)
validate_url (1.0.15)
activemodel (>= 3.0.0)
public_suffix
vite_rails (3.11.1)
railties (>= 5.1, < 9)
vite_ruby (~> 3.0, >= 3.2.2)
Expand All @@ -547,6 +607,10 @@ GEM
actionview (>= 8.0.0)
bindex (>= 0.4.0)
railties (>= 8.0.0)
webfinger (2.1.3)
activesupport
faraday (~> 2.0)
faraday-follow_redirects
webmock (3.26.2)
addressable (>= 2.8.0)
crack (>= 0.3.2)
Expand Down Expand Up @@ -609,6 +673,9 @@ DEPENDENCIES
maxminddb
memory_profiler
oj
omniauth (~> 2.1)
omniauth-rails_csrf_protection (~> 1.0)
omniauth_openid_connect (~> 0.8)
paper_trail
pg
premailer-rails
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/api/hackatime/v1/hackatime_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ def set_user
return render_unauthorized unless valid_key.present?

@user = valid_key.user
render_unauthorized unless @user
render_unauthorized unless @user&.authentication_allowed?
end

# allow either heartbeat or heartbeats
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ def ensure_api_access_allowed
render json: { error: "Unauthorized" }, status: :unauthorized if current_user&.api_access_restricted?
end

def ensure_no_pending_deletion
render json: { error: "Unauthorized" }, status: :unauthorized if current_user&.pending_deletion?
def ensure_profile_access_allowed
return if current_user&.authentication_allowed? && !current_user.pending_deletion?

render json: { error: "Unauthorized" }, status: :unauthorized
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/api/v1/authenticated/me_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module V1
module Authenticated
class MeController < ApplicationController
skip_before_action :ensure_api_access_allowed, only: :index
before_action :ensure_no_pending_deletion, only: :index
before_action :ensure_profile_access_allowed, only: :index

def index
app = doorkeeper_token&.application
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/api/v1/my/heartbeats_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def ensure_authenticated!
return render_unauthorized unless valid_key.present?

@current_user = valid_key.user
render_unauthorized unless @current_user
render_unauthorized unless @current_user&.authentication_allowed?
end

def current_user = @current_user
Expand Down
23 changes: 21 additions & 2 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,20 @@ def try_rack_mini_profiler_enable
end

def current_user
@current_user ||= User.find_by(id: session[:user_id]) if session[:user_id]
return @current_user if defined?(@current_user)

@current_user = resolve_session_user
end

def resolve_session_user
return unless session[:user_id]

user = User.find_by(id: session[:user_id])
session_version = session[:authentication_version] || 0
return user if user&.authentication_allowed? && user.authentication_version == session_version.to_i

reset_session
nil
end

def user_signed_in?
Expand All @@ -62,8 +75,14 @@ def persist_theme_cookie

def safe_return_url(url)
return nil if url.blank?
return nil unless url.start_with?("/") && !url.start_with?("//")
return nil if url.match?(/[\\\x00-\x1F\x7F]/)

uri = URI.parse(url)
return nil if uri.scheme || uri.host || !uri.path.start_with?("/") || uri.path.start_with?("//")

url
rescue URI::InvalidURIError
nil
end

# Build a return_data hash from a continue URL, extracting known query
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/concerns/admin_api_key_authentication.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@ def auth_admin_api_key(token)
true
end

def admin_api_user?(user) = user&.admin_level.in?(ADMIN_API_LEVELS)
def admin_api_user?(user) = user&.authentication_allowed? && user.admin_level.in?(ADMIN_API_LEVELS)
end
5 changes: 2 additions & 3 deletions app/controllers/deletion_requests_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ def create

def cancel
@deletion_request = current_user.active_deletion_request
if @deletion_request&.can_be_cancelled?
@deletion_request.cancel!
if @deletion_request&.cancel!
redirect_to my_settings_path, notice: "Your deletion request has been cancelled!"
else
redirect_to deletion_path
redirect_to my_settings_path, alert: "Your deletion request could not be cancelled."
end
end

Expand Down
28 changes: 22 additions & 6 deletions app/controllers/dev_controller.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class DevController < ApplicationController
before_action :ensure_development_environment
before_action :ensure_local_environment

def index
render plain: <<~TEXT
Expand All @@ -13,9 +13,14 @@ def log_me_in
email_address = EmailAddress.find_by(email: params[:email].downcase)
return render plain: "No local user has that email address.\n", status: :not_found unless email_address

reset_session
session[:user_id] = email_address.user_id
redirect_to root_path, notice: "Signed in as #{email_address.email}."
establish_local_session(email_address.user, label: email_address.email)
end

def log_me_in_user
user = User.find_by(id: params[:id])
return render plain: "No local user has that ID.\n", status: :not_found unless user

establish_local_session(user, label: "user ##{user.id}")
end

def log_me_out
Expand All @@ -25,7 +30,18 @@ def log_me_out

private

def ensure_development_environment
raise ActionController::RoutingError, "Not Found" unless Rails.env.development?
def establish_local_session(user, label:)
return render plain: "That local user cannot sign in.\n", status: :forbidden unless user.authentication_allowed?

reset_session
session[:user_id] = user.id
session[:authentication_version] = user.authentication_version
session[:auth_provider] = "development"
session[:authenticated_at] = Time.current.to_i
redirect_to root_path, notice: "Signed in as #{label}."
end

def ensure_local_environment
raise ActionController::RoutingError, "Not Found" unless Rails.env.local?
end
end
Loading
Loading