0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-06 13:08:40 +08:00
discourse/spec/integration/api_keys_spec.rb
Penar Musaraj d01973f6ab
FIX: store method in route matcher (#41512)
This ensures that the parameters stored include the method, that way
there is no caching collision between different methods.
2026-07-07 11:49:56 -04:00

159 lines
5.4 KiB
Ruby
Vendored

# frozen_string_literal: true
RSpec.describe "api keys" do
let(:user) { Fabricate(:user) }
let(:api_key) { ApiKey.create!(user_id: user.id, created_by_id: Discourse.system_user) }
it "works in headers" do
get "/session/current.json", headers: { HTTP_API_KEY: api_key.key }
expect(response.status).to eq(200)
expect(response.parsed_body["current_user"]["username"]).to eq(user.username)
end
it "does not work in parameters" do
get "/session/current.json", params: { api_key: api_key.key }
expect(response.status).to eq(404)
end
it "does not allow overloaded requests to bypass granular API key scopes" do
global_setting :reject_anonymous_min_queue_seconds, 1.0
admin = Fabricate(:admin)
topic = Fabricate(:topic)
Fabricate(:post, topic: topic)
scoped_api_key =
Fabricate(
:api_key,
user: admin,
api_key_scopes: [Fabricate.build(:api_key_scope, resource: "topics", action: "read")],
)
put "/t/#{topic.id}.json",
params: {
title: "This is an unauthorized title change",
},
headers: {
HTTP_API_KEY: scoped_api_key.key,
HTTP_X_REQUEST_START: "t=0",
}
expect(response.status).to eq(503)
expect(response.body).to eq(
"Server is currently experiencing high load. Please try again later.",
)
expect(topic.reload.title).not_to eq("This is an unauthorized title change")
end
it "allows parameters on ics routes" do
get "/u/#{user.username}/bookmarks.ics?api_key=#{api_key.key}&api_username=#{user.username.downcase}"
expect(response.status).to eq(200)
# Confirm not for JSON
get "/u/#{user.username}/bookmarks.json?api_key=#{api_key.key}&api_username=#{user.username.downcase}"
expect(response.status).to eq(403)
end
it "allows parameters for handle mail" do
admin_api_key = ApiKey.create!(user: Fabricate(:admin), created_by_id: Discourse.system_user)
post "/admin/email/handle_mail.json?api_key=#{admin_api_key.key}", params: { email: "blah" }
expect(response.status).to eq(200)
end
it "allows parameters for rss feeds" do
SiteSetting.login_required = true
get "/latest.rss?api_key=#{api_key.key}&api_username=#{user.username.downcase}"
expect(response.status).to eq(200)
# Confirm not allowed for json
get "/latest.json?api_key=#{api_key.key}&api_username=#{user.username.downcase}"
expect(response.status).to eq(403)
end
context "with a plugin registered filter" do
before do
plugin = Plugin::Instance.new
plugin.add_api_parameter_route methods: [:get], actions: ["session#current"]
end
it "allows parameter access to the registered route" do
get "/session/current.json", params: { api_key: api_key.key }
expect(response.status).to eq(200)
end
end
end
RSpec.describe "user api keys" do
let(:user) { Fabricate(:user) }
let(:user_api_key) { Fabricate(:readonly_user_api_key, user: user) }
it "updates last used time on use" do
freeze_time
user_api_key.update_columns(last_used_at: 7.days.ago)
get "/session/current.json", headers: { HTTP_USER_API_KEY: user_api_key.key }
expect(user_api_key.reload.last_used_at).to eq_time(Time.zone.now)
end
it "allows parameters on ics routes" do
get "/u/#{user.username}/bookmarks.ics?user_api_key=#{user_api_key.key}"
expect(response.status).to eq(200)
# Confirm not for JSON
get "/u/#{user.username}/bookmarks.json?user_api_key=#{user_api_key.key}"
expect(response.status).to eq(403)
end
it "allows parameters for rss feeds" do
SiteSetting.login_required = true
get "/latest.rss?user_api_key=#{user_api_key.key}"
expect(response.status).to eq(200)
# Confirm not allowed for json
get "/latest.json?user_api_key=#{user_api_key.key}"
expect(response.status).to eq(403)
end
it "can restrict scopes by parameters" do
admin = Fabricate(:admin)
calendar_key = Fabricate(:bookmarks_calendar_user_api_key, user: admin)
get "/u/#{user.username}/bookmarks.json", headers: { HTTP_USER_API_KEY: calendar_key.key }
expect(response.status).to eq(403) # Does not allow json
get "/u/#{user.username}/bookmarks.ics", headers: { HTTP_USER_API_KEY: calendar_key.key }
expect(response.status).to eq(200) # Allows ICS
# Now restrict the key
calendar_key.scopes.first.update(allowed_parameters: { username: admin.username })
get "/u/#{user.username}/bookmarks.ics", headers: { HTTP_USER_API_KEY: calendar_key.key }
expect(response.status).to eq(403) # Cannot access another users calendar
get "/u/#{admin.username}/bookmarks.ics", headers: { HTTP_USER_API_KEY: calendar_key.key }
expect(response.status).to eq(200) # Can access own calendar
end
context "with a plugin registered user api key scope" do
let(:user_api_key) { Fabricate(:user_api_key) }
before do
metadata = Plugin::Metadata.new
metadata.name = "My Amazing Plugin"
plugin = Plugin::Instance.new metadata
plugin.add_user_api_key_scope :my_magic_scope, methods: :get, actions: "session#current"
user_api_key.scopes = [UserApiKeyScope.new(name: "my-amazing-plugin:my_magic_scope")]
user_api_key.save!
end
it "allows parameter access to the registered route" do
get "/session/current.json", headers: { HTTP_USER_API_KEY: user_api_key.key }
expect(response.status).to eq(200)
end
end
end