summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Gemfile.lock4
-rw-r--r--app/controllers/api/users_controller.rb11
-rw-r--r--app/controllers/application_controller.rb2
-rw-r--r--app/controllers/invite_codes_controller.rb4
-rw-r--r--app/models/account.rb78
-rw-r--r--app/models/invite_code.rb2
-rw-r--r--app/views/invite_codes/_invite_code.html.haml2
-rw-r--r--app/views/invite_codes/index.html.haml4
-rw-r--r--lib/leap_web/version.rb2
-rw-r--r--test/functional/api/users_controller_test.rb22
-rw-r--r--test/integration/api/srp_test.rb2
-rw-r--r--test/integration/api/update_account_test.rb8
-rw-r--r--test/integration/browser/account_livecycle_test.rb15
-rw-r--r--test/unit/account_test.rb56
14 files changed, 149 insertions, 63 deletions
diff --git a/Gemfile.lock b/Gemfile.lock
index 8a2abc2..2ee1037 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,13 +1,13 @@
PATH
remote: engines/billing
specs:
- leap_web_billing (0.9.1)
+ leap_web_billing (0.9.2)
braintree
PATH
remote: engines/support
specs:
- leap_web_help (0.9.1)
+ leap_web_help (0.9.2)
PATH
remote: vendor/gems/certificate_authority
diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb
index 709e076..cb7b7bc 100644
--- a/app/controllers/api/users_controller.rb
+++ b/app/controllers/api/users_controller.rb
@@ -53,7 +53,7 @@ module Api
end
def update
- @user.account.update params[:user]
+ @user.account.update user_update_params
respond_with @user
end
@@ -67,6 +67,15 @@ module Api
private
+ def user_update_params
+ params.require(:user).permit :login,
+ :password_verifier,
+ :password_salt,
+ :recovery_code_verifier,
+ :recovery_code_salt,
+ :public_key
+ end
+
def release_handles
current_user.is_monitor? || params[:identities] == "destroy"
end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 1f37fea..d3cfc2b 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -99,7 +99,7 @@ class ApplicationController < ActionController::Base
#
# URL paths for which we don't enforce the locale as the prefix of the path.
#
- NON_LOCALE_PATHS = /^\/(assets|webfinger|.well-known|rails|key|[0-9]+)($|\/)/
+ NON_LOCALE_PATHS = /^\/(assets|webfinger|.well-known|rails|key|[0-9]+|new)($|\/)/
#
# For some requests, we ignore locale determination.
diff --git a/app/controllers/invite_codes_controller.rb b/app/controllers/invite_codes_controller.rb
index 6a7fef3..96836ee 100644
--- a/app/controllers/invite_codes_controller.rb
+++ b/app/controllers/invite_codes_controller.rb
@@ -7,7 +7,9 @@ class InviteCodesController < ApplicationController
def index
@invite = InviteCode.new # for the creation form.
- @invites = InviteCode.all.page(params[:page]).per(APP_CONFIG[:pagination_size])
+ @invites = InviteCode.by_updated_at.descending.
+ page(params[:page]).
+ per(APP_CONFIG[:pagination_size])
respond_with @invites
end
diff --git a/app/models/account.rb b/app/models/account.rb
index 3283bcc..d77c61f 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -25,57 +25,57 @@ class Account
# configuration by same name.
#
def self.create(attrs, options={})
+ User.new(attrs).tap do |user|
+ self.new(user).create(options)
+ end
+ end
+
+ def create(options={})
identity = nil
- user = nil
- user = User.new(attrs)
if options[:invite_required] == false
user.ignore_invites!
end
user.save
# this is not very atomic, but we do the best we can:
- if !user.is_tmp? && user.persisted?
+ return unless user.persisted?
+ if !user.is_tmp?
identity = user.identity
identity.user_id = user.id
identity.save
identity.errors.each do |attr, msg|
user.errors.add(attr, msg)
end
- if user.invite_required?
- user_invite_code = InviteCode.find_by_invite_code user.invite_code
- user_invite_code.invite_count += 1
- user_invite_code.save
- end
end
+ consume_invite_code if user.invite_required?
rescue VALIDATION_FAILED => ex
- user.errors.add(:base, ex.to_s) if user
+ user.errors.add(:base, ex.to_s)
ensure
- if creation_problem?(user, identity)
+ if creation_problem?(identity)
user.destroy if user && user.persisted?
identity.destroy if identity && identity.persisted?
end
- return user
end
def update(attrs)
if attrs[:password_verifier].present?
update_login(attrs[:login])
- @user.update_attributes attrs.slice(:password_verifier, :password_salt)
+ user.update_attributes attrs.slice(:password_verifier, :password_salt)
end
if attrs[:recovery_code_verifier].present?
- @user.update_attributes attrs.slice(:recovery_code_verifier, :recovery_code_salt)
+ user.update_attributes attrs.slice(:recovery_code_verifier, :recovery_code_salt)
end
# TODO: move into identity controller
key = update_pgp_key(attrs[:public_key])
- @user.errors.set :public_key, key.errors.full_messages
- @user.save && save_identities
- @user.refresh_identity
+ user.errors.set :public_key, key.errors.full_messages
+ user.save && save_identities
+ user.refresh_identity
end
def destroy(release_handles=false)
- return unless @user
- if !@user.is_tmp?
- @user.identities.each do |id|
+ return unless user
+ if !user.is_tmp?
+ user.identities.each do |id|
if release_handles == false
id.orphan!
else
@@ -83,44 +83,56 @@ class Account
end
end
end
- @user.destroy
+ user.destroy
end
# when a user is disable, all their data and associations remain
# in place, but the user should not be able to send email or
# create new authentication certificates.
def disable
- if @user && !@user.is_tmp?
- @user.enabled = false
- @user.save
- @user.identities.each do |id|
+ if user && !user.is_tmp?
+ user.enabled = false
+ user.save
+ user.identities.each do |id|
id.disable!
end
end
end
def enable
- @user.enabled = true
- @user.save
- @user.identities.each do |id|
+ user.enabled = true
+ user.save
+ user.identities.each do |id|
id.enable!
end
end
protected
+ attr_reader :user
+
+ def consume_invite_code
+ invite_code = InviteCode.find_by_invite_code user.invite_code
+ if user.is_test? && invite_code.max_uses == 1
+ invite_code.destroy
+ else
+ invite_code.invite_count += 1
+ invite_code.save
+ end
+ end
+
def update_login(login)
return unless login.present?
- @old_identity = Identity.for(@user)
- @user.login = login
- @new_identity = Identity.for(@user) # based on the new login
- @old_identity.destination = @user.email_address # alias old -> new
+ @old_identity = Identity.for(user)
+ user.login = login
+ @new_identity = Identity.for(user) # based on the new login
+ @old_identity.destination = user.email_address # alias old -> new
end
def update_pgp_key(key)
PgpKey.new(key).tap do |key|
if key.present? && key.valid?
- @new_identity ||= Identity.for(@user)
+ @new_identity ||= Identity.for(user)
@new_identity.set_key(:pgp, key)
end
end
@@ -130,7 +142,7 @@ class Account
@new_identity.try(:save) && @old_identity.try(:save)
end
- def self.creation_problem?(user, identity)
+ def creation_problem?(identity)
return true if user.nil? || !user.persisted? || user.errors.any?
if !user.is_tmp?
return true if identity.nil? || !identity.persisted? || identity.errors.any?
diff --git a/app/models/invite_code.rb b/app/models/invite_code.rb
index 9c6df66..8a56484 100644
--- a/app/models/invite_code.rb
+++ b/app/models/invite_code.rb
@@ -12,6 +12,8 @@ class InviteCode < CouchRest::Model::Base
design do
view :by_invite_code
view :by_invite_count
+ view :by_created_at
+ view :by_updated_at
end
def initialize(attributes = {}, options = {})
diff --git a/app/views/invite_codes/_invite_code.html.haml b/app/views/invite_codes/_invite_code.html.haml
index a3c420d..a167432 100644
--- a/app/views/invite_codes/_invite_code.html.haml
+++ b/app/views/invite_codes/_invite_code.html.haml
@@ -1,5 +1,7 @@
%tr
%td
+ = simple_date(invite_code.updated_at)
+ %td
= simple_date(invite_code.created_at)
%td
%input.invite-code{:value => invite_code.invite_code}
diff --git a/app/views/invite_codes/index.html.haml b/app/views/invite_codes/index.html.haml
index 40fccdf..98c49c7 100644
--- a/app/views/invite_codes/index.html.haml
+++ b/app/views/invite_codes/index.html.haml
@@ -11,10 +11,10 @@
%td= f.text_field :max_uses, style: 'width: 4em'
%td= f.submit t("helpers.submit.invites.create"), style: 'margin-bottom: 10px', class: 'btn btn-default'
-= table @invites, %w(created code uses actions)
+= table @invites, %w(updated created code uses actions)
-# select the text of the invite code when you click on it:
:javascript
$("input.invite-code").focus(function(){
this.select();
- }); \ No newline at end of file
+ });
diff --git a/lib/leap_web/version.rb b/lib/leap_web/version.rb
index 0c4f19d..fcce54a 100644
--- a/lib/leap_web/version.rb
+++ b/lib/leap_web/version.rb
@@ -1,3 +1,3 @@
module LeapWeb
- VERSION = "0.9.1" unless defined?(LeapWeb::VERSION)
+ VERSION = "0.9.2" unless defined?(LeapWeb::VERSION)
end
diff --git a/test/functional/api/users_controller_test.rb b/test/functional/api/users_controller_test.rb
index 88ecae0..ee183f9 100644
--- a/test/functional/api/users_controller_test.rb
+++ b/test/functional/api/users_controller_test.rb
@@ -4,28 +4,42 @@ class Api::UsersControllerTest < ApiControllerTest
test "user can change settings" do
user = find_record :user
- changed_attribs = record_attributes_for :user_with_settings
+ attribs = record_attributes_for(:user)
+ changed_attribs = attribs.slice 'login',
+ 'password_verifier',
+ 'password_salt'
account_settings = stub
account_settings.expects(:update).with(changed_attribs)
Account.expects(:new).with(user).returns(account_settings)
login user
- api_put :update, :user => changed_attribs, :id => user.id, :format => :json
+ api_put :update, :user => attribs, :id => user.id, :format => :json
assert_equal user, assigns[:user]
assert_response 204
assert @response.body.blank?, "Response should be blank"
end
+ test "deal with empty settings" do
+ user = find_record :user
+ login user
+ assert_raises ActionController::ParameterMissing do
+ api_put :update, :id => user.id, :format => :json
+ end
+ end
+
test "admin can update user" do
user = find_record :user
- changed_attribs = record_attributes_for :user_with_settings
+ attribs = record_attributes_for(:user)
+ changed_attribs = attribs.slice 'login',
+ 'password_verifier',
+ 'password_salt'
account_settings = stub
account_settings.expects(:update).with(changed_attribs)
Account.expects(:new).with(user).returns(account_settings)
login :is_admin? => true
- api_put :update, :user => changed_attribs, :id => user.id, :format => :json
+ api_put :update, :user => attribs, :id => user.id, :format => :json
assert_equal user, assigns[:user]
assert_response 204
diff --git a/test/integration/api/srp_test.rb b/test/integration/api/srp_test.rb
index b9605f9..ef5d9b8 100644
--- a/test/integration/api/srp_test.rb
+++ b/test/integration/api/srp_test.rb
@@ -46,7 +46,7 @@ class SrpTest < RackTest
@password = password
end
- def update_user(params)
+ def update_user(params = {})
put api_url("users/#{@user.id}.json"),
user_params(params),
auth_headers
diff --git a/test/integration/api/update_account_test.rb b/test/integration/api/update_account_test.rb
index f083dbc..dd28b06 100644
--- a/test/integration/api/update_account_test.rb
+++ b/test/integration/api/update_account_test.rb
@@ -19,6 +19,14 @@ class UpdateAccountTest < SrpTest
assert_login_required
end
+ test "empty request" do
+ authenticate
+ update_user
+ refute last_response.successful?
+ assert_equal 400, last_response.status
+ assert_equal '', last_response.body
+ end
+
test "update password via api" do
authenticate
update_user password: "No! Verify me instead."
diff --git a/test/integration/browser/account_livecycle_test.rb b/test/integration/browser/account_livecycle_test.rb
index cfab444..68775d3 100644
--- a/test/integration/browser/account_livecycle_test.rb
+++ b/test/integration/browser/account_livecycle_test.rb
@@ -63,6 +63,16 @@ class AccountLivecycleTest < BrowserIntegrationTest
assert_invalid_login(page)
end
+ test "failed login with locale" do
+ page.driver.add_header 'Accept-Language', 'de'
+ visit '/'
+ click_on 'Anmelden'
+ fill_in 'Nutzername', with: 'username'
+ fill_in 'Password', with: 'falsches password'
+ click_on 'Session erstellen'
+ assert_invalid_login(page, locale: :de)
+ end
+
test "account destruction" do
username, password = submit_signup
@@ -115,9 +125,10 @@ class AccountLivecycleTest < BrowserIntegrationTest
click_on 'Log In'
end
- def assert_invalid_login(page)
+ def assert_invalid_login(page, locale: nil)
assert page.has_selector? '.btn-primary.disabled'
- assert page.has_content? sanitize(I18n.t(:invalid_user_pass), tags: [])
+ message = I18n.t :invalid_user_pass, locale: locale
+ assert page.has_content? sanitize(message, tags: [])
assert page.has_no_selector? '.btn-primary.disabled'
end
diff --git a/test/unit/account_test.rb b/test/unit/account_test.rb
index 058e196..61b40b5 100644
--- a/test/unit/account_test.rb
+++ b/test/unit/account_test.rb
@@ -12,7 +12,7 @@ class AccountTest < ActiveSupport::TestCase
end
test "create a new account when invited" do
- user = Account.create(FactoryGirl.attributes_for(:user, :invite_code => @testcode.invite_code))
+ user = Account.create(user_attributes( :invite_code => @testcode.invite_code))
assert user.valid?, "unexpected errors: #{user.errors.inspect}"
assert user.persisted?
assert id = user.identity
@@ -23,7 +23,7 @@ class AccountTest < ActiveSupport::TestCase
test "fail to create account without invite" do
with_config invite_required: true do
- user = Account.create(FactoryGirl.attributes_for(:user))
+ user = Account.create(user_attributes)
assert !user.valid?, "user should not be valid"
assert !user.persisted?, "user should not have been saved"
assert_has_errors user, invite_code: "This is not a valid code"
@@ -32,7 +32,7 @@ class AccountTest < ActiveSupport::TestCase
test "allow invite_required override" do
with_config invite_required: true do
- user = Account.create(FactoryGirl.attributes_for(:user), :invite_required => false)
+ user = Account.create(user_attributes, :invite_required => false)
assert user.valid?, "unexpected errors: #{user.errors.inspect}"
assert user.persisted?, "user should have been saved"
user.account.destroy
@@ -41,7 +41,7 @@ class AccountTest < ActiveSupport::TestCase
test "create a new account" do
with_config invite_required: false do
- user = Account.create(FactoryGirl.attributes_for(:user))
+ user = Account.create(user_attributes)
assert user.valid?, "unexpected errors: #{user.errors.inspect}"
assert user.persisted?
user.account.destroy
@@ -50,7 +50,7 @@ class AccountTest < ActiveSupport::TestCase
test "error on reused username" do
with_config invite_required: false do
- attributes = FactoryGirl.attributes_for :user
+ attributes = user_attributes
user = Account.create attributes
dup = Account.create attributes
assert !dup.valid?
@@ -72,17 +72,17 @@ class AccountTest < ActiveSupport::TestCase
# We keep an identity that will block the handle from being reused.
assert_difference "Identity.count" do
assert_no_difference "User.count" do
- user = Account.create(FactoryGirl.attributes_for(:user, :invite_code => @testcode.invite_code))
+ user = Account.create(user_attributes( :invite_code => @testcode.invite_code))
user.account.destroy
end
end
end
test "change username and create alias" do
- user = Account.create(FactoryGirl.attributes_for(:user, :invite_code => @testcode.invite_code))
+ user = Account.create(user_attributes( :invite_code => @testcode.invite_code))
old_id = user.identity
old_email = user.email_address
- user.account.update(FactoryGirl.attributes_for(:user))
+ user.account.update(user_attributes)
user.reload
old_id.reload
assert user.valid?
@@ -97,7 +97,7 @@ class AccountTest < ActiveSupport::TestCase
end
test "create recovery code if it does not exist" do
- user = Account.create(FactoryGirl.attributes_for(:user, :invite_code => @testcode.invite_code))
+ user = Account.create(user_attributes( :invite_code => @testcode.invite_code))
user.account.update(:recovery_code_verifier => "abc", :recovery_code_salt => "123")
user.reload
@@ -108,7 +108,7 @@ class AccountTest < ActiveSupport::TestCase
end
test "update recovery code that already exists" do
- user = Account.create(FactoryGirl.attributes_for(:user,
+ user = Account.create(user_attributes(
:invite_code => @testcode.invite_code,
:recovery_code_verifier => "000",
:recovery_code_salt => "111"))
@@ -123,7 +123,7 @@ class AccountTest < ActiveSupport::TestCase
end
test "update password" do
- user = Account.create(FactoryGirl.attributes_for(:user, :invite_code => @testcode.invite_code))
+ user = Account.create(user_attributes( :invite_code => @testcode.invite_code))
user.account.update(:password_verifier => "551A8B", :password_salt => "551A8B")
assert_equal "551A8B", user.password_verifier
@@ -134,18 +134,38 @@ class AccountTest < ActiveSupport::TestCase
test "Invite code count goes up by 1 when the invite code is entered" do
with_config invite_required: true do
- user = Account.create(FactoryGirl.attributes_for(:user, :invite_code => @testcode.invite_code))
+ user = Account.create(user_attributes( :invite_code => @testcode.invite_code))
user_code = InviteCode.find_by_invite_code user.invite_code
- user_code.save
user.save
assert user.persisted?
assert_equal 1, user_code.invite_count
end
+ end
+
+ test "Single use invite code is destroyed when used by test user" do
+ with_config invite_required: true do
+ attrs = user_attributes invite_code: @testcode.invite_code
+ attrs[:login] = 'test_user_' + attrs[:login]
+ user = Account.create(attrs)
+ user.save
+ assert user.persisted?, user.errors.inspect
+ assert_nil InviteCode.find_by_invite_code user.invite_code
+ end
+ end
+ test "Single use invite code is destroyed when used by tmp user" do
+ with_config invite_required: true do
+ attrs = user_attributes invite_code: @testcode.invite_code
+ attrs[:login] = 'tmp_user_' + attrs[:login]
+ user = Account.create(attrs)
+ user.save
+ assert user.persisted?, user.errors.inspect
+ assert_nil InviteCode.find_by_invite_code user.invite_code
+ end
end
test "Invite code stays zero when invite code is not used" do
- #user = Account.create(FactoryGirl.attributes_for(:user, :invite_code => @testcode.invite_code))
+ #user = Account.create(user_attributes( :invite_code => @testcode.invite_code))
invalid_user = FactoryGirl.build(:user, :invite_code => @testcode.invite_code)
invalid_user.save
user_code = InviteCode.find_by_invite_code invalid_user.invite_code
@@ -155,7 +175,7 @@ class AccountTest < ActiveSupport::TestCase
end
test "disabled accounts have no cert fingerprints" do
- user = Account.create(FactoryGirl.attributes_for(:user))
+ user = Account.create(user_attributes)
cert = stub(expiry: 1.month.from_now, fingerprint: SecureRandom.hex)
user.identity.register_cert cert
user.identity.save
@@ -184,6 +204,8 @@ class AccountTest < ActiveSupport::TestCase
end
end
+ protected
+
# Tests for the presence of the errors given.
# Does not test for the absence of other errors - so there may be more.
def assert_has_errors(record, errors)
@@ -194,4 +216,8 @@ class AccountTest < ActiveSupport::TestCase
end
end
+ def user_attributes(attrs = {})
+ FactoryGirl.attributes_for :user, attrs
+ end
+
end