diff options
author | Benjamin Neff <benjamin@coding4coffee.ch> | 2022-07-23 06:30:24 +0300 |
---|---|---|
committer | Benjamin Neff <benjamin@coding4coffee.ch> | 2022-07-23 17:59:41 +0300 |
commit | 01f8f55dbb86cb4d141e5ef8d87176b528f1f36b (patch) | |
tree | ed2a3d1c22d03864a7a1137765d001ff4bca4ea3 | |
parent | 49ba740b45c57e4ec745736c84226dc55b18d10b (diff) |
Add parsing of newer versions of NodeInfo
Always take the newest versions both nodes support
-rw-r--r-- | lib/connection_tester.rb | 25 | ||||
-rw-r--r-- | lib/node_info.rb | 2 | ||||
-rw-r--r-- | spec/lib/connection_tester_spec.rb | 53 |
3 files changed, 61 insertions, 19 deletions
diff --git a/lib/connection_tester.rb b/lib/connection_tester.rb index 0e38f10d9..5957b80d5 100644 --- a/lib/connection_tester.rb +++ b/lib/connection_tester.rb @@ -3,7 +3,6 @@ class ConnectionTester include Diaspora::Logging - NODEINFO_SCHEMA = "http://nodeinfo.diaspora.software/ns/schema/1.0" NODEINFO_FRAGMENT = "/.well-known/nodeinfo" class << self @@ -124,8 +123,11 @@ class ConnectionTester def nodeinfo with_http_connection do |http| ni_resp = http.get(NODEINFO_FRAGMENT) - nd_resp = http.get(find_nodeinfo_url(ni_resp.body)) - find_software_version(nd_resp.body) + ni_urls = find_nodeinfo_urls(ni_resp.body) + raise NodeInfoFailure, "No supported NodeInfo version found" if ni_urls.empty? + + version, url = ni_urls.max + find_software_version(version, http.get(url).body) end rescue Faraday::ClientError => e raise HTTPFailure, "#{e.class}: #{e.message}" @@ -180,20 +182,23 @@ class ConnectionTester @result.ssl = (response.env.url.scheme == "https") end - # walk the JSON document, get the actual document location - def find_nodeinfo_url(body) + # walk the JSON document, get the actual document locations + def find_nodeinfo_urls(body) jrd = JSON.parse(body) links = jrd.fetch("links") raise NodeInfoFailure, "invalid JRD: '#/links' is not an array!" unless links.is_a?(Array) - links.find { |entry| - entry.fetch("rel") == NODEINFO_SCHEMA - }.fetch("href") + + supported_rel_map = NodeInfo::VERSIONS.index_by {|v| "http://nodeinfo.diaspora.software/ns/schema/#{v}" } + links.map {|entry| + version = supported_rel_map[entry.fetch("rel")] + [version, entry.fetch("href")] if version + }.compact.to_h end # walk the JSON document, find the version string - def find_software_version(body) + def find_software_version(version, body) info = JSON.parse(body) - JSON::Validator.validate!(NodeInfo.schema("1.0"), info) + JSON::Validator.validate!(NodeInfo.schema(version), info) sw = info.fetch("software") @result.software_version = "#{sw.fetch('name')} #{sw.fetch('version')}" end diff --git a/lib/node_info.rb b/lib/node_info.rb index 6237daeca..05c96dcb1 100644 --- a/lib/node_info.rb +++ b/lib/node_info.rb @@ -6,7 +6,7 @@ require "json-schema" module NodeInfo VERSIONS = %w[1.0 2.0 2.1].freeze SCHEMAS = {} # rubocop:disable Style/MutableConstant - private_constant :VERSIONS, :SCHEMAS + private_constant :SCHEMAS Document = Struct.new(:version, :software, :protocols, :services, :open_registrations, :usage, :metadata) do # rubocop:disable Lint/ConstantDefinitionInBlock diff --git a/spec/lib/connection_tester_spec.rb b/spec/lib/connection_tester_spec.rb index 7a11cc0a3..671fec860 100644 --- a/spec/lib/connection_tester_spec.rb +++ b/spec/lib/connection_tester_spec.rb @@ -106,25 +106,61 @@ describe ConnectionTester do end describe "#nodeinfo" do - let(:ni_wellknown) { {links: [{rel: ConnectionTester::NODEINFO_SCHEMA, href: "/nodeinfo"}]} } - - it "reads the version from the nodeinfo document" do - ni_document = NodeInfo.build do |doc| - doc.version = "1.0" + def build_ni_document(version) + NodeInfo.build do |doc| + doc.version = version doc.open_registrations = true doc.protocols.protocols << "diaspora" doc.software.name = "diaspora" doc.software.version = "a.b.c.d" end + end + + NodeInfo::VERSIONS.each do |version| + context "with version #{version}" do + let(:ni_wellknown) { + {links: [{rel: "http://nodeinfo.diaspora.software/ns/schema/#{version}", href: "/nodeinfo/#{version}"}]} + } + + it "reads the version from the nodeinfo document" do + ni_document = build_ni_document(version) + + stub_request(:get, "#{url}#{ConnectionTester::NODEINFO_FRAGMENT}") + .to_return(status: 200, body: JSON.generate(ni_wellknown)) + stub_request(:get, "#{url}/nodeinfo/#{version}") + .to_return(status: 200, body: JSON.generate(ni_document.as_json)) + + tester.nodeinfo + expect(result.software_version).to eq("diaspora a.b.c.d") + end + end + end + + it "uses the latest commonly supported version" do + ni_wellknown = {links: [ + {rel: "http://nodeinfo.diaspora.software/ns/schema/1.0", href: "/nodeinfo/1.0"}, + {rel: "http://nodeinfo.diaspora.software/ns/schema/1.1", href: "/nodeinfo/1.1"}, + {rel: "http://nodeinfo.diaspora.software/ns/schema/2.0", href: "/nodeinfo/2.0"}, + {rel: "http://nodeinfo.diaspora.software/ns/schema/9.0", href: "/nodeinfo/9.0"} + ]} + + ni_document = build_ni_document("2.0") stub_request(:get, "#{url}#{ConnectionTester::NODEINFO_FRAGMENT}") .to_return(status: 200, body: JSON.generate(ni_wellknown)) - stub_request(:get, "#{url}/nodeinfo").to_return(status: 200, body: JSON.generate(ni_document.as_json)) + stub_request(:get, "#{url}/nodeinfo/2.0").to_return(status: 200, body: JSON.generate(ni_document.as_json)) tester.nodeinfo expect(result.software_version).to eq("diaspora a.b.c.d") end + it "handles no common version gracefully" do + ni_wellknown = {links: [{rel: "http://nodeinfo.diaspora.software/ns/schema/1.1", href: "/nodeinfo/1.1"}]} + stub_request(:get, "#{url}#{ConnectionTester::NODEINFO_FRAGMENT}") + .to_return(status: 200, body: JSON.generate(ni_wellknown)) + expect { tester.nodeinfo }.to raise_error(ConnectionTester::NodeInfoFailure) + end + it "fails the nodeinfo document is missing" do stub_request(:get, "#{url}#{ConnectionTester::NODEINFO_FRAGMENT}").to_return(status: 404, body: "Not Found") expect { tester.nodeinfo }.to raise_error(ConnectionTester::HTTPFailure) @@ -137,16 +173,17 @@ describe ConnectionTester do end it "handles a invalid jrd document gracefully" do - invalid_wellknown = {links: {rel: ConnectionTester::NODEINFO_SCHEMA, href: "/nodeinfo"}} + invalid_wellknown = {links: {rel: "http://nodeinfo.diaspora.software/ns/schema/1.0", href: "/nodeinfo/1.0"}} stub_request(:get, "#{url}#{ConnectionTester::NODEINFO_FRAGMENT}") .to_return(status: 200, body: JSON.generate(invalid_wellknown)) expect { tester.nodeinfo }.to raise_error(ConnectionTester::NodeInfoFailure) end it "handles a invalid nodeinfo document gracefully" do + ni_wellknown = {links: [{rel: "http://nodeinfo.diaspora.software/ns/schema/1.0", href: "/nodeinfo/1.0"}]} stub_request(:get, "#{url}#{ConnectionTester::NODEINFO_FRAGMENT}") .to_return(status: 200, body: JSON.generate(ni_wellknown)) - stub_request(:get, "#{url}/nodeinfo").to_return(status: 200, body: '{"software": "invalid nodeinfo"}') + stub_request(:get, "#{url}/nodeinfo/1.0").to_return(status: 200, body: '{"software": "invalid nodeinfo"}') expect { tester.nodeinfo }.to raise_error(ConnectionTester::NodeInfoFailure) end end |