$OpenBSD: patch-lib_agcaldav_client_rb,v 1.2 2013/03/18 21:45:41 jasper Exp $ commit c13ea74da87d56c526f0187abe30e9d185f43374 Author: Geoff Evans Date: Wed Feb 20 11:01:50 2013 +1300 Subject:Adds Digest Authentication commit 20687529a3c3554d0f51dabd81e06b172a96b940 Author: Geoff Evans Date: Wed Mar 6 12:34:46 2013 +1300 Subject:Fix Digest to work over ssl. commit 7b411e884b3884ca1f49338e1e2f12925c58ae0d Author: Geoff Evans Date: Tue Mar 19 10:08:31 2013 +1300 Subject:Fix find_events for pure ruby --- lib/agcaldav/client.rb.orig Thu Jan 1 01:00:00 1970 +++ lib/agcaldav/client.rb Mon Mar 18 22:31:42 2013 @@ -17,6 +17,7 @@ module AgCalDAV @proxy_host = proxy_uri.host @proxy_port = proxy_uri.port.to_i end + uri = URI(data[:uri]) @host = uri.host @port = uri.port.to_i @@ -24,6 +25,24 @@ module AgCalDAV @user = data[:user] @password = data[:password] @ssl = uri.scheme == 'https' + + unless data[:authtype].nil? + @authtype = data[:authtype] + if @authtype == 'digest' + + @digest_auth = Net::HTTP::DigestAuth.new + @duri = URI.parse data[:uri] + @duri.user = @user + @duri.password = @password + + elsif @authtype == 'basic' + #Don't Raise or do anything else + else + raise "Authentication Type Specified Is Not Valid. Please use basic or digest" + end + else + @authtype = 'basic' + end end def __create_http @@ -44,14 +63,26 @@ module AgCalDAV events = [] res = nil __create_http.start {|http| + req = Net::HTTP::Report.new(@url, initheader = {'Content-Type'=>'application/xml'} ) - req.basic_auth @user, @password - req.body = AgCalDAV::Request::ReportVEVENT.new(DateTime.parse(data[:start]).strftime("%Y%m%dT%H%M"), - DateTime.parse(data[:end]).strftime("%Y%m%dT%H%M") ).to_xml + + if not @authtype == 'digest' + req.basic_auth @user, @password + else + req.add_field 'Authorization', digestauth('REPORT') + end + if data[:start].is_a? Integer + req.body = AgCalDAV::Request::ReportVEVENT.new(Time.at(data[:start]).utc.strftime("%Y%m%dT%H%M%S"), + Time.at(data[:end]).utc.strftime("%Y%m%dT%H%M%S") ).to_xml + else + req.body = AgCalDAV::Request::ReportVEVENT.new(DateTime.parse(data[:start]).utc.strftime("%Y%m%dT%H%M%S"), + DateTime.parse(data[:end]).utc.strftime("%Y%m%dT%H%M%S") ).to_xml + end res = http.request(req) } errorhandling res result = "" + xml = REXML::Document.new(res.body) REXML::XPath.each( xml, '//c:calendar-data/', {"c"=>"urn:ietf:params:xml:ns:caldav"} ){|c| result << c.text} r = Icalendar.parse(result) @@ -70,16 +101,21 @@ module AgCalDAV def find_event uuid res = nil __create_http.start {|http| - req = Net::HTTP::Get.new("#{@url}/#{uuid}.ics") - req.basic_auth @user, @password + req = Net::HTTP::Get.new("#{@url}/#{uuid}.ics") + if not @authtype == 'digest' + req.basic_auth @user, @password + else + req.add_field 'Authorization', digestauth('GET') + end res = http.request( req ) } errorhandling res - r = Icalendar.parse(res.body) - unless r.empty? - r.first.events.first + begin + r = Icalendar.parse(res.body) + rescue + return false else - return false + r.first.events.first end @@ -89,7 +125,11 @@ module AgCalDAV res = nil __create_http.start {|http| req = Net::HTTP::Delete.new("#{@url}/#{uuid}.ics") - req.basic_auth @user, @password + if not @authtype == 'digest' + req.basic_auth @user, @password + else + req.add_field 'Authorization', digestauth('DELETE') + end res = http.request( req ) } errorhandling res @@ -126,7 +166,11 @@ module AgCalDAV __create_http.start { |http| req = Net::HTTP::Put.new("#{@url}/#{uuid}.ics") req['Content-Type'] = 'text/calendar' - req.basic_auth @user, @password + if not @authtype == 'digest' + req.basic_auth @user, @password + else + req.add_field 'Authorization', digestauth('PUT') + end req.body = cstring res = http.request( req ) } @@ -147,19 +191,15 @@ module AgCalDAV end - - - - - - - - def find_todo uuid res = nil __create_http.start {|http| req = Net::HTTP::Get.new("#{@url}/#{uuid}.ics") - req.basic_auth @user, @password + if not @authtype == 'digest' + req.basic_auth @user, @password + else + req.add_field 'Authorization', digestauth('GET') + end res = http.request( req ) } errorhandling res @@ -196,7 +236,11 @@ module AgCalDAV __create_http.start { |http| req = Net::HTTP::Put.new("#{@url}/#{uuid}.ics") req['Content-Type'] = 'text/calendar' - req.basic_auth @user, @password + if not @authtype == 'digest' + req.basic_auth @user, @password + else + req.add_field 'Authorization', digestauth('PUT') + end req.body = cstring res = http.request( req ) } @@ -210,7 +254,11 @@ module AgCalDAV __create_http.start {|http| req = Net::HTTP::Report.new(@url, initheader = {'Content-Type'=>'application/xml'} ) - req.basic_auth @user, @password + if not @authtype == 'digest' + req.basic_auth @user, @password + else + req.add_field 'Authorization', digestauth('REPORT') + end req.body = AgCalDAV::Request::ReportVTODO.new.to_xml res = http.request( req ) } @@ -219,29 +267,52 @@ module AgCalDAV end private + + def digestauth method + + h = Net::HTTP.new @duri.host, @duri.port + if @ssl + h.use_ssl = @ssl + h.verify_mode = OpenSSL::SSL::VERIFY_NONE + end + req = Net::HTTP::Get.new @duri.request_uri + + res = h.request req + # res is a 401 response with a WWW-Authenticate header + + auth = @digest_auth.auth_header @duri, res['www-authenticate'], method + + return auth + end + def entry_with_uuid_exists? uuid res = nil + __create_http.start {|http| req = Net::HTTP::Get.new("#{@url}/#{uuid}.ics") - req.basic_auth @user, @password + if not @authtype == 'digest' + req.basic_auth @user, @password + else + req.add_field 'Authorization', digestauth('GET') + end + res = http.request( req ) - } - if res.body.empty? - return false + + } + begin + Icalendar.parse(res.body) + rescue + return false else - return true + return true end end - def errorhandling response raise AuthenticationError if response.code.to_i == 401 raise NotExistError if response.code.to_i == 410 raise APIError if response.code.to_i >= 500 end end - - - class AgCalDAVError < StandardError