Skip to content

Commit ea3175c

Browse files
committed
Allow enabling/disabling capabilities.
See mastodon/fediverse_auxiliary_service_provider_specifications#48 for context.
1 parent 3efc936 commit ea3175c

File tree

10 files changed

+173
-36
lines changed

10 files changed

+173
-36
lines changed

fasp_base/Gemfile.lock

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ GEM
9090
benchmark (0.4.0)
9191
bigdecimal (3.1.9)
9292
builder (3.3.0)
93-
concurrent-ruby (1.3.4)
94-
connection_pool (2.4.1)
93+
concurrent-ruby (1.3.5)
94+
connection_pool (2.5.0)
9595
crack (1.0.0)
9696
bigdecimal
9797
rexml
@@ -101,29 +101,30 @@ GEM
101101
irb (~> 1.10)
102102
reline (>= 0.3.8)
103103
drb (2.2.1)
104-
erubi (1.13.0)
104+
erubi (1.13.1)
105105
globalid (1.2.1)
106106
activesupport (>= 6.1)
107107
hashdiff (1.1.2)
108108
http-2 (1.0.2)
109109
httpx (1.4.0)
110110
http-2 (>= 1.0.0)
111-
i18n (1.14.6)
111+
i18n (1.14.7)
112112
concurrent-ruby (~> 1.0)
113113
io-console (0.8.0)
114-
irb (1.14.3)
114+
irb (1.15.1)
115+
pp (>= 0.6.0)
115116
rdoc (>= 4.0.0)
116117
reline (>= 0.4.2)
117-
json (2.9.1)
118-
language_server-protocol (3.17.0.3)
118+
json (2.10.1)
119+
language_server-protocol (3.17.0.4)
119120
linzer (0.6.2)
120121
openssl (~> 3.0, >= 3.0.0)
121122
rack (>= 2.2, < 4.0)
122123
starry (~> 0.2)
123124
stringio (~> 3.1, >= 3.1.2)
124125
uri (~> 1.0, >= 1.0.2)
125-
logger (1.6.4)
126-
loofah (2.23.1)
126+
logger (1.6.5)
127+
loofah (2.24.0)
127128
crass (~> 1.0.2)
128129
nokogiri (>= 1.12.0)
129130
mail (2.8.1)
@@ -133,50 +134,62 @@ GEM
133134
net-smtp
134135
marcel (1.0.4)
135136
mini_mime (1.1.5)
137+
mini_portile2 (2.8.8)
136138
minitest (5.25.4)
137-
net-imap (0.5.2)
139+
net-imap (0.5.6)
138140
date
139141
net-protocol
140142
net-pop (0.1.2)
141143
net-protocol
142144
net-protocol (0.2.2)
143145
timeout
144-
net-smtp (0.5.0)
146+
net-smtp (0.5.1)
145147
net-protocol
146148
nio4r (2.7.4)
147-
nokogiri (1.17.2-aarch64-linux)
149+
nokogiri (1.18.2)
150+
mini_portile2 (~> 2.8.2)
148151
racc (~> 1.4)
149-
nokogiri (1.17.2-arm-linux)
152+
nokogiri (1.18.2-aarch64-linux-gnu)
150153
racc (~> 1.4)
151-
nokogiri (1.17.2-arm64-darwin)
154+
nokogiri (1.18.2-aarch64-linux-musl)
152155
racc (~> 1.4)
153-
nokogiri (1.17.2-x86-linux)
156+
nokogiri (1.18.2-arm-linux-gnu)
154157
racc (~> 1.4)
155-
nokogiri (1.17.2-x86_64-darwin)
158+
nokogiri (1.18.2-arm-linux-musl)
156159
racc (~> 1.4)
157-
nokogiri (1.17.2-x86_64-linux)
160+
nokogiri (1.18.2-arm64-darwin)
161+
racc (~> 1.4)
162+
nokogiri (1.18.2-x86_64-darwin)
163+
racc (~> 1.4)
164+
nokogiri (1.18.2-x86_64-linux-gnu)
165+
racc (~> 1.4)
166+
nokogiri (1.18.2-x86_64-linux-musl)
158167
racc (~> 1.4)
159168
openssl (3.3.0)
160169
parallel (1.26.3)
161-
parser (3.3.6.0)
170+
parser (3.3.7.1)
162171
ast (~> 2.4.1)
163172
racc
173+
pp (0.6.2)
174+
prettyprint
175+
prettyprint (0.2.0)
164176
propshaft (1.1.0)
165177
actionpack (>= 7.0.0)
166178
activesupport (>= 7.0.0)
167179
rack
168180
railties (>= 7.0.0)
169-
psych (5.2.2)
181+
psych (5.2.3)
170182
date
171183
stringio
172184
public_suffix (6.0.1)
173185
puma (6.6.0)
174186
nio4r (~> 2.0)
175187
racc (1.8.1)
176-
rack (3.1.8)
177-
rack-session (2.0.0)
188+
rack (3.1.10)
189+
rack-session (2.1.0)
190+
base64 (>= 0.1.0)
178191
rack (>= 3.0.0)
179-
rack-test (2.1.0)
192+
rack-test (2.2.0)
180193
rack (>= 1.3)
181194
rackup (2.2.1)
182195
rack (>= 3)
@@ -211,31 +224,31 @@ GEM
211224
zeitwerk (~> 2.6)
212225
rainbow (3.1.1)
213226
rake (13.2.1)
214-
rdoc (6.10.0)
227+
rdoc (6.12.0)
215228
psych (>= 4.0.0)
216-
regexp_parser (2.9.3)
229+
regexp_parser (2.10.0)
217230
reline (0.6.0)
218231
io-console (~> 0.5)
219232
rexml (3.4.0)
220-
rubocop (1.69.2)
233+
rubocop (1.71.2)
221234
json (~> 2.3)
222235
language_server-protocol (>= 3.17.0)
223236
parallel (~> 1.10)
224237
parser (>= 3.3.0.2)
225238
rainbow (>= 2.2.2, < 4.0)
226239
regexp_parser (>= 2.9.3, < 3.0)
227-
rubocop-ast (>= 1.36.2, < 2.0)
240+
rubocop-ast (>= 1.38.0, < 2.0)
228241
ruby-progressbar (~> 1.7)
229242
unicode-display_width (>= 2.4.0, < 4.0)
230-
rubocop-ast (1.37.0)
243+
rubocop-ast (1.38.0)
231244
parser (>= 3.3.1.0)
232245
rubocop-minitest (0.36.0)
233246
rubocop (>= 1.61, < 2.0)
234247
rubocop-ast (>= 1.31.1, < 2.0)
235-
rubocop-performance (1.23.0)
248+
rubocop-performance (1.23.1)
236249
rubocop (>= 1.48.1, < 2.0)
237250
rubocop-ast (>= 1.31.1, < 2.0)
238-
rubocop-rails (2.27.0)
251+
rubocop-rails (2.29.1)
239252
activesupport (>= 4.2.0)
240253
rack (>= 1.1)
241254
rubocop (>= 1.52.0, < 2.0)
@@ -264,7 +277,7 @@ GEM
264277
timeout (0.4.3)
265278
tzinfo (2.0.6)
266279
concurrent-ruby (~> 1.0)
267-
unicode-display_width (3.1.2)
280+
unicode-display_width (3.1.4)
268281
unicode-emoji (~> 4.0, >= 4.0.4)
269282
unicode-emoji (4.0.4)
270283
uri (1.0.2)
@@ -273,7 +286,8 @@ GEM
273286
addressable (>= 2.8.0)
274287
crack (>= 0.3.2)
275288
hashdiff (>= 0.4.0, < 2.0.0)
276-
websocket-driver (0.7.6)
289+
websocket-driver (0.7.7)
290+
base64
277291
websocket-extensions (>= 0.1.0)
278292
websocket-extensions (0.1.5)
279293
zeitwerk (2.7.1)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
module FaspBase
2+
class Fasp::ActivationsController < ApplicationController
3+
include ApiAuthentication
4+
5+
def create
6+
current_server.enable_capability!(params[:capability_id], version: params[:version])
7+
8+
respond_to do |format|
9+
format.json { head :no_content }
10+
end
11+
rescue ArgumentError
12+
respond_to do |format|
13+
format.json { head :not_found }
14+
end
15+
end
16+
17+
def destroy
18+
current_server.disable_capability!(params[:capability_id], version: params[:version])
19+
20+
respond_to do |format|
21+
format.json { head :no_content }
22+
end
23+
end
24+
end
25+
end

