diff options
| -rw-r--r-- | app/controllers/application_controller.rb | 1 | ||||
| -rw-r--r-- | core/lib/extensions/couchrest.rb | 37 | ||||
| -rw-r--r-- | users/app/controllers/webfinger_controller.rb | 19 | ||||
| -rw-r--r-- | users/app/models/user.rb | 2 | ||||
| -rw-r--r-- | users/app/views/users/_public_key_field.html.haml | 1 | ||||
| -rw-r--r-- | users/app/views/users/edit.html.haml | 1 | ||||
| -rw-r--r-- | users/app/views/webfinger/host_meta.xml.erb | 11 | ||||
| -rw-r--r-- | users/app/views/webfinger/search.xml.erb | 7 | ||||
| -rw-r--r-- | users/config/locales/en.yml | 2 | ||||
| -rw-r--r-- | users/config/routes.rb | 2 | ||||
| -rw-r--r-- | users/lib/leap_web_users/engine.rb | 2 | ||||
| -rw-r--r-- | users/lib/webfinger.rb | 6 | ||||
| -rw-r--r-- | users/lib/webfinger/host_meta_presenter.rb | 30 | ||||
| -rw-r--r-- | users/lib/webfinger/user_presenter.rb | 35 | ||||
| -rw-r--r-- | users/test/functional/webfinger_controller_test.rb | 33 | ||||
| -rw-r--r-- | users/test/unit/webfinger/host_meta_presenter_test.rb | 24 | ||||
| -rw-r--r-- | users/test/unit/webfinger/user_presenter_test.rb | 49 | 
17 files changed, 248 insertions, 14 deletions
| diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index be7aa1f..06b245a 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,4 +2,5 @@ class ApplicationController < ActionController::Base    protect_from_forgery    ActiveSupport.run_load_hooks(:application_controller, self) +  end diff --git a/core/lib/extensions/couchrest.rb b/core/lib/extensions/couchrest.rb index 5938df4..ca4b608 100644 --- a/core/lib/extensions/couchrest.rb +++ b/core/lib/extensions/couchrest.rb @@ -1,23 +1,32 @@ -module CouchRest::Model::Designs +module CouchRest +  module Model::Designs -  class View +    class View -    # so we can called Ticket.method.descending or Ticket.method.ascending -    def ascending -      self +      # so we can called Ticket.method.descending or Ticket.method.ascending +      def ascending +        self +      end      end -  end -  class DesignMapper -    def load_views(dir) -      Dir.glob("#{dir}/*.js") do |js| -        name = File.basename(js, '.js') -        file = File.open(js, 'r') -        view name.to_sym, -          :map => file.read, -          :reduce => "function(key, values, rereduce) { return sum(values); }" +    class DesignMapper +      def load_views(dir) +        Dir.glob("#{dir}/*.js") do |js| +          name = File.basename(js, '.js') +          file = File.open(js, 'r') +          view name.to_sym, +            :map => file.read, +            :reduce => "function(key, values, rereduce) { return sum(values); }" +        end        end      end +    end +  class ModelRailtie +    config.action_dispatch.rescue_responses.merge!( +      'CouchRest::Model::DocumentNotFound' => :not_found, +      'RestClient::ResourceNotFound' => :not_found +    ) +  end  end diff --git a/users/app/controllers/webfinger_controller.rb b/users/app/controllers/webfinger_controller.rb new file mode 100644 index 0000000..8872802 --- /dev/null +++ b/users/app/controllers/webfinger_controller.rb @@ -0,0 +1,19 @@ +class WebfingerController < ApplicationController + +  respond_to :xml, :json +  layout false + +  def host_meta +    @host_meta = Webfinger::HostMetaPresenter.new(request) +    respond_with @host_meta +  end + +  def search +    username = params[:q].split('@')[0].to_s.downcase +    user = User.find_by_login(username) +    raise RECORD_NOT_FOUND, 'User not found' unless user.present? +    @presenter = Webfinger::UserPresenter.new(user, request) +    respond_with @presenter +  end + +end diff --git a/users/app/models/user.rb b/users/app/models/user.rb index 292fb13..80d49a3 100644 --- a/users/app/models/user.rb +++ b/users/app/models/user.rb @@ -9,6 +9,8 @@ class User < CouchRest::Model::Base    property :email_forward, String, :accessible => true    property :email_aliases, [LocalEmail] +  property :public_key, :accessible => true +    validates :login, :password_salt, :password_verifier,      :presence => true diff --git a/users/app/views/users/_public_key_field.html.haml b/users/app/views/users/_public_key_field.html.haml new file mode 100644 index 0000000..af88cbd --- /dev/null +++ b/users/app/views/users/_public_key_field.html.haml @@ -0,0 +1 @@ += f.input :public_key, :as => :text, :hint => t(:use_ascii_key), :input_html => {:class => "span5", :rows => 20} # will want to tweak this to be wide enough (maybe smaller text?) diff --git a/users/app/views/users/edit.html.haml b/users/app/views/users/edit.html.haml index 238c0eb..950a3b1 100644 --- a/users/app/views/users/edit.html.haml +++ b/users/app/views/users/edit.html.haml @@ -8,6 +8,7 @@      %legend=t :email_address      The associated email address is      = render @user.email_address, :as => :span +    = user_form_with 'public_key_field', :legend => :public_key      = user_form_with 'email_forward_field', :legend => :forward_email      = user_form_with 'email_aliases', :legend => :add_email_alias    = render 'tabs/tabs', :tabs => [:account, :email] diff --git a/users/app/views/webfinger/host_meta.xml.erb b/users/app/views/webfinger/host_meta.xml.erb new file mode 100644 index 0000000..cfcbcc0 --- /dev/null +++ b/users/app/views/webfinger/host_meta.xml.erb @@ -0,0 +1,11 @@ +<?xml version='1.0' encoding='UTF-8'?> +  <XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'> + +    <Subject><%= @host_meta.subject %></Subject> + +  <%- @host_meta.links.each do |rel, link| %> +    <Link rel='<%= rel %>' +      type='<%= link[:type] %>' +      template='<%= link[:template] %>' /> +  <%- end %> +  </XRD> diff --git a/users/app/views/webfinger/search.xml.erb b/users/app/views/webfinger/search.xml.erb new file mode 100644 index 0000000..7328552 --- /dev/null +++ b/users/app/views/webfinger/search.xml.erb @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"> +  <Subject><%= @presenter.subject %></Subject> +  <%- @presenter.links.each do |rel, link| %> +    <Link rel=<%=rel%> type=<%=link[:type]%> href="<%= link[:key] %>"/> +  <% end %> +</XRD> diff --git a/users/config/locales/en.yml b/users/config/locales/en.yml index 7a6ab90..493b5db 100644 --- a/users/config/locales/en.yml +++ b/users/config/locales/en.yml @@ -13,10 +13,12 @@ en:    set_email_address: "Set email address"    forward_email: "Forward email"    email_aliases: "Email aliases" +  public_key: "Public Key"    add_email_alias: "Add email alias"    user_updated_successfully: "Settings have been updated successfully."    user_created_successfully: "Successfully created your account."    email_alias_destroyed_successfully: "Successfully removed the alias '%{alias}'." +  use_ascii_key: "Use ASCII-armored PGP key"    activemodel:      models: diff --git a/users/config/routes.rb b/users/config/routes.rb index 0c2d8d9..4127862 100644 --- a/users/config/routes.rb +++ b/users/config/routes.rb @@ -18,4 +18,6 @@ Rails.application.routes.draw do      resources :email_aliases, :only => [:destroy], :id => /.*/    end +  get "/.well-known/host-meta" => 'webfinger#host_meta' +  get "/webfinger" => 'webfinger#search'  end diff --git a/users/lib/leap_web_users/engine.rb b/users/lib/leap_web_users/engine.rb index 7033576..f8ed71c 100644 --- a/users/lib/leap_web_users/engine.rb +++ b/users/lib/leap_web_users/engine.rb @@ -7,6 +7,8 @@ require "ruby-srp"  require "warden/session_serializer"  require "warden/strategies/secure_remote_password" +require "webfinger" +  module LeapWebUsers    class Engine < ::Rails::Engine diff --git a/users/lib/webfinger.rb b/users/lib/webfinger.rb new file mode 100644 index 0000000..dd49b41 --- /dev/null +++ b/users/lib/webfinger.rb @@ -0,0 +1,6 @@ +module Webfinger + +  autoload :HostMetaPresenter, 'webfinger/host_meta_presenter' +  autoload :UserPresenter, 'webfinger/user_presenter' + +end diff --git a/users/lib/webfinger/host_meta_presenter.rb b/users/lib/webfinger/host_meta_presenter.rb new file mode 100644 index 0000000..84ab7a9 --- /dev/null +++ b/users/lib/webfinger/host_meta_presenter.rb @@ -0,0 +1,30 @@ +require 'uri' + +class Webfinger::HostMetaPresenter +  def initialize(request) +    @request = request +  end + +  def to_json(options = {}) +    { +      subject: subject, +      links: links +    }.to_json(options) +  end + +  def subject +    url = URI.parse(@request.url) +    url.path = '' +    url.to_s +  end + +  def links +    { lrdd: { type: 'application/xrd+xml', template: webfinger_template } } +  end + +  protected + +  def webfinger_template(path = 'webfinger', query_param='q') +    "#{subject}/#{path}?#{query_param}={uri}" +  end +end diff --git a/users/lib/webfinger/user_presenter.rb b/users/lib/webfinger/user_presenter.rb new file mode 100644 index 0000000..329f477 --- /dev/null +++ b/users/lib/webfinger/user_presenter.rb @@ -0,0 +1,35 @@ +class Webfinger::UserPresenter +  include Rails.application.routes.url_helpers +  attr_accessor :user + +  def initialize(user, request) +    @user = user +    @request = request +  end + +  def to_json(options = {}) +    { +      subject: subject, +      links:   links +    }.to_json(options) +  end + +  def subject +    "acct:#{@user.email_address}" +  end + +  def links +    links = {} +    links[:public_key] = { type: 'PGP', href: key } if key +    return links +  end + +  protected + +  def key +    if @user.public_key.present? +      Base64.encode64(@user.public_key.to_s) +    end +  end + +end diff --git a/users/test/functional/webfinger_controller_test.rb b/users/test/functional/webfinger_controller_test.rb new file mode 100644 index 0000000..6597b69 --- /dev/null +++ b/users/test/functional/webfinger_controller_test.rb @@ -0,0 +1,33 @@ +require 'test_helper' + +class WebfingerControllerTest < ActionController::TestCase + +  test "get host meta xml" do +    get :host_meta, :format => :xml +    assert_response :success +    assert_equal "application/xml", response.content_type +  end + +  test "get host meta json" do +    get :host_meta, :format => :json +    assert_response :success +    assert_equal "application/json", response.content_type +  end + +  test "get user webfinger xml" do +    @user = stub_record :user, :public_key => 'my public key' +    User.stubs(:find_by_login).with(@user.login).returns(@user) +    get :search, :q => @user.email_address.to_s, :format => :xml +    assert_response :success +    assert_equal "application/xml", response.content_type +  end + +  test "get user webfinger json" do +    @user = stub_record :user, :public_key => 'my public key' +    User.stubs(:find_by_login).with(@user.login).returns(@user) +    get :search, :q => @user.email_address.to_s, :format => :json +    assert_response :success +    assert_equal "application/json", response.content_type +  end + +end diff --git a/users/test/unit/webfinger/host_meta_presenter_test.rb b/users/test/unit/webfinger/host_meta_presenter_test.rb new file mode 100644 index 0000000..af86404 --- /dev/null +++ b/users/test/unit/webfinger/host_meta_presenter_test.rb @@ -0,0 +1,24 @@ +require 'test_helper' +require 'webfinger' +require 'json' + +class Webfinger::HostMetaPresenterTest < ActiveSupport::TestCase + +  setup do +    @request = stub( +      url: "https://#{APP_CONFIG[:domain]}/.well-known/host-meta" +    ) +    @meta = Webfinger::HostMetaPresenter.new(@request) +  end + +  test "creates proper json" do +    hash = JSON.parse @meta.to_json +    assert_equal ["subject", "links"].sort, hash.keys.sort +    hash.each do |key, value| +      assert_equal @meta.send(key.to_sym).to_json, value.to_json +    end +  end + +end + + diff --git a/users/test/unit/webfinger/user_presenter_test.rb b/users/test/unit/webfinger/user_presenter_test.rb new file mode 100644 index 0000000..04aeb22 --- /dev/null +++ b/users/test/unit/webfinger/user_presenter_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' +require 'webfinger' +require 'json' + +class Webfinger::UserPresenterTest < ActiveSupport::TestCase + + +  setup do +    @user = stub( +      username: 'testuser', +      email_address: "testuser@#{APP_CONFIG[:domain]}" +    ) +    @request = stub( +      host: APP_CONFIG[:domain] +    ) +  end + +  test "user without key has no links" do +    @user.stubs :public_key => nil +    presenter = Webfinger::UserPresenter.new(@user, @request) +    assert_equal Hash.new, presenter.links +  end + +  test "user with key has corresponding link" do +    @user.stubs :public_key => "here's a key" +    presenter = Webfinger::UserPresenter.new(@user, @request) +    assert_equal [:public_key], presenter.links.keys +    assert_equal "PGP", presenter.links[:public_key][:type] +    assert_equal presenter.send(:key), presenter.links[:public_key][:href] +  end + +  test "key is base64 encoded" do +    @user.stubs :public_key => "here's a key" +    presenter = Webfinger::UserPresenter.new(@user, @request) +    assert_equal Base64.encode64(@user.public_key), presenter.send(:key) +  end + +  test "creates proper json representation" do +    @user.stubs :public_key => "here's a key" +    presenter = Webfinger::UserPresenter.new(@user, @request) +    hash = JSON.parse presenter.to_json +    assert_equal ["subject", "links"].sort, hash.keys.sort +    hash.each do |key, value| +      assert_equal presenter.send(key.to_sym).to_json, value.to_json +    end +  end + + +end | 
