Compare commits

..

2 Commits

Author SHA1 Message Date
Dan Milne
ab362aabac Remove the rate limit for the forward auth system
Some checks are pending
CI / scan_ruby (push) Waiting to run
CI / scan_js (push) Waiting to run
CI / lint (push) Waiting to run
CI / test (push) Waiting to run
CI / system-test (push) Waiting to run
2025-12-28 14:40:53 +11:00
Dan Milne
283feea175 Update depenencies, bump versoin 2025-11-30 23:13:25 +11:00
7 changed files with 97 additions and 75 deletions

View File

@@ -11,6 +11,8 @@
ARG RUBY_VERSION=3.4.6 ARG RUBY_VERSION=3.4.6
FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base
LABEL org.opencontainers.image.source=https://github.com/dkam/clinch
# Rails app lives here # Rails app lives here
WORKDIR /rails WORKDIR /rails

View File

@@ -35,11 +35,11 @@ gem "jwt", "~> 3.1"
gem "webauthn", "~> 3.0" gem "webauthn", "~> 3.0"
# Public Suffix List for domain parsing # Public Suffix List for domain parsing
gem "public_suffix", "~> 6.0" gem "public_suffix", "~> 7.0"
# Error tracking and performance monitoring (optional, configured via SENTRY_DSN) # Error tracking and performance monitoring (optional, configured via SENTRY_DSN)
gem "sentry-ruby", "~> 5.18" gem "sentry-ruby", "~> 6.2"
gem "sentry-rails", "~> 5.18" gem "sentry-rails", "~> 6.2"
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem "tzinfo-data", platforms: %i[ windows jruby ] gem "tzinfo-data", platforms: %i[ windows jruby ]

View File

