summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorelijah <elijah@riseup.net>2013-05-19 22:28:01 -0700
committerelijah <elijah@riseup.net>2013-05-19 22:28:01 -0700
commitf9d6b218be3bdbb2d3c544849b2ab92348d0e394 (patch)
tree71cd7ab6e5e9ffb4571b555324ada743c3d29387
parent5d2e69ad4f2b6214df52c617f5e6cb23d9f40944 (diff)
many related changes -- allow command line configs, validate addresses, overhaul bootstrap.
-rw-r--r--README.md28
-rwxr-xr-xbin/nickserver27
-rw-r--r--config/default.yml26
-rw-r--r--lib/nickserver.rb1
-rw-r--r--lib/nickserver/config.rb2
-rw-r--r--lib/nickserver/daemon.rb15
-rw-r--r--lib/nickserver/email_address.rb25
-rw-r--r--lib/nickserver/server.rb32
-rw-r--r--lib/nickserver/version.rb2
-rw-r--r--test/unit/nickserver_test.rb4
10 files changed, 117 insertions, 45 deletions
diff --git a/README.md b/README.md
index 1546d57..edeae59 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,15 @@
Nickserver
==================================
-Nickserver is a server running the Nicknym protocol. This daemon can be run by service providers in order to support Nicknym.
+Nickserver is a server running the Nicknym protocol. This daemon can be run by
+service providers in order to support Nicknym.
-Nicknym is a protocol to map user nicknames to public keys. With Nicknym, the user is able to think solely in terms of nickname, while still being able to communicate with a high degree of security (confidentiality, integrity, and authenticity). Essentially, Nicknym is a system for binding human-memorable nicknames to a cryptographic key via automatic discovery and automatic validation.
+Nicknym is a protocol to map user nicknames to public keys. With Nicknym, the
+user is able to think solely in terms of nickname, while still being able to
+communicate with a high degree of security (confidentiality, integrity, and
+authenticity). Essentially, Nicknym is a system for binding human-memorable
+nicknames to a cryptographic key via automatic discovery and automatic
+validation.
For more information, see https://leap.se/nicknym
@@ -20,7 +26,8 @@ You query the nickserver via HTTP. The API is very minimal:
curl -X POST -d address=alice@domain.org https://nicknym.domain.org:6425
-The response consists of a signed JSON document with fields for the available public keys corresponding to the address.
+The response consists of a signed JSON document with fields for the available
+public keys corresponding to the address.
For more details, see https://leap.se/nicknym
@@ -35,6 +42,13 @@ Installation
You have three fine options for installing nickserver:
+Install prerequisites
+
+ $ sudo apt-get install ruby1.9.1-dev libssl-dev
+
+Note: libssl-dev must be installed before installing the gem EventMachine,
+otherwise the gem will get built without TLS support.
+
Install from source:
$ git clone git://leap.se/nickserver
@@ -52,9 +66,13 @@ Install for development:
Configuration
==================================
-Nickserver loads the configuration files `config/default.yml` and `/etc/leap/nickserver.yml`, if it exists. See `config/default.yml` for the available options.
+Nickserver loads the configuration files `config/default.yml` and
+`/etc/leap/nickserver.yml`, if it exists. See `config/default.yml` for the
+available options.
-The default HKP host is set to https://hkps.pool.sks-keyservers.net. The CA for this pool is available here https://sks-keyservers.net/sks-keyservers.netCA.pem
+The default HKP host is set to https://hkps.pool.sks-keyservers.net. The CA
+for this pool is available here https://sks-keyservers.net/sks-
+keyservers.netCA.pem
Usage
==================================
diff --git a/bin/nickserver b/bin/nickserver
index 8843dde..062684f 100755
--- a/bin/nickserver
+++ b/bin/nickserver
@@ -4,27 +4,20 @@
# Nickserver key discovery daemon
#
-def load_library(name)
- begin # try without rubygems (might be already loaded or not present)
- require name
- rescue LoadError
- begin # try it as a gem
- require 'rubygems'
- require name
- rescue LoadError # try manually, requiring gems in Gemfile if it exists.
- base_directory = File.expand_path('../..', File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__)
- if File.exists?("#{base_directory}/Gemfile.lock")
- ENV['BUNDLE_GEMFILE'] ||= "#{base_directory}/Gemfile"
- require 'bundler'
- Bundler.require(:default)
- end
- $LOAD_PATH << "#{base_directory}/lib"
- require name
+def load_local_gem(dir_path='../..')
+ base_directory = File.expand_path(dir_path, File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__)
+ if !$LOAD_PATH.include? "#{base_directory}/lib"
+ if File.exists?("#{base_directory}/Gemfile.lock")
+ ENV['BUNDLE_GEMFILE'] ||= "#{base_directory}/Gemfile"
+ require 'bundler'
+ Bundler.require(:default)
end
+ $LOAD_PATH << "#{base_directory}/lib"
end
end
-load_library('nickserver')
+load_local_gem
+require 'nickserver'
Nickserver::Daemon.run('nickserver') do
EventMachine.run do
diff --git a/config/default.yml b/config/default.yml
index 4328cbd..c31b504 100644
--- a/config/default.yml
+++ b/config/default.yml
@@ -1,10 +1,24 @@
+#
+# nickserver daemon
+#
+port: 6425
+pid_file: '/tmp/nickserver.pid'
+log_file: '/tmp/nickserver.log'
+user: ~
+domain: ~
+domains: ~
+
+#
+# couch
+#
couch_host: 'localhost'
couch_port: 5984
couch_database: 'users'
-#couch_user: 'nickserver'
-#couch_password: 'blahblah'
+couch_user: ~
+couch_password: ~
+
+#
+# HKP
+#
hkp_url: 'https://hkps.pool.sks-keyservers.net:/pks/lookup'
-port: 6425
-pid_file: '/var/run/nickserver'
-user: 'nobody'
-log_file: '/var/log/nickserver.log'
+
diff --git a/lib/nickserver.rb b/lib/nickserver.rb
index 9e6464e..951dae9 100644
--- a/lib/nickserver.rb
+++ b/lib/nickserver.rb
@@ -1,6 +1,7 @@
require "nickserver/version"
require "nickserver/config"
+require "nickserver/email_address"
require "nickserver/couch/fetch_key"
diff --git a/lib/nickserver/config.rb b/lib/nickserver/config.rb
index b283d8b..be401f5 100644
--- a/lib/nickserver/config.rb
+++ b/lib/nickserver/config.rb
@@ -18,6 +18,8 @@ module Nickserver
attr_accessor :pid_file
attr_accessor :user
attr_accessor :log_file
+ attr_accessor :domain
+ attr_accessor :domains
attr_accessor :loaded
attr_accessor :verbose
diff --git a/lib/nickserver/daemon.rb b/lib/nickserver/daemon.rb
index e0bd527..651c6ce 100644
--- a/lib/nickserver/daemon.rb
+++ b/lib/nickserver/daemon.rb
@@ -67,7 +67,7 @@ module Nickserver
create_pid_file(Config.pid_file, Config.user)
catch_interrupt
redirect_output
- drop_permissions_to(Config.user)
+ drop_permissions_to(Config.user) if Config.user
File.umask 0000
yield
end
@@ -77,7 +77,7 @@ module Nickserver
File.open file, 'w' do |f|
f.write("#{Process.pid}\n")
end
- FileUtils.chown(user, nil, file)
+ FileUtils.chown(user, nil, file) if Process::Sys.getuid == 0
rescue Errno::EACCES
bail "insufficient permission to create to pid file `#{file}`"
rescue Errno::ENOENT
@@ -207,13 +207,22 @@ module Nickserver
when 'status' then ARGV.shift; @command = :status
when 'version' then ARGV.shift; @command = :version
when '--verbose' then ARGV.shift; Config.versbose = true
- when /^-/ then usage("Unknown option: #{ARGV[0].inspect}")
+ when /^-/ then override_default_config(ARGV.shift, ARGV.shift)
else break
end
end
usage("Missing command") unless @command
end
+ def override_default_config(flag, value)
+ flag = flag.sub /^--/, ''
+ if Config.respond_to?("#{flag}=")
+ Config.send("#{flag}=", value)
+ else
+ usage("Unknown option: --#{flag}")
+ end
+ end
+
#
# COMMANDS
#
diff --git a/lib/nickserver/email_address.rb b/lib/nickserver/email_address.rb
new file mode 100644
index 0000000..26053a2
--- /dev/null
+++ b/lib/nickserver/email_address.rb
@@ -0,0 +1,25 @@
+#
+# This rather crazy regexp is from here: http://code.iamcal.com/php/rfc822/
+# Licensed GPLv3
+#
+# It is too liberal, allowing "!@x" as a valid address, for example, but it does
+# follow the specification rather closely.
+#
+
+module Nickserver
+ EmailAddress = begin
+ qtext = '[^\\x0d\\x22\\x5c\\x80-\\xff]'
+ dtext = '[^\\x0d\\x5b-\\x5d\\x80-\\xff]'
+ atom = '[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+'
+ quoted_pair = '\\x5c[\\x00-\\x7f]'
+ domain_literal = "\\x5b(?:#{dtext}|#{quoted_pair})*\\x5d"
+ quoted_string = "\\x22(?:#{qtext}|#{quoted_pair})*\\x22"
+ domain_ref = atom
+ sub_domain = "(?:#{domain_ref}|#{domain_literal})"
+ word = "(?:#{atom}|#{quoted_string})"
+ domain = "#{sub_domain}(?:\\x2e#{sub_domain})*"
+ local_part = "#{word}(?:\\x2e#{word})*"
+ addr_spec = "#{local_part}\\x40#{domain}"
+ /\A#{addr_spec}\z/n
+ end
+end
diff --git a/lib/nickserver/server.rb b/lib/nickserver/server.rb
index 0bda4f1..2f4d4f0 100644
--- a/lib/nickserver/server.rb
+++ b/lib/nickserver/server.rb
@@ -21,7 +21,7 @@ module Nickserver
#
def self.start(opts={})
Nickserver::Config.load
- options = {:host => '0.0.0.0', :port => Nickserver::Config.port}.merge(opts)
+ options = {:host => '0.0.0.0', :port => Nickserver::Config.port.to_i}.merge(opts)
EM.start_server options[:host], options[:port], Nickserver::Server
end
@@ -34,6 +34,8 @@ module Nickserver
uid = get_uid_from_request
if uid.nil?
send_not_found
+ elsif uid !~ EmailAddress
+ send_error("Not a valid address")
else
send_key(uid)
end
@@ -42,11 +44,11 @@ module Nickserver
private
def send_error(msg = "not supported")
- send_response(:status => 500, :content => msg)
+ send_response(:status => 500, :content => "500 #{msg}\n")
end
- def send_not_found(msg = "404 Not Found")
- send_response(:status => 404, :content => msg)
+ def send_not_found(msg = "Not Found")
+ send_response(:status => 404, :content => "404 #{msg}\n")
end
def send_response(opts = {})
@@ -100,14 +102,24 @@ module Nickserver
# Return true if the user address is for a user of this service provider.
# e.g. if the provider is example.org, then alice@example.org returns true.
#
- # Currently, we rely on whatever hostname the client voluntarily specifies
- # in the headers of the http request.
+ # If 'domain' is not configured, we rely on the Host header of the HTTP request.
#
def local_address?(uid)
- hostname = @http_headers.split(/\0/).grep(/^Host: /).first.split(':')[1].strip.sub(/^nicknym\./, '')
- return uid =~ /^.*@#{Regexp.escape(hostname)}$/
- #rescue
- # false
+ uid_domain = uid.sub(/^.*@(.*)$/, "\\1")
+ if Config.domain
+ return uid_domain == Config.domain
+ else
+ # no domain configured, use Host header
+ host_header = @http_headers.split(/\0/).grep(/^Host: /).first
+ if host_header.nil?
+ send_error("HTTP request must include a Host header.")
+ else
+ host = host_header.split(':')[1].strip.sub(/^nicknym\./, '')
+ return uid_domain == host
+ end
+ end
+ rescue
+ return false
end
end
end \ No newline at end of file
diff --git a/lib/nickserver/version.rb b/lib/nickserver/version.rb
index 6e86d39..1910fe1 100644
--- a/lib/nickserver/version.rb
+++ b/lib/nickserver/version.rb
@@ -1,3 +1,3 @@
module Nickserver
- VERSION = "0.2.0"
+ VERSION = "0.2.1"
end
diff --git a/test/unit/nickserver_test.rb b/test/unit/nickserver_test.rb
index c746ef5..3a286fa 100644
--- a/test/unit/nickserver_test.rb
+++ b/test/unit/nickserver_test.rb
@@ -8,9 +8,7 @@ require 'json'
#
# (2) All requests to nickserver are to localhost.
#
-# (3) the "Host" header for requests to nickserver must be set, because this
-# is how it decides if a request is local. I am not happy about this design,
-# but that is how it works for now.
+# (3) the "Host" header for requests to nickserver must be set (or Config.domain set)
#
# (4) When stubbing requests to couchdb, the couchdb host is changed from the
# default (localhost) to a dummy value (notlocalhost).