diff options
author | jessib <jessib@riseup.net> | 2013-12-02 11:56:04 -0800 |
---|---|---|
committer | jessib <jessib@riseup.net> | 2013-12-02 11:56:04 -0800 |
commit | 2a2ffd46bf4e6009f2957fb4e4abdedbfa7e3245 (patch) | |
tree | 41dd790266aaa951dfa35889527f78015f8c4451 | |
parent | 8e9b65b01bbd9d44d4077d94f2dc4ac375cf8e85 (diff) | |
parent | 8de6f143e53af5287b41913dcf3c7969f452fbc9 (diff) |
Merge branch 'develop' into feature/service_level
-rw-r--r-- | Gemfile.lock | 4 | ||||
-rw-r--r-- | core/leap_web_core.gemspec | 2 | ||||
-rw-r--r-- | core/lib/extensions/couchrest.rb | 35 | ||||
-rw-r--r-- | core/lib/tasks/leap_web_core_tasks.rake | 29 | ||||
-rw-r--r-- | lib/leap_web/version.rb | 2 | ||||
-rw-r--r-- | users/app/controllers/keys_controller.rb | 12 | ||||
-rw-r--r-- | users/app/models/account.rb | 11 | ||||
-rw-r--r-- | users/app/models/identity.rb | 6 | ||||
-rw-r--r-- | users/app/models/pgp_key.rb | 48 | ||||
-rw-r--r-- | users/config/routes.rb | 2 | ||||
-rw-r--r-- | users/test/factories.rb | 8 | ||||
-rw-r--r-- | users/test/functional/keys_controller_test.rb | 32 | ||||
-rw-r--r-- | users/test/integration/api/account_flow_test.rb | 34 | ||||
-rw-r--r-- | users/test/integration/browser/account_test.rb | 4 |
14 files changed, 194 insertions, 35 deletions
diff --git a/Gemfile.lock b/Gemfile.lock index e6096fd..8d80546 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -25,7 +25,7 @@ PATH leap_web_core (0.2.5) couchrest (~> 1.1.3) couchrest_model (~> 2.0.0) - couchrest_session_store (~> 0.2.0) + couchrest_session_store (~> 0.2.1) json rails (~> 3.2.11) @@ -110,7 +110,7 @@ GEM couchrest (~> 1.1.3) mime-types (>= 1.15) tzinfo (>= 0.3.22) - couchrest_session_store (0.2.0) + couchrest_session_store (0.2.1) actionpack couchrest couchrest_model diff --git a/core/leap_web_core.gemspec b/core/leap_web_core.gemspec index e98c892..c745f00 100644 --- a/core/leap_web_core.gemspec +++ b/core/leap_web_core.gemspec @@ -19,7 +19,7 @@ Gem::Specification.new do |s| s.add_dependency "couchrest", "~> 1.1.3" s.add_dependency "couchrest_model", "~> 2.0.0" - s.add_dependency "couchrest_session_store", "~> 0.2.0" + s.add_dependency "couchrest_session_store", "~> 0.2.1" s.add_dependency "json" end diff --git a/core/lib/extensions/couchrest.rb b/core/lib/extensions/couchrest.rb index 91dfc1c..84cfbb3 100644 --- a/core/lib/extensions/couchrest.rb +++ b/core/lib/extensions/couchrest.rb @@ -47,28 +47,45 @@ module CouchRest def self.load_all_models_with_engines self.load_all_models_without_engines return unless defined?(Rails) - Dir[Rails.root + 'app/models/**/*.rb'].each do |path| - require path - end Dir[Rails.root + '*/app/models/**/*.rb'].each do |path| require path end end - def self.all_models_and_proxies - callbacks = migrate_each_model(find_models) - callbacks += migrate_each_proxying_model(find_proxying_models) - cleanup(callbacks) + class << self + alias_method_chain :load_all_models, :engines + end + + def dump_all_models + prepare_directory + find_models.each do |model| + model.design_docs.each do |design| + dump_design(model, design) + end + end end + protected + def dump_design(model, design) + dir = prepare_directory model.name.tableize + filename = design.id.sub('_design/','') + '.json' + puts dir + filename + design.checksum + File.open(dir + filename, "w") do |file| + file.write(JSON.pretty_generate(design.to_hash)) + end + end - class << self - alias_method_chain :load_all_models, :engines + def prepare_directory(dir = '') + dir = Rails.root + 'tmp' + 'designs' + dir + Dir.mkdir(dir) unless Dir.exists?(dir) + return dir end end end + end class ModelRailtie diff --git a/core/lib/tasks/leap_web_core_tasks.rake b/core/lib/tasks/leap_web_core_tasks.rake index ae5b79b..ec6abac 100644 --- a/core/lib/tasks/leap_web_core_tasks.rake +++ b/core/lib/tasks/leap_web_core_tasks.rake @@ -1,4 +1,25 @@ -# desc "Explaining what the task does" -# task :leap_web_core do -# # Task goes here -# end +namespace :couchrest do + + desc "Dump all the design docs found in each model" + task :dump => :environment do + CouchRest::Model::Utils::Migrate.load_all_models + CouchRest::Model::Utils::Migrate.dump_all_models + end +end + +namespace :cleanup do + + desc "Cleanup all expired session documents" + task :sessions => :environment do + # make sure this is the same as in + # config/initializers/session_store.rb + store = CouchRest::Session::Store.new expire_after: 1800 + store.cleanup(store.expired) + end + + desc "Cleanup all expired tokens" + task :tokens => :environment do + Token.destroy_all_expired + end +end + diff --git a/lib/leap_web/version.rb b/lib/leap_web/version.rb index 009ee29..f6f99ae 100644 --- a/lib/leap_web/version.rb +++ b/lib/leap_web/version.rb @@ -1,3 +1,3 @@ module LeapWeb - VERSION = "0.2.5" unless defined?(LeapWeb::VERSION) + VERSION = "0.2.8.rc" unless defined?(LeapWeb::VERSION) end diff --git a/users/app/controllers/keys_controller.rb b/users/app/controllers/keys_controller.rb new file mode 100644 index 0000000..949f2c0 --- /dev/null +++ b/users/app/controllers/keys_controller.rb @@ -0,0 +1,12 @@ +class KeysController < ApplicationController + + def show + user = User.find_by_login(params[:login]) + # layout won't be included if we render text + # we will show blank page if user doesn't have key (which shouldn't generally occur) + # and a 404 error if user doesn't exist + user ? (render text: user.public_key) : (raise ActionController::RoutingError.new('Not Found')) + + end + +end diff --git a/users/app/models/account.rb b/users/app/models/account.rb index 5c943bb..cf998e4 100644 --- a/users/app/models/account.rb +++ b/users/app/models/account.rb @@ -27,7 +27,8 @@ class Account @user.update_attributes attrs.slice(:password_verifier, :password_salt) end # TODO: move into identity controller - update_pgp_key(attrs[:public_key]) if attrs.has_key? :public_key + key = update_pgp_key(attrs[:public_key]) + @user.errors.set :public_key, key.errors.full_messages @user.save && save_identities @user.refresh_identity end @@ -49,8 +50,12 @@ class Account end def update_pgp_key(key) - @new_identity ||= Identity.for(@user) - @new_identity.set_key(:pgp, key) + PgpKey.new(key).tap do |key| + if key.present? && key.valid? + @new_identity ||= Identity.for(@user) + @new_identity.set_key(:pgp, key) + end + end end def save_identities diff --git a/users/app/models/identity.rb b/users/app/models/identity.rb index 97966d0..cbb540e 100644 --- a/users/app/models/identity.rb +++ b/users/app/models/identity.rb @@ -94,9 +94,9 @@ class Identity < CouchRest::Model::Base read_attribute('keys') || HashWithIndifferentAccess.new end - def set_key(type, value) - return if keys[type] == value - write_attribute('keys', keys.merge(type => value)) + def set_key(type, key) + return if keys[type] == key.to_s + write_attribute('keys', keys.merge(type => key.to_s)) end # for LoginFormatValidation diff --git a/users/app/models/pgp_key.rb b/users/app/models/pgp_key.rb new file mode 100644 index 0000000..66f8660 --- /dev/null +++ b/users/app/models/pgp_key.rb @@ -0,0 +1,48 @@ +class PgpKey + include ActiveModel::Validations + + KEYBLOCK_IDENTIFIERS = [ + '-----BEGIN PGP PUBLIC KEY BLOCK-----', + '-----END PGP PUBLIC KEY BLOCK-----', + ] + + # mostly for testing. + attr_accessor :keyblock + + validate :validate_keyblock_format + + def initialize(keyblock = nil) + @keyblock = keyblock + end + + def to_s + @keyblock + end + + def present? + @keyblock.present? + end + + # allow comparison with plain keyblock strings. + def ==(other) + self.equal?(other) or + # relax the comparison on line ends. + self.to_s.tr_s("\n\r", '') == other.tr_s("\r\n", '') + end + + protected + + def validate_keyblock_format + if keyblock_identifier_missing? + errors.add :public_key_block, + "does not look like an armored pgp public key block" + end + end + + def keyblock_identifier_missing? + KEYBLOCK_IDENTIFIERS.find do |identify| + !@keyblock.include?(identify) + end + end + +end diff --git a/users/config/routes.rb b/users/config/routes.rb index ccecfd5..69f9cf7 100644 --- a/users/config/routes.rb +++ b/users/config/routes.rb @@ -22,4 +22,6 @@ Rails.application.routes.draw do get "/.well-known/host-meta" => 'webfinger#host_meta' get "/webfinger" => 'webfinger#search' + get "/key/:login" => 'keys#show' + end diff --git a/users/test/factories.rb b/users/test/factories.rb index f5fb77d..ae00d43 100644 --- a/users/test/factories.rb +++ b/users/test/factories.rb @@ -23,4 +23,12 @@ FactoryGirl.define do user end + factory :pgp_key do + keyblock <<-EOPGP +-----BEGIN PGP PUBLIC KEY BLOCK----- ++Dummy+PGP+KEY+++Dummy+PGP+KEY+++Dummy+PGP+KEY+++Dummy+PGP+KEY+ +#{SecureRandom.base64(4032)} +-----END PGP PUBLIC KEY BLOCK----- + EOPGP + end end diff --git a/users/test/functional/keys_controller_test.rb b/users/test/functional/keys_controller_test.rb new file mode 100644 index 0000000..b69cbc0 --- /dev/null +++ b/users/test/functional/keys_controller_test.rb @@ -0,0 +1,32 @@ +require 'test_helper' + +class KeysControllerTest < ActionController::TestCase + + test "get existing public key" do + public_key = 'my public key' + @user = stub_record :user, :public_key => public_key + User.stubs(:find_by_login).with(@user.login).returns(@user) + get :show, :login => @user.login + assert_response :success + assert_equal "text/html", response.content_type + assert_equal public_key, response.body + end + + test "get non-existing public key for user" do + # this isn't a scenerio that should generally occur. + @user = stub_record :user + User.stubs(:find_by_login).with(@user.login).returns(@user) + get :show, :login => @user.login + assert_response :success + assert_equal "text/html", response.content_type + assert_equal '', response.body.strip + end + + test "get public key for non-existing user" do + # raise 404 error if user doesn't exist (doesn't need to be this routing error, but seems fine to assume for now): + assert_raise(ActionController::RoutingError) { + get :show, :login => 'asdkljslksjfdlskfj' + } + end + +end diff --git a/users/test/integration/api/account_flow_test.rb b/users/test/integration/api/account_flow_test.rb index e41befa..edd0859 100644 --- a/users/test/integration/api/account_flow_test.rb +++ b/users/test/integration/api/account_flow_test.rb @@ -96,27 +96,41 @@ class AccountFlowTest < RackTest assert server_auth["M2"] end - test "update user" do + test "prevent changing login without changing password_verifier" do server_auth = @srp.authenticate(self) - test_public_key = 'asdlfkjslfdkjasd' original_login = @user.login new_login = 'zaph' User.find_by_login(new_login).try(:destroy) Identity.by_address.key(new_login + '@' + APP_CONFIG[:domain]).each do |identity| identity.destroy end - put "http://api.lvh.me:3000/1/users/" + @user.id + '.json', :user => {:public_key => test_public_key, :login => new_login}, :format => :json + put "http://api.lvh.me:3000/1/users/" + @user.id + '.json', :user => {:login => new_login}, :format => :json assert last_response.successful? - assert_equal test_public_key, Identity.for(@user).keys[:pgp] # does not change login if no password_verifier is present assert_equal original_login, @user.login - # eventually probably want to remove most of this into a non-integration functional test - # should not overwrite public key: - put "http://api.lvh.me:3000/1/users/" + @user.id + '.json', :user => {:blee => :blah}, :format => :json - assert_equal test_public_key, Identity.for(@user).keys[:pgp] - # should overwrite public key: - put "http://api.lvh.me:3000/1/users/" + @user.id + '.json', :user => {:public_key => nil}, :format => :json + end + + test "upload pgp key" do + server_auth = @srp.authenticate(self) + key = FactoryGirl.build :pgp_key + put "http://api.lvh.me:3000/1/users/" + @user.id + '.json', :user => {:public_key => key}, :format => :json + assert_equal key, Identity.for(@user).keys[:pgp] + end + + # eventually probably want to remove most of this into a non-integration + # functional test + test "prevent uploading invalid key" do + server_auth = @srp.authenticate(self) + put "http://api.lvh.me:3000/1/users/" + @user.id + '.json', :user => {:public_key => :blah}, :format => :json assert_nil Identity.for(@user).keys[:pgp] end + test "prevent emptying public key" do + server_auth = @srp.authenticate(self) + key = FactoryGirl.build :pgp_key + put "http://api.lvh.me:3000/1/users/" + @user.id + '.json', :user => {:public_key => key}, :format => :json + put "http://api.lvh.me:3000/1/users/" + @user.id + '.json', :user => {:public_key => ""}, :format => :json + assert_equal key, Identity.for(@user).keys[:pgp] + end + end diff --git a/users/test/integration/browser/account_test.rb b/users/test/integration/browser/account_test.rb index b349489..3d281ae 100644 --- a/users/test/integration/browser/account_test.rb +++ b/users/test/integration/browser/account_test.rb @@ -66,7 +66,7 @@ class AccountTest < BrowserIntegrationTest end test "change pgp key" do - pgp_key = "My PGP Key Stub" + pgp_key = FactoryGirl.build :pgp_key username, password = submit_signup click_on "Account Settings" within('#update_pgp_key') do @@ -76,7 +76,7 @@ class AccountTest < BrowserIntegrationTest page.assert_selector 'input[value="Saving..."]' # at some point we're done: page.assert_no_selector 'input[value="Saving..."]' - assert page.has_field? 'Public key', with: pgp_key + assert page.has_field? 'Public key', with: pgp_key.to_s user = User.find_by_login(username) assert_equal pgp_key, user.public_key user.account.destroy |