diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c111b33 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.gem diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..debc11c --- /dev/null +++ b/Rakefile @@ -0,0 +1,8 @@ +require 'rake/testtask' + +Rake::TestTask.new do |t| + t.libs << 'test' +end + +desc "Run tests" +task :default => :test diff --git a/lib/sinatra/browserid.rb b/lib/sinatra/browserid.rb index 0ceda52..98aa60c 100644 --- a/lib/sinatra/browserid.rb +++ b/lib/sinatra/browserid.rb @@ -4,6 +4,8 @@ require 'json' require 'url_safe_base64' require 'jwt' +require 'simpleidn' +require 'ipaddr' require "sinatra/base" require 'sinatra/browserid/helpers' require 'sinatra/browserid/template' @@ -44,7 +46,7 @@ def self.registered(app) id_token["exp"] > Time.now.to_i && id_token["email_verified"] && id_token["nonce"] == session[:nonce]) - session[:browserid_email] = id_token["email"] + session[:browserid_email] = id_token['sub'] session.delete(:nonce) if session['redirect_url'] redirect session['redirect_url'] diff --git a/lib/sinatra/browserid/helpers.rb b/lib/sinatra/browserid/helpers.rb index 05f1b0d..3d27c5c 100644 --- a/lib/sinatra/browserid/helpers.rb +++ b/lib/sinatra/browserid/helpers.rb @@ -28,6 +28,28 @@ def authorized_email session[:browserid_email] end + # Normalize the email like the broker will do it, see + # https://github.com/portier/portier.github.io/blob/master/specs/Email-Normalization.md + def normalize_email(email) + begin + user, domain = email.split("@") + if user == nil or user.empty? + raise ArgumentError.new('user part must not be empty') + end + user = user.downcase + domain = SimpleIDN.to_ascii(domain).downcase + begin + IPAddr.new(domain) + rescue + # if domain could not be parsed as IP we are good + return user + "@" + domain + end + raise ArgumentError.new('domain must not be an IP') + rescue Exception => e + raise ArgumentError, 'Not a valid email adress: ' + e.message + end + end + # Returns the HTML to render the Persona login form. # Optionally takes a URL parameter for where the user should # be redirected to after the assert POST back. diff --git a/sinatra-portier.gemspec b/sinatra-portier.gemspec index cc75455..654139f 100644 --- a/sinatra-portier.gemspec +++ b/sinatra-portier.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = "sinatra-portier" - s.version = "1.4.0" + s.version = "1.5.0" s.authors = ["Pete Fritchman", "Malte Paskuda"] s.email = ["malte@paskuda.biz"] @@ -17,4 +17,7 @@ Gem::Specification.new do |s| s.add_dependency("sinatra", ">= 1.1.0") s.add_dependency("jwt", ">= 1.5.4") s.add_dependency("url_safe_base64", ">= 0.2.2") + s.add_dependency("simpleidn", ">= 0.0.9") + + s.required_ruby_version(">= 2.4.0") end diff --git a/test/test_normalization.rb b/test/test_normalization.rb new file mode 100644 index 0000000..94c6bf6 --- /dev/null +++ b/test/test_normalization.rb @@ -0,0 +1,31 @@ +require 'minitest/autorun' +require 'sinatra/portier.rb' + + +class NormalizationTest < Minitest::Test + include Sinatra::BrowserID::Helpers + def test_valid + assert_equal("example.foo+bar@example.com", normalize_email("example.foo+bar@example.com")) + assert_equal("example.foo+bar@example.com", normalize_email("EXAMPLE.FOO+BAR@EXAMPLE.COM")) + assert_equal("björn@xn--gteborg-90a.test", normalize_email("BJÖRN@göteborg.test")) + assert_equal("i̇ⅲ@xn--iiii-qwc.example", normalize_email("İⅢ@İⅢ.example")) + end + + def test_invalid + assert_raises("ArgumentError") { + normalize_email("foo") + } + assert_raises("ArgumentError") { + normalize_email("foo@") + } + assert_raises("ArgumentError") { + normalize_email("@foo.example") + } + assert_raises("ArgumentError") { + normalize_email("foo@127.0.0.1") + } + assert_raises("ArgumentError") { + normalize_email("foo@[::1]") + } + end +end