@@ -75,8 +75,8 @@ GEM
securerandom (>= 0.3) securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5) tzinfo (~> 2.0, >= 2.0.5)
uri (>= 0.13.1) uri (>= 0.13.1)
addressable (2.8.7) addressable (2.8.8)
public_suffix (>= 2.0.2, < 7.0) public_suffix (>= 2.0.2, < 8.0)
android_key_attestation (0.3.0) android_key_attestation (0.3.0)
ast (2.4.3) ast (2.4.3)
base64 (0.3.0) base64 (0.3.0)
@@ -85,13 +85,13 @@ GEM
bigdecimal (3.3.1) bigdecimal (3.3.1)
bindata (2.5.1) bindata (2.5.1)
bindex (0.8.1) bindex (0.8.1)
bootsnap (1.18.6) bootsnap (1.19.0)
msgpack (~> 1.2) msgpack (~> 1.2)
brakeman (7.1.0) brakeman (7.1.1)
racc racc
builder (3.3.0) builder (3.3.0)
bundler-audit (0.9.2) bundler-audit (0.9.3)
bundler (>= 1.2.0, < 3) bundler (>= 1.2.0)
thor (~> 1.0) thor (~> 1.0)
capybara (3.40.0) capybara (3.40.0)
addressable addressable
@@ -107,7 +107,7 @@ GEM
logger (~> 1.5) logger (~> 1.5)
chunky_png (1.4.0) chunky_png (1.4.0)
concurrent-ruby (1.3.5) concurrent-ruby (1.3.5)
connection_pool (2.5.4) connection_pool (2.5.5)
cose (1.3.1) cose (1.3.1)
cbor (~> 0.5.9) cbor (~> 0.5.9)
openssl-signature_algorithm (~> 1.0) openssl-signature_algorithm (~> 1.0)
@@ -119,7 +119,7 @@ GEM
dotenv (3.1.8) dotenv (3.1.8)
drb (2.2.3) drb (2.2.3)
ed25519 (1.4.0) ed25519 (1.4.0)
erb (5.1.3) erb (6.0.0)
erubi (1.13.1) erubi (1.13.1)
ffi (1.17.2-aarch64-linux-gnu) ffi (1.17.2-aarch64-linux-gnu)
ffi (1.17.2-aarch64-linux-musl) ffi (1.17.2-aarch64-linux-musl)
@@ -147,10 +147,10 @@ GEM
jbuilder (2.14.1) jbuilder (2.14.1)
actionview (>= 7.0.0) actionview (>= 7.0.0)
activesupport (>= 7.0.0) activesupport (>= 7.0.0)
json (2.15.2) json (2.16.0)
jwt (3.1.2) jwt (3.1.2)
base64 base64
kamal (2.8.1) kamal (2.9.0)
activesupport (>= 7.0) activesupport (>= 7.0)
base64 (~> 0.2) base64 (~> 0.2)
bcrypt_pbkdf (~> 1.0) bcrypt_pbkdf (~> 1.0)
@@ -184,7 +184,7 @@ GEM
mini_magick (5.3.1) mini_magick (5.3.1)
logger logger
mini_mime (1.1.5) mini_mime (1.1.5)
minitest (5.26.0) minitest (5.26.2)
msgpack (1.8.0) msgpack (1.8.0)
net-imap (0.5.12) net-imap (0.5.12)
date date
@@ -220,7 +220,7 @@ GEM
openssl (> 2.0) openssl (> 2.0)
ostruct (0.6.3) ostruct (0.6.3)
parallel (1.27.0) parallel (1.27.0)
parser (3.3.9.0) parser (3.3.10.0)
ast (~> 2.4.1) ast (~> 2.4.1)
racc racc
pp (0.6.3) pp (0.6.3)
@@ -234,7 +234,7 @@ GEM
psych (5.2.6) psych (5.2.6)
date date
stringio stringio
public_suffix (6.0.2) public_suffix (7.0.0)
puma (7.1.0) puma (7.1.0)
nio4r (~> 2.0) nio4r (~> 2.0)
racc (1.8.1) racc (1.8.1)
@@ -278,20 +278,20 @@ GEM
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
rainbow (3.1.1) rainbow (3.1.1)
rake (13.3.1) rake (13.3.1)
rdoc (6.15.1) rdoc (6.16.1)
erb erb
psych (>= 4.0.0) psych (>= 4.0.0)
tsort tsort
regexp_parser (2.11.3) regexp_parser (2.11.3)
reline (0.6.2) reline (0.6.3)
io-console (~> 0.5) io-console (~> 0.5)
rexml (3.4.4) rexml (3.4.4)
rotp (6.3.0) rotp (6.3.0)
rqrcode (3.1.0) rqrcode (3.1.1)
chunky_png (~> 1.0) chunky_png (~> 1.0)
rqrcode_core (~> 2.0) rqrcode_core (~> 2.0)
rqrcode_core (2.0.0) rqrcode_core (2.0.1)
rubocop (1.81.6) rubocop (1.81.7)
json (~> 2.3) json (~> 2.3)
language_server-protocol (~> 3.17.0.2) language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0) lint_roller (~> 1.1.0)
@@ -302,14 +302,14 @@ GEM
rubocop-ast (>= 1.47.1, < 2.0) rubocop-ast (>= 1.47.1, < 2.0)
ruby-progressbar (~> 1.7) ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 4.0) unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.47.1) rubocop-ast (1.48.0)
parser (>= 3.3.7.2) parser (>= 3.3.7.2)
prism (~> 1.4) prism (~> 1.4)
rubocop-performance (1.26.1) rubocop-performance (1.26.1)
lint_roller (~> 1.1) lint_roller (~> 1.1)
rubocop (>= 1.75.0, < 2.0) rubocop (>= 1.75.0, < 2.0)
rubocop-ast (>= 1.47.1, < 2.0) rubocop-ast (>= 1.47.1, < 2.0)
rubocop-rails (2.33.4) rubocop-rails (2.34.2)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
lint_roller (~> 1.1) lint_roller (~> 1.1)
rack (>= 1.1) rack (>= 1.1)
@@ -323,7 +323,7 @@ GEM
ruby-vips (2.2.5) ruby-vips (2.2.5)
ffi (~> 1.12) ffi (~> 1.12)
logger logger
rubyzip (3.2.1) rubyzip (3.2.2)
safety_net_attestation (0.5.0) safety_net_attestation (0.5.0)
jwt (>= 2.0, < 4.0) jwt (>= 2.0, < 4.0)
securerandom (0.4.1) securerandom (0.4.1)
@@ -333,10 +333,10 @@ GEM
rexml (~> 3.2, >= 3.2.5) rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 4.0) rubyzip (>= 1.2.2, < 4.0)
websocket (~> 1.0) websocket (~> 1.0)
sentry-rails (5.28.0) sentry-rails (6.2.0)
railties (>= 5.0) railties (>= 5.2.0)
sentry-ruby (~> 5.28.0) sentry-ruby (~> 6.2.0)
sentry-ruby (5.28.0) sentry-ruby (6.2.0)
bigdecimal bigdecimal
concurrent-ruby (~> 1.0, >= 1.0.2) concurrent-ruby (~> 1.0, >= 1.0.2)
solid_cable (3.0.12) solid_cable (3.0.12)
@@ -344,17 +344,17 @@ GEM
activejob (>= 7.2) activejob (>= 7.2)
activerecord (>= 7.2) activerecord (>= 7.2)
railties (>= 7.2) railties (>= 7.2)
solid_cache (1.0.8) solid_cache (1.0.10)
activejob (>= 7.2) activejob (>= 7.2)
activerecord (>= 7.2) activerecord (>= 7.2)
railties (>= 7.2) railties (>= 7.2)
sqlite3 (2.7.4-aarch64-linux-gnu) sqlite3 (2.8.1-aarch64-linux-gnu)
sqlite3 (2.7.4-aarch64-linux-musl) sqlite3 (2.8.1-aarch64-linux-musl)
sqlite3 (2.7.4-arm-linux-gnu) sqlite3 (2.8.1-arm-linux-gnu)
sqlite3 (2.7.4-arm-linux-musl) sqlite3 (2.8.1-arm-linux-musl)
sqlite3 (2.7.4-arm64-darwin) sqlite3 (2.8.1-arm64-darwin)
sqlite3 (2.7.4-x86_64-linux-gnu) sqlite3 (2.8.1-x86_64-linux-gnu)
sqlite3 (2.7.4-x86_64-linux-musl) sqlite3 (2.8.1-x86_64-linux-musl)
sshkit (1.24.0) sshkit (1.24.0)
base64 base64
logger logger
@@ -364,16 +364,16 @@ GEM
ostruct ostruct
stimulus-rails (1.3.4) stimulus-rails (1.3.4)
railties (>= 6.0.0) railties (>= 6.0.0)
stringio (3.1.7) stringio (3.1.8)
tailwindcss-rails (4.3.0) tailwindcss-rails (4.4.0)
railties (>= 7.0.0) railties (>= 7.0.0)
tailwindcss-ruby (~> 4.0) tailwindcss-ruby (~> 4.0)
tailwindcss-ruby (4.1.13) tailwindcss-ruby (4.1.16)
tailwindcss-ruby (4.1.13-aarch64-linux-gnu) tailwindcss-ruby (4.1.16-aarch64-linux-gnu)
tailwindcss-ruby (4.1.13-aarch64-linux-musl) tailwindcss-ruby (4.1.16-aarch64-linux-musl)
tailwindcss-ruby (4.1.13-arm64-darwin) tailwindcss-ruby (4.1.16-arm64-darwin)
tailwindcss-ruby (4.1.13-x86_64-linux-gnu) tailwindcss-ruby (4.1.16-x86_64-linux-gnu)
tailwindcss-ruby (4.1.13-x86_64-linux-musl) tailwindcss-ruby (4.1.16-x86_64-linux-musl)
thor (1.4.0) thor (1.4.0)
thruster (0.1.16) thruster (0.1.16)
thruster (0.1.16-aarch64-linux) thruster (0.1.16-aarch64-linux)
@@ -385,7 +385,7 @@ GEM
openssl (> 2.0) openssl (> 2.0)
openssl-signature_algorithm (~> 1.0) openssl-signature_algorithm (~> 1.0)
tsort (0.2.0) tsort (0.2.0)
turbo-rails (2.0.17) turbo-rails (2.0.20)
actionpack (>= 7.1.0) actionpack (>= 7.1.0)
railties (>= 7.1.0) railties (>= 7.1.0)
tzinfo (2.0.6) tzinfo (2.0.6)
@@ -393,7 +393,7 @@ GEM
unicode-display_width (3.2.0) unicode-display_width (3.2.0)
unicode-emoji (~> 4.1) unicode-emoji (~> 4.1)
unicode-emoji (4.1.0) unicode-emoji (4.1.0)
uri (1.1.0) uri (1.1.1)
useragent (0.16.11) useragent (0.16.11)
web-console (4.2.1) web-console (4.2.1)
actionview (>= 6.0.0) actionview (>= 6.0.0)
@@ -442,15 +442,15 @@ DEPENDENCIES
kamal kamal
letter_opener letter_opener
propshaft propshaft
public_suffix (~> 6.0) public_suffix (~> 7.0)
puma (>= 5.0) puma (>= 5.0)
rails (~> 8.1.1) rails (~> 8.1.1)
rotp (~> 6.3) rotp (~> 6.3)
rqrcode (~> 3.1) rqrcode (~> 3.1)
rubocop-rails-omakase rubocop-rails-omakase
selenium-webdriver selenium-webdriver
sentry-rails (~> 5.18) sentry-rails (~> 6.2)
sentry-ruby (~> 5.18) sentry-ruby (~> 6.2)
solid_cable solid_cable
solid_cache solid_cache
sqlite3 (>= 2.1) sqlite3 (>= 2.1)

