#!/home/ndw/ruby/bin/ruby
# -*- Ruby -*-

require 'cgi'
require "cgi/session"
require "cgi/session/pstore"
require "uri"

# load the openid library, first trying rubygems
begin
  require "openid"
rescue LoadError
  require "rubygems"
  Gem.path.push("/home/ndw/.gem")
  require_gem "ruby-openid"
end

# In real life, you want this to point to your site, not mine
# Hack!
if File.exists?("/home/ndw/.homepage")
  $root_uri = "http://localhost:8122/"
else
  $root_uri = "http://norman.walsh.name/"
end

def main()
  if $cgi.key?("action") && $cgi["action"] == 'complete'
    check_result()
    exit
  end

  if !$cgi.key?("openid_url")
    display_form()
    exit
  end

  openid_url = $cgi['openid_url'].dup # Get the string out of CGI's hands

  request = $consumer.begin(openid_url)

  if request.status == OpenID::SUCCESS
    policy_url = $root_uri + "openid/policy"
    request.add_extension_arg('sreg','policy_url', policy_url)
    request.add_extension_arg('sreg','required','email,nickname')
    request.add_extension_arg('sreg','optional','fullname,dob,gender,postcode,country')

    return_to = $root_uri + "cgi-bin/login?action=complete"
    return_to += "&sess_id=" + $session.session_id
    return_to += "&page=" + $cgi["page"] if $cgi.key?("page")
    return_to += "&uri=" + $cgi["uri"] if $cgi.key?("uri")

    # build the redirect
    redirect_url = request.redirect_url($trust_root, return_to)

    print "Status: 303 See Other\n"
    printf "Location: %s\n\n", redirect_url
  else
    print "Content-type: text/plain\n\n"
    print "OpenID consumer request failed:\n\n"
    p request
  end
end

def display_form()
  print "Content-type: text/html\n\n"
  print "<html xmlns='http://www.w3.org/1999/xhtml'>\n"
  print "<head>\n"
  print "<title>Login with OpenID</title>\n"
  print "<style type='text/css'>\n"
  print "/* Blatantly stolen from OpenID.net */\n"
  print "input.sexy {\n"
  print "   background: url(/graphics/login-bg.gif) no-repeat; \n"
  print "   background-color: #fff; \n"
  print "   background-position: 0 50%;\n"
  print "   color: #000;\n"
  print "   padding-left: 18px; \n"
  print "}\n"
  print "</style>\n"
  print "</head>\n"
  print "<body>\n"
  print "<h1>Login with OpenID</h1>\n"
  print "\n"
  print "<form action='/cgi-bin/login' method='get'>\n"
  print "<p>Login with your\n"
  print "<a href='http://openid.net/'>OpenID</a> URL.</p>\n"
  print "\n"
  print "<p>URL:\n"
  print "<input name='openid_url' class='sexy' size='60' />\n"
  print "<input id='submit' name='submit' value='Login' type='submit'/>\n"
  print "</p>\n"
  print "</form>\n"
  print "</body>\n"
  print "</html>\n"
end

def check_result()
  query = Hash.new
  $cgi.keys.each { |k| query[k] = $cgi[k].dup }

  # Ask the library to check the response that the server sent
  # us.  Status is a code indicating the response type. info is
  # either nil or a string containing more information about
  # the return type.

  response = $consumer.complete(query)

  if response.status == OpenID::FAILURE
    if response.identity_url
      message = "Verification of #{response.identity_url} failed"
    else
      message = 'Verification failed.'
    end

    # add on the failure message for a little debug info
    message += ' '+response.msg.to_s

    login_failure(message)

  elsif response.status == OpenID::SUCCESS
    # get the signed extension sreg arguments
    sreg = response.extension_response('sreg')
    login_success(response.identity_url, sreg)

  elsif response.status == OpenID::CANCEL
    login_failure("Verification cancelled.")

  else
    login_failure("Unknown response status: #{response.status}")
  end

  $session.delete
end

def login_success(identity, sreg)
  nick = sreg['nickname'] || sreg['fullname'] || identity

  print "Content-type: text/html\n\n"

  # In real life, you have to do something here to remember the success; perhaps
  # set a cookie or add something to the URI.

  print "<html xmlns='http://www.w3.org/1999/xhtml'>\n"
  print "<head>\n"
  print "<title>Logged in with OpenID</title>\n"
  print "</head>\n"
  print "<body>\n"

  print "<h1>Welcome "
  printf "%s!</h1>\n", nick

  print "<p>Your login was successful.</p>\n"

  if !(sreg.key?('nickname')||sreg.key?('fullname')) || !sreg.key?('email')
    print "<p>In the future, please login with a profile that includes your name\n"
    print "and email address.</p>\n"
  end

  print "</body>\n"
  print "</html>\n"
end

def login_failure(message)
  print "Content-type: text/html\n\n"
  print "<html xmlns='http://www.w3.org/1999/xhtml'>\n"
  print "<head>\n"
  print "<title>Login with OpenID</title>\n"
  print "</head>\n"
  print "<body>\n"
  print "<h1>Login with OpenID</h1>\n"
  printf "<p>Login failed: %s</p>\n", message
  print "<p><a href='/cgi-bin/login'>Try again?</a></p>\n"
  print "</body>\n"
  print "</html>\n"
end

$cgi = CGI.new("html4")
$session = CGI::Session.new($cgi,
                            'database_manager' => CGI::Session::PStore,  # use PStore
                            'session_key' => 'sess_id',                  # custom session key
                            'session_expires' => Time.now + 10 * 60,     # 10 minute timeout
                            'prefix' => 'pstore_sid_')                   # PStore option

$store_dir = "/home/ndw/norman.walsh.name/openid/store/"
$store = OpenID::FilesystemStore.new($store_dir)

filename = $store_dir + "foobar"
File.open(filename, "w").close

$base_url = $root_uri
$trust_root = $base_url
$consumer = OpenID::Consumer.new($session, $store)

main()
