From e05a1b0f5ae40a2aa17976b3009cd563b8e4660a Mon Sep 17 00:00:00 2001
From: Azul <azul@riseup.net>
Date: Sun, 1 May 2016 10:55:33 -0300
Subject: api: allow version bumping - bump to 2

---
 test/functional/api/certs_controller_test.rb       |  60 ++++++++
 test/functional/api/identities_controller_test.rb  |  24 ++++
 test/functional/api/messages_controller_test.rb    |  99 +++++++++++++
 test/functional/api/services_controller_test.rb    |  28 ++++
 test/functional/api/sessions_controller_test.rb    |  62 +++++++++
 test/functional/api/smtp_certs_controller_test.rb  |  43 ++++++
 test/functional/api/token_auth_test.rb             |  40 ++++++
 test/functional/api/users_controller_test.rb       | 135 ++++++++++++++++++
 .../configs_controller_with_static_tokens_test.rb  |  40 ------
 test/functional/v1/certs_controller_test.rb        |  60 --------
 test/functional/v1/identities_controller_test.rb   |  24 ----
 test/functional/v1/messages_controller_test.rb     |  99 -------------
 test/functional/v1/services_controller_test.rb     |  28 ----
 test/functional/v1/sessions_controller_test.rb     |  62 ---------
 test/functional/v1/smtp_certs_controller_test.rb   |  43 ------
 test/functional/v1/users_controller_test.rb        | 135 ------------------
 test/integration/api/cert_test.rb                  |  11 +-
 test/integration/api/signup_test.rb                |   2 +-
 test/integration/api/smtp_cert_test.rb             |  14 +-
 test/integration/api/srp_test.rb                   |  18 ++-
 test/integration/api/token_auth_test.rb            |   2 +-
 test/integration/api/update_account_test.rb        |   2 +-
 .../browser/account_livecycle_test.rb.orig         | 153 +++++++++++++++++++++
 test/integration/browser/security_test.rb          |   2 +-
 test/support/api_integration_test.rb               |   4 +
 25 files changed, 682 insertions(+), 508 deletions(-)
 create mode 100644 test/functional/api/certs_controller_test.rb
 create mode 100644 test/functional/api/identities_controller_test.rb
 create mode 100644 test/functional/api/messages_controller_test.rb
 create mode 100644 test/functional/api/services_controller_test.rb
 create mode 100644 test/functional/api/sessions_controller_test.rb
 create mode 100644 test/functional/api/smtp_certs_controller_test.rb
 create mode 100644 test/functional/api/token_auth_test.rb
 create mode 100644 test/functional/api/users_controller_test.rb
 delete mode 100644 test/functional/configs_controller_with_static_tokens_test.rb
 delete mode 100644 test/functional/v1/certs_controller_test.rb
 delete mode 100644 test/functional/v1/identities_controller_test.rb
 delete mode 100644 test/functional/v1/messages_controller_test.rb
 delete mode 100644 test/functional/v1/services_controller_test.rb
 delete mode 100644 test/functional/v1/sessions_controller_test.rb
 delete mode 100644 test/functional/v1/smtp_certs_controller_test.rb
 delete mode 100644 test/functional/v1/users_controller_test.rb
 create mode 100644 test/integration/browser/account_livecycle_test.rb.orig

(limited to 'test')