View File

@@ -15,10 +15,12 @@ I've completed all planned features:
* Forward Auth configured and working * Forward Auth configured and working
* OIDC provider with auto discovery, refresh tokens, and token revocation * OIDC provider with auto discovery, refresh tokens, and token revocation
* Configurable token expiry per application (access, refresh, ID tokens) * Configurable token expiry per application (access, refresh, ID tokens)
* Backchannel Logout
* Per-application logout / revoke
* Invite users by email, assign to groups * Invite users by email, assign to groups
* Self managed password reset by email * Self managed password reset by email
* Use Groups to assign Applications ( Family group can access Kavita, Developers can access Gitea ) * Use Groups to assign Applications ( Family group can access Kavita, Developers can access Gitea )
* Configurable Group and User custom claims for OIDC token * Configurable Group, User & App+User custom claims for OIDC token
* Display all Applications available to the user on their Dashboard * Display all Applications available to the user on their Dashboard
* Display all logged in sessions and OIDC logged in sessions * Display all logged in sessions and OIDC logged in sessions

View File

@@ -3,7 +3,7 @@ module Api
# ForwardAuth endpoints need session storage for return URL # ForwardAuth endpoints need session storage for return URL
allow_unauthenticated_access allow_unauthenticated_access
skip_before_action :verify_authenticity_token skip_before_action :verify_authenticity_token
rate_limit to: 100, within: 1.minute, only: :verify, with: -> { head :too_many_requests } # No rate limiting on forward_auth endpoint - proxy middleware hits this frequently
# GET /api/verify # GET /api/verify
# This endpoint is called by reverse proxies (Traefik, Caddy, nginx) # This endpoint is called by reverse proxies (Traefik, Caddy, nginx)

