Compare commits

..
38 Commits
Author SHA1 Message Date
Stanko Krtalić 94692026d3 Merge pull request #122 from basecamp/unfurl-blind-ssrf
Security: disallow blind SSRF to link-local IPs via URL unfurling
2025-12-03 08:12:24 +01:00
Stanko K.R. 0672673916 Disallow SSRF via IPv6 addresses mapped to IPv4 addresses 2025-12-03 08:08:34 +01:00
Jeremy Daer 5667262d1c Security: disallow blind SSRF to link-local IPs via URL unfurling 2025-12-02 21:33:44 -08:00
Stanko Krtalić 1babf3f9ed Merge pull request #121 from basecamp/fix-crash-on-mentions-when-upgrading-from-rails-7-to-8
Parse Rails 7 GIDs
2025-12-02 11:37:51 +01:00
Stanko K.R. 4d04f9beee Use urlsafe base64 decode 2025-12-02 11:34:12 +01:00
Stanko K.R. bebe518c74 Parse Rails 7 GIDs 2025-12-02 11:06:23 +01:00
Stanko K.R. 13897eac59 Set title on new releases to be the version number 2025-12-02 08:36:15 +01:00
Stanko Krtalić 6bb0ee2436 Merge pull request #120 from basecamp/allow-restricting-new-room-creation-to-admins
Add new has_json to add Account#settings to restrict room creation to only administrators
2025-12-02 08:27:29 +01:00
Stanko K.R. 550d4c75bd Invert the icon color in dark mode 2025-12-02 08:22:32 +01:00
Jason Zimdars 7b7b3f8a67 Rework toggle as switch 2025-12-01 23:13:54 -06:00
Stanko K.R. aec8747710 Fix failing system tests
Something broke when the dependencies were updated so I copied over the Gemfile.lock file from main - which is known to work
2025-12-01 16:34:51 +01:00
Stanko K.R. 71b5edae01 Run migrations 2025-12-01 15:31:53 +01:00
Stanko K.R. b1325ccee7 Bump Redis 2025-12-01 15:31:07 +01:00
David Heinemeier Hansson 5266ffc049 Always just go through the settings object 2025-12-01 15:26:06 +01:00
David Heinemeier Hansson bd3b0c5988 Not needed 2025-12-01 15:26:06 +01:00
David Heinemeier Hansson e8626f9d5d Use rails edge that now includes the feature 2025-12-01 15:26:06 +01:00
David Heinemeier Hansson 796195c2cc Give up on the auto delegation to get a cleaner API 2025-12-01 15:26:06 +01:00
David Heinemeier Hansson 559629537b We don't need to specify the default any more 2025-12-01 15:26:06 +01:00
David Heinemeier Hansson 42c411b660 Use upstream version of has_json 2025-12-01 15:25:39 +01:00
David Heinemeier Hansson 6c59b8c82b Use public_send instead of send 2025-12-01 15:25:39 +01:00
David Heinemeier Hansson 20ba1cf2ae Ensure mutable string is used to prevent warning 2025-12-01 15:25:06 +01:00
David Heinemeier Hansson d323c3cfc0 Now required to be explicitly included
Not sure why
2025-12-01 15:23:57 +01:00
David Heinemeier Hansson 53671b48e0 Update to latest Rails 8.2.0 alpha 2025-12-01 15:23:23 +01:00
David Heinemeier Hansson 66b4e41281 Rename 2025-12-01 15:23:23 +01:00
David Heinemeier Hansson 6476bab4cc Use consistent yield naming 2025-12-01 15:23:23 +01:00
David Heinemeier Hansson f7c3aaa2a9 Allow for default values 2025-12-01 15:23:23 +01:00
David Heinemeier Hansson 593f8dd04c No need for self 2025-12-01 15:23:23 +01:00
David Heinemeier Hansson d3b6507ce2 Layer on top a more pleasant API for the default case 2025-12-01 15:23:23 +01:00
David Heinemeier Hansson 32be03a240 Rely on method missing 2025-12-01 15:23:23 +01:00
David Heinemeier Hansson 8e94a4aa1e Better wording 2025-12-01 15:23:23 +01:00
David Heinemeier Hansson 15db4033bc Enforce restriction to create new rooms 2025-12-01 15:22:37 +01:00
David Heinemeier Hansson f56e33e323 Fix fetching missing values 2025-12-01 15:22:36 +01:00
David Heinemeier Hansson bea2c89c2b Add new has_json to add Account#settings to restrict room creation to only administrators 2025-12-01 15:22:36 +01:00
Stanko Krtalić b7c7d99dcd Merge pull request #119 from basecamp/upgrade-to-rails-8.2.alpha
Upgrade to Rails 8.2.0.alpha
2025-12-01 13:59:28 +01:00
Stanko K.R. 6197f20a31 Upgrade to Rails 8.2.0.alpha 2025-12-01 13:50:53 +01:00
Stanko Krtalić 02023b0f0c Merge pull request #118 from basecamp/modernize-scripts
Create release first
2025-12-01 12:22:04 +01:00
Stanko K.R. af81a4c1ac Create release first 2025-12-01 12:21:08 +01:00
Stanko Krtalić d4a132865a Merge pull request #117 from basecamp/modernize-scripts
Modernize scripts
2025-12-01 12:01:13 +01:00
22 changed files with 250 additions and 105 deletions