fasp_base/app/models/fasp_base/server.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,25 @@ def url(path)
3030
"#{base}#{path}"
3131
end
3232

33+
def capability_enabled?(capability, version:)
34+
enabled_capabilities && enabled_capabilities.include?({ "id" => capability, "version" => version })
35+
end
36+
37+
def enable_capability!(capability, version:)
38+
raise ArgumentError, "unsupported capability" unless FaspBase.supports?(capability, version:)
39+
self.enabled_capabilities ||= []
40+
enabled_capabilities << { "id" => capability, "version" => version.to_i }
41+
enabled_capabilities.uniq!
42+
save!
43+
end
44+
45+
def disable_capability!(capability, version:)
46+
return if enabled_capabilities.blank?
47+
48+
enabled_capabilities.delete({ "id" => capability, "version" => version.to_i })
49+
save!
50+
end
51+
3352
private
3453

3554
def create_keypair

fasp_base/config/routes.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
FaspBase::Engine.routes.draw do
22
namespace :fasp do
3+
resources :capabilities, only: [] do
4+
resource :activation, path: "/:version/activation", only: [ :create, :destroy ]
5+
end
36
resource :provider_info, only: :show
47
end
58

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
class AddEnabledCapabilitiesToFaspBaseServers < ActiveRecord::Migration[8.0]
2+
def change
3+
add_column :fasp_base_servers, :enabled_capabilities, :json
4+
end
5+
end