View File

@@ -18,34 +18,47 @@
</div> </div>
<div> <div>
<%= form.label :icon, "Application Icon", class: "block text-sm font-medium text-gray-700" %> <div class="flex items-center justify-between">
<% begin %> <%= form.label :icon, "Application Icon", class: "block text-sm font-medium text-gray-700" %>
<% if application.icon.attached? && application.persisted? && application.icon.blob&.persisted? %> <a href="https://dashboardicons.com" target="_blank" rel="noopener noreferrer" class="text-xs text-blue-600 hover:text-blue-800 flex items-center gap-1">
<div class="mt-2 mb-3 flex items-center gap-4"> <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<%= image_tag application.icon, class: "h-16 w-16 rounded-lg object-cover border border-gray-200", alt: "Current icon" %> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path>
<div class="text-sm text-gray-600"> </svg>
<p class="font-medium">Current icon</p> Browse icons at dashboardicons.com
<p class="text-xs"><%= number_to_human_size(application.icon.blob.byte_size) %></p> </a>
</div>
<% if application.icon.attached? && application.persisted? %>
<% begin %>
<%# Only show icon if we can successfully get its URL (blob is persisted) %>
<% if application.icon.blob&.persisted? && application.icon.blob.key.present? %>
<div class="mt-2 mb-3 flex items-center gap-4">
<%= image_tag application.icon, class: "h-16 w-16 rounded-lg object-cover border border-gray-200", alt: "Current icon" %>
<div class="text-sm text-gray-600">
<p class="font-medium">Current icon</p>
<p class="text-xs"><%= number_to_human_size(application.icon.blob.byte_size) %></p>
</div>
</div> </div>
</div> <% end %>
<% end %> <% rescue ArgumentError => e %>
<% rescue ArgumentError => e %> <%# Handle case where icon attachment exists but can't generate signed_id %>
<%# Handle case where icon attachment exists but can't generate signed_id %> <% if e.message.include?("Cannot get a signed_id for a new record") %>
<% if e.message.include?("Cannot get a signed_id for a new record") %> <div class="mt-2 mb-3 text-sm text-gray-600">
<div class="mt-2 mb-3 text-sm text-gray-600"> <p class="font-medium">Icon uploaded</p>
<p class="font-medium">Icon uploaded</p> <p class="text-xs">File will be processed shortly</p>
<p class="text-xs">File will be processed shortly</p> </div>
</div> <% else %>
<% else %> <%# Re-raise if it's a different error %>
<%# Re-raise if it's a different error %> <% raise e %>
<% raise e %> <% end %>
<% end %> <% end %>
<% end %> <% end %>
<div class="mt-2" data-controller="file-drop"> <div class="mt-2" data-controller="file-drop image-paste">
<div class="flex justify-center px-6 pt-5 pb-6 border-2 border-gray-300 border-dashed rounded-md hover:border-blue-400 transition-colors" <div class="flex justify-center px-6 pt-5 pb-6 border-2 border-gray-300 border-dashed rounded-md hover:border-blue-400 transition-colors"
data-file-drop-target="dropzone" data-file-drop-target="dropzone"
data-action="dragover->file-drop#dragover dragleave->file-drop#dragleave drop->file-drop#drop"> data-image-paste-target="dropzone"
data-action="dragover->file-drop#dragover dragleave->file-drop#dragleave drop->file-drop#drop paste->image-paste#handlePaste"
tabindex="0">
<div class="space-y-1 text-center"> <div class="space-y-1 text-center">
<svg class="mx-auto h-12 w-12 text-gray-400" stroke="currentColor" fill="none" viewBox="0 0 48 48"> <svg class="mx-auto h-12 w-12 text-gray-400" stroke="currentColor" fill="none" viewBox="0 0 48 48">
<path d="M28 8H12a4 4 0 00-4 4v20m32-12v8m0 0v8a4 4 0 01-4 4H12a4 4 0 01-4-4v-4m32-4l-3.172-3.172a4 4 0 00-5.656 0L28 28M8 32l9.172-9.172a4 4 0 015.656 0L28 28m0 0l4 4m4-24h8m-4-4v8m-12 4h.02" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> <path d="M28 8H12a4 4 0 00-4 4v20m32-12v8m0 0v8a4 4 0 01-4 4H12a4 4 0 01-4-4v-4m32-4l-3.172-3.172a4 4 0 00-5.656 0L28 28M8 32l9.172-9.172a4 4 0 015.656 0L28 28m0 0l4 4m4-24h8m-4-4v8m-12 4h.02" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
@@ -56,11 +69,16 @@
<%= form.file_field :icon, <%= form.file_field :icon,
accept: "image/png,image/jpg,image/jpeg,image/gif,image/svg+xml", accept: "image/png,image/jpg,image/jpeg,image/gif,image/svg+xml",
class: "sr-only", class: "sr-only",
data: { file_drop_target: "input", action: "change->file-drop#handleFiles" } %> data: {
file_drop_target: "input",
image_paste_target: "input",
action: "change->file-drop#handleFiles"
} %>
</label> </label>
<p class="pl-1">or drag and drop</p> <p class="pl-1">or drag and drop</p>
</div> </div>
<p class="text-xs text-gray-500">PNG, JPG, GIF, or SVG up to 2MB</p> <p class="text-xs text-gray-500">PNG, JPG, GIF, or SVG up to 2MB</p>
<p class="text-xs text-blue-600 font-medium mt-2">💡 Tip: Click here and press Ctrl+V (or Cmd+V) to paste an image from your clipboard</p>
</div> </div>
</div> </div>
<div data-file-drop-target="preview" class="mt-3 hidden"> <div data-file-drop-target="preview" class="mt-3 hidden">

View File

@@ -1,5 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Clinch module Clinch
VERSION = "0.6.1" VERSION = "0.6.3"
end end