webfinger-1.0.2/ 0000755 0001756 0001757 00000000000 12736020316 012523 5 ustar pravi pravi webfinger-1.0.2/spec/ 0000755 0001756 0001757 00000000000 12736020316 013455 5 ustar pravi pravi webfinger-1.0.2/spec/spec_helper.rb 0000644 0001756 0001757 00000000406 12736020316 016273 0 ustar pravi pravi require 'simplecov'
SimpleCov.start do
add_filter 'spec'
end
require 'rspec'
require 'rspec/its'
require 'webfinger'
RSpec.configure do |config|
config.expect_with :rspec do |c|
c.syntax = [:should, :expect]
end
end
require 'helpers/webmock_helper' webfinger-1.0.2/spec/webfinger/ 0000755 0001756 0001757 00000000000 12736020316 015425 5 ustar pravi pravi webfinger-1.0.2/spec/webfinger/response_spec.rb 0000644 0001756 0001757 00000002057 12736020316 020626 0 ustar pravi pravi require 'spec_helper'
describe WebFinger::Response do
let(:_subject_) { 'acct:nov@matake.jp' }
let(:aliases) { ['mailto:nov@matake.jp'] }
let(:properties) do
{'http://webfinger.net/rel/name' => 'Nov Matake'}
end
let(:links) do
[{
rel: 'http://openid.net/specs/connect/1.0/issuer',
href: 'https://openid.example.com/'
}.with_indifferent_access]
end
let(:attributes) do
{
subject: _subject_,
aliases: aliases,
properties: properties,
links: links
}.with_indifferent_access
end
subject do
WebFinger::Response.new attributes
end
its(:subject) { should == _subject_ }
its(:aliases) { should == aliases }
its(:properties) { should == properties }
its(:links) { should == links }
describe '#link_for' do
context 'when unknown' do
it do
subject.link_for('unknown').should be_nil
end
end
context 'otherwise' do
it do
subject.link_for('http://openid.net/specs/connect/1.0/issuer').should == links.first
end
end
end
end webfinger-1.0.2/spec/webfinger/debugger/ 0000755 0001756 0001757 00000000000 12736020316 017211 5 ustar pravi pravi webfinger-1.0.2/spec/webfinger/debugger/request_filter_spec.rb 0000644 0001756 0001757 00000001724 12736020316 023611 0 ustar pravi pravi require 'spec_helper'
describe WebFinger::Debugger::RequestFilter do
let(:resource_endpoint) { 'https://example.com/resources' }
let(:request) { HTTP::Message.new_request(:get, URI.parse(resource_endpoint)) }
let(:response) { HTTP::Message.new_response({:hello => 'world'}.to_json) }
let(:request_filter) { WebFinger::Debugger::RequestFilter.new }
describe '#filter_request' do
it 'should log request' do
expect(WebFinger.logger).to receive(:info).with(
"======= [WebFinger] HTTP REQUEST STARTED =======\n" +
request.dump
)
request_filter.filter_request(request)
end
end
describe '#filter_response' do
it 'should log response' do
expect(WebFinger.logger).to receive(:info).with(
"--------------------------------------------------\n" +
response.dump +
"\n======= [WebFinger] HTTP REQUEST FINISHED ======="
)
request_filter.filter_response(request, response)
end
end
end webfinger-1.0.2/spec/helpers/ 0000755 0001756 0001757 00000000000 12736020316 015117 5 ustar pravi pravi webfinger-1.0.2/spec/helpers/webmock_helper.rb 0000644 0001756 0001757 00000001517 12736020316 020436 0 ustar pravi pravi require 'webmock/rspec'
module WebMockHelper
def mock_json(endpoint, response_file, options = {})
endpoint = endpoint.to_s
stub_request(:get, endpoint).with(
request_for(options)
).to_return(
response_for(response_file, options)
)
yield
a_request(:get, endpoint).with(
request_for(options)
).should have_been_made.once
end
private
def request_for(options = {})
request = {}
if options[:query]
request[:query] = options[:query]
end
request
end
def response_for(response_file, options = {})
response = {}
response[:body] = File.new(File.join(File.dirname(__FILE__), '../mock_json', "#{response_file}.json"))
if options[:status]
response[:status] = options[:status]
end
response
end
end
include WebMockHelper
WebMock.disable_net_connect! webfinger-1.0.2/spec/mock_json/ 0000755 0001756 0001757 00000000000 12736020316 015437 5 ustar pravi pravi webfinger-1.0.2/spec/mock_json/device_info.json 0000644 0001756 0001757 00000000217 12736020316 020604 0 ustar pravi pravi {
"subject": "device:p1.example.com",
"links": [{
"rel": "http://example.com/rel/tipsi",
"href": "http://192.168.1.5/npap/"
}]
}
webfinger-1.0.2/spec/mock_json/all.json 0000644 0001756 0001757 00000001253 12736020316 017103 0 ustar pravi pravi {
"expires": "2012-11-16T19:41:35Z",
"subject": "acct:nov@example.com",
"aliases": ["http://nov.example.com/"],
"properties": {
"http://example.com/rel/role/": "employee"
},
"links": [{
"rel": "http://webfinger.net/rel/avatar",
"type": "image/jpeg",
"href": "http://nov.example.com/profile_picture.png"
}, {
"rel": "http://webfinger.net/rel/profile-page",
"href": "http://nov.example.com/"
}, {
"rel": "blog",
"type": "text/html",
"href": "http://blogs.nov.example.com/",
"titles": {
"en-us": "Nov's Blog",
"ja": "Novのブログ"
}
}, {
"rel": "vcard",
"href": "http://nov.example.com/me.vcf"
}]
}
webfinger-1.0.2/spec/mock_json/open_id.json 0000644 0001756 0001757 00000000464 12736020316 017753 0 ustar pravi pravi {
"expires": "2012-11-16T19:41:35Z",
"subject": "acct:nov@example.com",
"aliases": ["http://nov.example.com/"],
"properties": {
"http://example.com/rel/role/": "employee"
},
"links": [{
"rel": "http://openid.net/specs/connect/1.0/issuer",
"href": "https://openid.example.com/"
}]
}
webfinger-1.0.2/spec/mock_json/email_config.json 0000644 0001756 0001757 00000001116 12736020316 020745 0 ustar pravi pravi {
"subject": "mailto:nov@example.com",
"links": [{
"rel": "http://example.net/rel/smtp-server",
"properties": {
"http://example.net/email/host": "smtp.example.com",
"http://example.net/email/port": "587",
"http://example.net/email/login-required": "yes",
"http://example.net/email/transport": "starttls"
}
}, {
"rel": "http://example.net/rel/imap-server",
"properties": {
"http://example.net/email/host": "imap.example.com",
"http://example.net/email/port": "993",
"http://example.net/email/transport": "ssl"
}
}]
}
webfinger-1.0.2/spec/webfinger_spec.rb 0000644 0001756 0001757 00000014667 12736020316 017002 0 ustar pravi pravi require 'spec_helper'
describe WebFinger do
let(:resource) { 'acct:nov@example.com' }
describe '#discover!' do
{
'example.com' => 'https://example.com',
'example.com/~nov/' => 'https://example.com',
'nov@example.com' => 'https://example.com',
'nov.matake@example.com' => 'https://example.com',
'acct:nov@example.com' => 'https://example.com',
'mailto:nov@example.com' => 'https://example.com',
'device:example.com' => 'https://example.com',
'unknown:nov@example.com' => 'https://example.com',
'http://example.com/nov' => 'https://example.com',
'https://example.com/nov' => 'https://example.com',
'example.com:8080' => 'https://example.com:8080',
'example.com:8080/~nov/' => 'https://example.com:8080',
'nov@example.com:8080' => 'https://example.com:8080',
'nov.matake@example.com:8080' => 'https://example.com:8080',
'acct:nov@example.com:8080' => 'https://example.com:8080',
'mailto:nov@example.com:8080' => 'https://example.com:8080',
'device:example.com:8080' => 'https://example.com:8080',
'unknown:nov@example.com:8080' => 'https://example.com:8080',
'http://example.com:8080' => 'https://example.com:8080',
'https://example.com:8080' => 'https://example.com:8080',
'discover.example.com' => 'https://discover.example.com',
'discover.example.com/~nov/' => 'https://discover.example.com',
'nov@discover.example.com' => 'https://discover.example.com',
'nov.matake@discover.example.com' => 'https://discover.example.com',
'acct:nov@discover.example.com' => 'https://discover.example.com',
'mailto:nov@discover.example.com' => 'https://discover.example.com',
'device:discover.example.com' => 'https://discover.example.com',
'unknown:nov@discover.example.com' => 'https://discover.example.com',
'http://discover.example.com/nov' => 'https://discover.example.com',
'https://discover.example.com/nov' => 'https://discover.example.com',
'discover.example.com:8080' => 'https://discover.example.com:8080',
'discover.example.com:8080/~nov/' => 'https://discover.example.com:8080',
'nov@discover.example.com:8080' => 'https://discover.example.com:8080',
'nov.matake@discover.example.com:8080' => 'https://discover.example.com:8080',
'acct:nov@discover.example.com:8080' => 'https://discover.example.com:8080',
'mailto:nov@discover.example.com:8080' => 'https://discover.example.com:8080',
'device:discover.example.com:8080' => 'https://discover.example.com:8080',
'unknown:nov@discover.example.com:8080' => 'https://discover.example.com:8080',
'http://discover.example.com:8080/nov' => 'https://discover.example.com:8080',
'https://discover.example.com:8080/nov' => 'https://discover.example.com:8080'
}.each do |resource, base_url|
endpoint = File.join base_url, '/.well-known/webfinger'
context "when resource=#{resource}" do
it "should access to #{endpoint}" do
mock_json endpoint, 'all', query: {resource: resource} do
response = WebFinger.discover! resource
response.should be_instance_of WebFinger::Response
end
end
end
end
context 'with rel option' do
shared_examples_for :discovery_with_rel do
let(:query_string) do
query_params = [{resource: resource}.to_query]
Array(rel).each do |_rel_|
query_params << {rel: _rel_}.to_query
end
query_params.join('&')
end
it 'should request with rel' do
query_string.scan('rel').count.should == Array(rel).count
mock_json 'https://example.com/.well-known/webfinger', 'all', query: query_string do
response = WebFinger.discover! resource, rel: rel
response.should be_instance_of WebFinger::Response
end
end
end
context 'when single rel' do
let(:rel) { 'http://openid.net/specs/connect/1.0/issuer' }
it_behaves_like :discovery_with_rel
end
context 'when multiple rel' do
let(:rel) { ['http://openid.net/specs/connect/1.0/issuer', 'vcard'] }
it_behaves_like :discovery_with_rel
end
end
context 'when error' do
{
400 => WebFinger::BadRequest,
401 => WebFinger::Unauthorized,
403 => WebFinger::Forbidden,
404 => WebFinger::NotFound,
500 => WebFinger::HttpError
}.each do |status, exception_class|
context "when status=#{status}" do
it "should raise #{exception_class}" do
expect do
mock_json 'https://example.com/.well-known/webfinger', 'all', query: {resource: resource}, status: [status, 'HTTPError'] do
response = WebFinger.discover! resource
end
end.to raise_error exception_class
end
end
end
end
end
describe '#logger' do
subject { WebFinger.logger }
context 'as default' do
it { should be_instance_of Logger }
end
context 'when specified' do
let(:logger) { 'Rails.logger or something' }
before { WebFinger.logger = logger }
it { should == logger }
end
end
describe '#debugging?' do
subject { WebFinger.debugging? }
context 'as default' do
it { should == false }
end
context 'when debugging' do
before { WebFinger.debug! }
it { should == true }
context 'when debugging mode canceled' do
before { WebFinger.debugging = false }
it { should == false }
end
end
end
describe '#url_builder' do
subject { WebFinger.url_builder }
context 'as default' do
it { should == URI::HTTPS }
end
context 'when specified' do
let(:url_builder) { 'URI::HTTP or something' }
before { WebFinger.url_builder = url_builder }
it { should == url_builder }
end
end
describe '#http_client' do
subject { WebFinger.http_client }
describe '#request_filter' do
subject { WebFinger.http_client.request_filter.collect(&:class) }
context 'as default' do
it { should_not include WebFinger::Debugger::RequestFilter }
end
context 'when debugging' do
before { WebFinger.debug! }
it { should include WebFinger::Debugger::RequestFilter }
end
end
end
end webfinger-1.0.2/LICENSE.txt 0000644 0001756 0001757 00000002052 12736020316 014345 0 ustar pravi pravi Copyright (c) 2012 nov matake
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. webfinger-1.0.2/VERSION 0000644 0001756 0001757 00000000005 12736020316 013566 0 ustar pravi pravi 1.0.2 webfinger-1.0.2/README.rdoc 0000644 0001756 0001757 00000004243 12736020316 014334 0 ustar pravi pravi = WebFinger
An Ruby WebFinger client library.
{
}[http://travis-ci.org/nov/webfinger]
Following the latest WebFinger spec discussed at IETF WebFinger WG.
http://tools.ietf.org/html/draft-ietf-appsawg-webfinger
If you found something different from the latest spec, open an issue please.
== Installation
Add this line to your application's Gemfile:
gem 'webfinger'
And then execute:
$ bundle
Or install it yourself as:
$ gem install webfinger
== Usage
=== Basic
You can discover resource metadata.
WebFinger.discover! 'acct:nov@connect-op.heroku.com'
WebFinger.discover! 'connect-op.heroku.com'
WebFinger.discover! 'http://connect-op.heroku.com'
You can also specify link relations via "rel" option.
WebFinger.discover! 'acct:nov@connect-op.heroku.com', rel: 'http://openid.net/specs/connect/1.0/issuer'
WebFinger.discover! 'acct:nov@connect-op.heroku.com', rel: ['http://openid.net/specs/connect/1.0/issuer', 'vcard']
=== Caching
Caching is important in HTTP-based discovery.
If you set your own cache object to WebFinger.cache
, this gem caches the discovery result until it expires.
(the expiry is calculated based on the "expires" value in JRD response)
# Set Cache
WebFinger.cache = Rails.cache
WebFinger.discover! 'acct:nov@connect-op.heroku.com' # do HTTP request
WebFinger.discover! 'acct:nov@connect-op.heroku.com' # use cache, no HTTP request
=== Debugging
Once you turn-on debugging, you can see all HTTP request/response in your log.
# Turn on debugging
WebFinger.debug!
# Set logger (OPTIONAL, ::Logger.new(STDOUT) is used as default)
WebFinger.logger = Rails.logger
You can also specify URL builder to force non-HTTPS access. (NOTE: allow non-HTTPS access only for debugging, not on your production.)
WebFinger.url_builder = URI::HTTP # default URI::HTTPS
== Contributing
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request
== Copyright
Copyright (c) 2012 nov matake. See LICENSE for details. webfinger-1.0.2/webfinger.gemspec 0000644 0001756 0001757 00000002005 12736020316 016035 0 ustar pravi pravi Gem::Specification.new do |gem|
gem.name = "webfinger"
gem.version = File.read("VERSION").delete("\n\r")
gem.authors = ["nov matake"]
gem.email = ["nov@matake.jp"]
gem.description = %q{Ruby WebFinger client library}
gem.summary = %q{Ruby WebFinger client library, following IETF WebFinger WG spec updates.}
gem.homepage = "https://github.com/nov/webfinger"
gem.license = 'MIT'
gem.files = `git ls-files`.split($/)
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
gem.require_paths = ["lib"]
gem.add_runtime_dependency "httpclient", ">= 2.4"
gem.add_runtime_dependency "multi_json"
gem.add_runtime_dependency "activesupport"
gem.add_development_dependency "rake"
gem.add_development_dependency "rspec"
gem.add_development_dependency 'rspec-its'
gem.add_development_dependency "simplecov"
gem.add_development_dependency "webmock", ">= 1.6.2"
end
webfinger-1.0.2/.travis.yml 0000644 0001756 0001757 00000000117 12736020316 014633 0 ustar pravi pravi before_install:
- gem install bundler
rvm:
- 2.0
- 2.1
- 2.2
- 2.3.0 webfinger-1.0.2/Gemfile 0000644 0001756 0001757 00000000046 12736020316 014016 0 ustar pravi pravi source 'https://rubygems.org'
gemspec webfinger-1.0.2/lib/ 0000755 0001756 0001757 00000000000 12736020316 013271 5 ustar pravi pravi webfinger-1.0.2/lib/webfinger.rb 0000644 0001756 0001757 00000002241 12736020316 015565 0 ustar pravi pravi require 'httpclient'
require 'multi_json'
require 'active_support'
require 'active_support/core_ext'
module WebFinger
VERSION = File.read(
File.join(File.dirname(__FILE__), '../VERSION')
).delete("\n\r")
module_function
def discover!(resource, options = {})
Request.new(resource, options).discover!
end
def logger
@logger
end
def logger=(logger)
@logger = logger
end
self.logger = ::Logger.new(STDOUT)
logger.progname = 'WebFinger'
def debugging?
@debugging
end
def debugging=(boolean)
@debugging = boolean
end
def debug!
self.debugging = true
end
self.debugging = false
def url_builder
@url_builder ||= URI::HTTPS
end
def url_builder=(builder)
@url_builder = builder
end
def http_client
_http_client_ = HTTPClient.new(
agent_name: "WebFinger (#{VERSION})"
)
_http_client_.request_filter << Debugger::RequestFilter.new if debugging?
http_config.try(:call, _http_client_)
_http_client_
end
def http_config(&block)
@http_config ||= block
end
end
require 'webfinger/debugger'
require 'webfinger/exception'
require 'webfinger/request'
require 'webfinger/response' webfinger-1.0.2/lib/webfinger/ 0000755 0001756 0001757 00000000000 12736020316 015241 5 ustar pravi pravi webfinger-1.0.2/lib/webfinger/response.rb 0000644 0001756 0001757 00000000632 12736020316 017425 0 ustar pravi pravi # NOTE:
# Make a JSON Resource Descriptor (JRD) gem as separate one and use it as superclass?
module WebFinger
class Response < ActiveSupport::HashWithIndifferentAccess
[:subject, :aliases, :properties, :links].each do |method|
define_method method do
self[method]
end
end
def link_for(rel)
links.detect do |link|
link[:rel] == rel
end
end
end
end webfinger-1.0.2/lib/webfinger/request.rb 0000644 0001756 0001757 00000003607 12736020316 017264 0 ustar pravi pravi module WebFinger
class Request
attr_accessor :resource, :relations
def initialize(resource, options = {})
self.resource = resource
self.relations = Array(options[:rel] || options[:relations])
@options = options
end
def discover!
handle_response do
WebFinger.http_client.get_content endpoint.to_s
end
end
private
def endpoint
path = '/.well-known/webfinger'
host, port = host_and_port
WebFinger.url_builder.build [nil, host, port, path, query_string, nil]
end
def host_and_port
uri = URI.parse(resource) rescue nil
if uri.try(:host).present?
[uri.host, [80, 443].include?(uri.port) ? nil : uri.port]
else
scheme_or_host, host_or_port, port_or_nil = resource.split('@').last.split('/').first.split(':')
case host_or_port
when nil, /\d+/
[scheme_or_host, host_or_port.try(:to_i)]
else
[host_or_port, port_or_nil.try(:to_i)]
end
end
end
def query_string
query_params.join('&')
end
def query_params
query_params = [{resource: resource}]
relations.each do |relation|
query_params << {rel: relation}
end
query_params.collect(&:to_query)
end
def handle_response
raw_response = yield
jrd = MultiJson.load(raw_response).with_indifferent_access
Response.new jrd
rescue HTTPClient::BadResponseError => e
case e.res.try(:status)
when nil
raise e
when 400
raise BadRequest.new('Bad Request', raw_response)
when 401
raise Unauthorized.new('Unauthorized', raw_response)
when 403
raise Forbidden.new('Forbidden', raw_response)
when 404
raise NotFound.new('Not Found', raw_response)
else
raise HttpError.new(e.res.status, e.res.reason, raw_response)
end
end
end
end webfinger-1.0.2/lib/webfinger/debugger/ 0000755 0001756 0001757 00000000000 12736020316 017025 5 ustar pravi pravi webfinger-1.0.2/lib/webfinger/debugger/request_filter.rb 0000644 0001756 0001757 00000001257 12736020316 022414 0 ustar pravi pravi module WebFinger
module Debugger
class RequestFilter
# Callback called in HTTPClient (before sending a request)
# request:: HTTP::Message
def filter_request(request)
started = "======= [WebFinger] HTTP REQUEST STARTED ======="
WebFinger.logger.info [started, request.dump].join("\n")
end
# Callback called in HTTPClient (after received a response)
# request:: HTTP::Message
# response:: HTTP::Message
def filter_response(request, response)
finished = "======= [WebFinger] HTTP REQUEST FINISHED ======="
WebFinger.logger.info ['-' * 50, response.dump, finished].join("\n")
end
end
end
end webfinger-1.0.2/lib/webfinger/debugger.rb 0000644 0001756 0001757 00000000120 12736020316 017343 0 ustar pravi pravi Dir[File.dirname(__FILE__) + '/debugger/*.rb'].each do |file|
require file
end webfinger-1.0.2/lib/webfinger/exception.rb 0000644 0001756 0001757 00000001430 12736020316 017562 0 ustar pravi pravi module WebFinger
class Exception < StandardError; end
class HttpError < Exception
attr_accessor :status, :response
def initialize(status, message = nil, response = nil)
super message
@status = status
@response = response
end
end
class BadRequest < HttpError
def initialize(message = nil, response = nil)
super 400, message, response
end
end
class Unauthorized < HttpError
def initialize(message = nil, response = nil)
super 401, message, response
end
end
class Forbidden < HttpError
def initialize(message = nil, response = nil)
super 403, message, response
end
end
class NotFound < HttpError
def initialize(message = nil, response = nil)
super 404, message, response
end
end
end webfinger-1.0.2/Rakefile 0000644 0001756 0001757 00000000622 12736020316 014170 0 ustar pravi pravi require 'bundler'
Bundler::GemHelper.install_tasks
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec)
namespace :coverage do
desc "Open coverage report"
task :report do
require 'simplecov'
`open "#{File.join SimpleCov.coverage_path, 'index.html'}"`
end
end
task :spec do
Rake::Task[:'coverage:report'].invoke unless ENV['TRAVIS_RUBY_VERSION']
end
task :default => :spec webfinger-1.0.2/.gitignore 0000644 0001756 0001757 00000000233 12736020316 014511 0 ustar pravi pravi *.gem
*.rbc
.bundle
.config
.yardoc
Gemfile.lock
InstalledFiles
_yardoc
coverage*
doc/
lib/bundler/man
pkg
rdoc
spec/reports
test/tmp
test/version_tmp
tmp