No files matched your search

+3 -1
View File
@@ -4,9 +4,11 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
# Rails
gem "rails", github: "rails/rails", branch: "main"
gem "ostruct"
gem "benchmark"
# Drivers
gem "sqlite3", "~> 2.7"
gem "sqlite3"
gem "redis", "~> 5.4"
# Deployment
+85 -80
View File
@@ -26,32 +26,32 @@ GIT
GIT
remote: https://github.com/rails/rails.git
revision: 02660cd9e84aa57c6cf3bf6e08cc18e18292e2fa
revision: 1a02651ac37fb64b4de2a2b73461d86acf9c98fb
branch: main
specs:
actioncable (8.1.0.alpha)
actionpack (= 8.1.0.alpha)
activesupport (= 8.1.0.alpha)
actioncable (8.2.0.alpha)
actionpack (= 8.2.0.alpha)
activesupport (= 8.2.0.alpha)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
zeitwerk (~> 2.6)
actionmailbox (8.1.0.alpha)
actionpack (= 8.1.0.alpha)
activejob (= 8.1.0.alpha)
activerecord (= 8.1.0.alpha)
activestorage (= 8.1.0.alpha)
activesupport (= 8.1.0.alpha)
actionmailbox (8.2.0.alpha)
actionpack (= 8.2.0.alpha)
activejob (= 8.2.0.alpha)
activerecord (= 8.2.0.alpha)
activestorage (= 8.2.0.alpha)
activesupport (= 8.2.0.alpha)
mail (>= 2.8.0)
actionmailer (8.1.0.alpha)
actionpack (= 8.1.0.alpha)
actionview (= 8.1.0.alpha)
activejob (= 8.1.0.alpha)
activesupport (= 8.1.0.alpha)
actionmailer (8.2.0.alpha)
actionpack (= 8.2.0.alpha)
actionview (= 8.2.0.alpha)
activejob (= 8.2.0.alpha)
activesupport (= 8.2.0.alpha)
mail (>= 2.8.0)
rails-dom-testing (~> 2.2)
actionpack (8.1.0.alpha)
actionview (= 8.1.0.alpha)
activesupport (= 8.1.0.alpha)
actionpack (8.2.0.alpha)
actionview (= 8.2.0.alpha)
activesupport (= 8.2.0.alpha)
nokogiri (>= 1.8.5)
rack (>= 2.2.4)
rack-session (>= 1.0.1)
@@ -59,65 +59,65 @@ GIT
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
useragent (~> 0.16)
actiontext (8.1.0.alpha)
actiontext (8.2.0.alpha)
action_text-trix (~> 2.1.15)
actionpack (= 8.1.0.alpha)
activerecord (= 8.1.0.alpha)
activestorage (= 8.1.0.alpha)
activesupport (= 8.1.0.alpha)
actionpack (= 8.2.0.alpha)
activerecord (= 8.2.0.alpha)
activestorage (= 8.2.0.alpha)
activesupport (= 8.2.0.alpha)
globalid (>= 0.6.0)
nokogiri (>= 1.8.5)
actionview (8.1.0.alpha)
activesupport (= 8.1.0.alpha)
actionview (8.2.0.alpha)
activesupport (= 8.2.0.alpha)
builder (~> 3.1)
erubi (~> 1.11)
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
activejob (8.1.0.alpha)
activesupport (= 8.1.0.alpha)
activejob (8.2.0.alpha)
activesupport (= 8.2.0.alpha)
globalid (>= 0.3.6)
activemodel (8.1.0.alpha)
activesupport (= 8.1.0.alpha)
activerecord (8.1.0.alpha)
activemodel (= 8.1.0.alpha)
activesupport (= 8.1.0.alpha)
activemodel (8.2.0.alpha)
activesupport (= 8.2.0.alpha)
activerecord (8.2.0.alpha)
activemodel (= 8.2.0.alpha)
activesupport (= 8.2.0.alpha)
timeout (>= 0.4.0)
activestorage (8.1.0.alpha)
actionpack (= 8.1.0.alpha)
activejob (= 8.1.0.alpha)
activerecord (= 8.1.0.alpha)
activesupport (= 8.1.0.alpha)
activestorage (8.2.0.alpha)
actionpack (= 8.2.0.alpha)
activejob (= 8.2.0.alpha)
activerecord (= 8.2.0.alpha)
activesupport (= 8.2.0.alpha)
marcel (~> 1.0)
activesupport (8.1.0.alpha)
activesupport (8.2.0.alpha)
base64
benchmark (>= 0.3)
bigdecimal
concurrent-ruby (~> 1.0, >= 1.3.1)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2)
json
logger (>= 1.4.2)
minitest (>= 5.1)
securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5)
uri (>= 0.13.1)
rails (8.1.0.alpha)
actioncable (= 8.1.0.alpha)
actionmailbox (= 8.1.0.alpha)
actionmailer (= 8.1.0.alpha)
actionpack (= 8.1.0.alpha)
actiontext (= 8.1.0.alpha)
actionview (= 8.1.0.alpha)
activejob (= 8.1.0.alpha)
activemodel (= 8.1.0.alpha)
activerecord (= 8.1.0.alpha)
activestorage (= 8.1.0.alpha)
activesupport (= 8.1.0.alpha)
rails (8.2.0.alpha)
actioncable (= 8.2.0.alpha)
actionmailbox (= 8.2.0.alpha)
actionmailer (= 8.2.0.alpha)
actionpack (= 8.2.0.alpha)
actiontext (= 8.2.0.alpha)
actionview (= 8.2.0.alpha)
activejob (= 8.2.0.alpha)
activemodel (= 8.2.0.alpha)
activerecord (= 8.2.0.alpha)
activestorage (= 8.2.0.alpha)
activesupport (= 8.2.0.alpha)
bundler (>= 1.15.0)
railties (= 8.1.0.alpha)
railties (8.1.0.alpha)
actionpack (= 8.1.0.alpha)
activesupport (= 8.1.0.alpha)
railties (= 8.2.0.alpha)
railties (8.2.0.alpha)
actionpack (= 8.2.0.alpha)
activesupport (= 8.2.0.alpha)
irb (~> 1.13)
rackup (>= 1.0.0)
rake (>= 12.2)
@@ -135,8 +135,8 @@ GEM
ast (2.4.3)
base64 (0.3.0)
bcrypt (3.1.20)
benchmark (0.4.1)
bigdecimal (3.2.2)
benchmark (0.5.0)
bigdecimal (3.3.1)
brakeman (7.1.1)
racc
builder (3.3.0)
@@ -151,17 +151,17 @@ GEM
xpath (~> 3.2)
chunky_png (1.4.0)
concurrent-ruby (1.3.5)
connection_pool (2.5.3)
connection_pool (2.5.5)
crack (1.0.0)
bigdecimal
rexml
crass (1.0.6)
date (3.4.1)
date (3.5.0)
debug (1.11.0)
irb (~> 1.10)
reline (>= 0.3.8)
drb (2.2.3)
erb (5.0.2)
erb (6.0.0)
erubi (1.13.1)
faker (3.5.2)
i18n (>= 1.8.11, < 2)
@@ -172,7 +172,7 @@ GEM
geared_pagination (1.2.0)
activesupport (>= 5.0)
addressable (>= 2.5.0)
globalid (1.2.1)
globalid (1.3.0)
activesupport (>= 6.1)
hashdiff (1.2.0)
i18n (1.14.7)
@@ -181,7 +181,7 @@ GEM
mini_magick (>= 4.9.5, < 6)
ruby-vips (>= 2.0.17, < 3)
io-console (0.8.1)
irb (1.15.2)
irb (1.15.3)
pp (>= 0.6.0)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
@@ -201,17 +201,18 @@ GEM
loofah (2.24.1)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
mail (2.8.1)
mail (2.9.0)
logger
mini_mime (>= 0.1.1)
net-imap
net-pop
net-smtp
marcel (1.0.4)
marcel (1.1.0)
matrix (0.4.3)
mini_magick (5.3.1)
logger
mini_mime (1.1.5)
minitest (5.25.5)
minitest (5.26.2)
mocha (2.7.1)
ruby2_keywords (>= 0.0.5)
mono_logger (1.1.2)
@@ -220,7 +221,7 @@ GEM
ruby2_keywords (~> 0.0.1)
net-http-persistent (4.0.6)
connection_pool (~> 2.2, >= 2.2.4)
net-imap (0.5.9)
net-imap (0.5.12)
date
net-protocol
net-pop (0.1.2)
@@ -229,16 +230,17 @@ GEM
timeout
net-smtp (0.5.1)
net-protocol
nio4r (2.7.4)
nokogiri (1.18.9-aarch64-linux-gnu)
nio4r (2.7.5)
nokogiri (1.18.10-aarch64-linux-gnu)
racc (~> 1.4)
nokogiri (1.18.9-arm64-darwin)
nokogiri (1.18.10-arm64-darwin)
racc (~> 1.4)
nokogiri (1.18.9-x86_64-darwin)
nokogiri (1.18.10-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.18.9-x86_64-linux-gnu)
nokogiri (1.18.10-x86_64-linux-gnu)
racc (~> 1.4)
openssl (3.3.0)
ostruct (0.6.3)
parallel (1.27.0)
parser (3.3.9.0)
ast (~> 2.4.1)
@@ -246,7 +248,7 @@ GEM
platform_agent (1.0.1)
activesupport (>= 5.2.0)
useragent (~> 0.16.3)
pp (0.6.2)
pp (0.6.3)
prettyprint
prettyprint (0.2.0)
prism (1.4.0)
@@ -257,7 +259,7 @@ GEM
puma (6.6.1)
nio4r (~> 2.0)
racc (1.8.1)
rack (3.2.0)
rack (3.2.4)
rack-protection (4.1.1)
base64 (>= 0.1.0)
logger (>= 1.6.0)
@@ -281,10 +283,11 @@ GEM
activesupport (> 3.1)
railties (> 3.1)
rainbow (3.1.1)
rake (13.3.0)
rdoc (6.14.2)
rake (13.3.1)
rdoc (6.16.1)
erb
psych (>= 4.0.0)
tsort
redis (5.4.1)
redis-client (>= 0.22.0)
redis-client (0.25.2)
@@ -292,7 +295,7 @@ GEM
redis-namespace (1.11.0)
redis (>= 4)
regexp_parser (2.11.2)
reline (0.6.2)
reline (0.6.3)
io-console (~> 0.5)
resque (2.7.0)
mono_logger (~> 1)
@@ -367,21 +370,21 @@ GEM
sqlite3 (2.7.3-x86_64-linux-gnu)
stimulus-rails (1.3.4)
railties (>= 6.0.0)
stringio (3.1.7)
stringio (3.1.8)
thor (1.4.0)
thruster (0.1.15-aarch64-linux)
thruster (0.1.15-arm64-darwin)
thruster (0.1.15-x86_64-darwin)
thruster (0.1.15-x86_64-linux)
tilt (2.6.1)
timeout (0.4.3)
timeout (0.4.4)
tsort (0.2.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (3.1.5)
unicode-emoji (~> 4.0, >= 4.0.4)
unicode-emoji (4.0.4)
uri (1.0.3)
uri (1.1.1)
useragent (0.16.11)
web-push (3.0.2)
jwt (~> 3.0)
@@ -407,6 +410,7 @@ PLATFORMS
DEPENDENCIES
bcrypt
benchmark
brakeman
capybara
debug
@@ -418,6 +422,7 @@ DEPENDENCIES
kredis
mocha
net-http-persistent
ostruct
platform_agent
propshaft!
puma (~> 6.6)
@@ -431,7 +436,7 @@ DEPENDENCIES
selenium-webdriver
sentry-rails
sentry-ruby
sqlite3 (~> 2.7)
sqlite3
stimulus-rails
thruster
turbo-rails!
+1 -1
View File
@@ -17,7 +17,7 @@ class AccountsController < ApplicationController
end
def account_params
params.require(:account).permit(:name, :logo)
params.require(:account).permit(:name, :logo, settings: {})
end
def account_users
@@ -3,6 +3,7 @@ class Rooms::ClosedsController < RoomsController
before_action :ensure_can_administer, only: %i[ update ]
before_action :remember_last_room_visited, only: :show
before_action :force_room_type, only: %i[ edit update ]
before_action :ensure_permission_to_create_rooms, only: %i[ new create ]
DEFAULT_ROOM_NAME = "New room"
@@ -3,6 +3,7 @@ class Rooms::OpensController < RoomsController
before_action :ensure_can_administer, only: %i[ update ]
before_action :remember_last_room_visited, only: :show
before_action :force_room_type, only: %i[ edit update ]
before_action :ensure_permission_to_create_rooms, only: %i[ new create ]
DEFAULT_ROOM_NAME = "New room"
+6
View File
@@ -31,6 +31,12 @@ class RoomsController < ApplicationController
head :forbidden unless Current.user.can_administer?(@room)
end
def ensure_permission_to_create_rooms
if Current.account.settings.restrict_room_creation_to_administrators? && !Current.user.administrator?
head :forbidden
end
end
def find_messages
messages = @room.messages.with_creator.with_attachment_details.with_boosts
+1
View File
@@ -2,4 +2,5 @@ class Account < ApplicationRecord
include Joinable
has_one_attached :logo
has_json :settings, restrict_room_creation_to_administrators: false
end
+1 -1
View File
@@ -53,7 +53,7 @@ class Webhook < ApplicationRecord
end
def extract_text_from(response)
response.body.dup.force_encoding("UTF-8") if response.code == "200" && response.content_type.in?(%w[ text/html text/plain ])
String.new(response.body).force_encoding("UTF-8") if response.code == "200" && response.content_type.in?(%w[ text/html text/plain ])
end
def receive_text_reply_to(room, text:)
+24
View File
@@ -64,6 +64,30 @@
<% end %>
</div>
<% end %>
<div class="margin-block-start pad-block pad-inline-double fill-shade border-radius">
<%= form_with model: @account, method: :put, data: { controller: "form" }, class: "flex align-center gap center" do |form| %>
<div class="flex-item-grow flex align-center gap txt-align-start">
<%= image_tag "crown.svg", class: "colorize--black", aria: { hidden: "true" }, size: 18 %> Must be admin to create new rooms
</div>
<%= form.fields_for :settings, @account.settings do |settings_form| %>
<%= settings_form.hidden_field :restrict_room_creation_to_administrators,
value: !Current.account.settings.restrict_room_creation_to_administrators? %>
<% end %>
<label class="switch">
<input type="checkbox"
class="switch__input"
<%= "checked" if Current.account.settings.restrict_room_creation_to_administrators? %>
data-action="change->form#submit">
<span class="switch__btn round"></span>
<span class="for-screen-reader">
Must be admin to create new rooms
</span>
</label>
<% end %>
</div>
<% else %>
<%= account_logo_tag style: "txt-xx-large center" %>
<h1 class="flex-item-grow txt-x-large"><%= @account.name %></h1>
+4 -2
View File
@@ -36,8 +36,10 @@
<% end %>
</div>
<%= link_to new_rooms_open_path, class: "rooms__new-btn btn room align-center gap txt-reversed", aria: { label: "New Chat Room" } do %>
<%= image_tag "add.svg", size: 20, aria: { hidden: "true" }, style: "view-transition-name: new-room" %>
<% if Current.user.administrator? || !Current.account.settings.restrict_room_creation_to_administrators? %>
<%= link_to new_rooms_open_path, class: "rooms__new-btn btn room align-center gap txt-reversed", aria: { label: "New Chat Room" } do %>
<%= image_tag "add.svg", size: 20, aria: { hidden: "true" }, style: "view-transition-name: new-room" %>
<% end %>
<% end %>
</div>
+11 -14
View File
@@ -45,23 +45,20 @@ on(:local) do
end
end
announcing "Tagging as #{VERSION}" do
on(:local) do
execute :git, :fetch, :origin, "--tags"
announcing "Creating GitHub release v#{VERSION}..." do
notes_file = "tmp/release_notes.md"
unless system "git tag -a v#{VERSION} -m 'Version #{VERSION}\n\n- list important changes here' -e"
abort "Failed to create tag; check that the version doesn't already exist"
on(:local) do
execute :mkdir, "-p", "tmp"
File.write(notes_file, "# What's Changed\n\n- \n")
system ENV["EDITOR"] || "vim", notes_file
unless system "gh", "release", "create", "v#{VERSION}", "--title", "v#{VERSION}", "--notes-file", notes_file
abort "Failed to create release; check that the version doesn't already exist"
end
unless test :git, :push, "--tags"
abort "Failed to push tag; check that the version doesn't already exist"
end
end
end
announcing "Creating GitHub release..." do
on(:local) do
execute :gh, :release, :create, "v#{VERSION}", "--notes-from-tag"
execute :rm, notes_file
end
end
+1 -1
View File
@@ -7,7 +7,7 @@ Bundler.require(*Rails.groups)
module Campfire
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 8.1
config.load_defaults 8.2
# Please, add to the `ignore` list any other `lib` subdirectories that do
# not contain `.rb` files, or that should not be reloaded or eager loaded.
@@ -0,0 +1,5 @@
class AddAccountSettings < ActiveRecord::Migration[7.2]
def change
add_column :accounts, :settings, :json
end
end
Generated
+2 -1
View File
@@ -10,12 +10,13 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[8.1].define(version: 2025_11_26_115722) do
ActiveRecord::Schema[8.2].define(version: 2025_11_26_130131) do
create_table "accounts", force: :cascade do |t|
t.datetime "created_at", null: false
t.text "custom_styles"
t.string "join_code", null: false
t.string "name", null: false
t.json "settings"
t.datetime "updated_at", null: false
end
+8 -3
View File
@@ -16,13 +16,18 @@ ActiveSupport.on_load(:action_text_content) do
decoded_gid = if data = encoded_message.dig("_rails", "data")
data
elsif data = encoded_message.dig("_rails", "message")
# Rails 7 used an older format of GID that serialized the payload using Marshall
# Since we intentionally skip signature verification, we can't safely unmarshal the data
# To work around this, we manually extract the GID from the marshaled data
Base64.urlsafe_decode64(data).match(%r{(gid://campfire/[^/]+/\d+)})&.to_s
else
nil
end
model = GlobalID.find(decoded_gid)
model.model_name.to_s.in?(ATTACHABLES_PERMITTED_WITH_INVALID_SIGNATURES) ? model : nil
if model = GlobalID.find(decoded_gid)
model.model_name.to_s.in?(ATTACHABLES_PERMITTED_WITH_INVALID_SIGNATURES) ? model : nil
end
end
rescue ActiveRecord::RecordNotFound
nil
+1 -1
View File
@@ -16,7 +16,7 @@ module RestrictedHTTP
def private_ip?(ip)
IPAddr.new(ip).then do |ipaddr|
ipaddr.private? || ipaddr.loopback? || LOCAL_IP.include?(ipaddr)
ipaddr.private? || ipaddr.loopback? || ipaddr.link_local? || ipaddr.ipv4_mapped? || LOCAL_IP.include?(ipaddr)
end
rescue IPAddr::InvalidAddressError
true
@@ -29,6 +29,16 @@ class Rooms::ClosedsControllerTest < ActionDispatch::IntegrationTest
assert_redirected_to room_url(Room.last)
end
test "create forbidden by non-admin when account restricts creation to admins" do
accounts(:signal).settings.restrict_room_creation_to_administrators = true
accounts(:signal).save!
sign_in :jz
post rooms_closeds_url, params: { room: { name: "My New Room" }, user_ids: [ users(:david).id, users(:kevin).id, users(:jason).id ] }
assert_response :forbidden
end
test "update with membership revisions" do
assert_difference -> { rooms(:designers).reload.users.count }, -1 do
put rooms_closed_url(rooms(:designers)), params: {
@@ -24,6 +24,15 @@ class Rooms::OpensControllerTest < ActionDispatch::IntegrationTest
assert_redirected_to room_url(Room.last)
end
test "create forbidden by non-admin when account restricts creation to admins" do
accounts(:signal).settings.restrict_room_creation_to_administrators = true
accounts(:signal).save!
sign_in :jz
post rooms_opens_url, params: { room: { name: "My New Room" } }
assert_response :forbidden
end
test "only admins or creators can update" do
sign_in :jz
@@ -0,0 +1,39 @@
require "test_helper"
class ActionText::AttachmentTest < ActiveSupport::TestCase
setup do
@user = users(:david)
end
test "from_node" do
html = %Q(<action-text-attachment sgid="#{@user.attachable_sgid}"></action-text-attachment>)
node = ActionText::Fragment.wrap(html).find_all(ActionText::Attachment.tag_name).first
attachment = ActionText::Attachment.from_node(node)
assert_equal @user, attachment.attachable
end
test "from_node with a Rails 7 SGID" do
gid = @user.to_gid.to_s
marshaled_gid = Base64.urlsafe_encode64(Marshal.dump(gid))
rails7_payload = { "_rails" => { "message" => marshaled_gid, "exp" => nil, "pur" => "attachable" } }
rails7_message = Base64.strict_encode64(JSON.generate(rails7_payload))
rails7_sgid = "#{rails7_message}--invalidsignature"
html = %Q(<action-text-attachment sgid="#{rails7_sgid}"></action-text-attachment>)
node = ActionText::Fragment.wrap(html).find_all(ActionText::Attachment.tag_name).first
attachment = ActionText::Attachment.from_node(node)
assert_equal @user, attachment.attachable
end
test "from_node with an invalid SGID" do
room = rooms(:pets).tap { |r| r.extend ActionText::Attachable }
html = %Q(<action-text-attachment sgid="#{room.attachable_sgid}invalid"></action-text-attachment>)
node = ActionText::Fragment.wrap(html).find_all(ActionText::Attachment.tag_name).first
attachment = ActionText::Attachment.from_node(node)
assert_kind_of ActionText::Attachables::MissingAttachable, attachment.attachable
end
end
+14
View File
@@ -1,4 +1,18 @@
require "test_helper"
class AccountTest < ActiveSupport::TestCase
test "settings" do
accounts(:signal).settings.restrict_room_creation_to_administrators = true
assert accounts(:signal).settings.restrict_room_creation_to_administrators?
assert_equal({ "restrict_room_creation_to_administrators" => true }, accounts(:signal)[:settings])
accounts(:signal).update!(settings: { "restrict_room_creation_to_administrators" => "true" })
assert accounts(:signal).reload.settings.restrict_room_creation_to_administrators?
accounts(:signal).settings.restrict_room_creation_to_administrators = false
assert_not accounts(:signal).settings.restrict_room_creation_to_administrators?
assert_equal({ "restrict_room_creation_to_administrators" => false }, accounts(:signal)[:settings])
accounts(:signal).update!(settings: { "restrict_room_creation_to_administrators" => "false" })
assert_not accounts(:signal).reload.settings.restrict_room_creation_to_administrators?
end
end
+22
View File
@@ -21,6 +21,28 @@ class Opengraph::LocationTest < ActiveSupport::TestCase
assert_equal [ "is not public" ], location.errors[:url]
end
test "link-local addresses are blocked" do
Resolv.stubs(:getaddress).with("metadata.internal").returns("169.254.169.254")
location = Opengraph::Location.new("https://metadata.internal")
assert_not location.valid?
assert_equal [ "is not public" ], location.errors[:url]
end
test "IPv6 addresses mapped to IPv4 addresses are blocked" do
Resolv.stubs(:getaddress).with("metadata.internal").returns("::ffff:192.168.1.1")
location = Opengraph::Location.new("https://metadata.internal")
assert_not location.valid?
assert_equal [ "is not public" ], location.errors[:url]
Resolv.stubs(:getaddress).with("metadata.internal").returns("::ffff:c0a8:0101")
location = Opengraph::Location.new("https://metadata.internal")
assert_not location.valid?
assert_equal [ "is not public" ], location.errors[:url]
end
test "avoid reading file urls when expecting HTML" do
large_file = Opengraph::Location.new("https://www.example.com/100gb.zip")
+1
View File
@@ -5,6 +5,7 @@ require "rails/test_help"
require "minitest/unit"
require "mocha/minitest"
require "webmock/minitest"
require "turbo/broadcastable/test_helper"
WebMock.enable!