diff --git a/test/functional/api/certs_controller_test.rb b/test/functional/api/certs_controller_test.rb
new file mode 100644
index 0000000..137ed92
--- /dev/null
+++ b/test/functional/api/certs_controller_test.rb
@@ -0,0 +1,60 @@
+require_relative '../../test_helper'
+
+class Api::CertsControllerTest < ActionController::TestCase
+
+  test "create unlimited cert without login" do
+    with_config allow_anonymous_certs: true do
+      cert = expect_cert('UNLIMITED')
+      post :create
+      assert_response :success
+      assert_equal cert.to_s, @response.body
+    end
+  end
+
+  test "create limited cert" do
+    with_config allow_limited_certs: true do
+      login
+      cert = expect_cert('LIMITED')
+      post :create
+      assert_response :success
+      assert_equal cert.to_s, @response.body
+    end
+  end
+
+  test "fail to create cert when disabled" do
+    login :enabled? => false
+    post :create
+    assert_access_denied
+  end
+
+  test "create unlimited cert" do
+    login effective_service_level: ServiceLevel.new(id: 2)
+    cert = expect_cert('UNLIMITED')
+    post :create
+    assert_response :success
+    assert_equal cert.to_s, @response.body
+  end
+
+  test "GET still works as an alias" do
+    login effective_service_level: ServiceLevel.new(id: 2)
+    cert = expect_cert('UNLIMITED')
+    get :show
+    assert_response :success
+    assert_equal cert.to_s, @response.body
+  end
+
+  test "redirect if no eip service offered" do
+    post :create
+    assert_response :redirect
+  end
+
+  protected
+
+  def expect_cert(prefix)
+    cert = stub :to_s => "#{prefix.downcase} cert"
+    ClientCertificate.expects(:new).
+      with(:prefix => prefix).
+      returns(cert)
+    return cert
+  end
+end
diff --git a/test/functional/api/identities_controller_test.rb b/test/functional/api/identities_controller_test.rb
new file mode 100644
index 0000000..e803ee7
--- /dev/null
+++ b/test/functional/api/identities_controller_test.rb
@@ -0,0 +1,24 @@
+require_relative '../../test_helper'
+
+class Api::IdentitiesControllerTest < ActionController::TestCase
+
+  test "api monitor can fetch identity" do
+    monitor_auth do
+      identity = FactoryGirl.create :identity
+      get :show, :id => identity.address, :format => 'json'
+      assert_response :success
+      assert_equal identity, assigns(:identity)
+
+      get :show, :id => "blahblahblah", :format => 'json'
+      assert_response :not_found
+    end
+  end
+
+
+  test "anonymous cannot fetch identity" do
+    identity = FactoryGirl.create :identity
+    get :show, :id => identity.address, :format => 'json'
+    assert_response :forbidden
+  end
+
+end
diff --git a/test/functional/api/messages_controller_test.rb b/test/functional/api/messages_controller_test.rb
new file mode 100644
index 0000000..01641d4
--- /dev/null
+++ b/test/functional/api/messages_controller_test.rb
@@ -0,0 +1,99 @@
+require 'test_helper'
+
+class Api::MessagesControllerTest < ActionController::TestCase
+
+  setup do
+    @user = FactoryGirl.build(:user)
+    @user.save
+  end
+
+  # NOTE: the available languages for test are :en and :de
+  # so :es will result in english response.
+
+  test "get the motd" do
+    with_config("customization_directory" => Rails.root+'test/files') do
+      login @user
+      get :index, :locale => 'es'
+      body = JSON.parse(response.body)
+      message1 = "<p>\"This\" is a <strong>very</strong> fine message. <a href=\"https://bitmask.net\">https://bitmask.net</a></p>\n"
+      assert_equal 2, body.size, 'there should be two messages'
+      assert_equal message1, body.first["text"], 'first message text should match files/motd/1.en.md'
+    end
+  end
+
+  test "get localized motd" do
+    with_config("customization_directory" => Rails.root+'test/files') do
+      login @user
+      get :index, :locale => 'de'
+      body = JSON.parse(response.body)
+      message1 = "<p>Dies ist eine sehr feine Nachricht. <a href=\"https://bitmask.net\">https://bitmask.net</a></p>\n"
+      assert_equal message1, body.first["text"], 'first message text should match files/motd/1.de.md'
+    end
+  end
+
+  test "get empty motd" do
+    login @user
+    get :index
+    assert_equal "[]", response.body, "motd response should be empty if no motd directory exists"
+  end
+
+  ##
+  ## For now, only the static file MOTD is supported, not messages in the db.
+  ## so, this is disabled:
+  ##
+=begin
+  setup do
+    InviteCodeValidator.any_instance.stubs(:validate)
+    @user = FactoryGirl.build(:user)
+    @user.save
+    @message = Message.new(:text => 'a test message')
+    @message.user_ids_to_show << @user.id
+    @message.save
+  end
+
+  teardown do
+    @message.destroy
+    @user.destroy
+  end
+
+  test "get messages for user" do
+    login @user
+    get :index
+    assert response.body.include? @message.text
+    assert response.body.include? @message.id
+  end
+
+  test "mark message read for user" do
+    login @user
+    assert @message.user_ids_to_show.include?(@user.id)
+    assert !@message.user_ids_have_shown.include?(@user.id)
+    put :update, :id => @message.id
+    @message.reload
+    assert !@message.user_ids_to_show.include?(@user.id)
+    assert @message.user_ids_have_shown.include?(@user.id)
+    assert_success :marked_as_read
+  end
+
+  test "do not get seen messages" do
+    login @user
+    put :update, :id => @message.id
+    @message.reload
+    get :index
+    assert !(response.body.include? @message.text)
+    assert !(response.body.include? @message.id)
+  end
+
+
+  test "mark read responds even with bad inputs" do
+    login @user
+    put :update, :id => 'more nonsense'
+    assert_not_found
+ end
+
+  test "fails if not authenticated" do
+    get :index, :format => :json
+    assert_login_required
+  end
+=end
+
+end
diff --git a/test/functional/api/services_controller_test.rb b/test/functional/api/services_controller_test.rb
new file mode 100644
index 0000000..b1dc9f3
--- /dev/null
+++ b/test/functional/api/services_controller_test.rb
@@ -0,0 +1,28 @@
+require 'test_helper'
+
+class Api::ServicesControllerTest < ActionController::TestCase
+
+  test "anonymous user gets login required service info" do
+    get :show, format: :json
+    assert_json_response error: 'not_authorized_login',
+      message: 'Please log in to perform that action.'
+  end
+
+  test "anonymous user gets vpn service info" do
+    with_config allow_anonymous_certs: true do
+      get :show, format: :json
+      assert_json_response name: 'anonymous',
+        eip_rate_limit: false,
+        description: 'anonymous access to the VPN'
+    end
+  end
+
+  test "user can see their service info" do
+    login
+    get :show, format: :json
+    default_level = APP_CONFIG[:default_service_level]
+    assert_json_response APP_CONFIG[:service_levels][default_level]
+  end
+
+end
+
diff --git a/test/functional/api/sessions_controller_test.rb b/test/functional/api/sessions_controller_test.rb
new file mode 100644
index 0000000..0633578
--- /dev/null
+++ b/test/functional/api/sessions_controller_test.rb
@@ -0,0 +1,62 @@
+require 'test_helper'
+
+# This is a simple controller unit test.
+# We're stubbing out both warden and srp.
+# There's an integration test testing the full rack stack and srp
+class Api::SessionsControllerTest < ActionController::TestCase
+
+  setup do
+    @request.env['HTTP_HOST'] = 'api.lvh.me'
+    @user = stub_record :user, {}, true
+    @client_hex = 'a123'
+  end
+
+  test "renders json" do
+    get :new, :format => :json
+    assert_response :success
+    assert_json_error nil
+  end
+
+  test "renders warden errors" do
+    request.env['warden.options'] = {attempted_path: 'path/to/controller'}
+    strategy = stub :message => {:field => :translate_me}
+    request.env['warden'].stubs(:winning_strategy).returns(strategy)
+    I18n.expects(:t).with(:translate_me).at_least_once.returns("translation stub")
+    get :new, :format => :json
+    assert_response 422
+    assert_json_error :field => "translation stub"
+  end
+
+  # Warden takes care of parsing the params and
+  # rendering the response. So not much to test here.
+  test "should perform handshake" do
+    request.env['warden'].expects(:authenticate!)
+    # make sure we don't get a template missing error:
+    @controller.stubs(:render)
+    post :create, :login => @user.login, 'A' => @client_hex
+  end
+
+  test "should authenticate" do
+    request.env['warden'].expects(:authenticate!)
+    @controller.stubs(:current_user).returns(@user)
+    handshake = stub(:to_hash => {h: "ash"})
+    session[:handshake] = handshake
+
+    post :update, :id => @user.login, :client_auth => @client_hex
+
+    assert_nil session[:handshake]
+    assert_response :success
+    assert json_response.keys.include?("id")
+    assert json_response.keys.include?("token")
+    assert token = Token.find_by_token(json_response['token'])
+    assert_equal @user.id, token.user_id
+  end
+
+  test "destroy should logout" do
+    login
+    expect_logout
+    delete :destroy
+    assert_response 204
+  end
+
+end
diff --git a/test/functional/api/smtp_certs_controller_test.rb b/test/functional/api/smtp_certs_controller_test.rb
new file mode 100644
index 0000000..2142675
--- /dev/null
+++ b/test/functional/api/smtp_certs_controller_test.rb
@@ -0,0 +1,43 @@
+require 'test_helper'
+
+class Api::SmtpCertsControllerTest < ActionController::TestCase
+
+  test "no smtp cert without login" do
+    with_config allow_anonymous_certs: true do
+      post :create
+      assert_login_required
+    end
+  end
+
+  test "require service level with email" do
+    login
+    post :create
+    assert_access_denied
+  end
+
+  test "send cert with username" do
+    login effective_service_level: ServiceLevel.new(id: 2)
+    cert = expect_cert(@current_user.email_address)
+    cert.expects(:fingerprint).returns('fingerprint')
+    post :create
+    assert_response :success
+    assert_equal cert.to_s, @response.body
+  end
+
+  test "fail to create cert when disabled" do
+    login :enabled? => false
+    post :create
+    assert_access_denied
+  end
+
+  protected
+
+  def expect_cert(email)
+    cert = stub to_s: "#{email.downcase} cert",
+      expiry: 1.month.from_now.utc.at_midnight
+    ClientCertificate.expects(:new).
+      with(:common_name => email).
+      returns(cert)
+    return cert
+  end
+end
diff --git a/test/functional/api/token_auth_test.rb b/test/functional/api/token_auth_test.rb
new file mode 100644
index 0000000..17a4775
--- /dev/null
+++ b/test/functional/api/token_auth_test.rb
@@ -0,0 +1,40 @@
+#
+# tests for authenticating an admin or monitor user
+# via static configured tokens.
+#
+
+require 'test_helper'
+
+class Api::TokenAuthTest < ActionController::TestCase
+  tests Api::ConfigsController
+
+  def test_login_via_api_token
+    with_config(:allow_anonymous_certs => false) do
+      monitor_auth do
+        get :index
+        assert assigns(:token), 'should have authenticated via api token'
+        assert assigns(:token).is_a? ApiToken
+        assert @controller.send(:current_user).is_a? ApiMonitorUser
+      end
+    end
+  end
+
+  def test_fail_api_auth_when_ip_not_allowed
+    with_config(:allow_anonymous_certs => false) do
+      allowed = "99.99.99.99"
+      new_config = {api_tokens: APP_CONFIG["api_tokens"].merge(allowed_ips: [allowed])}
+      with_config(new_config) do
+        monitor_auth do
+          request.env['REMOTE_ADDR'] = "1.1.1.1"
+          get :index
+          assert_nil assigns(:token), "should not be able to auth with api token when ip restriction doesn't allow it"
+          request.env['REMOTE_ADDR'] = allowed
+          get :index
+          assert assigns(:token), "should have authenticated via api token"
+        end
+      end
+    end
+  end
+
+end
+
diff --git a/test/functional/api/users_controller_test.rb b/test/functional/api/users_controller_test.rb
new file mode 100644
index 0000000..bc2e312
--- /dev/null
+++ b/test/functional/api/users_controller_test.rb
@@ -0,0 +1,135 @@
+require_relative '../../test_helper'
+
+class Api::UsersControllerTest < ActionController::TestCase
+
+  test "user can change settings" do
+    user = find_record :user
+    changed_attribs = record_attributes_for :user_with_settings
+    account_settings = stub
+    account_settings.expects(:update).with(changed_attribs)
+    Account.expects(:new).with(user).returns(account_settings)
+
+    login user
+    put :update, :user => changed_attribs, :id => user.id, :format => :json
+
+    assert_equal user, assigns[:user]
+    assert_response 204
+    assert @response.body.blank?, "Response should be blank"
+  end
+
+  test "admin can update user" do
+    user = find_record :user
+    changed_attribs = record_attributes_for :user_with_settings
+    account_settings = stub
+    account_settings.expects(:update).with(changed_attribs)
+    Account.expects(:new).with(user).returns(account_settings)
+
+    login :is_admin? => true
+    put :update, :user => changed_attribs, :id => user.id, :format => :json
+
+    assert_equal user, assigns[:user]
+    assert_response 204
+  end
+
+  test "user cannot update other user" do
+    user = find_record :user
+    login
+    put :update, id: user.id,
+      user: record_attributes_for(:user_with_settings),
+      :format => :json
+    assert_access_denied
+  end
+
+  test "should create new user" do
+    user_attribs = record_attributes_for :user
+    user = User.new(user_attribs)
+    Account.expects(:create).with(user_attribs).returns(user)
+
+    post :create, :user => user_attribs, :format => :json
+
+    assert_nil session[:user_id]
+    assert_json_response user
+    assert_response :success
+  end
+
+  test "should redirect to signup form on failed attempt" do
+    user_attribs = record_attributes_for :user
+    user_attribs.slice!('login')
+    user = User.new(user_attribs)
+    assert !user.valid?
+    Account.expects(:create).with(user_attribs).returns(user)
+
+    post :create, :user => user_attribs, :format => :json
+
+    assert_json_error user.errors.messages
+    assert_response 422
+  end
+
+  test "admin can autocomplete users" do
+    login :is_admin? => true
+    get :index, :query => 'a', :format => :json
+
+    assert_response :success
+    assert assigns(:users)
+  end
+
+  test "create returns forbidden if registration is closed" do
+    user_attribs = record_attributes_for :user
+    with_config(allow_registration: false) do
+      post :create, :user => user_attribs, :format => :json
+      assert_response :forbidden
+    end
+  end
+
+  test "admin can show user" do
+    user = FactoryGirl.create :user
+    login :is_admin? => true
+    get :show, :id => 0, :login => user.login, :format => :json
+    assert_response :success
+    assert_json_response user
+    get :show, :id => user.id, :format => :json
+    assert_response :success
+    assert_json_response user
+    get :show, :id => "0", :format => :json
+    assert_response :not_found
+  end
+
+  test "normal users cannot show user" do
+    user = find_record :user
+    login
+    get :show, :id => 0, :login => user.login, :format => :json
+    assert_access_denied
+  end
+
+  test "api monitor auth can create and destroy test users" do
+    # should work even with registration off and/or invites required
+    with_config(allow_registration: false, invite_required: true) do
+      monitor_auth do
+        user_attribs = record_attributes_for :test_user
+        post :create, :user => user_attribs, :format => :json
+        assert_response :success
+        delete :destroy, :id => assigns(:user).id, :format => :json
+        assert_response :success
+      end
+    end
+  end
+
+  test "api monitor auth cannot create normal users" do
+    monitor_auth do
+      user_attribs = record_attributes_for :user
+      post :create, :user => user_attribs, :format => :json
+      assert_response :forbidden
+    end
+  end
+
+  test "api monitor auth cannot delete normal users" do
+    post :create, :user => record_attributes_for(:user), :format => :json
+    assert_response :success
+    normal_user_id = assigns(:user).id
+    monitor_auth do
+      delete :destroy, :id => normal_user_id, :format => :json
+      assert_response :forbidden
+    end
+  end
+
+end
diff --git a/test/functional/configs_controller_with_static_tokens_test.rb b/test/functional/configs_controller_with_static_tokens_test.rb
deleted file mode 100644
index 79739fe..0000000
--- a/test/functional/configs_controller_with_static_tokens_test.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-#
-# tests for authenticating an admin or monitor user
-# via static configured tokens.
-#
-
-require 'test_helper'
-
-class ConfigsControllerWithStaticTokensTest < ActionController::TestCase
-  tests V1::ConfigsController
-
-  def test_login_via_api_token
-    with_config(:allow_anonymous_certs => false) do
-      monitor_auth do
-        get :index
-        assert assigns(:token), 'should have authenticated via api token'
-        assert assigns(:token).is_a? ApiToken
-        assert @controller.send(:current_user).is_a? ApiMonitorUser
-      end
-    end
-  end
-
-  def test_fail_api_auth_when_ip_not_allowed
-    with_config(:allow_anonymous_certs => false) do
-      allowed = "99.99.99.99"
-      new_config = {api_tokens: APP_CONFIG["api_tokens"].merge(allowed_ips: [allowed])}
-      with_config(new_config) do
-        monitor_auth do
-          request.env['REMOTE_ADDR'] = "1.1.1.1"
-          get :index
-          assert_nil assigns(:token), "should not be able to auth with api token when ip restriction doesn't allow it"
-          request.env['REMOTE_ADDR'] = allowed
-          get :index
-          assert assigns(:token), "should have authenticated via api token"
-        end
-      end
-    end
-  end
-
-end
-
diff --git a/test/functional/v1/certs_controller_test.rb b/test/functional/v1/certs_controller_test.rb
deleted file mode 100644
index 04c1c86..0000000
--- a/test/functional/v1/certs_controller_test.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-require_relative '../../test_helper'
-
-class V1::CertsControllerTest < ActionController::TestCase
-
-  test "create unlimited cert without login" do
-    with_config allow_anonymous_certs: true do
-      cert = expect_cert('UNLIMITED')
-      post :create
-      assert_response :success
-      assert_equal cert.to_s, @response.body
-    end
-  end
-
-  test "create limited cert" do
-    with_config allow_limited_certs: true do
-      login
-      cert = expect_cert('LIMITED')
-      post :create
-      assert_response :success
-      assert_equal cert.to_s, @response.body
-    end
-  end
-
-  test "fail to create cert when disabled" do
-    login :enabled? => false
-    post :create
-    assert_access_denied
-  end
-
-  test "create unlimited cert" do
-    login effective_service_level: ServiceLevel.new(id: 2)
-    cert = expect_cert('UNLIMITED')
-    post :create
-    assert_response :success
-    assert_equal cert.to_s, @response.body
-  end
-
-  test "GET still works as an alias" do
-    login effective_service_level: ServiceLevel.new(id: 2)
-    cert = expect_cert('UNLIMITED')
-    get :show
-    assert_response :success
-    assert_equal cert.to_s, @response.body
-  end
-
-  test "redirect if no eip service offered" do
-    post :create
-    assert_response :redirect
-  end
-
-  protected
-
-  def expect_cert(prefix)
-    cert = stub :to_s => "#{prefix.downcase} cert"
-    ClientCertificate.expects(:new).
-      with(:prefix => prefix).
-      returns(cert)
-    return cert
-  end
-end
diff --git a/test/functional/v1/identities_controller_test.rb b/test/functional/v1/identities_controller_test.rb
deleted file mode 100644
index 6410c44..0000000
--- a/test/functional/v1/identities_controller_test.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../test_helper'
-
-class V1::IdentitiesControllerTest < ActionController::TestCase
-
-  test "api monitor can fetch identity" do
-    monitor_auth do
-      identity = FactoryGirl.create :identity
-      get :show, :id => identity.address, :format => 'json'
-      assert_response :success
-      assert_equal identity, assigns(:identity)
-
-      get :show, :id => "blahblahblah", :format => 'json'
-      assert_response :not_found
-    end
-  end
-
-
-  test "anonymous cannot fetch identity" do
-    identity = FactoryGirl.create :identity
-    get :show, :id => identity.address, :format => 'json'
-    assert_response :forbidden
-  end
-
-end
diff --git a/test/functional/v1/messages_controller_test.rb b/test/functional/v1/messages_controller_test.rb
deleted file mode 100644
index f37cca0..0000000
--- a/test/functional/v1/messages_controller_test.rb
+++ /dev/null
@@ -1,99 +0,0 @@
-require 'test_helper'
-
-class V1::MessagesControllerTest < ActionController::TestCase
-
-  setup do
-    @user = FactoryGirl.build(:user)
-    @user.save
-  end
-
-  # NOTE: the available languages for test are :en and :de
-  # so :es will result in english response.
-
-  test "get the motd" do
-    with_config("customization_directory" => Rails.root+'test/files') do
-      login @user
-      get :index, :locale => 'es'
-      body = JSON.parse(response.body)
-      message1 = "<p>\"This\" is a <strong>very</strong> fine message. <a href=\"https://bitmask.net\">https://bitmask.net</a></p>\n"
-      assert_equal 2, body.size, 'there should be two messages'
-      assert_equal message1, body.first["text"], 'first message text should match files/motd/1.en.md'
-    end
-  end
-
-  test "get localized motd" do
-    with_config("customization_directory" => Rails.root+'test/files') do
-      login @user
-      get :index, :locale => 'de'
-      body = JSON.parse(response.body)
-      message1 = "<p>Dies ist eine sehr feine Nachricht. <a href=\"https://bitmask.net\">https://bitmask.net</a></p>\n"
-      assert_equal message1, body.first["text"], 'first message text should match files/motd/1.de.md'
-    end
-  end
-
-  test "get empty motd" do
-    login @user
-    get :index
-    assert_equal "[]", response.body, "motd response should be empty if no motd directory exists"
-  end
-
-  ##
-  ## For now, only the static file MOTD is supported, not messages in the db.
-  ## so, this is disabled:
-  ##
-=begin
-  setup do
-    InviteCodeValidator.any_instance.stubs(:validate)
-    @user = FactoryGirl.build(:user)
-    @user.save
-    @message = Message.new(:text => 'a test message')
-    @message.user_ids_to_show << @user.id
-    @message.save
-  end
-
-  teardown do
-    @message.destroy
-    @user.destroy
-  end
-
-  test "get messages for user" do
-    login @user
-    get :index
-    assert response.body.include? @message.text
-    assert response.body.include? @message.id
-  end
-
-  test "mark message read for user" do
-    login @user
-    assert @message.user_ids_to_show.include?(@user.id)
-    assert !@message.user_ids_have_shown.include?(@user.id)
-    put :update, :id => @message.id
-    @message.reload
-    assert !@message.user_ids_to_show.include?(@user.id)
-    assert @message.user_ids_have_shown.include?(@user.id)
-    assert_success :marked_as_read
-  end
-
-  test "do not get seen messages" do
-    login @user
-    put :update, :id => @message.id
-    @message.reload
-    get :index
-    assert !(response.body.include? @message.text)
-    assert !(response.body.include? @message.id)
-  end
-
-
-  test "mark read responds even with bad inputs" do
-    login @user
-    put :update, :id => 'more nonsense'
-    assert_not_found
- end
-
-  test "fails if not authenticated" do
-    get :index, :format => :json
-    assert_login_required
-  end
-=end
-
-end
diff --git a/test/functional/v1/services_controller_test.rb b/test/functional/v1/services_controller_test.rb
deleted file mode 100644
index 039eb27..0000000
--- a/test/functional/v1/services_controller_test.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require 'test_helper'
-
-class V1::ServicesControllerTest < ActionController::TestCase
-
-  test "anonymous user gets login required service info" do
-    get :show, format: :json
-    assert_json_response error: 'not_authorized_login',
-      message: 'Please log in to perform that action.'
-  end
-
-  test "anonymous user gets vpn service info" do
-    with_config allow_anonymous_certs: true do
-      get :show, format: :json
-      assert_json_response name: 'anonymous',
-        eip_rate_limit: false,
-        description: 'anonymous access to the VPN'
-    end
-  end
-
-  test "user can see their service info" do
-    login
-    get :show, format: :json
-    default_level = APP_CONFIG[:default_service_level]
-    assert_json_response APP_CONFIG[:service_levels][default_level]
-  end
-
-end
-
diff --git a/test/functional/v1/sessions_controller_test.rb b/test/functional/v1/sessions_controller_test.rb
deleted file mode 100644
index 8bb6acd..0000000
--- a/test/functional/v1/sessions_controller_test.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-require 'test_helper'
-
-# This is a simple controller unit test.
-# We're stubbing out both warden and srp.
-# There's an integration test testing the full rack stack and srp
-class V1::SessionsControllerTest < ActionController::TestCase
-
-  setup do
-    @request.env['HTTP_HOST'] = 'api.lvh.me'
-    @user = stub_record :user, {}, true
-    @client_hex = 'a123'
-  end
-
-  test "renders json" do
-    get :new, :format => :json
-    assert_response :success
-    assert_json_error nil
-  end
-
-  test "renders warden errors" do
-    request.env['warden.options'] = {attempted_path: 'path/to/controller'}
-    strategy = stub :message => {:field => :translate_me}
-    request.env['warden'].stubs(:winning_strategy).returns(strategy)
-    I18n.expects(:t).with(:translate_me).at_least_once.returns("translation stub")
-    get :new, :format => :json
-    assert_response 422
-    assert_json_error :field => "translation stub"
-  end
-
-  # Warden takes care of parsing the params and
-  # rendering the response. So not much to test here.
-  test "should perform handshake" do
-    request.env['warden'].expects(:authenticate!)
-    # make sure we don't get a template missing error:
-    @controller.stubs(:render)
-    post :create, :login => @user.login, 'A' => @client_hex
-  end
-
-  test "should authenticate" do
-    request.env['warden'].expects(:authenticate!)
-    @controller.stubs(:current_user).returns(@user)
-    handshake = stub(:to_hash => {h: "ash"})
-    session[:handshake] = handshake
-
-    post :update, :id => @user.login, :client_auth => @client_hex
-
-    assert_nil session[:handshake]
-    assert_response :success
-    assert json_response.keys.include?("id")
-    assert json_response.keys.include?("token")
-    assert token = Token.find_by_token(json_response['token'])
-    assert_equal @user.id, token.user_id
-  end
-
-  test "destroy should logout" do
-    login
-    expect_logout
-    delete :destroy
-    assert_response 204
-  end
-
-end
diff --git a/test/functional/v1/smtp_certs_controller_test.rb b/test/functional/v1/smtp_certs_controller_test.rb
deleted file mode 100644
index 1b03995..0000000
--- a/test/functional/v1/smtp_certs_controller_test.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-require 'test_helper'
-
-class V1::SmtpCertsControllerTest < ActionController::TestCase
-
-  test "no smtp cert without login" do
-    with_config allow_anonymous_certs: true do
-      post :create
-      assert_login_required
-    end
-  end
-
-  test "require service level with email" do
-    login
-    post :create
-    assert_access_denied
-  end
-
-  test "send cert with username" do
-    login effective_service_level: ServiceLevel.new(id: 2)
-    cert = expect_cert(@current_user.email_address)
-    cert.expects(:fingerprint).returns('fingerprint')
-    post :create
-    assert_response :success
-    assert_equal cert.to_s, @response.body
-  end
-
-  test "fail to create cert when disabled" do
-    login :enabled? => false
-    post :create
-    assert_access_denied
-  end
-
-  protected
-
-  def expect_cert(email)
-    cert = stub to_s: "#{email.downcase} cert",
-      expiry: 1.month.from_now.utc.at_midnight
-    ClientCertificate.expects(:new).
-      with(:common_name => email).
-      returns(cert)
-    return cert
-  end
-end
diff --git a/test/functional/v1/users_controller_test.rb b/test/functional/v1/users_controller_test.rb
deleted file mode 100644
index 3f7bad3..0000000
--- a/test/functional/v1/users_controller_test.rb
+++ /dev/null
@@ -1,135 +0,0 @@
-require_relative '../../test_helper'
-
-class V1::UsersControllerTest < ActionController::TestCase
-
-  test "user can change settings" do
-    user = find_record :user
-    changed_attribs = record_attributes_for :user_with_settings
-    account_settings = stub
-    account_settings.expects(:update).with(changed_attribs)
-    Account.expects(:new).with(user).returns(account_settings)
-
-    login user
-    put :update, :user => changed_attribs, :id => user.id, :format => :json
-
-    assert_equal user, assigns[:user]
-    assert_response 204
-    assert @response.body.blank?, "Response should be blank"
-  end
-
-  test "admin can update user" do
-    user = find_record :user
-    changed_attribs = record_attributes_for :user_with_settings
-    account_settings = stub
-    account_settings.expects(:update).with(changed_attribs)
-    Account.expects(:new).with(user).returns(account_settings)
-
-    login :is_admin? => true
-    put :update, :user => changed_attribs, :id => user.id, :format => :json
-
-    assert_equal user, assigns[:user]
-    assert_response 204
-  end
-
-  test "user cannot update other user" do
-    user = find_record :user
-    login
-    put :update, id: user.id,
-      user: record_attributes_for(:user_with_settings),
-      :format => :json
-    assert_access_denied
-  end
-
-  test "should create new user" do
-    user_attribs = record_attributes_for :user
-    user = User.new(user_attribs)
-    Account.expects(:create).with(user_attribs).returns(user)
-
-    post :create, :user => user_attribs, :format => :json
-
-    assert_nil session[:user_id]
-    assert_json_response user
-    assert_response :success
-  end
-
-  test "should redirect to signup form on failed attempt" do
-    user_attribs = record_attributes_for :user
-    user_attribs.slice!('login')
-    user = User.new(user_attribs)
-    assert !user.valid?
-    Account.expects(:create).with(user_attribs).returns(user)
-
-    post :create, :user => user_attribs, :format => :json
-
-    assert_json_error user.errors.messages
-    assert_response 422
-  end
-
-  test "admin can autocomplete users" do
-    login :is_admin? => true
-    get :index, :query => 'a', :format => :json
-
-    assert_response :success
-    assert assigns(:users)
-  end
-
-  test "create returns forbidden if registration is closed" do
-    user_attribs = record_attributes_for :user
-    with_config(allow_registration: false) do
-      post :create, :user => user_attribs, :format => :json
-      assert_response :forbidden
-    end
-  end
-
-  test "admin can show user" do
-    user = FactoryGirl.create :user
-    login :is_admin? => true
-    get :show, :id => 0, :login => user.login, :format => :json
-    assert_response :success
-    assert_json_response user
-    get :show, :id => user.id, :format => :json
-    assert_response :success
-    assert_json_response user
-    get :show, :id => "0", :format => :json
-    assert_response :not_found
-  end
-
-  test "normal users cannot show user" do
-    user = find_record :user
-    login
-    get :show, :id => 0, :login => user.login, :format => :json
-    assert_access_denied
-  end
-
-  test "api monitor auth can create and destroy test users" do
-    # should work even with registration off and/or invites required
-    with_config(allow_registration: false, invite_required: true) do
-      monitor_auth do
-        user_attribs = record_attributes_for :test_user
-        post :create, :user => user_attribs, :format => :json
-        assert_response :success
-        delete :destroy, :id => assigns(:user).id, :format => :json
-        assert_response :success
-      end
-    end
-  end
-
-  test "api monitor auth cannot create normal users" do
-    monitor_auth do
-      user_attribs = record_attributes_for :user
-      post :create, :user => user_attribs, :format => :json
-      assert_response :forbidden
-    end
-  end
-
-  test "api monitor auth cannot delete normal users" do
-    post :create, :user => record_attributes_for(:user), :format => :json
-    assert_response :success
-    normal_user_id = assigns(:user).id
-    monitor_auth do
-      delete :destroy, :id => normal_user_id, :format => :json
-      assert_response :forbidden
-    end
-  end
-
-end
diff --git a/test/integration/api/cert_test.rb b/test/integration/api/cert_test.rb
index 772901d..289d3c6 100644
--- a/test/integration/api/cert_test.rb
+++ b/test/integration/api/cert_test.rb
@@ -5,7 +5,7 @@ class CertTest < ApiIntegrationTest
 
   test "retrieve eip cert" do
     login
-    get '/1/cert', {}, RACK_ENV
+    get cert_url, {}, RACK_ENV
     assert_text_response
     assert_response_includes "BEGIN RSA PRIVATE KEY"
     assert_response_includes "END RSA PRIVATE KEY"
@@ -14,13 +14,13 @@ class CertTest < ApiIntegrationTest
   end
 
   test "fetching certs requires login by default" do
-    get '/1/cert', {}, RACK_ENV
+    get cert_url, {}, RACK_ENV
     assert_login_required
   end
 
   test "retrieve anonymous eip cert" do
     with_config allow_anonymous_certs: true do
-      get '/1/cert', {}, RACK_ENV
+      get cert_url, {}, RACK_ENV
       assert_text_response
       assert_response_includes "BEGIN RSA PRIVATE KEY"
       assert_response_includes "END RSA PRIVATE KEY"
@@ -28,4 +28,9 @@ class CertTest < ApiIntegrationTest
       assert_response_includes "END CERTIFICATE"
     end
   end
+
+  def cert_url
+    "/#{api_version}/cert"
+  end
+
 end
diff --git a/test/integration/api/signup_test.rb b/test/integration/api/signup_test.rb
index 7216496..dc24420 100644
--- a/test/integration/api/signup_test.rb
+++ b/test/integration/api/signup_test.rb
@@ -1,4 +1,4 @@
-require_relative '../../test_helper'
+require 'test_helper'
 require_relative 'srp_test'
 
 class SignupTest < SrpTest
diff --git a/test/integration/api/smtp_cert_test.rb b/test/integration/api/smtp_cert_test.rb
index 681d509..53382c1 100644
--- a/test/integration/api/smtp_cert_test.rb
+++ b/test/integration/api/smtp_cert_test.rb
@@ -11,7 +11,7 @@ class SmtpCertTest < ApiIntegrationTest
   test "retrieve smtp cert" do
     @user = FactoryGirl.create :user, effective_service_level_code: 2, :invite_code => @testcode.invite_code
     login
-    post '/1/smtp_cert', {}, RACK_ENV
+    post smtp_cert_url, {}, RACK_ENV
     assert_text_response
     assert_response_includes "BEGIN RSA PRIVATE KEY"
     assert_response_includes "END RSA PRIVATE KEY"
@@ -22,7 +22,7 @@ class SmtpCertTest < ApiIntegrationTest
   test "cert and key" do
     @user = FactoryGirl.create :user, effective_service_level_code: 2, :invite_code => @testcode.invite_code
     login
-    post '/1/smtp_cert', {}, RACK_ENV
+    post smtp_cert_url, {}, RACK_ENV
     assert_text_response
     cert = OpenSSL::X509::Certificate.new(get_response.body)
     key = OpenSSL::PKey::RSA.new(get_response.body)
@@ -34,7 +34,7 @@ class SmtpCertTest < ApiIntegrationTest
   test "fingerprint is stored with identity" do
     @user = FactoryGirl.create :user, effective_service_level_code: 2, :invite_code => @testcode.invite_code
     login
-    post '/1/smtp_cert', {}, RACK_ENV
+    post smtp_cert_url, {}, RACK_ENV
     assert_text_response
     cert = OpenSSL::X509::Certificate.new(get_response.body)
     fingerprint = OpenSSL::Digest::SHA1.hexdigest(cert.to_der).scan(/../).join(':')
@@ -48,14 +48,18 @@ class SmtpCertTest < ApiIntegrationTest
   test "fetching smtp certs requires email account" do
 
     login
-    post '/1/smtp_cert', {}, RACK_ENV
+    post smtp_cert_url, {}, RACK_ENV
     assert_access_denied
   end
 
   test "no anonymous smtp certs" do
     with_config allow_anonymous_certs: true do
-      post '/1/smtp_cert', {}, RACK_ENV
+      post smtp_cert_url, {}, RACK_ENV
       assert_login_required
     end
   end
+
+  def smtp_cert_url
+    "/#{api_version}/smtp_cert"
+  end
 end
diff --git a/test/integration/api/srp_test.rb b/test/integration/api/srp_test.rb
index 463abcd..b9605f9 100644
--- a/test/integration/api/srp_test.rb
+++ b/test/integration/api/srp_test.rb
@@ -14,7 +14,7 @@ class SrpTest < RackTest
 
   # this test wraps the api and implements the interface the ruby-srp client.
   def handshake(login, aa)
-    post "http://api.lvh.me:3000/1/sessions.json",
+    post api_url("sessions.json"),
       :login => login,
       'A' => aa,
       :format => :json
@@ -27,7 +27,7 @@ class SrpTest < RackTest
   end
 
   def validate(m)
-    put "http://api.lvh.me:3000/1/sessions/" + @login + '.json',
+    put api_url("sessions/#{@login}.json"),
       :client_auth => m,
       :format => :json
     return JSON.parse(last_response.body)
@@ -39,7 +39,7 @@ class SrpTest < RackTest
 
   def register_user(login = "integration_test", password = 'srp, verify me!', invite_code = @testcode.invite_code)
     cleanup_user(login)
-    post 'http://api.lvh.me:3000/1/users.json',
+    post api_url('users.json'),
       user_params(login: login, password: password, invite_code: invite_code)
     assert(@user = User.find_by_login(login), 'user should have been created: %s' % last_response_errors)
     @login = login
@@ -47,7 +47,7 @@ class SrpTest < RackTest
   end
 
   def update_user(params)
-    put "http://api.lvh.me:3000/1/users/" + @user.id + '.json',
+    put api_url("users/#{@user.id}.json"),
       user_params(params),
       auth_headers
   end
@@ -68,7 +68,7 @@ class SrpTest < RackTest
   end
 
   def logout(params=nil, headers=nil)
-    delete "http://api.lvh.me:3000/1/logout.json",
+    delete api_url("logout.json"),
       params || {format: :json},
       headers || auth_headers
   end
@@ -112,4 +112,12 @@ class SrpTest < RackTest
   rescue
     ""
   end
+
+  def api_url(path)
+    "http://api.lvh.me:3000/#{api_version}/#{path}"
+  end
+
+  def api_version
+    2
+  end
 end
diff --git a/test/integration/api/token_auth_test.rb b/test/integration/api/token_auth_test.rb
index 3b83f23..7b20b00 100644
--- a/test/integration/api/token_auth_test.rb
+++ b/test/integration/api/token_auth_test.rb
@@ -1,4 +1,4 @@
-require_relative '../../test_helper'
+require 'test_helper'
 require_relative 'srp_test'
 
 class TokenAuthTest < SrpTest
diff --git a/test/integration/api/update_account_test.rb b/test/integration/api/update_account_test.rb
index 16bbb8c..1492006 100644
--- a/test/integration/api/update_account_test.rb
+++ b/test/integration/api/update_account_test.rb
@@ -14,7 +14,7 @@ class UpdateAccountTest < SrpTest
 
   test "require token" do
     authenticate
-    put "http://api.lvh.me:3000/1/users/" + @user.id + '.json',
+    put "http://api.lvh.me:3000/2/users/" + @user.id + '.json',
       user_params(password: "No! Verify me instead.")
     assert_login_required
   end
diff --git a/test/integration/browser/account_livecycle_test.rb.orig b/test/integration/browser/account_livecycle_test.rb.orig
new file mode 100644
index 0000000..d1f800b
--- /dev/null
+++ b/test/integration/browser/account_livecycle_test.rb.orig
@@ -0,0 +1,153 @@
+require 'test_helper'
+
+class AccountLivecycleTest < BrowserIntegrationTest
+
+  teardown do
+    Identity.destroy_all_orphaned
+  end
+
+  test "signup successfully when invited" do
+    username, password = submit_signup
+    assert page.has_content?("Welcome #{username}")
+    click_on 'Log Out'
+    assert page.has_content?("Log In")
+    assert_equal '/', current_path
+    assert user = User.find_by_login(username)
+    user.account.destroy
+  end
+
+  test "signup successfully without invitation" do
+    with_config invite_required: false do
+
+      username ||= "test_#{SecureRandom.urlsafe_base64}".downcase
+      password ||= SecureRandom.base64
+
+      visit '/users/new'
+      fill_in 'Username', with: username
+      fill_in 'Password', with: password
+      fill_in 'Password confirmation', with: password
+      click_on 'Sign Up'
+
+      assert page.has_content?("Welcome #{username}")
+    end
+  end
+
+  test "signup with username ending in dot json" do
+    username = Faker::Internet.user_name + '.json'
+    submit_signup username
+    assert page.has_content?("Welcome #{username}")
+  end
+
+  test "signup with reserved username" do
+    username = 'certmaster'
+    submit_signup username
+    assert page.has_content?("is reserved.")
+  end
+
+  test "successful login" do
+    username, password = submit_signup
+    click_on 'Log Out'
+    attempt_login(username, password)
+    assert page.has_content?("Welcome #{username}")
+    within('.sidenav li.active') do
+      assert page.has_content?("Overview")
+    end
+    User.find_by_login(username).account.destroy
+  end
+
+  test "failed login" do
+    visit '/'
+    attempt_login("username", "wrong password")
+    assert_invalid_login(page)
+  end
+
+  test "account destruction" do
+    username, password = submit_signup
+
+    click_on I18n.t('account_settings')
+    click_on I18n.t('destroy_my_account')
+    assert page.has_content?(I18n.t('account_destroyed'))
+    assert_equal 1, Identity.by_address.key("#{username}@test.me").count
+    attempt_login(username, password)
+    assert_invalid_login(page)
+  end
+
+  test "handle blocked after account destruction" do
+    username, password = submit_signup
+    click_on I18n.t('account_settings')
+    click_on I18n.t('destroy_my_account')
+    submit_signup(username)
+    assert page.has_content?('has already been taken')
+  end
+
+  test "change pgp key" do
+    with_config user_actions: ['change_pgp_key'] do
+      pgp_key = FactoryGirl.build :pgp_key
+      login
+      click_on "Account Settings"
+      within('#update_pgp_key') do
+        fill_in 'Public key', with: pgp_key
+        click_on 'Save'
+      end
+      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.to_s
+      @user.reload
+      assert_equal pgp_key, @user.public_key
+    end
+  end
+
+<<<<<<< HEAD:test/integration/browser/account_livecycle_test.rb
+=======
+
+  # trying to seed an invalid A for srp login
+  test "detects attempt to circumvent SRP" do
+    InviteCodeValidator.any_instance.stubs(:validate)
+
+    user = FactoryGirl.create :user
+    visit '/login'
+    fill_in 'Username', with: user.login
+    fill_in 'Password', with: "password"
+    inject_malicious_js
+    click_on 'Log In'
+    assert page.has_content?("Invalid random key")
+    assert page.has_no_content?("Welcome")
+    user.destroy
+  end
+
+  test "reports internal server errors" do
+    Api::UsersController.any_instance.stubs(:create).raises
+    submit_signup
+    assert page.has_content?("server failed")
+  end
+
+  test "does not render signup form without js" do
+    Capybara.current_driver = :rack_test # no js
+    visit '/signup'
+    assert page.has_no_content?("Username")
+    assert page.has_no_content?("Password")
+  end
+
+  test "does not render login form without js" do
+    Capybara.current_driver = :rack_test # no js
+    visit '/login'
+    assert page.has_no_content?("Username")
+    assert page.has_no_content?("Password")
+  end
+
+>>>>>>> api: allow version bumping - bump to 2:test/integration/browser/account_test.rb
+  def attempt_login(username, password)
+    click_on 'Log In'
+    fill_in 'Username', with: username
+    fill_in 'Password', with: password
+    click_on 'Log In'
+  end
+
+  def assert_invalid_login(page)
+    assert page.has_selector? '.btn-primary.disabled'
+    assert page.has_content? I18n.t(:invalid_user_pass)
+    assert page.has_no_selector? '.btn-primary.disabled'
+  end
+
+end
diff --git a/test/integration/browser/security_test.rb b/test/integration/browser/security_test.rb
index c13acd8..825d50b 100644
--- a/test/integration/browser/security_test.rb
+++ b/test/integration/browser/security_test.rb
@@ -22,7 +22,7 @@ class SecurityTest < BrowserIntegrationTest
   end
 
   test "reports internal server errors" do
-    V1::UsersController.any_instance.stubs(:create).raises
+    Api::UsersController.any_instance.stubs(:create).raises
     submit_signup
     assert page.has_content?("server failed")
   end
diff --git a/test/support/api_integration_test.rb b/test/support/api_integration_test.rb
index 3b3481b..cea480c 100644
--- a/test/support/api_integration_test.rb
+++ b/test/support/api_integration_test.rb
@@ -3,6 +3,10 @@ class ApiIntegrationTest < ActionDispatch::IntegrationTest
   DUMMY_TOKEN = Token.new
   RACK_ENV = {'HTTP_AUTHORIZATION' => %Q(Token token="#{DUMMY_TOKEN.to_s}")}
 
+  def api_version
+    2
+  end
+
   setup do
     @testcode = InviteCode.new
     @testcode.save!
-- 
cgit v1.2.3