# Copyright (C) 2003-2005 Kouichirou Eto, All rights reserved.

$LOAD_PATH.unshift("../../compat") unless $LOAD_PATH.include?("../../compat")
require "base64"

module Qwik
  class Action
    def check_basicauth # ref. webrick/httpauth.rb
      auth = @req["Authorization"]
      return if auth.nil?
      return unless /^Basic\s+(.*)/o =~ auth
      user, pass = Base64.decode64($1).split(":", 2)
      if user
	raise InvalidUserError if user.nil? || user == ""
	raise InvalidUserError unless MailAddress.new(user).valid?
	gen = @memory.passgen
	raise InvalidUserError if !gen.match?(user, pass)

	@req.user = user
	@req.auth = "basicauth"
      end
    end

    def act_basicauth # ref. webrick/httpauth.rb
      if !@req.user # Try to Login by using Basic Auth.
	realm = "qwik"
	@res["WWW-Authenticate"] = "Basic realm=\"#{realm}\""
	# status code must be 401
	return c_notice(_("Login by Basic Auth"), nil, 401){[
	    [:h2, _("Do login by Basic Auth.")],
	    [:p, _("Please input ID(E-mail) and password.")],
	    [:hr],
	    [:p,_("Go back")," : ",[:a,{:href=>"FrontPage.html"},"FrontPage"]]
	  ]}
      end

      # Already logged in.
      if @req.auth != "basicauth" # But, the method is not Basic Auth.
	return c_notice(_("Login by cookie")){[
	    [:h2, _("You are already login by cookie.")],
	    [:hr],
	    [:p,_("Go back")," : ",[:a,{:href=>"FrontPage.html"},"FrontPage"]]
	  ]}
      end

      return c_notice(_("Login by Basic Auth")){[
	  [:h2, _("Login by using Basic Auth.")],
	  [:hr],
	  [:p,_("Go back")," : ",[:a,{:href=>"FrontPage.html"},"FrontPage"]]
	]}
    end

    def basicauth_logout
      return c_notice(_("Basic Auth") + " " + _("Logout")){[
	  [:h2, _("Can not logout.")],
	  [:p, _("You can not logout in Basic Auth mode."), [:br],
	    _("Please close browser and access again.")],
	  [:hr],
	  [:p,_("Go back")," : ",[:a,{:href=>"FrontPage.html"},"FrontPage"]]
	]}
    end
  end
end

if $0 == __FILE__
  $LOAD_PATH << "../../lib" unless $LOAD_PATH.include?("../../lib")
  require "t/test"
  $debug = true
end

if $debug
  class TC_ActBasicAuth < Test::Unit::TestCase
    include TestSession

    def test_all
      t_add_user

      # See the FrontPage.
      session("/test/")
      assert_text("FrontPage", "title")

      # See the FrontPage before Login.
      session("/test/") {|req|
	req.cookies.clear
      }
      assert_text("Login", "title")
      assert_xpath([:meta,{:content=>"0; url=.login", "http-equiv"=>"Refresh"}],
		   "//meta[2]")

      # See the Login page.
      session("/test/.login") {|req|
	req.cookies.clear
      }
      assert_text("Login", "title")
      assert_xpath([:a, {:href=>".getpass"}, [:em, "Get Password"]],
		   "//div[@class='section']/a")
      assert_xpath([:a, {:href=>".basicauth"}, "Login by Basic Auth"],
		   "//div[@class='section']/a[2]")

      # See the Basic Auth Login page.
      session("/test/.basicauth") {|req|
	req.cookies.clear
      }
      assert_text("Login by Basic Auth", "title")
      assert_equal(401, @res.status)
      assert_equal("Basic realm=\"qwik\"", @res["WWW-Authenticate"])

      # test base64
      assert_equal("dXNlckBlLmNvbTo5NTk4ODU5Mw==\n",
		   Base64.encode64(DEFAULT_USER+":95988593"))

      # Try to Login by Basic Auth.
      session("/test/.basicauth") {|req|
	req.cookies.clear
	req.header["authorization"] =
	  ["Basic dGVzdEBleGFtcGxlLmNvbTo0NDQ4NDEyNQ=="]
      }
      assert_text("Login by Basic Auth", "title")
      assert_equal(200, @res.status)
      assert_equal(nil, @res["WWW-Authenticate"])
      assert_text("FrontPage", "a")
      assert_xpath([:a, {:href=>"FrontPage.html"}, "FrontPage"], "//a")

      # Try to see FrontPage
      session("/test/") {|req|
	req.cookies.clear
	req.header["authorization"] =
	  ["Basic dXNlckBlLmNvbTo5NTk4ODU5Mw=="]
      }
      assert_text("FrontPage", "title")

      # test_logout
      session("/test/.logout") {|req|
	req.cookies.clear
	req.header["authorization"] =
	  ["Basic dXNlckBlLmNvbTo5NTk4ODU5Mw=="]
      }
      assert_text("Basic Auth Logout", "title")
      assert_text("Can not logout.", "h2")
    end
  end
end