fasp_base/lib/fasp_base.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,10 @@ def self.base_url
1818
protocol = Rails.env.production? ? "https" : "http"
1919
"#{protocol}://#{domain}/fasp"
2020
end
21+
22+
def self.supports?(capability, version:)
23+
capabilities.any? do |supported_capability|
24+
supported_capability[:id] == capability && supported_capability[:version].start_with?(version.to_s)
25+
end
26+
end
2127
end

fasp_base/lib/generators/fasp_base/install/templates/initializers/fasp_base.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
f.domain = ENV["DOMAIN"] || ActionController::Base.default_url_options[:host] || "localhost:3000"
77

88
# Add supported capabilities here:
9-
f.capabilities = [ ]
9+
f.capabilities = []
1010

1111
# Additional metadata
1212
# f.privacy_policy_url = ENV["PRIVACY_POLICY_URL"]

fasp_base/test/dummy/db/schema.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#
1111
# It's strongly recommended that you check this file into your version control system.
1212

13-
ActiveRecord::Schema[8.0].define(version: 2024_11_18_142403) do
13+
ActiveRecord::Schema[8.0].define(version: 2025_02_12_113456) do
1414
create_table "fasp_base_servers", force: :cascade do |t|
1515
t.string "base_url", null: false
1616
t.integer "user_id", null: false
@@ -20,6 +20,7 @@
2020
t.string "fasp_remote_id"
2121
t.string "public_key_pem"
2222
t.string "registration_completion_uri"
23+
t.json "enabled_capabilities"
2324
t.index [ "base_url" ], name: "index_fasp_base_servers_on_base_url", unique: true
2425
t.index [ "user_id" ], name: "index_fasp_base_servers_on_user_id"
2526
end
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
require "test_helper"
2+
3+
class ActivationTest < ActionDispatch::IntegrationTest
4+
include FaspBase::IntegrationTestHelper
5+
6+
setup do
7+
@server = fasp_base_servers(:mastodon_server)
8+
FaspBase.capabilities = [
9+
{ id: "test", version: "5.4" }
10+
]
11+
end
12+
13+
teardown do
14+
FaspBase.capabilities = []
15+
end
16+
17+
test "POST /fasp/capabilities/:name/:version/activation enables capability" do
18+
post fasp_base.fasp_capability_activation_path("test", version: "5"),
19+
as: :json,
20+
headers: request_authentication_headers(@server, :post, fasp_base.fasp_capability_activation_url("test", version: "5"), "")
21+
22+
assert_response :no_content
23+
assert @server.reload.capability_enabled?("test", version: 5)
24+
end
25+
26+
test "DELETE /fasp/capabilities/:name/:version/activation disables capability" do
27+
@server.enable_capability!("test", version: 5)
28+
29+
delete fasp_base.fasp_capability_activation_path("test", version: "5"),
30+
as: :json,
31+
headers: request_authentication_headers(@server, :delete, fasp_base.fasp_capability_activation_url("test", version: "5"), "")
32+
33+
assert_response :no_content
34+
assert_not @server.reload.capability_enabled?("test", version: 5)
35+
end
36+
end

fasp_base/test/models/fasp_base/server_test.rb

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,36 @@
22

33
module FaspBase
44
class ServerTest < ActiveSupport::TestCase
5-
# test "the truth" do
6-
# assert true
7-
# end
5+
setup do
6+
@server = fasp_base_servers(:mastodon_server)
7+
FaspBase.capabilities = [
8+
{ id: "test", version: "2.1" }
9+
]
10+
end
11+
12+
teardown do
13+
FaspBase.capabilities = []
14+
end
15+
16+
test "#enable_capability! enables a capability" do
17+
assert_not @server.capability_enabled?("test", version: 2)
18+
@server.enable_capability!("test", version: 2)
19+
20+
assert @server.capability_enabled?("test", version: 2)
21+
end
22+
23+
test "#enable_capability! raises if a capability is unknown/unsupported" do
24+
assert_raises ArgumentError do
25+
@server.enable_capability!("unknown", version: 4)
26+
end
27+
end
28+
29+
test "#disable_capability! disables a capability that was previously enabled" do
30+
@server.enable_capability!("test", version: 2)
31+
assert @server.capability_enabled?("test", version: 2)
32+
@server.disable_capability!("test", version: 2)
33+
34+
assert_not @server.capability_enabled?("test", version: "2")
35+
end
836
end
937
end

0 commit comments

Comments
 (0)