steam login works
This commit is contained in:
parent
73e4e8a52f
commit
35cb0e2ce8
4 changed files with 96 additions and 23 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
# L4D Tools - Architecture & Implementation Plan
|
# L4D Tools - Architecture & Implementation Plan
|
||||||
|
|
||||||
**Date**: January 18, 2026
|
**Date**: January 18, 2026
|
||||||
**Status**: MVP Implementation Complete
|
**Status**: MVP Implementation Complete
|
||||||
**Framework**: Rails 8.1.2 with SQLite + Hotwire + Solid Queue
|
**Framework**: Rails 8.1.2 with SQLite + Hotwire + Solid Queue
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -84,7 +84,7 @@ Template Show → Click "Spawn Server"
|
||||||
→ Enter server name and port
|
→ Enter server name and port
|
||||||
→ (Optional) Override startup parameters
|
→ (Optional) Override startup parameters
|
||||||
→ Click "Spawn Server"
|
→ Click "Spawn Server"
|
||||||
|
|
||||||
Background (SpawnServerJob):
|
Background (SpawnServerJob):
|
||||||
→ Create /opt/l4d2/servers/{server_id}/ with subdirs
|
→ Create /opt/l4d2/servers/{server_id}/ with subdirs
|
||||||
→ Generate server.cfg from template ConfigOptions
|
→ Generate server.cfg from template ConfigOptions
|
||||||
|
|
@ -280,8 +280,8 @@ WS /cable → ActionCable (LogChannel)
|
||||||
|
|
||||||
### Frontend (Slim + Hotwire)
|
### Frontend (Slim + Hotwire)
|
||||||
|
|
||||||
**Templating**: All views use Slim (not ERB)
|
**Templating**: All views use Slim (not ERB)
|
||||||
**Interactivity**: Hotwire (Turbo + Stimulus) for SPA-like experience
|
**Interactivity**: Hotwire (Turbo + Stimulus) for SPA-like experience
|
||||||
**Styling**: Basic CSS in `app/assets/stylesheets/application.css`
|
**Styling**: Basic CSS in `app/assets/stylesheets/application.css`
|
||||||
|
|
||||||
Key Views:
|
Key Views:
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,89 @@
|
||||||
|
require "net/http"
|
||||||
|
|
||||||
class SessionsController < ApplicationController
|
class SessionsController < ApplicationController
|
||||||
skip_before_action :authenticate_user!
|
skip_before_action :authenticate_user!, only: [ :auth_request, :steam_callback ]
|
||||||
|
|
||||||
def auth_request
|
def auth_request
|
||||||
# Manually trigger OmniAuth Steam strategy
|
# Build Steam OpenID URL
|
||||||
request.env['omniauth.strategy'] = OmniAuth::Strategies::Steam.new(nil)
|
steam_openid_url = "https://steamcommunity.com/openid/login"
|
||||||
auth = request.env['omniauth.strategy'].request_phase
|
# Use the actual request host/protocol for both return_to and realm to avoid signature mismatch
|
||||||
redirect_to auth
|
base_url = request.base_url
|
||||||
|
return_url = "#{base_url}#{steam_callback_path}"
|
||||||
|
|
||||||
|
Rails.logger.info("Steam auth_request return_url=#{return_url} realm=#{base_url}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"openid.ns" => "http://specs.openid.net/auth/2.0",
|
||||||
|
"openid.identity" => "http://specs.openid.net/auth/2.0/identifier_select",
|
||||||
|
"openid.claimed_id" => "http://specs.openid.net/auth/2.0/identifier_select",
|
||||||
|
"openid.mode" => "checkid_setup",
|
||||||
|
"openid.return_to" => return_url,
|
||||||
|
"openid.realm" => base_url,
|
||||||
|
"openid.ns.sreg" => "http://openid.net/extensions/sreg/1.1",
|
||||||
|
"openid.sreg.required" => "email"
|
||||||
|
}
|
||||||
|
|
||||||
|
redirect_to "#{steam_openid_url}?#{params.to_query}", allow_other_host: true
|
||||||
end
|
end
|
||||||
|
|
||||||
def steam_callback
|
def steam_callback
|
||||||
auth_hash = request.env["omniauth.auth"]
|
# Get the OpenID response
|
||||||
|
openid_response = request.params
|
||||||
|
|
||||||
if auth_hash
|
# Verify the response with Steam
|
||||||
user = User.find_or_create_from_steam(auth_hash)
|
if verify_steam_response(openid_response)
|
||||||
session[:user_id] = user.id
|
# Extract Steam ID from identity URL
|
||||||
redirect_to dashboard_path, notice: "Logged in successfully!"
|
# Format: http://steamcommunity.com/openid/id/[STEAMID]
|
||||||
|
identity_url = openid_response["openid.identity"]
|
||||||
|
|
||||||
|
if identity_url && identity_url.include?("/id/")
|
||||||
|
steam_id = identity_url.split("/id/").last
|
||||||
|
|
||||||
|
# Create mock auth_hash for compatibility with our User model
|
||||||
|
auth_hash = {
|
||||||
|
"uid" => steam_id,
|
||||||
|
"info" => {
|
||||||
|
"nickname" => "Steam User #{steam_id}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
user = User.find_or_create_from_steam(auth_hash)
|
||||||
|
session[:user_id] = user.id
|
||||||
|
redirect_to dashboard_path, notice: "Logged in successfully!"
|
||||||
|
else
|
||||||
|
redirect_to root_path, alert: "Could not extract Steam ID from response."
|
||||||
|
end
|
||||||
else
|
else
|
||||||
redirect_to root_path, alert: "Steam authentication failed."
|
redirect_to root_path, alert: "Steam authentication failed: Invalid response signature."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def verify_steam_response(response)
|
||||||
|
# Steam expects only openid.* keys and mode=check_auth for validation
|
||||||
|
openid_params = response.to_h.select { |k, _| k.to_s.start_with?("openid.") }
|
||||||
|
return false unless openid_params["openid.mode"] == "id_res"
|
||||||
|
|
||||||
|
# Per OpenID 2.0 spec, the verification mode is "check_authentication"
|
||||||
|
verify_params = openid_params.merge("openid.mode" => "check_authentication")
|
||||||
|
|
||||||
|
Rails.logger.info("Steam verify payload: #{verify_params.inspect}")
|
||||||
|
|
||||||
|
uri = URI.parse("https://steamcommunity.com/openid/login")
|
||||||
|
http = Net::HTTP.new(uri.host, uri.port)
|
||||||
|
http.use_ssl = true
|
||||||
|
|
||||||
|
request = Net::HTTP::Post.new(uri.path)
|
||||||
|
request.set_form_data(verify_params)
|
||||||
|
|
||||||
|
begin
|
||||||
|
response = http.request(request)
|
||||||
|
Rails.logger.info("Steam verify response body: #{response.body.inspect}")
|
||||||
|
response.body.include?("is_valid:true")
|
||||||
|
rescue StandardError => e
|
||||||
|
Rails.logger.error("Steam verification error: #{e.message}")
|
||||||
|
false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -24,4 +91,8 @@ class SessionsController < ApplicationController
|
||||||
session[:user_id] = nil
|
session[:user_id] = nil
|
||||||
redirect_to root_path, notice: "Logged out successfully!"
|
redirect_to root_path, notice: "Logged out successfully!"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def omniauth_failure
|
||||||
|
redirect_to root_path, alert: "Steam authentication failed: #{params[:message]}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,13 @@
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
<% if flash.any? %>
|
||||||
|
<div class="flash-messages">
|
||||||
|
<% flash.each do |type, message| %>
|
||||||
|
<div class="flash flash-<%= type %>"><%= message %></div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
<%= yield %>
|
<%= yield %>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,2 @@
|
||||||
Rails.application.config.middleware.use OmniAuth::Builder do
|
# OmniAuth is not used - we implement direct Steam OpenID 2.0 protocol
|
||||||
provider :steam, ENV["STEAM_API_KEY"] || "test"
|
# This file is kept for reference but the middleware is disabled
|
||||||
end
|
|
||||||
|
|
||||||
OmniAuth.config.on_failure = proc { |env|
|
|
||||||
OmniAuth::FailureEndpoint.new(env).redirect_to_failure
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue