Merge branch 'master' into openstreetbugs

This commit is contained in:
Tom Hughes 2011-06-22 22:36:43 +01:00
commit 7c98b41cc8
64 changed files with 2178 additions and 218 deletions

View file

@ -186,6 +186,7 @@ class AmfController < ApplicationController
user = getuser(usertoken) user = getuser(usertoken)
if !user then return -1,"You are not logged in, so Potlatch can't write any changes to the database." end if !user then return -1,"You are not logged in, so Potlatch can't write any changes to the database." end
unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked') end unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked') end
if REQUIRE_TERMS_AGREED and user.terms_agreed.nil? then return -1,"You must accept the contributor terms before you can edit." end
if cstags if cstags
if !tags_ok(cstags) then return -1,"One of the tags is invalid. Linux users may need to upgrade to Flash Player 10.1." end if !tags_ok(cstags) then return -1,"One of the tags is invalid. Linux users may need to upgrade to Flash Player 10.1." end
@ -573,6 +574,8 @@ class AmfController < ApplicationController
user = getuser(usertoken) user = getuser(usertoken)
if !user then return -1,"You are not logged in, so the relation could not be saved." end if !user then return -1,"You are not logged in, so the relation could not be saved." end
unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked') end unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked') end
if REQUIRE_TERMS_AGREED and user.terms_agreed.nil? then return -1,"You must accept the contributor terms before you can edit." end
if !tags_ok(tags) then return -1,"One of the tags is invalid. Linux users may need to upgrade to Flash Player 10.1." end if !tags_ok(tags) then return -1,"One of the tags is invalid. Linux users may need to upgrade to Flash Player 10.1." end
tags = strip_non_xml_chars tags tags = strip_non_xml_chars tags
@ -661,7 +664,10 @@ class AmfController < ApplicationController
user = getuser(usertoken) user = getuser(usertoken)
if !user then return -1,"You are not logged in, so the way could not be saved." end if !user then return -1,"You are not logged in, so the way could not be saved." end
unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked') end unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked') end
if REQUIRE_TERMS_AGREED and user.terms_agreed.nil? then return -1,"You must accept the contributor terms before you can edit." end
if pointlist.length < 2 then return -2,"Server error - way is only #{points.length} points long." end if pointlist.length < 2 then return -2,"Server error - way is only #{points.length} points long." end
if !tags_ok(attributes) then return -1,"One of the tags is invalid. Linux users may need to upgrade to Flash Player 10.1." end if !tags_ok(attributes) then return -1,"One of the tags is invalid. Linux users may need to upgrade to Flash Player 10.1." end
attributes = strip_non_xml_chars attributes attributes = strip_non_xml_chars attributes
@ -767,6 +773,8 @@ class AmfController < ApplicationController
user = getuser(usertoken) user = getuser(usertoken)
if !user then return -1,"You are not logged in, so the point could not be saved." end if !user then return -1,"You are not logged in, so the point could not be saved." end
unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked') end unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked') end
if REQUIRE_TERMS_AGREED and user.terms_agreed.nil? then return -1,"You must accept the contributor terms before you can edit." end
if !tags_ok(tags) then return -1,"One of the tags is invalid. Linux users may need to upgrade to Flash Player 10.1." end if !tags_ok(tags) then return -1,"One of the tags is invalid. Linux users may need to upgrade to Flash Player 10.1." end
tags = strip_non_xml_chars tags tags = strip_non_xml_chars tags
@ -850,6 +858,7 @@ class AmfController < ApplicationController
user = getuser(usertoken) user = getuser(usertoken)
unless user then return -1,"You are not logged in, so the way could not be deleted." end unless user then return -1,"You are not logged in, so the way could not be deleted." end
unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked') end unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked') end
if REQUIRE_TERMS_AGREED and user.terms_agreed.nil? then return -1,"You must accept the contributor terms before you can edit." end
way_id = way_id.to_i way_id = way_id.to_i
nodeversions = {} nodeversions = {}

View file

@ -11,7 +11,7 @@ class ApplicationController < ActionController::Base
@user = User.find(session[:user], :conditions => {:status => ["active", "confirmed", "suspended"]}) @user = User.find(session[:user], :conditions => {:status => ["active", "confirmed", "suspended"]})
if @user.status == "suspended" if @user.status == "suspended"
session[:user] = nil session.delete(:user)
session_expires_automatically session_expires_automatically
redirect_to :controller => "user", :action => "suspended" redirect_to :controller => "user", :action => "suspended"
@ -50,7 +50,7 @@ class ApplicationController < ActionController::Base
# method, otherwise an OAuth token was used, which has to be checked. # method, otherwise an OAuth token was used, which has to be checked.
unless current_token.nil? unless current_token.nil?
unless current_token.read_attribute(cap) unless current_token.read_attribute(cap)
render :text => "OAuth token doesn't have that capability.", :status => :forbidden report_error "OAuth token doesn't have that capability.", :forbidden
return false return false
end end
end end
@ -61,11 +61,14 @@ class ApplicationController < ActionController::Base
def require_cookies def require_cookies
if request.cookies["_osm_session"].to_s == "" if request.cookies["_osm_session"].to_s == ""
if params[:cookie_test].nil? if params[:cookie_test].nil?
session[:cookie_test] = true
redirect_to params.merge(:cookie_test => "true") redirect_to params.merge(:cookie_test => "true")
return false return false
else else
flash.now[:warning] = t 'application.require_cookies.cookies_needed' flash.now[:warning] = t 'application.require_cookies.cookies_needed'
end end
else
session.delete(:cookie_test)
end end
end end
@ -81,6 +84,11 @@ class ApplicationController < ActionController::Base
end end
def require_allow_write_api def require_allow_write_api
require_capability(:allow_write_api) require_capability(:allow_write_api)
if REQUIRE_TERMS_AGREED and @user.terms_agreed.nil?
report_error "You must accept the contributor terms before you can edit.", :forbidden
return false
end
end end
def require_allow_read_gpx def require_allow_read_gpx
require_capability(:allow_read_gpx) require_capability(:allow_read_gpx)

View file

@ -27,22 +27,53 @@ class UserController < ApplicationController
render :update do |page| render :update do |page|
page.replace_html "contributorTerms", :partial => "terms" page.replace_html "contributorTerms", :partial => "terms"
end end
elsif using_open_id?
# The redirect from the OpenID provider reenters here
# again and we need to pass the parameters through to
# the open_id_authentication function
@user = session.delete(:new_user)
openid_verify(nil, @user) do |user|
end
if @user.openid_url.nil? or @user.invalid?
render :action => 'new'
else else
render :action => 'terms'
end
else
session[:referer] = params[:referer]
@title = t 'user.terms.title' @title = t 'user.terms.title'
@user = User.new(params[:user]) if params[:user] @user = User.new(params[:user]) if params[:user]
if params[:user] and params[:user][:openid_url] and @user.pass_crypt.empty?
# We are creating an account with OpenID and no password
# was specified so create a random one
@user.pass_crypt = ActiveSupport::SecureRandom.base64(16)
@user.pass_crypt_confirmation = @user.pass_crypt
end
if @user if @user
if @user.invalid? if @user.invalid?
if @user.new_record? if @user.new_record?
# Something is wrong with a new user, so rerender the form
render :action => :new render :action => :new
else else
# Error in existing user, so go to account settings
flash[:errors] = @user.errors flash[:errors] = @user.errors
redirect_to :action => :account, :display_name => @user.display_name redirect_to :action => :account, :display_name => @user.display_name
end end
elsif @user.terms_agreed? elsif @user.terms_agreed?
# Already agreed to terms, so just show settings
redirect_to :action => :account, :display_name => @user.display_name redirect_to :action => :account, :display_name => @user.display_name
elsif params[:user] and params[:user][:openid_url] and not params[:user][:openid_url].empty?
# Verify OpenID before moving on
session[:new_user] = @user
openid_verify(params[:user][:openid_url], @user)
end end
else else
# Not logged in, so redirect to the login page
redirect_to :action => :login, :referer => request.request_uri redirect_to :action => :login, :referer => request.request_uri
end end
end end
@ -94,10 +125,11 @@ class UserController < ApplicationController
@user.languages = request.user_preferred_languages @user.languages = request.user_preferred_languages
@user.terms_agreed = Time.now.getutc @user.terms_agreed = Time.now.getutc
@user.terms_seen = true @user.terms_seen = true
@user.openid_url = nil if @user.openid_url and @user.openid_url.empty?
if @user.save if @user.save
flash[:notice] = t 'user.new.flash create success message', :email => @user.email flash[:notice] = t 'user.new.flash create success message', :email => @user.email
Notifier.deliver_signup_confirm(@user, @user.tokens.create(:referer => params[:referer])) Notifier.deliver_signup_confirm(@user, @user.tokens.create(:referer => session.delete(:referer)))
session[:token] = @user.tokens.create.token session[:token] = @user.tokens.create.token
redirect_to :action => 'login', :referer => params[:referer] redirect_to :action => 'login', :referer => params[:referer]
else else
@ -136,22 +168,25 @@ class UserController < ApplicationController
@user.preferred_editor = params[:user][:preferred_editor] @user.preferred_editor = params[:user][:preferred_editor]
end end
if @user.save @user.openid_url = nil if params[:user][:openid_url].empty?
set_locale
if @user.new_email.nil? or @user.new_email.empty? if params[:user][:openid_url].length > 0 and
flash[:notice] = t 'user.account.flash update success' params[:user][:openid_url] != @user.openid_url
# If the OpenID has changed, we want to check that it is a
# valid OpenID and one the user has control over before saving
# it as a password equivalent for the user.
session[:new_user] = @user
openid_verify(params[:user][:openid_url], @user)
else else
flash[:notice] = t 'user.account.flash update success confirm needed' update_user(@user)
begin
Notifier.deliver_email_confirm(@user, @user.tokens.create)
rescue
# Ignore errors sending email
end end
end elsif using_open_id?
# The redirect from the OpenID provider reenters here
redirect_to :action => "account", :display_name => @user.display_name # again and we need to pass the parameters through to
# the open_id_authentication function
@user = session.delete(:new_user)
openid_verify(nil, @user) do |user|
update_user(user)
end end
else else
if flash[:errors] if flash[:errors]
@ -217,46 +252,26 @@ class UserController < ApplicationController
def new def new
@title = t 'user.new.title' @title = t 'user.new.title'
@referer = params[:referer] || session[:referer]
if session[:user]
# The user is logged in already, so don't show them the signup # The user is logged in already, so don't show them the signup
# page, instead send them to the home page # page, instead send them to the home page
redirect_to :controller => 'site', :action => 'index' if session[:user] redirect_to :controller => 'site', :action => 'index'
elsif not params['openid'].nil?
flash.now[:notice] = t 'user.new.openid association'
end
end end
def login def login
@title = t 'user.login.title' if params[:username] or using_open_id?
session[:remember_me] ||= params[:remember_me]
session[:referer] ||= params[:referer]
if params[:user] if using_open_id?
email_or_display_name = params[:user][:email] openid_authentication(params[:openid_url])
pass = params[:user][:password]
user = User.authenticate(:username => email_or_display_name, :password => pass)
if user
session[:user] = user.id
session_expires_after 1.month if params[:remember_me]
target = params[:referer] || url_for(:controller => :site, :action => :index)
# The user is logged in, so decide where to send them:
#
# - If they haven't seen the contributor terms, send them there.
# - If they have a block on them, show them that.
# - If they were referred to the login, send them back there.
# - Otherwise, send them to the home page.
if REQUIRE_TERMS_SEEN and not user.terms_seen
redirect_to :controller => :user, :action => :terms, :referer => target
elsif user.blocked_on_view
redirect_to user.blocked_on_view, :referer => target
else else
redirect_to target password_authentication(params[:username], params[:password])
end
elsif user = User.authenticate(:username => email_or_display_name, :password => pass, :pending => true)
flash.now[:error] = t 'user.login.account not active', :reconfirm => url_for(:action => 'confirm_resend', :display_name => user.display_name)
elsif User.authenticate(:username => email_or_display_name, :password => pass, :suspended => true)
webmaster = link_to t('user.login.webmaster'), "mailto:webmaster@openstreetmap.org"
flash.now[:error] = t 'user.login.account suspended', :webmaster => webmaster
else
flash.now[:error] = t 'user.login.auth failure'
end end
elsif flash[:notice].nil? elsif flash[:notice].nil?
flash.now[:notice] = t 'user.login.notice' flash.now[:notice] = t 'user.login.notice'
@ -272,9 +287,9 @@ class UserController < ApplicationController
if token if token
token.destroy token.destroy
end end
session[:token] = nil session.delete(:token)
end end
session[:user] = nil session.delete(:user)
session_expires_automatically session_expires_automatically
if params[:referer] if params[:referer]
redirect_to params[:referer] redirect_to params[:referer]
@ -476,6 +491,175 @@ class UserController < ApplicationController
private private
##
# handle password authentication
def password_authentication(username, password)
if user = User.authenticate(:username => username, :password => password)
successful_login(user)
elsif user = User.authenticate(:username => username, :password => password, :pending => true)
failed_login t('user.login.account not active', :reconfirm => url_for(:action => 'confirm_resend', :display_name => user.display_name))
elsif User.authenticate(:username => username, :password => password, :suspended => true)
webmaster = link_to t('user.login.webmaster'), "mailto:webmaster@openstreetmap.org"
failed_login t('user.login.account suspended', :webmaster => webmaster)
else
failed_login t('user.login.auth failure')
end
end
##
# handle OpenID authentication
def openid_authentication(openid_url)
# If we don't appear to have a user for this URL then ask the
# provider for some extra information to help with signup
if openid_url and User.find_by_openid_url(openid_url)
required = nil
else
required = [:nickname, :email, "http://axschema.org/namePerson/friendly", "http://axschema.org/contact/email"]
end
# Start the authentication
authenticate_with_open_id(openid_expand_url(openid_url), :required => required) do |result, identity_url, sreg, ax|
if result.successful?
# We need to use the openid url passed back from the OpenID provider
# rather than the one supplied by the user, as these can be different.
#
# For example, you can simply enter yahoo.com in the login box rather
# than a user specific url. Only once it comes back from the provider
# provider do we know the unique address for the user.
if user = User.find_by_openid_url(identity_url)
case user.status
when "pending" then
failed_login t('user.login.account not active')
when "active", "confirmed" then
successful_login(user)
when "suspended" then
webmaster = link_to t('user.login.webmaster'), "mailto:webmaster@openstreetmap.org"
failed_login t('user.login.account suspended', :webmaster => webmaster)
else
failed_login t('user.login.auth failure')
end
else
# Guard against not getting any extension data
sreg = Hash.new if sreg.nil?
ax = Hash.new if ax.nil?
# We don't have a user registered to this OpenID, so redirect
# to the create account page with username and email filled
# in if they have been given by the OpenID provider through
# the simple registration protocol.
nickname = sreg["nickname"] || ax["http://axschema.org/namePerson/friendly"]
email = sreg["email"] || ax["http://axschema.org/contact/email"]
redirect_to :controller => 'user', :action => 'new', :nickname => nickname, :email => email, :openid => identity_url
end
elsif result.missing?
failed_login t('user.login.openid missing provider')
elsif result.invalid?
failed_login t('user.login.openid invalid')
else
failed_login t('user.login.auth failure')
end
end
end
##
# verify an OpenID URL
def openid_verify(openid_url, user)
user.openid_url = openid_url
authenticate_with_open_id(openid_expand_url(openid_url)) do |result, identity_url|
if result.successful?
# We need to use the openid url passed back from the OpenID provider
# rather than the one supplied by the user, as these can be different.
#
# For example, you can simply enter yahoo.com in the login box rather
# than a user specific url. Only once it comes back from the provider
# provider do we know the unique address for the user.
user.openid_url = identity_url
yield user
elsif result.missing?
flash.now[:error] = t 'user.login.openid missing provider'
elsif result.invalid?
flash.now[:error] = t 'user.login.openid invalid'
else
flash.now[:error] = t 'user.login.auth failure'
end
end
end
##
# special case some common OpenID providers by applying heuristics to
# try and come up with the correct URL based on what the user entered
def openid_expand_url(openid_url)
if openid_url.nil?
return nil
elsif openid_url.match(/(.*)gmail.com(\/?)$/) or openid_url.match(/(.*)googlemail.com(\/?)$/)
# Special case gmail.com as it is potentially a popular OpenID
# provider and, unlike yahoo.com, where it works automatically, Google
# have hidden their OpenID endpoint somewhere obscure this making it
# somewhat less user friendly.
return 'https://www.google.com/accounts/o8/id'
else
return openid_url
end
end
##
# process a successful login
def successful_login(user)
session[:user] = user.id
session_expires_after 1.month if session[:remember_me]
target = session[:referer] || url_for(:controller => :site, :action => :index)
# The user is logged in, so decide where to send them:
#
# - If they haven't seen the contributor terms, send them there.
# - If they have a block on them, show them that.
# - If they were referred to the login, send them back there.
# - Otherwise, send them to the home page.
if REQUIRE_TERMS_SEEN and not user.terms_seen
redirect_to :controller => :user, :action => :terms, :referer => target
elsif user.blocked_on_view
redirect_to user.blocked_on_view, :referer => target
else
redirect_to target
end
session.delete(:remember_me)
session.delete(:referer)
end
##
# process a failed login
def failed_login(message)
flash[:error] = message
redirect_to :action => 'login', :referer => session[:referer]
session.delete(:remember_me)
session.delete(:referer)
end
##
# update a user's details
def update_user(user)
if user.save
set_locale
if user.new_email.nil? or user.new_email.empty?
flash.now[:notice] = t 'user.account.flash update success'
else
flash.now[:notice] = t 'user.account.flash update success confirm needed'
begin
Notifier.deliver_email_confirm(user, user.tokens.create)
rescue
# Ignore errors sending email
end
end
end
end
## ##
# require that the user is a administrator, or fill out a helpful error message # require that the user is a administrator, or fill out a helpful error message
# and return them to the user page. # and return them to the user page.

View file

@ -1,2 +1,16 @@
module UserHelper module UserHelper
def openid_logo
image_tag "openid_small.png", :alt => t('user.login.openid_logo_alt'), :class => "openid_logo"
end
def openid_button(name, url)
link_to_function(
image_tag("#{name}.png", :alt => t("user.login.openid_providers.#{name}.alt")),
nil,
:title => t("user.login.openid_providers.#{name}.title")
) do |page|
page[:login_form][:openid_url][:value] = url
page[:login_form].submit()
end
end
end end

View file

@ -23,13 +23,14 @@ class User < ActiveRecord::Base
validates_confirmation_of :pass_crypt#, :message => ' must match the confirmation password' validates_confirmation_of :pass_crypt#, :message => ' must match the confirmation password'
validates_uniqueness_of :display_name, :allow_nil => true validates_uniqueness_of :display_name, :allow_nil => true
validates_uniqueness_of :email validates_uniqueness_of :email
validates_uniqueness_of :openid_url, :allow_nil => true
validates_length_of :pass_crypt, :within => 8..255 validates_length_of :pass_crypt, :within => 8..255
validates_length_of :display_name, :within => 3..255, :allow_nil => true validates_length_of :display_name, :within => 3..255, :allow_nil => true
validates_email_format_of :email validates_email_format_of :email, :if => Proc.new { |u| u.email_changed? }
validates_email_format_of :new_email, :allow_blank => true validates_email_format_of :new_email, :allow_blank => true, :if => Proc.new { |u| u.new_email_changed? }
validates_format_of :display_name, :with => /^[^\/;.,?]*$/ validates_format_of :display_name, :with => /^[^\/;.,?]*$/, :if => Proc.new { |u| u.display_name_changed? }
validates_format_of :display_name, :with => /^\S/, :message => "has leading whitespace" validates_format_of :display_name, :with => /^\S/, :message => "has leading whitespace", :if => Proc.new { |u| u.display_name_changed? }
validates_format_of :display_name, :with => /\S$/, :message => "has trailing whitespace" validates_format_of :display_name, :with => /\S$/, :message => "has trailing whitespace", :if => Proc.new { |u| u.display_name_changed? }
validates_numericality_of :home_lat, :allow_nil => true validates_numericality_of :home_lat, :allow_nil => true
validates_numericality_of :home_lon, :allow_nil => true validates_numericality_of :home_lon, :allow_nil => true
validates_numericality_of :home_zoom, :only_integer => true, :allow_nil => true validates_numericality_of :home_zoom, :only_integer => true, :allow_nil => true

View file

@ -15,13 +15,18 @@ private
if old_record and if old_record and
(new_record.nil? or (new_record.nil? or
old_record.visible? != new_record.visible? or old_record.visible? != new_record.visible? or
old_record.display_name != new_record.display_name) old_record.display_name != new_record.display_name or
old_record.image != new_record.image)
old_record.diary_entries.each do |entry| old_record.diary_entries.each do |entry|
expire_action(:controller => 'diary_entry', :action => 'view', :display_name => old_record.display_name, :id => entry.id) expire_action(:controller => 'diary_entry', :action => 'view', :display_name => old_record.display_name, :id => entry.id)
expire_action(:controller => 'diary_entry', :action => 'list', :language => entry.language_code, :display_name => nil) expire_action(:controller => 'diary_entry', :action => 'list', :language => entry.language_code, :display_name => nil)
expire_action(:controller => 'diary_entry', :action => 'rss', :language => entry.language_code, :display_name => nil) expire_action(:controller => 'diary_entry', :action => 'rss', :language => entry.language_code, :display_name => nil)
end end
old_record.diary_comments.each do |comment|
expire_action(:controller => 'diary_entry', :action => 'view', :display_name => comment.diary_entry.user.display_name, :id => comment.diary_entry.id)
end
expire_action(:controller => 'diary_entry', :action => 'list', :language => nil, :display_name => nil) expire_action(:controller => 'diary_entry', :action => 'list', :language => nil, :display_name => nil)
expire_action(:controller => 'diary_entry', :action => 'list', :language => nil, :display_name => old_record.display_name) expire_action(:controller => 'diary_entry', :action => 'list', :language => nil, :display_name => old_record.display_name)

View file

@ -27,6 +27,11 @@
<td><%= f.password_field :pass_crypt_confirmation, {:value => '', :size => 30, :maxlength => 255, :autocomplete => :off} %></td> <td><%= f.password_field :pass_crypt_confirmation, {:value => '', :size => 30, :maxlength => 255, :autocomplete => :off} %></td>
</tr> </tr>
<tr>
<td class="fieldName" ><%= t 'user.account.openid.openid' %></td>
<td><%= f.text_field :openid_url, {:id => "openid_url", :class => "openid_url"} %> <span class="minorNote">(<a href="<%= t 'user.account.openid.link' %>" target="_new"><%= t 'user.account.openid.link text' %></a>)</span></td>
</tr>
<tr> <tr>
<td class="fieldName" valign="top"><%= t 'user.account.public editing.heading' %></td> <td class="fieldName" valign="top"><%= t 'user.account.public editing.heading' %></td>
<td> <td>

View file

@ -1,25 +1,80 @@
<div id="login_wrapper"> <div id="login_wrapper">
<div id="login_login"> <div id="login_login">
<h1><%= t 'user.login.heading' %></h1> <h1><%= t 'user.login.heading' %></h1>
<p><%= t 'user.login.already have' %></p> <% form_tag({ :action => "login" }, { :id => "login_form" }) do %>
<% form_tag :action => 'login' do %>
<%= hidden_field_tag('referer', h(params[:referer])) %> <%= hidden_field_tag('referer', h(params[:referer])) %>
<p><%= t 'user.login.with username' %></p>
<table id="loginForm"> <table id="loginForm">
<tr><td class="fieldName"><%= t 'user.login.email or username' %></td><td><%= text_field('user', 'email',{:value => "", :size => 28, :maxlength => 255, :tabindex => 1}) %></td></tr> <tr><td class="fieldName"><%= t 'user.login.email or username' %></td><td><%= text_field_tag "username", params[:username], :size => 28, :maxlength => 255, :tabindex => 1 %></td></tr>
<tr><td class="fieldName"><%= t 'user.login.password' %></td><td><%= password_field('user', 'password',{:value => "", :size => 28, :maxlength => 255, :tabindex => 2}) %> <span class="minorNote">(<%= link_to t('user.login.lost password link'), :controller => 'user', :action => 'lost_password' %>)</span></td></tr> <tr><td class="fieldName"><%= t 'user.login.password' %></td><td><%= password_field_tag "password", "", :size => 28, :maxlength => 255, :tabindex => 2 %> <span class="minorNote">(<%= link_to t('user.login.lost password link'), :controller => 'user', :action => 'lost_password' %>)</span></td></tr>
<tr><td class="fieldName"><label for="remember_me"><%= t 'user.login.remember' %></label></td><td><%= check_box_tag "remember_me", "yes", false, :tabindex => 3 %></td></tr> <tr><td class="fieldName"><label for="remember_me"><%= t 'user.login.remember' %></label></td><td><%= check_box_tag "remember_me", "yes", false, :tabindex => 3 %></td></tr>
</table> </table>
<%= submit_tag t('user.login.login_button'), :tabindex => 3 %> <%= submit_tag t('user.login.login_button'), :tabindex => 3 %>
<br clear="all" />
<p><%= t 'user.login.with openid' %></p>
<table id="login_openid_buttons">
<tr>
<td>
<%=
link_to_function(image_tag("openid.png", :alt => t("user.login.openid_providers.openid.title")), nil, :title => t("user.login.openid_providers.openid.title")) do |page|
page[:login_form][:openid_url].value = "http://"
page[:login_openid_buttons].hide
page[:login_openid_url].show
page[:login_openid_submit].show
end
%>
</td>
<td><%= openid_button "google", "gmail.com" %></td>
<td><%= openid_button "yahoo", "me.yahoo.com" %></td>
<td><%= openid_button "myopenid", "myopenid.com" %></td>
<td><%= openid_button "wordpress", "wordpress.com" %></td>
<td><%= openid_button "aol", "aol.com" %></td>
</tr>
</table>
<table>
<tr id="login_openid_url">
<td class="fieldName nowrap">
<%= t 'user.login.openid', :logo => openid_logo %>
</td>
<td>
<%= text_field_tag("openid_url", "", { :size => 28, :maxlength => 255, :tabindex => 3, :class => "openid_url" }) %>
<span class="minorNote">(<a href="<%= t 'user.account.openid.link' %>" target="_new"><%= t 'user.account.openid.link text' %></a>)</span>
</td>
</tr>
<tr>
<td class="fieldName nowrap" id="remember_me_label"><label for="remember_me"><%= t 'user.login.remember' %></label></td>
<td width="100%"><%= check_box_tag "remember_me", "yes", false, :tabindex => 5 %></td>
</tr>
</table>
<%= submit_tag t('user.login.login_button'), :tabindex => 6, :id => "login_openid_submit" %>
<% end %> <% end %>
<br clear="all" /> <br clear="all" />
</div> </div>
<div id="login_signup"> <div id="login_signup">
<h2><%= t 'user.login.new to osm' %></h2> <h2><%= t 'user.login.new to osm' %></h2>
<p><%= t 'user.login.to make changes' %></p> <p><%= t 'user.login.to make changes' %></p>
<p><%= t 'user.login.create account minute' %></p> <p><%= t 'user.login.create account minute' %></p>
<p><%= button_to t('user.login.register now'), :action => :new, :referer => params[:referer] %></p> <p><%= button_to t('user.login.register now'), :action => :new, :referer => params[:referer] %></p>
<br clear="all" />
<br clear="both">
</div> </div>
</div> </div>
<%=
update_page_tag do |page|
page[:login_openid_url].hide
page[:login_openid_submit].hide
end
%>

View file

@ -2,37 +2,89 @@
<% if Acl.find_by_address(request.remote_ip, :conditions => {:k => "no_account_creation"}) %> <% if Acl.find_by_address(request.remote_ip, :conditions => {:k => "no_account_creation"}) %>
<p><%= t 'user.new.no_auto_account_create' %> <p><%= t 'user.new.no_auto_account_create' %></p>
</p>
<p><%= t 'user.new.contact_webmaster' %> <p><%= t 'user.new.contact_webmaster' %></p>
</p>
<% else %> <% else %>
<p><%= t 'user.new.fill_form' %> <p><%= t 'user.new.fill_form' %></p>
</p>
<%= error_messages_for 'user' %> <%= error_messages_for 'user' %>
<% form_tag :action => 'terms' do %> <% form_tag :action => 'terms' do %>
<%= hidden_field_tag('referer', h(params[:referer])) unless params[:referer].nil? %> <%= hidden_field_tag('referer', h(@referer)) unless @referer.nil? %>
<table id="signupForm">
<tr><td class="fieldName"><%= t 'user.new.email address' %></td><td><%= text_field('user', 'email',{:size => 50, :maxlength => 255, :tabindex => 1}) %></td></tr> <table id="signupForm">
<tr><td class="fieldName"><%= t 'user.new.confirm email address' %></td><td><%= text_field('user', 'email_confirmation',{:size => 50, :maxlength => 255, :tabindex => 2}) %></td></tr> <tr>
<tr><td></td><td><span class="minorNote"><%= t 'user.new.not displayed publicly' %></span></td></tr> <td class="fieldName"><%= t 'user.new.email address' %></td>
<tr><td colspan="2">&nbsp;<!--vertical spacer--></td></tr> <td><%= text_field(:user, :email, { :size => 50, :maxlength => 255, :tabindex => 1, :value => params[:email] }) %></td>
<tr><td class="fieldName"><%= t 'user.new.display name' %></td><td><%= text_field('user', 'display_name',{:size => 30, :maxlength => 255, :tabindex => 3}) %></td></tr> </tr>
<tr><td></td><td><span class="minorNote"><%= t 'user.new.display name description' %></span></td></tr> <tr>
<tr><td colspan="2">&nbsp;<!--vertical spacer--></td></tr> <td class="fieldName"><%= t 'user.new.confirm email address' %></td>
<tr><td class="fieldName"><%= t 'user.new.password' %></td><td><%= password_field('user', 'pass_crypt',{:size => 30, :maxlength => 255, :tabindex => 4}) %></td></tr> <td><%= text_field(:user, :email_confirmation, { :size => 50, :maxlength => 255, :tabindex => 2, :value => params[:email] }) %></td>
<tr><td class="fieldName"><%= t 'user.new.confirm password' %></td><td><%= password_field('user', 'pass_crypt_confirmation',{:size => 30, :maxlength => 255, :tabindex => 5}) %></td></tr> </tr>
<tr>
<td></td>
<td><span class="minorNote"><%= t 'user.new.not displayed publicly' %></span></td>
</tr>
<tr><td colspan="2">&nbsp;<!--vertical spacer--></td></tr> <tr><td colspan="2">&nbsp;<!--vertical spacer--></td></tr>
<tr><td></td><td align="right"><input type="submit" value="<%= t'user.new.continue' %>" tabindex="6"></td></tr>
</table> <tr>
<td class="fieldName"><%= t 'user.new.display name' %></td>
<td><%= text_field(:user, :display_name, { :size => 30, :maxlength => 255, :tabindex => 3, :value => params[:nickname] }) %></td></tr>
<tr>
<td></td>
<td><span class="minorNote"><%= t 'user.new.display name description' %></span></td>
</tr>
<tr id="openid_spacer"><td colspan="2">&nbsp;<!--vertical spacer--></td></tr>
<tr>
<td class="fieldName"><%= t 'user.new.openid', :logo => openid_logo %></td>
<td><%= text_field(:user, :openid_url, { :id => "openid_url", :size => 50, :maxlength => 255, :tabindex => 4, :value => params[:openid], :class => "openid_url" }) %></td>
</tr>
<tr><td colspan="2">&nbsp;<!--vertical spacer--></td></tr>
<tr>
<td class="fieldName"><%= t 'user.new.password' %></td>
<td><%= password_field(:user, :pass_crypt, { :size => 30, :maxlength => 255, :tabindex => 5 }) %></td>
</tr>
<tr>
<td class="fieldName"><%= t 'user.new.confirm password' %></td>
<td><%= password_field(:user, :pass_crypt_confirmation, { :size => 30, :maxlength => 255, :tabindex => 6 }) %></td>
</tr>
<tr>
<td></td>
<td>
<span id="openid_prompt" class="minorNote"><%= link_to_function(t('user.new.use openid', :logo => openid_logo)) { |page| page.hide 'openid_prompt'; page.show 'openid_spacer', 'openid_url', 'openid_note' } %></span>
<span id="openid_note" class="minorNote"><%= t 'user.new.openid no password' %></span>
</td>
</tr>
<tr><td colspan="2" >&nbsp;<!--vertical spacer--></td></tr>
<tr>
<td></td>
<td align="right"><%= submit_tag t('user.new.continue'), :tabindex => 6 %></td>
</tr>
</table>
<% end %> <% end %>
<%=
update_page_tag do |page|
if params[:openid] or (@user and @user.openid_url)
page[:openid_prompt].hide
else
page[:openid_spacer].hide
page[:openid_url].hide
page[:openid_note].hide
end
end
%>
<%= javascript_include_tag 'https://ethnio.com/remotes/62786' %> <%= javascript_include_tag 'https://ethnio.com/remotes/62786' %>
<% end %> <% end %>

View file

@ -33,12 +33,13 @@
</p> </p>
<p> <p>
<%= hidden_field_tag('referer', h(params[:referer])) unless params[:referer].nil? %> <%= hidden_field_tag('referer', h(params[:referer])) unless params[:referer].nil? %>
<% if params[:user] %> <% if @user.new_record? %>
<%= hidden_field('user', 'email') %> <%= hidden_field('user', 'email') %>
<%= hidden_field('user', 'email_confirmation') %> <%= hidden_field('user', 'email_confirmation') %>
<%= hidden_field('user', 'display_name') %> <%= hidden_field('user', 'display_name') %>
<%= hidden_field('user', 'pass_crypt') %> <%= hidden_field('user', 'pass_crypt') %>
<%= hidden_field('user', 'pass_crypt_confirmation') %> <%= hidden_field('user', 'pass_crypt_confirmation') %>
<%= hidden_field('user', 'openid_url') %>
<% end %> <% end %>
<div id="buttons"> <div id="buttons">
<%= submit_tag(t('user.terms.decline'), :name => "decline", :id => "decline") %> <%= submit_tag(t('user.terms.decline'), :name => "decline", :id => "decline") %>

View file

@ -71,6 +71,8 @@ standard_settings: &standard_settings
#potlatch2_key: "" #potlatch2_key: ""
# Whether to require users to view the CTs before continuing to edit... # Whether to require users to view the CTs before continuing to edit...
require_terms_seen: false require_terms_seen: false
# Whether to require users to agree to the CTs before editing
require_terms_agreed: false
development: development:
<<: *standard_settings <<: *standard_settings

View file

@ -0,0 +1 @@
OpenIdAuthentication.store = :file

View file

