Implement NodeInfo

Closes #902
This commit is contained in:
Karina Kwiatek 2023-01-04 17:08:05 +01:00
parent 3105cb74b4
commit b35108e9d0
6 changed files with 171 additions and 2 deletions

View File

@ -88,6 +88,7 @@ group :development, :test do
gem "factory_bot_rails", require: false
gem "faker"
gem "haml_lint", require: false
gem "json-schema"
gem "letter_opener" # Use this just in local test environments
gem "rails-controller-testing"
gem "rake"

View File

@ -225,6 +225,8 @@ GEM
mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3)
json (2.6.3)
json-schema (3.0.0)
addressable (>= 2.8)
jwt (2.6.0)
kaminari (1.2.2)
activesupport (>= 4.1.0)
@ -567,6 +569,7 @@ DEPENDENCIES
hcaptcha (~> 7.0)
httparty
i18n-js (= 4.0)
json-schema
jwt (~> 2.6)
letter_opener
lograge

View File

@ -0,0 +1,58 @@
# frozen_string_literal: true
class WellKnown::NodeInfoController < ApplicationController
def discovery
expires_in 3.days, public: true
render json: {
links: [
rel: "http://nodeinfo.diaspora.software/ns/schema/2.1",
href: node_info_url
]
}
end
def nodeinfo
expires_in 30.minutes, public: true
render json: {
version: "2.1",
software: software_info,
protocols: %i[],
services: {
inbound: inbound_services,
outbound: outbound_services
},
usage: usage_stats,
# We don't implement this so we can always return true for now
openRegistrations: true,
metadata: {}
}
end
private
def software_info
{
name: "Retrospring",
version: Retrospring::Version.to_s,
repository: "https://github.com/Retrospring/retrospring"
}
end
def usage_stats
{
users: {
total: User.count
}
}
end
def inbound_services = []
def outbound_services
{
"twitter" => APP_CONFIG.dig("sharing", "twitter", "enabled")
}.select { |_service, available| available }.keys
end
end

View File

@ -56,7 +56,7 @@ features:
# OAuth tokens
sharing:
twitter:
enabled: true
enabled: false
# Get the tokens from https://apps.twitter.com
consumer_key: ''
consumer_secret: ''

View File

@ -172,7 +172,12 @@ Rails.application.routes.draw do
get "/feedback/bugs(/*any)", to: "feedback#bugs", as: "feedback_bugs"
get "/feedback/feature_requests(/*any)", to: "feedback#features", as: "feedback_features"
get "/.well-known/change-password", to: redirect("/settings/account")
namespace :well_known, path: "/.well-known" do
get "/change-password", to: redirect("/settings/account")
get "/nodeinfo", to: "node_info#discovery"
end
get "/nodeinfo/2.1", to: "well_known/node_info#nodeinfo", as: :node_info
puts "processing time of routes.rb: #{"#{(Time.zone.now - start).round(3).to_s.ljust(5, '0')}s".light_green}"
end

View File

@ -0,0 +1,102 @@
# frozen_string_literal: true
require "rails_helper"
describe WellKnown::NodeInfoController do
describe "#discovery" do
subject { get :discovery }
it "returns the expected response" do
subject
parsed = JSON.parse(response.body)
expect(parsed).to eq({
"links" => [
{
"rel" => "http://nodeinfo.diaspora.software/ns/schema/2.1",
"href" => "http://test.host/nodeinfo/2.1"
}
]
})
end
end
describe "#nodeinfo" do
subject { get :nodeinfo }
it "is valid as specified by the schema" do
get(:discovery)
schema = response.body
subject
parsed = JSON.parse(response.body)
messages = JSON::Validator.fully_validate(schema, parsed)
expect(messages).to be_empty
end
context "version is 2023.0120.1" do
before do
allow(Retrospring::Version).to receive(:to_s).and_return("2023.0102.1")
end
it "returns the correct version" do
subject
parsed = JSON.parse(response.body)
expect(parsed["software"]).to eq({
"name" => "Retrospring",
"version" => "2023.0102.1",
"repository" => "https://github.com/Retrospring/retrospring"
})
end
end
context "Twitter integration enabled" do
before do
stub_const("APP_CONFIG", {
"sharing" => {
"twitter" => {
"enabled" => true
}
}
})
end
it "includes Twitter in outbound services" do
subject
parsed = JSON.parse(response.body)
expect(parsed.dig("services", "outbound")).to include("twitter")
end
end
context "Twitter integration disabled" do
before do
stub_const("APP_CONFIG", {
"sharing" => {
"twitter" => {
"enabled" => false
}
}
})
end
it "includes Twitter in outbound services" do
subject
parsed = JSON.parse(response.body)
parsed.dig("services", "outbound").should_not include("twitter")
end
end
context "site has users" do
let(:num_users) { rand(10..50) }
before do
FactoryBot.create_list(:user, num_users)
end
it "includes the correct user count" do
subject
parsed = JSON.parse(response.body)
expect(parsed.dig("usage", "users", "total")).to eq(num_users)
end
end
end
end