@ -1067,6 +1067,9 @@ en:
<ul id="contributors"> <ul id="contributors">
<li><strong>Australia</strong>: Contains suburb data based <li><strong>Australia</strong>: Contains suburb data based
on Australian Bureau of Statistics data.</li> on Australian Bureau of Statistics data.</li>
<li><strong>Austria</strong>: Contains data from
<a href="http://data.wien.gv.at/">Stadt Wien</a> under
<a href="http://creativecommons.org/licenses/by/3.0/at/deed.de">CC-BY</a>.</li>
<li><strong>Canada</strong>: Contains data from <li><strong>Canada</strong>: Contains data from
GeoBase&reg;, GeoGratis (&copy; Department of Natural GeoBase&reg;, GeoGratis (&copy; Department of Natural
Resources Canada), CanVec (&copy; Department of Natural Resources Canada), CanVec (&copy; Department of Natural
@ -1534,15 +1537,15 @@ en:
login: login:
title: "Login" title: "Login"
heading: "Login" heading: "Login"
please login: "Please login or %{create_user_link}."
create_account: "create an account"
email or username: "Email Address or Username:" email or username: "Email Address or Username:"
password: "Password:" password: "Password:"
openid: "%{logo} OpenID:"
remember: "Remember me:" remember: "Remember me:"
lost password link: "Lost your password?" lost password link: "Lost your password?"
login_button: "Login" login_button: "Login"
register now: Register now register now: Register now
already have: Already have an OpenStreetMap account? Please login. with username: "Already have an OpenStreetMap account? Please login with your username and password:"
with openid: "Alternatively please use your OpenID to login:"
new to osm: New to OpenStreetMap? new to osm: New to OpenStreetMap?
to make changes: To make changes to the OpenStreetMap data, you must have an account. to make changes: To make changes to the OpenStreetMap data, you must have an account.
create account minute: Create an account. It only takes a minute. create account minute: Create an account. It only takes a minute.
@ -1551,6 +1554,28 @@ en:
webmaster: webmaster webmaster: webmaster
auth failure: "Sorry, could not log in with those details." auth failure: "Sorry, could not log in with those details."
notice: "<a href=\"http://www.osmfoundation.org/wiki/License/We_Are_Changing_The_License\">Find out more about OpenStreetMap's upcoming license change</a> (<a href=\"http://wiki.openstreetmap.org/wiki/ODbL/We_Are_Changing_The_License\">translations</a>) (<a href=\"http://wiki.openstreetmap.org/wiki/Talk:ODbL/Upcoming\">discussion</a>)" notice: "<a href=\"http://www.osmfoundation.org/wiki/License/We_Are_Changing_The_License\">Find out more about OpenStreetMap's upcoming license change</a> (<a href=\"http://wiki.openstreetmap.org/wiki/ODbL/We_Are_Changing_The_License\">translations</a>) (<a href=\"http://wiki.openstreetmap.org/wiki/Talk:ODbL/Upcoming\">discussion</a>)"
openid missing provider: "Sorry, could not contact your OpenID provider"
openid invalid: "Sorry, your OpenID seems to be malformed"
openid_logo_alt: "Log in with an OpenID"
openid_providers:
openid:
title: Login with OpenID
alt: Login with an OpenID URL
google:
title: Login with Google
alt: Login with a Google OpenID
yahoo:
title: Login with Yahoo
alt: Login with a Yahoo OpenID
myopenid:
title: Login with myOpenID
alt: Login with a myOpenID OpenID
wordpress:
title: Login with Wordpress
alt: Login with a Wordpress OpenID
aol:
title: Login with AOL
alt: Login with an AOL OpenID
logout: logout:
title: "Logout" title: "Logout"
heading: "Logout from OpenStreetMap" heading: "Logout from OpenStreetMap"
@ -1583,8 +1608,21 @@ en:
not displayed publicly: 'Not displayed publicly (see <a href="http://wiki.openstreetmap.org/wiki/Privacy_Policy" title="wiki privacy policy including section on email addresses">privacy policy</a>)' not displayed publicly: 'Not displayed publicly (see <a href="http://wiki.openstreetmap.org/wiki/Privacy_Policy" title="wiki privacy policy including section on email addresses">privacy policy</a>)'
display name: "Display Name:" display name: "Display Name:"
display name description: "Your publicly displayed username. You can change this later in the preferences." display name description: "Your publicly displayed username. You can change this later in the preferences."
openid: "%{logo} OpenID:"
password: "Password:" password: "Password:"
confirm password: "Confirm Password:" confirm password: "Confirm Password:"
use openid: "Alternatively, use %{logo} OpenID to login"
openid no password: "With OpenID a password is not required, but some extra tools or server may still need one."
openid association: |
<p>Your OpenID is not associated with a OpenStreetMap account yet.</p>
<ul>
<li>If you are new to OpenStreetMap, please create a new account using the form below.</li>
<li>
If you already have an account, you can login to your account
using your username and password and then associate the account
with your OpenID in your user settings.
</li>
</ul>
continue: Continue continue: Continue
flash create success message: "Thanks for signing up. We've sent a confirmation note to %{email} and as soon as you confirm your account you'll be able to get mapping.<br /><br />If you use an antispam system which sends confirmation requests then please make sure you whitelist webmaster@openstreetmap.org as we are unable to reply to any confirmation requests." flash create success message: "Thanks for signing up. We've sent a confirmation note to %{email} and as soon as you confirm your account you'll be able to get mapping.<br /><br />If you use an antispam system which sends confirmation requests then please make sure you whitelist webmaster@openstreetmap.org as we are unable to reply to any confirmation requests."
terms accepted: "Thanks for accepting the new contributor terms!" terms accepted: "Thanks for accepting the new contributor terms!"
@ -1674,6 +1712,10 @@ en:
current email address: "Current Email Address:" current email address: "Current Email Address:"
new email address: "New Email Address:" new email address: "New Email Address:"
email never displayed publicly: "(never displayed publicly)" email never displayed publicly: "(never displayed publicly)"
openid:
openid: "OpenID:"
link: "http://wiki.openstreetmap.org/wiki/OpenID"
link text: "what is this?"
public editing: public editing:
heading: "Public editing:" heading: "Public editing:"
enabled: "Enabled. Not anonymous and can edit data." enabled: "Enabled. Not anonymous and can edit data."

View file

@ -1011,6 +1011,8 @@ is:
current email address: "Núverandi netfang:" current email address: "Núverandi netfang:"
delete image: Eyða þessari mynd delete image: Eyða þessari mynd
email never displayed publicly: (aldrei sýnt opinberlega) email never displayed publicly: (aldrei sýnt opinberlega)
openid:
link text: "hvað er openID?"
flash update success: Stillingarnar þínar voru uppfærðar. flash update success: Stillingarnar þínar voru uppfærðar.
flash update success confirm needed: Stillingarnar þínar voru uppfærðar. Póstur var sendur á netfangið þitt sem þú þarft að bregðast við til að netfangið þitt verði staðfest. flash update success confirm needed: Stillingarnar þínar voru uppfærðar. Póstur var sendur á netfangið þitt sem þú þarft að bregðast við til að netfangið þitt verði staðfest.
home location: "Staðsetning:" home location: "Staðsetning:"
@ -1070,6 +1072,28 @@ is:
remember: "Muna innskráninguna:" remember: "Muna innskráninguna:"
title: Innskrá title: Innskrá
webmaster: vefstjóra webmaster: vefstjóra
openid_heading: "Innskráning með OpenID:"
username_heading: "Innskráning með OpenStreetMap aðgang:"
openid_logo_alt: "Innskrá með OpenID"
openid_providers:
openid:
title: Innskrá með OpenID slóð
alt: Innskrá með OpenID slóð
yahoo:
title: Innsrká með Yahoo! OpenID
alt: Innsrká með Yahoo! OpenID
google:
title: Innsrká með Google OpenID
alt: Innsrká með Google OpenID
myopenid:
title: Innsrká með myOpenID OpenID
alt: Innsrká með myOpenID OpenID
wordpress:
title: Innsrká með Wordpress.com OpenID
alt: Innsrká með Wordpress.com OpenID
myspace:
title: Innsrká með MySpace OpenID
alt: Innsrká með MySpace OpenID
logout: logout:
heading: Útskrá heading: Útskrá
logout_button: Útskrá logout_button: Útskrá
@ -1101,6 +1125,21 @@ is:
no_auto_account_create: Því miður getum við eki búið til reikning fyrir þig sjálfkrafa. no_auto_account_create: Því miður getum við eki búið til reikning fyrir þig sjálfkrafa.
not displayed publicly: Ekki sýnt opinberlega (sjá <a href="http://wiki.openstreetmap.org/index.php?uselang=is&title=Privacy_Policy" title="Meðferð persónuupplýsinga, þ.á.m. netfanga">meðferð persónuupplýsinga</a>) not displayed publicly: Ekki sýnt opinberlega (sjá <a href="http://wiki.openstreetmap.org/index.php?uselang=is&title=Privacy_Policy" title="Meðferð persónuupplýsinga, þ.á.m. netfanga">meðferð persónuupplýsinga</a>)
password: "Lykilorð:" password: "Lykilorð:"
openID associate: "Tengja OpenID við þennan aðgang"
openID: "OpenID:"
openID description: '(Valfrjálst) Ef þú ert með <a href="http://wiki.openstreetmap.org/wiki/openID">OpenID</a> getur þú tengt það við nýja aðganginn þinn.'
openID nopassword: "Með OpenID þarft þú ekki að gefa upp lykilorð við innskráningu. Í stað þess notar þú OpenID."
openID association: |
Þetta OpenID er ekki tengt við neinn OpenStreetMap aðgang.
<ul>
<li>Ef þú ert ekki með OpenStreetMap aðgang getur þú búið til nýjan aðgang hér fyrir neðan.</li>
<li>
Ef þú ert þegar með aðgang skaltu innskrá þig með
honum. Svo getur þú tengt OpenID við aðganginn þinn á
stillingarsíðunni.
</li>
</ul>
signup: Nýskrá
title: Nýskrá title: Nýskrá
no_such_user: no_such_user:
body: Það er ekki til notandi með nafninu %{user}. Kannski slóstu nafnið rangt inn eða fylgdir ógildum tengli. body: Það er ekki til notandi með nafninu %{user}. Kannski slóstu nafnið rangt inn eða fylgdir ógildum tengli.

View file

@ -0,0 +1,11 @@
class AddOpenId < ActiveRecord::Migration
def self.up
add_column :users, :openid_url, :string
add_index :users, [:openid_url], :name => "user_openid_url_idx", :unique => true
end
def self.down
remove_index :users, :name => "user_openid_url_idx"
remove_column :users, :openid_url
end
end

BIN
public/images/aol.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
public/images/google.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
public/images/myopenid.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
public/images/openid.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 874 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 B

BIN
public/images/wordpress.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
public/images/yahoo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -4,10 +4,12 @@ relation[type=restriction] node { z-index:11; icon-image: icons/restriction.png;
/* Interactive way behaviour */ /* Interactive way behaviour */
way :hover { z-index: 2; width: eval('_width+10'); color: #ffff99; } way::highlight :hover { z-index: 2; width: eval('_width+10'); color: #ffff99; }
way :selected { z-index: 2; width: eval('_width+10'); color: yellow; opacity: 0.7;} way::highlight :hover :background { color: lightcyan; }
way :restrictfrom { z-index: -1; width: eval('_width+10'); color: red; opacity: 0.7;} way::highlight :selected { z-index: 2; width: eval('_width+10'); color: yellow; opacity: 0.7;}
way :restrictto { z-index: -1; width: eval('_width+10'); color: blue; opacity: 0.7;} way::highlight :selected :background { color: cyan; }
way::highlight :restrictfrom { z-index: -1; width: eval('_width+10'); color: red; opacity: 0.7;}
way::highlight :restrictto { z-index: -1; width: eval('_width+10'); color: blue; opacity: 0.7;}
/*way !:drawn !:hasTags{ z-index:10; width: 0.5; color: red; }*/ /*way !:drawn !:hasTags{ z-index:10; width: 0.5; color: red; }*/
way !:drawn { z-index:10; width: 1; color: #333333; } way !:drawn { z-index:10; width: 1; color: #333333; }
way :tiger { casing-color: #ff00ff;} way :tiger { casing-color: #ff00ff;}
@ -20,5 +22,6 @@ node !:drawn :poi { z-index: 2; icon-image: circle; icon-width: 4; color: green;
node !:drawn :hasTags { z-index: 9; icon-image: circle; icon-width: 4; color: black; } node !:drawn :hasTags { z-index: 9; icon-image: circle; icon-width: 4; color: black; }
node :hasTags :selectedway { z-index: 9; icon-image: square; icon-width: 8; color: black; layer: 5; } node :hasTags :selectedway { z-index: 9; icon-image: square; icon-width: 8; color: black; layer: 5; }
node !:drawn :selectedway { z-index: 9; icon-image: square; icon-width: 8; color: red; casing-color: #cc0000; casing-width: 1; layer: 5; } node !:drawn :selectedway { z-index: 9; icon-image: square; icon-width: 8; color: red; casing-color: #cc0000; casing-width: 1; layer: 5; }
node :selected { z-index: 1; icon-image: square; icon-width: eval('_width+10'); color: yellow; interactive: no; layer: 5; } node::selectedNode :selected { z-index: 1; icon-image: square; icon-width: eval('_width+10'); color: yellow; interactive: no; layer: 5; }
node :junction :selectedway { z-index: 8; icon-image: square; icon-width: 12; casing-color: black; casing-width: 1; layer: 5; } node::selectedNode :selected :background { color: cyan; }
node::junctionNode :junction :selectedway { z-index: 8; icon-image: square; icon-width: 12; casing-color: black; casing-width: 1; layer: 5; }

View file

@ -28,10 +28,10 @@ way[leisure=pitch] :area { z-index: 6; color: #88bb44; width: 2; fill-color:
way[landuse=recreation_ground] :area { color: green; fill-color: green; set .area_small_name;} way[landuse=recreation_ground] :area { color: green; fill-color: green; set .area_small_name;}
way[amenity=parking] :area { color: #bbaa66; width: 1; fill-color: #bbaa66; fill-opacity: 0.2; } way[amenity=parking] :area { color: #bbaa66; width: 1; fill-color: #bbaa66; fill-opacity: 0.2; }
way[public_transport=pay_scale_area] :area { color: gray; width: 1; fill-color: gray; fill-opacity: 0.1; } way[public_transport=pay_scale_area] :area { color: gray; width: 1; fill-color: gray; fill-opacity: 0.1; }
way[man_made=pier] { z-index: 4; color: #777; width: 3; casing-color: black; casing-width: 5;} way[man_made=pier] { z-index: 4; color: #777; width: 3; casing-color: black; casing-width: 1;}
way[man_made=pier][floating=yes] { dashes: 4,2; casing-color: #444;} way[man_made=pier][floating=yes] { dashes: 4,2; casing-color: #444;}
way[leisure=marina] :area { color: pink; fill-color: pink; fill-opacity: 0.4; set .area_small_name;} way[leisure=marina] :area { color: pink; fill-color: pink; fill-opacity: 0.4; set .area_small_name;}
way[leisure=slipway] { color: grey; width: 3; casing-color: blue; casing-width: 7; } way[leisure=slipway] { color: grey; width: 3; casing-color: blue; casing-width: 2; }
way[leisure=golf_course] :area { color: #44ee22; width: 2; fill-color: #44ee22; fill-opacity: 0.2; set .area_small_name;} way[leisure=golf_course] :area { color: #44ee22; width: 2; fill-color: #44ee22; fill-opacity: 0.2; set .area_small_name;}
way[boundary] { color: #000066; width: 2; opacity: 0.6; dashes: 24,4, 4, 4; z-index: 4;} way[boundary] { color: #000066; width: 2; opacity: 0.6; dashes: 24,4, 4, 4; z-index: 4;}
/* Perhaps should be filled, on lower zooms. */ /* Perhaps should be filled, on lower zooms. */

View file

@ -1,7 +1,7 @@
/* Route relations */ /* Route relations */
relation[type=route] way { z-index: 1; width: 13; color: blue; opacity: 0.3; } relation[type=route] way::route { z-index: 1; width: 13; color: blue; opacity: 0.3; }
relation[type=route][route=bicycle][network=ncn] way { z-index: 1; width: 12; color: red; opacity: 0.3; } relation[type=route][route=bicycle][network=ncn] way::route { z-index: 1; width: 12; color: red; opacity: 0.3; }
relation[type=route][route=bicycle][network=rcn] way { z-index: 1; width: 12; color: cyan; opacity: 0.3; } relation[type=route][route=bicycle][network=rcn] way::route { z-index: 1; width: 12; color: cyan; opacity: 0.3; }
relation[type=route][route=bicycle][network=lcn] way { z-index: 1; width: 12; color: blue; opacity: 0.3; } relation[type=route][route=bicycle][network=lcn] way::route { z-index: 1; width: 12; color: blue; opacity: 0.3; }
relation[type=route][route=foot] way { z-index: 1; width: 10; color: #80ff80; opacity: 0.6; } relation[type=route][route=foot] way::route { z-index: 1; width: 10; color: #80ff80; opacity: 0.6; }

View file

@ -7,23 +7,23 @@ way[highway=primary],way[highway=primary_link],
way[highway=secondary],way[highway=secondary_link], way[highway=secondary],way[highway=secondary_link],
way[highway=tertiary],way[highway=tertiary_link], way[highway=tertiary],way[highway=tertiary_link],
way[highway=residential],way[highway=unclassified] { text: name; text-color: black; font-size: 10; text-position: line; text-halo-color: white; text-halo-radius: 2; } way[highway=residential],way[highway=unclassified] { text: name; text-color: black; font-size: 10; text-position: line; text-halo-color: white; text-halo-radius: 2; }
way[highway=motorway],way[highway=motorway_link] { z-index: 9; color: #809BC0; width: 7; casing-color: black; casing-width: 8; } way[highway=motorway],way[highway=motorway_link] { z-index: 9; color: #809BC0; width: 7; casing-color: black; casing-width: 1; }
way[highway=trunk],way[highway=trunk_link] { z-index: 9; color: #7FC97F; width: 7; casing-color: black; casing-width: 8; } way[highway=trunk],way[highway=trunk_link] { z-index: 9; color: #7FC97F; width: 7; casing-color: black; casing-width: 1; }
way[highway=primary],way[highway=primary_link] { z-index: 8; color: #E46D71; width: 7; casing-color: black; casing-width: 8; } way[highway=primary],way[highway=primary_link] { z-index: 8; color: #E46D71; width: 7; casing-color: black; casing-width: 1; }
way[highway=secondary],way[highway=secondary_link] { z-index: 7; color: #FDBF6F; width: 7; casing-width: 8; } way[highway=secondary],way[highway=secondary_link] { z-index: 7; color: #FDBF6F; width: 7; casing-width: 1; }
way[highway=tertiary] { z-index: 6; color: #FEFECB; width: 5; casing-width: 7; } way[highway=tertiary] { z-index: 6; color: #FEFECB; width: 5; casing-width: 1; }
way[highway=unclassified] { z-index: 6; color: #D0D0D0; width: 5; casing-width: 7; } way[highway=unclassified] { z-index: 6; color: #D0D0D0; width: 5; casing-width: 1; }
way[highway=tertiary_link] { z-index: 5; color: #FEFECB; width: 4; casing-width: 5; } way[highway=tertiary_link] { z-index: 5; color: #FEFECB; width: 4; casing-width: 1; }
way[highway=residential] { z-index: 5; color: #E8E8E8; width: 5; casing-color: gray; casing-width: 7; } way[highway=residential] { z-index: 5; color: #E8E8E8; width: 5; casing-color: gray; casing-width: 1; }
way[highway=service][service!=parking_aisle] { color: white; width: 3; casing-color: gray; casing-width: 5; } way[highway=service][service!=parking_aisle] { color: white; width: 3; casing-color: gray; casing-width: 1; }
way[highway=service][service=parking_aisle] { color: white; width: 1; casing-color: #aaaaaa; casing-width: 2; } way[highway=service][service=parking_aisle] { color: white; width: 1; casing-color: #aaaaaa; casing-width: 1; }
way[highway=service][service=alley] { color: white; width: 2; dashes: 6,2; casing-color: black; casing-width: 4; } way[highway=service][service=alley] { color: white; width: 2; dashes: 6,2; casing-color: black; casing-width: 1; }
way[highway=road] { color: gray; width: 5; casing-color: white; casing-width: 7; } way[highway=road] { color: gray; width: 5; casing-color: white; casing-width: 1; }
way[highway=living_street] { z-index: 5; color: #ddffee; width: 3; casing-color: #555555; casing-width: 4; } way[highway=living_street] { z-index: 5; color: #ddffee; width: 3; casing-color: #555555; casing-width: 1; }
/* Road areas */ /* Road areas */
way[highway=pedestrian] !:area { color: #ddddee; width: 5; casing-color: #555555; casing-width: 6; casing-dashes: 2,4;} way[highway=pedestrian] !:area { color: #ddddee; width: 5; casing-color: #555555; casing-width: 1; casing-dashes: 2,4;}
way[highway=pedestrian] :area { color: #555555; width: 1; fill-color: #ddddee; fill-opacity: 0.8; } way[highway=pedestrian] :area { color: #555555; width: 1; fill-color: #ddddee; fill-opacity: 0.8; }
/* Paths */ /* Paths */
@ -35,29 +35,28 @@ way[highway=bridleway] { z-index:9; color: #996644; width: 2; dashes: 4, 2, 2, 2
way[highway=track] { color: #996644; width: 2; dashes: 4, 2; set .path;} way[highway=track] { color: #996644; width: 2; dashes: 4, 2; set .path;}
way[highway=path] { color: brown; width: 2; dashes: 2, 2; set .path;} way[highway=path] { color: brown; width: 2; dashes: 2, 2; set .path;}
way[highway=cycleway] { color: blue; width: 2; dashes: 4, 2; set .path;} way[highway=cycleway] { color: blue; width: 2; dashes: 4, 2; set .path;}
way[railway=tram] { z-index: 11; color: #999999; width: 2; casing-color: black; casing-width: 6; } way[railway=tram] { z-index: 11; color: #999999; width: 2; casing-color: black; casing-width: 2; }
way .path { text:name; text-color: black; text-position: offset; text-offset: 5;} way .path { text:name; text-color: black; text-position: offset; text-offset: 5;}
/* Under construction */ /* Under construction */
way[highway=proposed] { color: #88ffff; width: 6; dashes: 8, 4; } way[highway=proposed] { color: #88ffff; width: 6; dashes: 8, 4; }
way[highway=construction] { color: #ffffbb; width: 6; dashes: 8, 4; casing-color: #0000aa; casing-width: 8; casing-dashes: 8,4;} way[highway=construction] { color: #ffffbb; width: 6; dashes: 8, 4; casing-color: #0000aa; casing-width: 1; casing-dashes: 8,4;}
way[construction=rail] way[construction=rail] { z-index: 6; color: black; width: 5; dashes: 6, 6, 4, 8;}
{ z-index: 6; color: black; width: 5; dashes: 6, 6, 4, 8;} way[construction=rail]::inner { z-index: 7; color: white; width: 3; dashes: 6,18; }
{ z-index: 7; color: white; width: 3; dashes: 6,18; }
/* Railways */ /* Railways */
way[railway=rail] way[railway=rail] { z-index: 6; color: black; width: 5; }
{ z-index: 6; color: black; width: 5; } way[railway=rail]::dashes { z-index: 7; color: white; width: 3; dashes: 12,12; }
{ z-index: 7; color: white; width: 3; dashes: 12,12; }
way[railway=platform] { color:black; width: 2; } way[railway=platform] { color:black; width: 2; }
way[railway=subway]
{ z-index: 6; color: #444444; width: 5; } way[railway=subway] { z-index: 6; color: #444444; width: 5; }
{ z-index: 7; color: white; width: 3; dashes: 8,8; } way[railway=subway]::dashes { z-index: 7; color: white; width: 3; dashes: 8,8; }
way[railway=disused],way[railway=abandoned]
{ z-index: 6; color: #444400; width: 3; dashes: 17, 2, 5, 0; } way[railway=disused],way[railway=abandoned] { z-index: 6; color: #444400; width: 3; dashes: 17, 2, 5, 0; }
{ z-index: 7; color: #999999; width: 2; dashes: 12,12; } way[railway=disused]::dashes,way[railway=abandoned]::dashes { z-index: 7; color: #999999; width: 2; dashes: 12,12; }
/* Waterways */ /* Waterways */
@ -70,25 +69,26 @@ way[waterway][tunnel=yes] {dashes: 8,4;}
/* Aeroways */ /* Aeroways */
way[aeroway=aerodrome] :area way[aeroway=aerodrome] :area
{ z-index: 3; color: #bb44bb; width: 3; casing-color: #66066; casing-width: 4; } { z-index: 3; color: #bb44bb; width: 3; casing-color: #66066; casing-width: 1; }
way|z-15[aeroway=aerodrome] :area way|z-15[aeroway=aerodrome] :area
{ z-index: 3; fill-color: #bb99bb; fill-opacity: 0.5;} { z-index: 3; fill-color: #bb99bb; fill-opacity: 0.5;}
way[aeroway=taxiway] !:area { z-index: 8; color: #999999; width: 3; casing-color: #aa66aa; casing-width: 6; } way[aeroway=taxiway] !:area { z-index: 8; color: #999999; width: 3; casing-color: #aa66aa; casing-width: 2; }
way[aeroway=taxiway] :area { z-index: 8; color: #bb99bb; width: 3; fill-color: #ccaacc; } way[aeroway=taxiway] :area { z-index: 8; color: #bb99bb; width: 3; fill-color: #ccaacc; }
way|z17-[aeroway=runway] !:area
{ z-index: 9; color: black; width: 11; casing-color: #aa66aa; casing-width: 12; } way|z17-[aeroway=runway] !:area { z-index: 9; color: black; width: 11; casing-color: #aa66aa; casing-width: 1; }
{ z-index: 10; color: white; width: 9; dashes: 0, 20, 4, 76; } way|z17-[aeroway=runway]::aa !:area { z-index: 10; color: white; width: 9; dashes: 0, 20, 4, 76; }
{ z-index: 11; color: black; width: 7; } way|z17-[aeroway=runway]::bb !:area { z-index: 11; color: black; width: 7; }
{ z-index: 12; color: white; width: 5; dashes: 0, 20, 4, 76; } way|z17-[aeroway=runway]::cc !:area { z-index: 12; color: white; width: 5; dashes: 0, 20, 4, 76; }
{ z-index: 13; color: black; width: 3; } way|z17-[aeroway=runway]::dd !:area { z-index: 13; color: black; width: 3; }
{ z-index: 14; color: white; width: 1; dashes: 4, 16; } way|z17-[aeroway=runway]::ee !:area { z-index: 14; color: white; width: 1; dashes: 4, 16; }
way|z15-16[aeroway=runway] !:area
{ z-index: 9; color: black; width: 5; } way|z15-16[aeroway=runway] !:area { z-index: 9; color: black; width: 5; }
{ z-index: 12; color: white; width: 5; dashes: 0, 20, 4, 76; } way|z15-16[aeroway=runway]::aa !:area { z-index: 12; color: white; width: 5; dashes: 0, 20, 4, 76; }
{ z-index: 13; color: black; width: 3; } way|z15-16[aeroway=runway]::bb !:area { z-index: 13; color: black; width: 3; }
{ z-index: 14; color: white; width: 1; dashes: 4, 16; } way|z15-16[aeroway=runway]::cc !:area { z-index: 14; color: white; width: 1; dashes: 4, 16; }
way|z-14[aeroway=runway] !:area
{ z-index: 9; color: #444444; width: 3; } way|z-14[aeroway=runway] !:area { z-index: 9; color: #444444; width: 3; }
way[aeroway=runway] :area { z-index: 9; color: black; width: 3; fill-color: #775577; } way[aeroway=runway] :area { z-index: 9; color: black; width: 3; fill-color: #775577; }
way[aeroway=apron] :area { z-index: 4; color: #cc66cc; width: 1; fill-color: #ddaadd; fill-opacity: 0.5;} way[aeroway=apron] :area { z-index: 4; color: #cc66cc; width: 1; fill-color: #ddaadd; fill-opacity: 0.5;}
@ -99,27 +99,25 @@ way[barrier=fence] {color: #000000; width: 1; dashes: 8,4,2,4; }
/* Power */ /* Power */
way[power=line] {color: darkgray; width: 3; dashes: 12,2; casing-color: black; casing-width: 8; casing-dashes: 4, 38;} way[power=line] {color: darkgray; width: 3; dashes: 12,2; casing-color: black; casing-width: 2; casing-dashes: 4, 38;}
way[power=minor_line] {color: gray; width: 2; dashes: 2,4; casing-width: 8; casing-color: white; casing-dashes: 2,22;} way[power=minor_line] {color: gray; width: 2; dashes: 2,4; casing-width: 3; casing-color: white; casing-dashes: 2,22;}
way[power=station] :area { color: black; width: 2; fill-color: #666666; fill-opacity: 0.6; set .area_small_name;} way[power=station] :area { color: black; width: 2; fill-color: #666666; fill-opacity: 0.6; set .area_small_name;}
way[power=generator] :area { color: black; width: 2; fill-color: #444444; fill-opacity: 0.6; set .area_small_name;} way[power=generator] :area { color: black; width: 2; fill-color: #444444; fill-opacity: 0.6; set .area_small_name;}
/* Leisure */ /* Leisure */
way[golf=hole] {color: darkgreen; width: 5; casing-color: green; casing-width: 10; } way[golf=hole] {color: darkgreen; width: 5; casing-color: green; casing-width: 2; }
way[leisure=sports_centre] :area { color: #66ddcc; fill-color: #66ddcc; set .area_small_name; } way[leisure=sports_centre] :area { color: #66ddcc; fill-color: #66ddcc; set .area_small_name; }
/* Physical decoration */ /* Physical decoration */
way[bridge=yes], way[bridge=viaduct], way[bridge=suspension] way[bridge=yes]::bridge1, way[bridge=viaduct]::bridge1, way[bridge=suspension]::bridge1 { z-index: 4; color: white; width: eval('_width+3'); }
{ z-index: 4; color: white; width: eval('_width+3'); } way[bridge=yes]::bridge2, way[bridge=viaduct]::bridge2, way[bridge=suspension]::bridge2 { z-index: 3; color: black; width: eval('_width+6'); }
{ z-index: 3; color: black; width: eval('_width+6'); } way[tunnel=yes][!waterway]::bridge1 { z-index: 4; color: white; width: eval('_width+2'); }
way[tunnel=yes][!waterway] way[tunnel=yes][!waterway]::bridge2 { z-index: 3; color: black; width: eval('_width+6'); dashes: 4,4; }
{ z-index: 4; color: white; width: eval('_width+2'); }
{ z-index: 3; color: black; width: eval('_width+6'); dashes: 4,4; }
/* Attribute decoration */ /* Attribute decoration */
way[oneway=yes], way[junction=roundabout] { z-index: 15; color: #444444; width: 2; dashes: 15,35; line-style: arrows; } way[oneway=yes]::arrows, way[junction=roundabout]::arrows { z-index: 15; color: #444444; width: 2; dashes: 15,35; line-style: arrows; }
way[oneway=-1] { z-index: 15; color: #444444; width: 2; dashes: 15,35; line-style: arrows-reversed; } way[oneway=-1]::arrows { z-index: 15; color: #444444; width: 2; dashes: 15,35; line-style: arrows-reversed; }

View file

@ -12,12 +12,12 @@
/* Access */ /* Access */
way[access=private],way[access=no] { z-index: 10; color: red; width: eval('_width+2'); dashes: 2,5;} way[access=private]::access,way[access=no]::access { z-index: 10; color: red; width: eval('_width+2'); dashes: 2,5;}
way[access=permissive] { z-index: 10; color: green; width: eval('_width+2'); dashes: 1,3;} way[access=permissive]::access { z-index: 10; color: green; width: eval('_width+2'); dashes: 1,3;}
/* Physical */ /* Physical */
way[embankment=yes], way[cutting=yes] way[embankment=yes]::hatches, way[cutting=yes]::hatches
{ z-index: 3; opacity: 0.5; color: grey; width: eval('_width+5'); dashes: 2, 2; } { z-index: 3; opacity: 0.5; color: grey; width: eval('_width+5'); dashes: 2, 2; }
/* Interactive behaviour */ /* Interactive behaviour */
@ -28,8 +28,8 @@ way .area_small_name {text-color: black; font-size: 9; text: name; text-halo: #f
/* Direction on selected ways */ /* Direction on selected ways */
way[highway][!oneway][junction!=roundabout]:selected, way[highway][!oneway][junction!=roundabout]::direction :selected,
way[aerial_way]:selected { z-index: 14; color: #999922; width: 2; dashes: 3,60; line-style: arrows; } way[aerial_way]::direction :selected { z-index: 14; color: #999922; width: 2; dashes: 3,60; line-style: arrows; }
way[waterway]:selected { z-index: 14; color: #4444CC; width: 2; dashes: 5,60; line-style: arrows; } way[waterway]::direction :selected { z-index: 14; color: #4444CC; width: 2; dashes: 5,60; line-style: arrows; }
way[railway] :selected{ z-index: 14; color: #999999; width: 3; dashes: 4,92; line-style: arrows; } way[railway]::direction :selected{ z-index: 14; color: #999999; width: 3; dashes: 4,92; line-style: arrows; }

View file

@ -12,12 +12,12 @@
/* Access */ /* Access */
way[access=private],way[access=no] { z-index: 10; color: red; width: eval('_width+2'); dashes: 2,5;} way[access=private]::access,way[access=no]::access { z-index: 10; color: red; width: eval('_width+2'); dashes: 2,5;}
way[access=permissive] { z-index: 10; color: green; width: eval('_width+2'); dashes: 1,3;} way[access=permissive]::access { z-index: 10; color: green; width: eval('_width+2'); dashes: 1,3;}
/* Physical */ /* Physical */
way[embankment=yes], way[cutting=yes] way[embankment=yes]::hatches, way[cutting=yes]::hatches
{ z-index: 3; opacity: 0.5; color: grey; width: eval('_width+5'); dashes: 2, 2; } { z-index: 3; opacity: 0.5; color: grey; width: eval('_width+5'); dashes: 2, 2; }
/* Interactive behaviour */ /* Interactive behaviour */
@ -28,8 +28,8 @@ way .area_small_name {text-color: black; font-size: 9; text: name; text-halo: #f
/* Direction on selected ways */ /* Direction on selected ways */
way[highway][!oneway][junction!=roundabout]:selected, way[highway][!oneway][junction!=roundabout]::direction :selected,
way[aerial_way]:selected { z-index: 14; color: #999922; width: 2; dashes: 3,60; line-style: arrows; } way[aerial_way]::direction :selected { z-index: 14; color: #999922; width: 2; dashes: 3,60; line-style: arrows; }
way[waterway]:selected { z-index: 14; color: #4444CC; width: 2; dashes: 5,60; line-style: arrows; } way[waterway]::direction :selected { z-index: 14; color: #4444CC; width: 2; dashes: 5,60; line-style: arrows; }
way[railway] :selected{ z-index: 14; color: #999999; width: 3; dashes: 4,92; line-style: arrows; } way[railway]::direction :selected{ z-index: 14; color: #999999; width: 3; dashes: 4,92; line-style: arrows; }

View file

@ -27,17 +27,17 @@ way[highway=primary],way[highway=primary_link],
way[highway=secondary],way[highway=secondary_link], way[highway=secondary],way[highway=secondary_link],
way[highway=tertiary],way[highway=tertiary_link], way[highway=tertiary],way[highway=tertiary_link],
way[highway=residential] { text: name; text-color: black; font-size: 7; text-position: line;}*/ way[highway=residential] { text: name; text-color: black; font-size: 7; text-position: line;}*/
way[highway=motorway],way[highway=motorway_link] { z-index: 9; color: #bfbfcf; width: 7; casing-color: #506077; casing-width: 9; } way[highway=motorway],way[highway=motorway_link] { z-index: 9; color: #bfbfcf; width: 7; casing-color: #506077; casing-width: 1; }
way[highway=trunk],way[highway=trunk_link] { z-index: 9; color: #c8d8c8; width: 7; casing-color: #477147; casing-width: 9; } way[highway=trunk],way[highway=trunk_link] { z-index: 9; color: #c8d8c8; width: 7; casing-color: #477147; casing-width: 1; }
way[highway=primary],way[highway=primary_link] { z-index: 8; color: #d8c8c8; width: 7; casing-color: #8d4346; casing-width: 9; } way[highway=primary],way[highway=primary_link] { z-index: 8; color: #d8c8c8; width: 7; casing-color: #8d4346; casing-width: 1; }
way[highway=secondary],way[highway=secondary_link] { z-index: 7; color: #eeeec9; width: 7; casing-color: #a37b48; casing-width: 9; } way[highway=secondary],way[highway=secondary_link] { z-index: 7; color: #eeeec9; width: 7; casing-color: #a37b48; casing-width: 1; }
way[highway=tertiary],way[highway=unclassified] { z-index: 6; color: #eeeec9; width: 5; casing-color: #999999; casing-width: 7; } way[highway=tertiary],way[highway=unclassified] { z-index: 6; color: #eeeec9; width: 5; casing-color: #999999; casing-width: 1; }
way[highway=residential] { z-index: 5; color: white; width: 5; casing-color: #999; casing-width: 7; } way[highway=residential] { z-index: 5; color: white; width: 5; casing-color: #999; casing-width: 1; }
way[highway=service] { color: white; width: 3; casing-color: #999; casing-width: 5; } way[highway=service] { color: white; width: 3; casing-color: #999; casing-width: 1; }
/* Pedestrian precincts need to be treated carefully. Only closed-loops with an explicit /* Pedestrian precincts need to be treated carefully. Only closed-loops with an explicit
area=yes tag should be filled. The below doesn't yet work as intended. */ area=yes tag should be filled. The below doesn't yet work as intended. */
way[highway=pedestrian] !:area { color: #ddddee; width: 5; casing-color: #555555; casing-width: 6; } way[highway=pedestrian] !:area { color: #ddddee; width: 5; casing-color: #555555; casing-width: 1; }
way[highway=pedestrian] :area { color: #555555; width: 1; fill-color: #ddddee; fill-opacity: 0.8; } way[highway=pedestrian] :area { color: #555555; width: 1; fill-color: #ddddee; fill-opacity: 0.8; }
way[highway=steps] { color: #be6c6c; width: 2; dashes: 4, 2; } way[highway=steps] { color: #be6c6c; width: 2; dashes: 4, 2; }
@ -107,26 +107,22 @@ node[barrier=cattle_grid] { icon-image: icons/cattle_grid.png; }*/
/* We can stack styles at different z-index (depth) */ /* We can stack styles at different z-index (depth) */
way[railway=rail] way[railway=rail] { z-index: 6; color: #444444; width: 5; }
{ z-index: 6; color: #444444; width: 5; } way[railway=rail]::dashes { z-index: 7; color: white; width: 3; dashes: 12,12; }
{ z-index: 7; color: white; width: 3; dashes: 12,12; }
way[railway=platform] { color:black; width: 2; } way[railway=platform] { color:black; width: 2; }
way[railway=subway] way[railway=subway] { z-index: 6; color: #444444; width: 5; }
{ z-index: 6; color: #444444; width: 5; } way[railway=subway]::dashes { z-index: 7; color: white; width: 3; dashes: 8,8; }
{ z-index: 7; color: white; width: 3; dashes: 8,8; }
/* Bridge */ /* Bridge */
way[bridge=yes], way[bridge=viaduct], way[bridge=suspension] way[bridge=yes]::bridge1, way[bridge=viaduct]::bridge1, way[bridge=suspension]::bridge1 { z-index: 4; color: white; width: eval('_width+3'); }
{ z-index: 4; color: white; width: eval('_width+3'); } way[bridge=yes]::bridge2, way[bridge=viaduct]::bridge2, way[bridge=suspension]::bridge2 { z-index: 3; color: black; width: eval('_width+6'); }
{ z-index: 3; color: black; width: eval('_width+6'); }
/* Tunnel */ /* Tunnel */
way[tunnel=yes] way[tunnel=yes]::tunnel1 { z-index: 4; color: white; width: eval('_width+2'); }
{ z-index: 4; color: white; width: eval('_width+2'); } way[tunnel=yes]::tunnel2 { z-index: 3; color: black; width: eval('_width+6'); dashes: 4,4; }
{ z-index: 3; color: black; width: eval('_width+6'); dashes: 4,4; }
/* Oneway */ /* Oneway */
way[oneway=yes] { z-index: 10; color: #6c70d5; width: 2; dashes: 10,30; line-style: arrows; } way[oneway=yes]::arrows { z-index: 10; color: #6c70d5; width: 2; dashes: 10,30; line-style: arrows; }
/* Change the road colour based on dynamically set "highlighted" tag (see earlier) */ /* Change the road colour based on dynamically set "highlighted" tag (see earlier) */
@ -136,24 +132,16 @@ way .highlighted { color: pink; }
/* Interactive editors may choose different behaviour when a user mouses-over or selects /* Interactive editors may choose different behaviour when a user mouses-over or selects
an object. Potlatch 2 supports these but the stand-alone Halcyon viewer does not */ an object. Potlatch 2 supports these but the stand-alone Halcyon viewer does not */
way :hover { z-index: 2; width: eval('_width+10'); color: #ffff99; } @import("stylesheets/core_interactive.css");
way :selected { z-index: 2; width: eval('_width+10'); color: yellow; opacity: 0.7;}
way !:drawn { z-index:10; width: 0.5; color: gray; }
node :selectedway { z-index: 9; icon-image: square; icon-width: 8; color: red; casing-color: #cc0000; casing-width: 1;}
node :hoverway { z-index: 9; icon-image: square; icon-width: 7; color: blue; }
node !:drawn :poi { z-index: 2; icon-image: circle; icon-width: 3; color: lightsteelblue; casing-color: black; casing-width: 1; }
node :selected { z-index: 1; icon-image: square; icon-width: eval('_width+10'); color: yellow; }
node :junction :selectedway { z-index: 8; icon-image: square; icon-width: 12; casing-color: black; casing-width: 1; }
/* Descendant selectors provide an easy way to style relations: this example means "any way /* Descendant selectors provide an easy way to style relations: this example means "any way
which is part of a relation whose type=route". */ which is part of a relation whose type=route". */
relation[type=route] way { z-index: 1; width: 17; color: yellow; opacity: 0.3; } relation[type=route] way::routeline { z-index: 1; width: 17; color: yellow; opacity: 0.3; }
relation[type=route][route=bicycle][network=ncn] way { z-index: 1; width: 12; color: red; opacity: 0.3; } relation[type=route][route=bicycle][network=ncn] way::routeline { z-index: 1; width: 12; color: red; opacity: 0.3; }
relation[type=route][route=bicycle][network=rcn] way { z-index: 1; width: 12; color: cyan; opacity: 0.3; } relation[type=route][route=bicycle][network=rcn] way::routeline { z-index: 1; width: 12; color: cyan; opacity: 0.3; }
relation[type=route][route=bicycle][network=lcn] way { z-index: 1; width: 12; color: blue; opacity: 0.3; } relation[type=route][route=bicycle][network=lcn] way::routeline { z-index: 1; width: 12; color: blue; opacity: 0.3; }
relation[type=route][route=bicycle][network=mtb] way { z-index: 1; width: 12; color: #48a448; opacity: 0.3; } relation[type=route][route=bicycle][network=mtb] way::routeline { z-index: 1; width: 12; color: #48a448; opacity: 0.3; }

View file

@ -18,3 +18,11 @@
way .area_small_name {text-color: black; font-size: 9; text: name; text-halo: #ffffaa; text-halo-radius: 2; text-position: center;} way .area_small_name {text-color: black; font-size: 9; text: name; text-halo: #ffffaa; text-halo-radius: 2; text-position: center;}
@import("stylesheets/core_interactive.css"); @import("stylesheets/core_interactive.css");
/* Test rendering for licence status */
way[_status=no]::status { z-index: 0; width: 20; color: red; }
way[_status=partial]::status { z-index: 0; width: 20; color: red; opacity: 0.4; }
way[_status=unsure]::status { z-index: 0; width: 20; color: orange; opacity: 0.4; }
node[_status=no]::status { z-index: 0; icon-image: square; icon-width: 15; color: red; }
node[_status=partial]::status { z-index: 0; icon-image: square; icon-width: 15; color: red; opacity: 0.4; }
node[_status=unsure]::status { z-index: 0; icon-image: square; icon-width: 15; color: orange; opacity: 0.4; }

View file

@ -723,6 +723,21 @@ table.browse_details th {
margin-top: 5px; margin-top: 5px;
} }
table#login_openid_buttons {
padding-bottom: 10px;
}
#login_openid_buttons td {
padding-left: 10px;
padding-right: 10px;
padding-top: 5px;
padding-bottom: 5px;
}
#login_openid_buttons img {
border: 0;
}
#login_signup form.button-to div { #login_signup form.button-to div {
margin: 0px; margin: 0px;
padding: 0px; padding: 0px;
@ -927,6 +942,11 @@ input[type="submit"] {
border: 1px solid black; border: 1px solid black;
} }
input.openid_url {
background: url('../images/openid_input.png') repeat-y left white;
padding-left: 16px;
}
/* Rules for user images */ /* Rules for user images */
img.user_image { img.user_image {
@ -969,3 +989,10 @@ abbr.geo {
.table1 { .table1 {
background: #fff; background: #fff;
} }
/* Rules for OpenID logo */
.openid_logo {
vertical-align: text-bottom;
border: 0;
}

View file

@ -126,16 +126,28 @@ h1 {
/* Rules for the login form */ /* Rules for the login form */
#loginForm input#user_email { #login_login input#user_email {
width: 100%; width: 100%;
max-width: 18em; max-width: 18em;
} }
#loginForm input#user_password { #login_login input#user_password {
width: 100%; width: 100%;
max-width: 18em; max-width: 18em;
} }
#login_login input#openid_url {
width: 100%;
max-width: 18em;
}
#login_openid_buttons td {
padding-left: 2px;
padding-right: 2px;
padding-top: 2px;
padding-bottom: 2px;
}
/* Rules for the profile page */ /* Rules for the profile page */
.user_map { .user_map {

View file

@ -84,3 +84,14 @@ terms_not_seen_user:
display_name: not_agreed display_name: not_agreed
data_public: true data_public: true
terms_seen: false terms_seen: false
openid_user:
id: 8
email: openid-user@example.com
status: active
pass_crypt: <%= Digest::MD5.hexdigest('test') %>
creation_time: "2008-05-01 01:23:45"
display_name: openIDuser
data_public: true
openid_url: http://localhost:1123/john.doe?openid.success=true
terms_seen: true

View file

@ -12,7 +12,7 @@ class ClientApplicationTest < ActionController::IntegrationTest
assert_redirected_to "controller" => "user", "action" => "login", "cookie_test" => "true" assert_redirected_to "controller" => "user", "action" => "login", "cookie_test" => "true"
follow_redirect! follow_redirect!
assert_response :success assert_response :success
post '/login', {'user[email]' => "test@example.com", 'user[password]' => "test", :referer => '/user/test2'} post '/login', {'username' => "test@example.com", 'password' => "test", :referer => '/user/test2'}
assert_response :redirect assert_response :redirect
follow_redirect! follow_redirect!
assert_response :success assert_response :success

View file

@ -39,7 +39,7 @@ class UserBlocksTest < ActionController::IntegrationTest
# revoke the ban # revoke the ban
get '/login' get '/login'
assert_response :success assert_response :success
post '/login', {'user[email]' => moderator.email, 'user[password]' => "test", :referer => "/blocks/#{block.id}/revoke"} post '/login', {'username' => moderator.email, 'password' => "test", :referer => "/blocks/#{block.id}/revoke"}
assert_response :redirect assert_response :redirect
follow_redirect! follow_redirect!
assert_response :success assert_response :success

View file

@ -3,6 +3,10 @@ require File.dirname(__FILE__) + '/../test_helper'
class UserCreationTest < ActionController::IntegrationTest class UserCreationTest < ActionController::IntegrationTest
fixtures :users fixtures :users
def setup
openid_setup
end
def test_create_user_form def test_create_user_form
I18n.available_locales.each do |locale| I18n.available_locales.each do |locale|
get '/user/new', {}, {"accept_language" => locale.to_s} get '/user/new', {}, {"accept_language" => locale.to_s}
@ -94,8 +98,12 @@ class UserCreationTest < ActionController::IntegrationTest
referer = "/traces/mine" referer = "/traces/mine"
assert_difference('User.count') do assert_difference('User.count') do
assert_difference('ActionMailer::Base.deliveries.size', 1) do assert_difference('ActionMailer::Base.deliveries.size', 1) do
post_via_redirect "/user/save", post "/user/terms",
{:user => { :email => new_email, :email_confirmation => new_email, :display_name => display_name, :pass_crypt => password, :pass_crypt_confirmation => password}, :referer => referer } {:user => { :email => new_email, :email_confirmation => new_email, :display_name => display_name, :pass_crypt => password, :pass_crypt_confirmation => password}, :referer => referer }
assert_response :success
assert_template 'terms'
post_via_redirect "/user/save",
{:user => { :email => new_email, :email_confirmation => new_email, :display_name => display_name, :pass_crypt => password, :pass_crypt_confirmation => password} }
end end
end end
@ -127,4 +135,99 @@ class UserCreationTest < ActionController::IntegrationTest
assert_response :success assert_response :success
assert_template "trace/list.html.erb" assert_template "trace/list.html.erb"
end end
def test_user_create_openid_success
new_email = "newtester-openid@osm.org"
display_name = "new_tester-openid"
password = "testtest"
assert_difference('User.count') do
assert_difference('ActionMailer::Base.deliveries.size', 1) do
post "/user/terms",
{:user => { :email => new_email, :email_confirmation => new_email, :display_name => display_name, :openid_url => "http://localhost:1123/john.doe?openid.success=newuser", :pass_crypt => "", :pass_crypt_confirmation => ""}}
assert_response :redirect
res = openid_request(@response.redirected_to)
post '/user/terms', res
assert_response :success
assert_template 'terms'
post '/user/save',
{:user => { :email => new_email, :email_confirmation => new_email, :display_name => display_name, :openid_url => "http://localhost:1123/john.doe?openid.success=newuser", :pass_crypt => password, :pass_crypt_confirmation => password}}
assert_response :redirect
follow_redirect!
end
end
# Check the page
assert_response :success
assert_template 'login'
ActionMailer::Base.deliveries.clear
end
def test_user_create_openid_failure
new_email = "newtester-openid2@osm.org"
display_name = "new_tester-openid2"
password = "testtest2"
assert_difference('User.count',0) do
assert_difference('ActionMailer::Base.deliveries.size',0) do
post "/user/terms",
{:user => { :email => new_email, :email_confirmation => new_email, :display_name => display_name, :openid_url => "http://localhost:1123/john.doe?openid.failure=newuser", :pass_crypt => "", :pass_crypt_confirmation => ""}}
assert_response :redirect
res = openid_request(@response.redirected_to)
post '/user/terms', res
assert_response :success
assert_template 'user/new'
end
end
ActionMailer::Base.deliveries.clear
end
def test_user_create_openid_redirect
new_email = "redirect_tester_openid@osm.org"
display_name = "redirect_tester_openid"
password = ""
# nothing special about this page, just need a protected page to redirect back to.
referer = "/traces/mine"
assert_difference('User.count') do
assert_difference('ActionMailer::Base.deliveries.size', 1) do
post "/user/terms",
{:user => { :email => new_email, :email_confirmation => new_email, :display_name => display_name, :openid_url => "http://localhost:1123/john.doe?openid.success=newuser", :pass_crypt => "", :pass_crypt_confirmation => ""}, :referer => referer }
assert_response :redirect
res = openid_request(@response.location)
post '/user/terms', res
assert_response :success
assert_template 'terms'
post_via_redirect "/user/save",
{:user => { :email => new_email, :email_confirmation => new_email, :display_name => display_name, :openid_url => "http://localhost:1123/john.doe?openid.success=newuser", :pass_crypt => "testtest", :pass_crypt_confirmation => "testtest"} }
end
end
# Check the e-mail
register_email = ActionMailer::Base.deliveries.first
assert_equal register_email.to[0], new_email
# Check that the confirm account url is correct
confirm_regex = Regexp.new("/user/redirect_tester_openid/confirm\\?confirm_string=([a-zA-Z0-9]*)")
assert_match(confirm_regex, register_email.body)
confirm_string = confirm_regex.match(register_email.body)[1]
# Check the page
assert_response :success
assert_template 'login'
ActionMailer::Base.deliveries.clear
# Go to the confirmation page
get 'user/confirm', { :confirm_string => confirm_string }
assert_response :success
assert_template 'user/confirm'
post 'user/confirm', { :confirm_string => confirm_string, :confirm_action => 'submit' }
assert_response :redirect # to trace/mine in original referrer
follow_redirect!
assert_response :redirect # but it not redirects to /user/<display_name>/traces
follow_redirect!
assert_response :success
assert_template "trace/list.html.erb"
end
end end

View file

@ -11,7 +11,7 @@ class UserDiariesTest < ActionController::IntegrationTest
assert_response :success assert_response :success
assert_template 'user/login' assert_template 'user/login'
# We can now login # We can now login
post '/login', {'user[email]' => "test@openstreetmap.org", 'user[password]' => "test", :referer => '/diary/new'} post '/login', {'username' => "test@openstreetmap.org", 'password' => "test", :referer => '/diary/new'}
assert_response :redirect assert_response :redirect
#print @response.body #print @response.body
# Check that there is some payload alerting the user to the redirect # Check that there is some payload alerting the user to the redirect

View file

@ -0,0 +1,91 @@
require File.dirname(__FILE__) + '/../test_helper'
class UserLoginTest < ActionController::IntegrationTest
fixtures :users
def setup
openid_setup
end
def test_login_openid_success
get '/login'
assert_response :redirect
assert_redirected_to "controller" => "user", "action" => "login", "cookie_test" => "true"
follow_redirect!
assert_response :success
post '/login', {'openid_url' => "http://localhost:1123/john.doe?openid.success=true", :referer => "/browse"}
assert_response :redirect
res = openid_request(@response.redirected_to)
res2 = post '/login', res
assert_response :redirect
follow_redirect!
assert_response :success
assert_template 'changeset/list'
end
def test_login_openid_cancel
get '/login'
assert_response :redirect
assert_redirected_to "controller" => "user", "action" => "login", "cookie_test" => "true"
follow_redirect!
assert_response :success
post '/login', {'openid_url' => "http://localhost:1123/john.doe", :referer => "/diary"}
assert_response :redirect
res = openid_request(@response.redirected_to)
post '/login', res
assert_response :redirect
follow_redirect!
assert_response :success
assert_template 'login'
end
def test_login_openid_invalid_provider
get '/login'
assert_response :redirect
assert_redirected_to "controller" => "user", "action" => "login", "cookie_test" => "true"
follow_redirect!
assert_response :success
#Use a different port that doesn't have the OpenID provider running on to test an invalid openID
post '/login', {'openid_url' => "http://localhost:1124/john.doe", :referer => "/diary"}
assert_response :redirect
follow_redirect!
assert_response :success
assert_template 'login'
end
def test_login_openid_invalid_url
get '/login'
assert_response :redirect
assert_redirected_to "controller" => "user", "action" => "login", "cookie_test" => "true"
follow_redirect!
assert_response :success
#Use a url with an invalid protocol to make sure it handles that correctly too
post '/login', {'openid_url' => "htt://localhost:1123/john.doe", :referer => "/diary"}
assert_response :redirect
follow_redirect!
assert_response :success
assert_template 'login'
end
def test_login_openid_unknown
get '/login'
assert_response :redirect
assert_redirected_to "controller" => "user", "action" => "login", "cookie_test" => "true"
follow_redirect!
assert_response :success
post '/login', {'openid_url' => "http://localhost:1123/john.doe?openid.success=true_somethingelse", :referer => "/diary"}
assert_response :redirect
res = openid_request(@response.redirected_to)
res2 = post '/login', res
assert_response :redirect
follow_redirect!
assert_response :success
assert_template 'user/new'
end
end

View file

@ -22,7 +22,7 @@ class UserRolesControllerTest < ActionController::IntegrationTest
assert_redirected_to "controller" => "user", "action" => "login", "cookie_test" => "true" assert_redirected_to "controller" => "user", "action" => "login", "cookie_test" => "true"
follow_redirect! follow_redirect!
assert_response :success assert_response :success
post '/login', {'user[email]' => users(user).email, 'user[password]' => "test", :referer => "/"} post '/login', {'username' => users(user).email, 'password' => "test", :referer => "/"}
assert_response :redirect assert_response :redirect
follow_redirect! follow_redirect!
assert_response :success assert_response :success
@ -40,7 +40,7 @@ class UserRolesControllerTest < ActionController::IntegrationTest
assert_redirected_to "controller" => "user", "action" => "login", "cookie_test" => "true" assert_redirected_to "controller" => "user", "action" => "login", "cookie_test" => "true"
follow_redirect! follow_redirect!
assert_response :success assert_response :success
post '/login', {'user[email]' => users(user).email, 'user[password]' => "test", :referer => "/"} post '/login', {'username' => users(user).email, 'password' => "test", :referer => "/"}
assert_response :redirect assert_response :redirect
follow_redirect! follow_redirect!
assert_response :success assert_response :success

View file

@ -3,6 +3,43 @@ require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
require 'test_help' require 'test_help'
load 'composite_primary_keys/fixtures.rb' load 'composite_primary_keys/fixtures.rb'
# This monkey patch is to make tests where a rack module alters
# the response work with rails 2 - it can be dropped when we move
# to rails 3.
module ActionController
module Integration
class Session
def process_with_capture(method, path, parameters = nil, headers = nil)
status = process_without_capture(method, path, parameters, headers)
@controller = ActionController::Base.last_controller
@request = @controller.request
@response.session = @controller.response.session
@response.template = @controller.response.template
@response.redirected_to = @response.location
status
end
alias_method_chain :process, :capture
end
module ControllerCapture
module ClassMethods
mattr_accessor :last_controller
def clear_last_instantiation!
self.last_controller = nil
end
def new_with_capture(*args)
controller = new_without_capture(*args)
self.last_controller ||= controller
controller
end
end
end
end
end
class ActiveSupport::TestCase class ActiveSupport::TestCase
# Transactional fixtures accelerate your tests by wrapping each test method # Transactional fixtures accelerate your tests by wrapping each test method
# in a transaction that's rolled back on completion. This ensures that the # in a transaction that's rolled back on completion. This ensures that the
@ -146,5 +183,43 @@ class ActiveSupport::TestCase
assert_select "span[class=translation_missing]", false, "Missing translation #{msg}" assert_select "span[class=translation_missing]", false, "Missing translation #{msg}"
end end
# Set things up for OpenID testing
def openid_setup
begin
# Test if the ROTS (Ruby OpenID Test Server) is already running
rots_response = Net::HTTP.get_response(URI.parse("http://localhost:1123/"))
rescue
# It isn't, so start a new instance.
rots = IO.popen(RAILS_ROOT + "/vendor/gems/rots-0.2.1/bin/rots --silent")
# Wait for up to 30 seconds for the server to start and respond before continuing
for i in (1 .. 30)
begin
sleep 1
rots_response = Net::HTTP.get_response(URI.parse("http://localhost:1123/"))
# If the rescue block doesn't fire, ROTS is up and running and we can continue
break
rescue
# If the connection failed, do nothing and repeat the loop
end
end
# Arrange to kill the process when we exit - note that we need
# to kill it really har due to a bug in ROTS
Kernel.at_exit do
Process.kill("KILL", rots.pid)
end
end
end
def openid_request(openid_request_uri)
openid_response = Net::HTTP.get_response(URI.parse(openid_request_uri))
openid_response_uri = URI(openid_response['Location'])
openid_response_qs = Rack::Utils.parse_query(openid_response_uri.query)
return openid_response_qs
end
# Add more helper methods to be used by all tests here... # Add more helper methods to be used by all tests here...
end end

112
vendor/gems/rots-0.2.1/.specification vendored Normal file
View file

@ -0,0 +1,112 @@
--- !ruby/object:Gem::Specification
name: rots
version: !ruby/object:Gem::Version
prerelease: false
segments:
- 0
- 2
- 1
version: 0.2.1
platform: ruby
authors:
- Roman Gonzalez
autorequire:
bindir: bin
cert_chain: []
date: 2010-05-11 00:00:00 +01:00
default_executable: rots
dependencies:
- !ruby/object:Gem::Dependency
name: rspec
prerelease: false
requirement: &id001 !ruby/object:Gem::Requirement
requirements:
- - ">="
- !ruby/object:Gem::Version
segments:
- 0
version: "0"
type: :development
version_requirements: *id001
- !ruby/object:Gem::Dependency
name: rack
prerelease: false
requirement: &id002 !ruby/object:Gem::Requirement
requirements:
- - ">="
- !ruby/object:Gem::Version
segments:
- 0
version: "0"
type: :development
version_requirements: *id002
- !ruby/object:Gem::Dependency
name: ruby-openid
prerelease: false
requirement: &id003 !ruby/object:Gem::Requirement
requirements:
- - ">="
- !ruby/object:Gem::Version
segments:
- 0
version: "0"
type: :development
version_requirements: *id003
description: |
Ruby OpenID Test Server (ROST) provides a basic OpenID server made in top of the Rack gem.
With this small server, you can make dummy OpenID request for testing purposes,
the success of the response will depend on a parameter given on the url of the authentication request.
email: romanandreg@gmail.com
executables:
- rots
extensions: []
extra_rdoc_files:
- README
files:
- AUTHORS
- README
- Rakefile
- bin/rots
- lib/rots.rb
- lib/rots/identity_page_app.rb
- lib/rots/server_app.rb
- lib/rots/test_helper.rb
- rots.gemspec
- spec/server_app_spec.rb
- spec/spec_helper.rb
has_rdoc: true
homepage: http://github.com/roman
licenses: []
post_install_message:
rdoc_options: []
require_paths:
- lib
required_ruby_version: !ruby/object:Gem::Requirement
requirements:
- - ">="
- !ruby/object:Gem::Version
segments:
- 0
version: "0"
required_rubygems_version: !ruby/object:Gem::Requirement
requirements:
- - ">="
- !ruby/object:Gem::Version
segments:
- 0
version: "0"
requirements: []
rubyforge_project: rots
rubygems_version: 1.3.6
signing_key:
specification_version: 3
summary: an OpenID server for making tests of OpenID clients implementations
test_files:
- spec/server_app_spec.rb
- spec/spec_helper.rb

2
vendor/gems/rots-0.2.1/AUTHORS vendored Normal file
View file

@ -0,0 +1,2 @@
* Roman Gonzalez <romanandreg@gmail.com>
* Anibal Rojas <anibal@rojas.net.ve>

64
vendor/gems/rots-0.2.1/README vendored Normal file
View file

@ -0,0 +1,64 @@
= Ruby OpenID Test Server (ROTS), a dummy OpenID server that makes consumer tests dead easy.
ROTS is a minimal implementation of an OpenID server, developed on top of the Rack middleware, this
server provides an easy to use interface to make testing OpenID consumers really easy.
== No more mocks
Have you always wanted to test the authentication of an OpenID consumer implementation, but find your self
in a point where is to hard to mock? A lot of people have been there.
With ROTS, you only need to specify an identity url provided by the dummy server, passing with it a flag
saying that you want the authentication to be successful. It handles SREG extensions as well.
== How does it works
When you install the ROTS gem, a binary called rots is provided for starting the server (for more
info about what options you have when executing this file, check the -h option).
By default, rots will have a test user called "John Doe", with an OpenID identity "john.doe".
If you want to use your own test user name, you can specify a config file to rots. The
default configuration file looks like this:
# Default configuration file
identity: john.doe
sreg:
nickname: jdoe
fullname: John Doe
email: jhon@doe.com
dob: 1985-09-21
gender: M
You can specify a new config file using the option --config.
== Getting Started
The best way to get started, is running the rots server, and then starting to execute your OpenID consumer tests/specs. You just have to specify the identity url of your test user, if you want the OpenID response be successful just add the openid.success=true flag to the user identity url. If you don't specify the flag it
will return a cancel response instead.
Example:
it "should authenticate with OpenID" do
post("/consumer_openid_login", 'identity_url' => 'http://localhost:1132/john.doe?openid.success=true')
end
== Copyright
Copyright (C) 2009 Roman Gonzalez <romanandreg@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

125
vendor/gems/rots-0.2.1/Rakefile vendored Normal file
View file

@ -0,0 +1,125 @@
# Rakefile for Rack. -*-ruby-*-
require 'rake/rdoctask'
require 'rake/testtask'
require 'spec/rake/spectask'
desc "Run all the tests"
task :default => [:spec]
desc "Do predistribution stuff"
task :predist => [:changelog, :rdoc]
desc "Make an archive as .tar.gz"
task :dist => [:fulltest, :predist] do
sh "git archive --format=tar --prefix=#{release}/ HEAD^{tree} >#{release}.tar"
sh "pax -waf #{release}.tar -s ':^:#{release}/:' RDOX SPEC ChangeLog doc"
sh "gzip -f -9 #{release}.tar"
end
# Helper to retrieve the "revision number" of the git tree.
def git_tree_version
#if File.directory?(".git")
# @tree_version ||= `git describe`.strip.sub('-', '.')
# @tree_version << ".0" unless @tree_version.count('.') == 2
#else
$: << "lib"
require 'rots'
@tree_version = Rots.release
#end
@tree_version
end
def gem_version
git_tree_version.gsub(/-.*/, '')
end
def release
"ruby-openid-tester-#{git_tree_version}"
end
def manifest
`git ls-files`.split("\n")
end
desc "Generate a ChangeLog"
task :changelog do
File.open("ChangeLog", "w") do |out|
`git log -z`.split("\0").map do |chunk|
author = chunk[/Author: (.*)/, 1].strip
date = chunk[/Date: (.*)/, 1].strip
desc, detail = $'.strip.split("\n", 2)
detail ||= ""
detail.rstrip!
out.puts "#{date} #{author}"
out.puts " * #{desc.strip}"
out.puts detail unless detail.empty?
out.puts
end
end
end
begin
require 'rubygems'
require 'rake'
require 'rake/clean'
require 'rake/packagetask'
require 'rake/gempackagetask'
require 'fileutils'
rescue LoadError
# Too bad.
else
spec = Gem::Specification.new do |s|
s.name = "rots"
s.version = gem_version
s.platform = Gem::Platform::RUBY
s.summary = "an OpenID server for making tests of OpenID clients implementations"
s.description = <<-EOF
Ruby OpenID Test Server (ROST) provides a basic OpenID server made in top of the Rack gem.
With this small server, you can make dummy OpenID request for testing purposes,
the success of the response will depend on a parameter given on the url of the authentication request.
EOF
s.files = manifest
s.bindir = 'bin'
s.executables << 'rots'
s.require_path = 'lib'
s.has_rdoc = true
s.extra_rdoc_files = ['README']
s.test_files = Dir['spec/*_spec.rb']
s.author = 'Roman Gonzalez'
s.email = 'romanandreg@gmail.com'
s.homepage = 'http://github.com/roman'
s.rubyforge_project = 'rots'
s.add_development_dependency 'rspec'
s.add_development_dependency 'rack'
s.add_development_dependency 'ruby-openid', '~> 2.0.0'
end
Rake::GemPackageTask.new(spec) do |p|
p.gem_spec = spec
p.need_tar = false
p.need_zip = false
end
end
Spec::Rake::SpecTask.new do |t|
end
desc "Generate RDoc documentation"
Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.options << '--line-numbers' << '--inline-source' <<
'--main' << 'README' <<
'--title' << 'ROTS Documentation' <<
'--charset' << 'utf-8'
rdoc.rdoc_dir = "doc"
rdoc.rdoc_files.include 'README'
rdoc.rdoc_files.include('lib/ruby_openid_test_server.rb')
rdoc.rdoc_files.include('lib/ruby_openid_test_server/*.rb')
end

99
vendor/gems/rots-0.2.1/bin/rots vendored Executable file
View file

@ -0,0 +1,99 @@
#!/usr/bin/env ruby
# -*- ruby -*-
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
require "rubygems"
require "optparse"
require "rack"
require "yaml"
require "rots"
server_options = {
:debugger => false,
:port => 1123,
:verbose => true,
:storage => File.join('.', 'tmp', 'rots'),
:config => <<-DEFAULT_CONFIG
# Default configuration file
identity: john.doe
sreg:
nickname: jdoe
fullname: John Doe
email: jhon@doe.com
dob: 1985-09-21
gender: M
DEFAULT_CONFIG
}
opts = OptionParser.new do |opts|
opts.banner = "Usage: rots [options]"
opts.separator ""
opts.separator "Options:"
opts.on("-p", "--port PORT",
"use PORT (default: 1123)") do |port|
server_options[:port] = port
end
opts.on("-s", "--storage PATH",
"use PATH as the OpenID Server storage path (default: ./tmp/rots)") do |storage_path|
server_options[:storage] = storage_path
end
opts.on("-c", "--config FILE.yaml",
"server configuration YAML file") do |config_path|
abort "\x1B[31mConfiguration file #{config_path} not found\x1B[0m" unless File.exists?(config_path)
server_options[:config] = File.new(config_path)
end
opts.on("-s", "--silent",
"If specified, the server will be in silent mode") do
server_options[:verbose] = false
end
opts.on("-d", "--debugger") do
server_options[:debugger] = true
end
opts.separator ""
opts.separator "Common options:"
opts.on_tail("-h", "--help", "Show this help message") do
puts opts
exit
end
end
opts.parse!(ARGV)
config = YAML.load(server_options[:config])
require "ruby-debug" if server_options[:debugger]
server = Rack::Builder.new do
use Rack::Lint
if server_options[:verbose]
use Rack::CommonLogger, STDOUT
use Rack::ShowExceptions
end
map ("/%s" % config['identity']) do
run Rots::IdentityPageApp.new(config, server_options)
end
map "/server" do
run Rots::ServerApp.new(config, server_options)
end
end
puts "\x1B[32mRunning OpenID Test server on port 1123\x1B[0m" if server_options[:verbose]
begin
Rack::Handler::Mongrel.run server, :Port => server_options[:port]
rescue LoadError
if server_options[:verbose]
Rack::Handler::WEBrick.run server, :Port => server_options[:port]
else
Rack::Handler::WEBrick.run server, :Port => server_options[:port], :AccessLog => [], :Logger => WEBrick::Log::new("/dev/null", 7)
end
end

11
vendor/gems/rots-0.2.1/lib/rots.rb vendored Normal file
View file

@ -0,0 +1,11 @@
module Rots
def self.release
"0.2.1"
end
end
require "rots/server_app"
require "rots/identity_page_app"
require "rots/test_helper"

View file

@ -0,0 +1,36 @@
require 'rack/request'
require 'rack/response'
require 'rack/utils'
require 'openid'
class Rots::IdentityPageApp
def initialize(config, server_options)
@server_options = server_options
@config = config
end
def call(env)
@request = Rack::Request.new(env)
Rack::Response.new do |response|
response.write <<-HERE
<html>
<head>
<link rel="openid2.provider" href="#{op_endpoint}" />
<link rel="openid.server" href="#{op_endpoint}" />
</head>
<body>
<h1>This is #{@config['identity']} identity page</h1>
</body>
</html>
HERE
end.finish
end
def op_endpoint
"http://%s:%d/server/%s" % [@request.host,
@request.port,
(@request.params['openid.success'] ? '?openid.success=true' : '')]
end
end

View file

@ -0,0 +1,147 @@
require 'openid'
require 'openid/extension'
require 'openid/extensions/sreg'
require 'openid/store/filesystem'
require 'openid/util'
require 'rack/request'
require 'rack/utils'
require 'fileutils'
module Rots
class ServerApp
attr_accessor :request,:openid_request,
:response, :openid_response,
:server
def initialize(config, server_options)
@server_options = server_options
@sreg_fields = config['sreg']
end
def call(env)
on_openid_request(env) do
if !is_checkid_request?
@openid_response = @server.handle_request(@openid_request)
reply_consumer
elsif is_checkid_immediate?
process_immediate_checkid_request
else
process_checkid_request
end
end
end
protected
def on_openid_request(env)
create_wrappers(env)
if @openid_request.nil?
[200, {'Content-Type' => 'text/html'},
["<html><body><h1>ROTS => This is an OpenID endpoint</h1></body></html>"] ]
else
yield
end
end
def create_wrappers(env)
@request = Rack::Request.new(env)
@server = OpenID::Server::Server.new(storage, op_endpoint)
@openid_request = @server.decode_request(@request.params)
@openid_sreg_request = OpenID::SReg::Request.from_openid_request(@openid_request) unless @openid_request.nil?
end
def is_checkid_request?
@openid_request.is_a?(OpenID::Server::CheckIDRequest)
end
def is_checkid_immediate?
@openid_request && @openid_request.immediate
end
def process_immediate_checkid_request
# TODO: We should enable the user to configure
# if she wants immediate request support or not
url = OpenID::Util.append_args(@openid_request.return_to,
@request.params.merge('openid.mode' => 'setup_needed'))
redirect(url)
end
def process_checkid_request
if checkid_request_is_valid?
return_successful_openid_response
else
return_cancel_openid_response
end
end
def checkid_request_is_valid?
@request.params['openid.success'] == 'true'
end
def return_successful_openid_response
@openid_response = @openid_request.answer(true)
process_sreg_extension
# TODO: Add support for SREG extension
@server.signatory.sign(@openid_response) if @openid_response.needs_signing
reply_consumer
end
def process_sreg_extension
return if @openid_sreg_request.nil?
response = OpenID::SReg::Response.extract_response(@openid_sreg_request, @sreg_fields)
@openid_response.add_extension(response)
end
def return_cancel_openid_response
redirect(@openid_request.cancel_url)
end
def reply_consumer
web_response = @server.encode_response(@openid_response)
case web_response.code
when OpenID::Server::HTTP_OK
success(web_response.body)
when OpenID::Server::HTTP_REDIRECT
redirect(web_response.headers['location'])
else
bad_request
end
end
def redirect(uri)
[ 303, {'Content-Length'=>'0', 'Content-Type'=>'text/plain',
'Location' => uri},
[] ]
end
def bad_request()
[ 400, {'Content-Type'=>'text/plain', 'Content-Length'=>'0'},
[] ]
end
def storage
# create the folder if it doesn't exist
FileUtils.mkdir_p(@server_options[:storage]) unless File.exist?(@server_options[:storage])
OpenID::Store::Filesystem.new(@server_options[:storage])
end
def success(text="")
Rack::Response.new(text).finish
end
def op_endpoint
if @request.url =~ /(.*\?openid.success=true)/
$1
elsif @request.url =~ /([^?]*)/
$1
else
nil
end
end
end
end

View file

@ -0,0 +1,16 @@
require "openid/consumer"
require "openid/consumer/checkid_request.rb"
require "net/http"
module Rots::TestHelper
def openid_request(openid_request_uri)
openid_response = Net::HTTP.get_response(URI.parse(openid_request_uri))
openid_response_uri = URI(openid_response['Location'])
openid_response_qs = Rack::Utils.parse_query(openid_response_uri.query)
{ :url => openid_response_uri.to_s,
:query_params => openid_response_qs }
end
end

31
vendor/gems/rots-0.2.1/rots.gemspec vendored Normal file
View file

@ -0,0 +1,31 @@
# -*- encoding: utf-8 -*-
Gem::Specification.new do |s|
s.name = "rots"
s.version = '0.2.1'
s.platform = Gem::Platform::RUBY
s.summary = "an OpenID server for making tests of OpenID clients implementations"
s.description = <<-EOF
Ruby OpenID Test Server (ROST) provides a basic OpenID server made in top of the Rack gem.
With this small server, you can make dummy OpenID request for testing purposes,
the success of the response will depend on a parameter given on the url of the authentication request.
EOF
s.files = ["AUTHORS", "README", "Rakefile", "bin/rots", "lib/rots.rb", "lib/rots/identity_page_app.rb", "lib/rots/server_app.rb", "lib/rots/test_helper.rb","rots.gemspec", "spec/server_app_spec.rb", "spec/spec_helper.rb"]
s.bindir = 'bin'
s.executables << 'rots'
s.require_path = 'lib'
s.has_rdoc = true
s.extra_rdoc_files = ['README']
s.test_files = ['spec/server_app_spec.rb', 'spec/spec_helper.rb']
s.author = 'Roman Gonzalez'
s.email = 'romanandreg@gmail.com'
s.homepage = 'http://github.com/roman'
s.rubyforge_project = 'rots'
s.add_development_dependency 'rspec'
s.add_development_dependency 'rack'
s.add_development_dependency 'ruby-openid'
end

View file

@ -0,0 +1,99 @@
require File.join(File.dirname(__FILE__), 'spec_helper')
# This is just a comment test
describe Rots::ServerApp do
describe "when the request is not an OpenID request" do
it "should return a helpful message saying that is an OpenID endpoint" do
request = Rack::MockRequest.new(Rots::ServerApp.new({'sreg' => {}},
{:storage => File.join(*%w(. tmp rots)) }))
response = request.get("/")
response.should be_ok
response.body.should == "<html><body><h1>ROTS => This is an OpenID endpoint</h1></body></html>"
end
end
describe "when the request is an OpenID request" do
before(:each) do
@request = Rack::MockRequest.new(Rots::ServerApp.new({
'identity' => 'john.doe',
'sreg' => {
'email' => "john@doe.com",
'nickname' => 'johndoe',
'fullname' => "John Doe",
'dob' => "1985-09-21",
'gender' => "M"
}},
{:storage => File.join(*%w(. tmp rots))}
))
end
describe "and it is a check_id request" do
describe "and is immediate" do
it "should return an openid.mode equal to setup_needed" do
response = checkid_immediate(@request)
params = openid_params(response)
params['openid.mode'].should == 'setup_needed'
end
end
describe "and is not immediate" do
describe "with a success flag" do
it "should return an openid.mode equal to id_res" do
response = checkid_setup(@request, 'openid.success' => 'true')
params = openid_params(response)
params['openid.mode'].should == 'id_res'
end
end
describe "without a success flag" do
it "should return an openid.mode equal to cancel" do
response = checkid_setup(@request)
params = openid_params(response)
params['openid.mode'].should == 'cancel'
end
end
describe "using SREG extension with a success flag" do
it "should return an openid.mode equal to id_res" do
response = checkid_setup(@request, 'openid.success' => 'true')
params = openid_params(response)
params['openid.mode'].should == 'id_res'
end
it "should return all the sreg fields" do
response = checkid_setup(@request, {
'openid.success' => true,
'openid.ns.sreg' => OpenID::SReg::NS_URI,
'openid.sreg.required' => 'email,nickname,fullname',
'openid.sreg.optional' => 'dob,gender'
})
params = openid_params(response)
params['openid.sreg.email'].should == "john@doe.com"
params['openid.sreg.nickname'].should == 'johndoe'
params['openid.sreg.fullname'].should == "John Doe"
params['openid.sreg.dob'].should == "1985-09-21"
params['openid.sreg.gender'].should == "M"
end
end
end
end
end
end

View file

@ -0,0 +1,73 @@
$:.unshift(File.dirname(__FILE__), '..', 'lib')
require "rubygems"
require "spec"
require "rack"
require "rots"
module Rots::RequestHelper
def checkid_setup(request, params={}, with_associate=true)
assoc_handle = make_association(request) if with_associate
send_checkid(request, :setup, params, assoc_handle)
end
def checkid_immediate(request, params={}, with_associate=true)
assoc_handle = make_association(request) if with_associate
send_checkid(request, :immediate, params, assoc_handle)
end
def openid_params(response)
uri = URI(response.headers['Location'])
Rack::Utils.parse_query(uri.query)
end
protected
def send_checkid(request, mode, params={}, assoc_handle = nil)
params = self.send(:"checkid_#{mode}_params", params)
params.merge('openid.assoc_handle' => assoc_handle) if assoc_handle
qs = "/?" + Rack::Utils.build_query(params)
request.get(qs)
end
def make_association(request)
associate_qs = Rack::Utils.build_query(associate_params)
response = request.post('/', :input => associate_qs)
parse_assoc_handle_from(response)
end
def parse_assoc_handle_from(response)
response.body.split("\n")[0].match(/^assoc_handle:(.*)$/).captures[0]
end
def checkid_setup_params(params = {})
{
"openid.ns" => "http://specs.openid.net/auth/2.0",
"openid.mode" => "checkid_setup",
"openid.claimed_id" => 'john.doe',
"openid.identity" => 'john.doe',
"openid.return_to" => "http://www.google.com"
# need to specify the openid_handle by hand
}.merge!(params)
end
def checkid_immediate_params(params = {})
checkid_setup_params({'openid.mode' => 'checkid_immediate'}.merge!(params))
end
def associate_params
{
"openid.ns" => "http://specs.openid.net/auth/2.0",
"openid.mode" => "associate",
"openid.session_type" => "DH-SHA1",
"openid.assoc_type" => "HMAC-SHA1",
"openid.dh_consumer_public" =>
"U672/RsDUNxAFFAXA+ShVh5LMD2CRdsoqdqhDCPUzfCNy2f44uTWuid/MZuGfJmiVA7QmxqM3GSb8EVq3SGK8eGEwwyzUtatqHidx72rfwAav5AUrZTnwSPQJyiCFrKNGmNhXdRJzcfzSkgaC3hVz2kpADzEevIExG6agns1sYY="
}
end
end
Spec::Runner.configure do |config|
config.include Rots::RequestHelper
end

View file

@ -0,0 +1,37 @@
* Dump heavy lifting off to rack-openid gem. OpenIdAuthentication is just a simple controller concern.
* Fake HTTP method from OpenID server since they only support a GET. Eliminates the need to set an extra route to match the server's reply. [Josh Peek]
* OpenID 2.0 recommends that forms should use the field name "openid_identifier" rather than "openid_url" [Josh Peek]
* Return open_id_response.display_identifier to the application instead of .endpoints.claimed_id. [nbibler]
* Add Timeout protection [Rick]
* An invalid identity url passed through authenticate_with_open_id will no longer raise an InvalidOpenId exception. Instead it will return Result[:missing] to the completion block.
* Allow a return_to option to be used instead of the requested url [Josh Peek]
* Updated plugin to use Ruby OpenID 2.x.x [Josh Peek]
* Tied plugin to ruby-openid 1.1.4 gem until we can make it compatible with 2.x [DHH]
* Use URI instead of regexps to normalize the URL and gain free, better matching #8136 [dkubb]
* Allow -'s in #normalize_url [Rick]
* remove instance of mattr_accessor, it was breaking tests since they don't load ActiveSupport. Fix Timeout test [Rick]
* Throw a InvalidOpenId exception instead of just a RuntimeError when the URL can't be normalized [DHH]
* Just use the path for the return URL, so extra query parameters don't interfere [DHH]
* Added a new default database-backed store after experiencing trouble with the filestore on NFS. The file store is still available as an option [DHH]
* Added normalize_url and applied it to all operations going through the plugin [DHH]
* Removed open_id? as the idea of using the same input box for both OpenID and username has died -- use using_open_id? instead (which checks for the presence of params[:openid_url] by default) [DHH]
* Added OpenIdAuthentication::Result to make it easier to deal with default situations where you don't care to do something particular for each error state [DHH]
* Stop relying on root_url being defined, we can just grab the current url instead [DHH]

View file

@ -0,0 +1,223 @@
OpenIdAuthentication
====================
Provides a thin wrapper around the excellent ruby-openid gem from JanRan. Be sure to install that first:
gem install ruby-openid
To understand what OpenID is about and how it works, it helps to read the documentation for lib/openid/consumer.rb
from that gem.
The specification used is http://openid.net/specs/openid-authentication-2_0.html.
Prerequisites
=============
OpenID authentication uses the session, so be sure that you haven't turned that off.
Alternatively, you can use the file-based store, which just relies on on tmp/openids being present in RAILS_ROOT. But be aware that this store only works if you have a single application server. And it's not safe to use across NFS. It's recommended that you use the database store if at all possible. To use the file-based store, you'll also have to add this line to your config/environment.rb:
OpenIdAuthentication.store = :file
This particular plugin also relies on the fact that the authentication action allows for both POST and GET operations.
If you're using RESTful authentication, you'll need to explicitly allow for this in your routes.rb.
The plugin also expects to find a root_url method that points to the home page of your site. You can accomplish this by using a root route in config/routes.rb:
map.root :controller => 'articles'
This plugin relies on Rails Edge revision 6317 or newer.
Example
=======
This example is just to meant to demonstrate how you could use OpenID authentication. You might well want to add
salted hash logins instead of plain text passwords and other requirements on top of this. Treat it as a starting point,
not a destination.
Note that the User model referenced in the simple example below has an 'identity_url' attribute. You will want to add the same or similar field to whatever
model you are using for authentication.
Also of note is the following code block used in the example below:
authenticate_with_open_id do |result, identity_url|
...
end
In the above code block, 'identity_url' will need to match user.identity_url exactly. 'identity_url' will be a string in the form of 'http://example.com' -
If you are storing just 'example.com' with your user, the lookup will fail.
There is a handy method in this plugin called 'normalize_url' that will help with validating OpenID URLs.
OpenIdAuthentication.normalize_url(user.identity_url)
The above will return a standardized version of the OpenID URL - the above called with 'example.com' will return 'http://example.com/'
It will also raise an InvalidOpenId exception if the URL is determined to not be valid.
Use the above code in your User model and validate OpenID URLs before saving them.
config/routes.rb
map.root :controller => 'articles'
map.resource :session
app/views/sessions/new.erb
<% form_tag(session_url) do %>
<p>
<label for="name">Username:</label>
<%= text_field_tag "name" %>
</p>
<p>
<label for="password">Password:</label>
<%= password_field_tag %>
</p>
<p>
...or use:
</p>
<p>
<label for="openid_identifier">OpenID:</label>
<%= text_field_tag "openid_identifier" %>
</p>
<p>
<%= submit_tag 'Sign in', :disable_with => "Signing in&hellip;" %>
</p>
<% end %>
app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def create
if using_open_id?
open_id_authentication
else
password_authentication(params[:name], params[:password])
end
end
protected
def password_authentication(name, password)
if @current_user = @account.users.authenticate(params[:name], params[:password])
successful_login
else
failed_login "Sorry, that username/password doesn't work"
end
end
def open_id_authentication
authenticate_with_open_id do |result, identity_url|
if result.successful?
if @current_user = @account.users.find_by_identity_url(identity_url)
successful_login
else
failed_login "Sorry, no user by that identity URL exists (#{identity_url})"
end
else
failed_login result.message
end
end
end
private
def successful_login
session[:user_id] = @current_user.id
redirect_to(root_url)
end
def failed_login(message)
flash[:error] = message
redirect_to(new_session_url)
end
end
If you're fine with the result messages above and don't need individual logic on a per-failure basis,
you can collapse the case into a mere boolean:
def open_id_authentication
authenticate_with_open_id do |result, identity_url|
if result.successful? && @current_user = @account.users.find_by_identity_url(identity_url)
successful_login
else
failed_login(result.message || "Sorry, no user by that identity URL exists (#{identity_url})")
end
end
end
Simple Registration OpenID Extension
====================================
Some OpenID Providers support this lightweight profile exchange protocol. See more: http://www.openidenabled.com/openid/simple-registration-extension
You can support it in your app by changing #open_id_authentication
def open_id_authentication(identity_url)
# Pass optional :required and :optional keys to specify what sreg fields you want.
# Be sure to yield registration, a third argument in the #authenticate_with_open_id block.
authenticate_with_open_id(identity_url,
:required => [ :nickname, :email ],
:optional => :fullname) do |result, identity_url, registration|
case result.status
when :missing
failed_login "Sorry, the OpenID server couldn't be found"
when :invalid
failed_login "Sorry, but this does not appear to be a valid OpenID"
when :canceled
failed_login "OpenID verification was canceled"
when :failed
failed_login "Sorry, the OpenID verification failed"
when :successful
if @current_user = @account.users.find_by_identity_url(identity_url)
assign_registration_attributes!(registration)
if current_user.save
successful_login
else
failed_login "Your OpenID profile registration failed: " +
@current_user.errors.full_messages.to_sentence
end
else
failed_login "Sorry, no user by that identity URL exists"
end
end
end
end
# registration is a hash containing the valid sreg keys given above
# use this to map them to fields of your user model
def assign_registration_attributes!(registration)
model_to_registration_mapping.each do |model_attribute, registration_attribute|
unless registration[registration_attribute].blank?
@current_user.send("#{model_attribute}=", registration[registration_attribute])
end
end
end
def model_to_registration_mapping
{ :login => 'nickname', :email => 'email', :display_name => 'fullname' }
end
Attribute Exchange OpenID Extension
===================================
Some OpenID providers also support the OpenID AX (attribute exchange) protocol for exchanging identity information between endpoints. See more: http://openid.net/specs/openid-attribute-exchange-1_0.html
Accessing AX data is very similar to the Simple Registration process, described above -- just add the URI identifier for the AX field to your :optional or :required parameters. For example:
authenticate_with_open_id(identity_url,
:required => [ :email, 'http://schema.openid.net/birthDate' ]) do |result, identity_url, registration|
This would provide the sreg data for :email, and the AX data for 'http://schema.openid.net/birthDate'
Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license

View file

@ -0,0 +1,12 @@
if Rails.version < '3'
config.gem 'rack-openid', :lib => 'rack/openid', :version => '>=0.2.1'
end
require 'open_id_authentication'
config.middleware.use OpenIdAuthentication
config.after_initialize do
OpenID::Util.logger = Rails.logger
ActionController::Base.send :include, OpenIdAuthentication
end

View file

@ -0,0 +1,129 @@
require 'uri'
require 'openid'
require 'rack/openid'
module OpenIdAuthentication
def self.new(app)
store = OpenIdAuthentication.store
if store.nil?
Rails.logger.warn "OpenIdAuthentication.store is nil. Using in-memory store."
end
::Rack::OpenID.new(app, OpenIdAuthentication.store)
end
def self.store
@@store
end
def self.store=(*store_option)
store, *parameters = *([ store_option ].flatten)
@@store = case store
when :memory
require 'openid/store/memory'
OpenID::Store::Memory.new
when :file
require 'openid/store/filesystem'
OpenID::Store::Filesystem.new(Rails.root.join('tmp/openids'))
when :memcache
require 'memcache'
require 'openid/store/memcache'
OpenID::Store::Memcache.new(MemCache.new(parameters))
else
store
end
end
self.store = nil
class Result
ERROR_MESSAGES = {
:missing => "Sorry, the OpenID server couldn't be found",
:invalid => "Sorry, but this does not appear to be a valid OpenID",
:canceled => "OpenID verification was canceled",
:failed => "OpenID verification failed",
:setup_needed => "OpenID verification needs setup"
}
def self.[](code)
new(code)
end
def initialize(code)
@code = code
end
def status
@code
end
ERROR_MESSAGES.keys.each { |state| define_method("#{state}?") { @code == state } }
def successful?
@code == :successful
end
def unsuccessful?
ERROR_MESSAGES.keys.include?(@code)
end
def message
ERROR_MESSAGES[@code]
end
end
protected
# The parameter name of "openid_identifier" is used rather than
# the Rails convention "open_id_identifier" because that's what
# the specification dictates in order to get browser auto-complete
# working across sites
def using_open_id?(identifier = nil) #:doc:
identifier ||= open_id_identifier
!identifier.blank? || request.env[Rack::OpenID::RESPONSE]
end
def authenticate_with_open_id(identifier = nil, options = {}, &block) #:doc:
identifier ||= open_id_identifier
if request.env[Rack::OpenID::RESPONSE]
complete_open_id_authentication(&block)
else
begin_open_id_authentication(identifier, options, &block)
end
end
private
def open_id_identifier
params[:openid_identifier] || params[:openid_url]
end
def begin_open_id_authentication(identifier, options = {})
options[:identifier] = identifier
value = Rack::OpenID.build_header(options)
response.headers[Rack::OpenID::AUTHENTICATE_HEADER] = value
head :unauthorized
end
def complete_open_id_authentication
response = request.env[Rack::OpenID::RESPONSE]
identifier = response.display_identifier
case response.status
when OpenID::Consumer::SUCCESS
yield Result[:successful], identifier,
OpenID::SReg::Response.from_success_response(response),
OpenID::AX::FetchResponse.from_success_response(response)
when :missing
yield Result[:missing], identifier, nil
when :invalid
yield Result[:invalid], identifier, nil
when OpenID::Consumer::CANCEL
yield Result[:canceled], identifier, nil
when OpenID::Consumer::FAILURE
yield Result[:failed], identifier, nil
when OpenID::Consumer::SETUP_NEEDED
yield Result[:setup_needed], response.setup_url, nil
end
end
end

View file

@ -22,9 +22,8 @@ module SessionPersistence
def _persist_session def _persist_session
if session[session_persistence_key] if session[session_persistence_key]
request.session_options = request.session_options.dup request.session_options[:expires] = Time.now + session[session_persistence_key]
request.session_options[:expire_after] = session[session_persistence_key] request.session_options[:expire_after] = session[session_persistence_key]
request.session_options.freeze
end end
end end
end end