Class NFSN::Manager
In: nfsn-api.rb
Parent: Object
Error BadAuthenticationError BadTimestampError NotImplementedError APIObject Member Email Account Site DNS ::Exception Manager LogDevice NFSN dot/f_0.png

The main entry point for using this API. Use this to access all the other components of the API.

Methods

Public Class methods

The login parameter should be your NFSN membership login name. api_key is your NFSN-issued API key. Setting the optional debug parameter to true will increase the log verbosity.

[Source]

# File nfsn-api.rb, line 88
        def initialize(login, api_key, debug = false)
                @login = login
                @api_key = api_key
                @debug = debug

                @logger = Logger.new(NFSN::LogDevice.new($stderr))
                @logger.datetime_format = "%d %b %Y %H:%M:%S"
                @logger.level = @debug ? Logger::DEBUG : Logger::INFO

                @hostname = "api.nearlyfreespeech.net"
                @server_error = @error = nil
                @error_response = nil

                @timestamp = nil      # Timestamp of last request generated
                @time_nudge = 0
        end

Public Instance methods

Returns an NFSN::Account object.

[Source]

# File nfsn-api.rb, line 219
        def accountHandle(account_id)
                NFSN::Account.new(self, account_id)
        end

[Source]

# File nfsn-api.rb, line 153
        def describeError
                fail "no error yet!" unless @error and @error_response
                @error_response.each_capitalized { |key, val|
                        $stderr.puts "\t#{key}: #{val}"
                }
                require "pp"; pp @error
        end

Returns an NFSN::DNS object.

[Source]

# File nfsn-api.rb, line 224
        def dnsHandle(hostname)
                NFSN::DNS.new(self, hostname)
        end

method should be one of :GET, :PUT, :POST, indicating the type of API call. For :GET, data is ignored. For :PUT, data should be the data to store. For :POST, data should be a Hash of attributes.

This should only be called from NFSN::APIObject or a descendent.

[Source]

# File nfsn-api.rb, line 168
        def doOp(method, uri, data = nil)
                http = Net::HTTP.new(uri.host, uri.port)
                http.use_ssl = (uri.scheme == "https")
                http.verify_mode = OpenSSL::SSL::VERIFY_NONE
                req = nil
                if method == :GET
                        req = Net::HTTP::Get.new(uri.request_uri)
                elsif method == :PUT
                        req = Net::HTTP::Put.new(uri.request_uri)
                        req.body = data.to_s
                elsif method == :POST
                        req = Net::HTTP::Post.new(uri.path)
                        req.form_data = data
                else
                        fail "Bad HTTP method '#{method}'!"
                end

                auth_str = genAuthHeader(uri, req.body || "")
                req["Host"] = @hostname
                req["X-NFSN-Authentication"] = auth_str

                @logger.debug "#{method} #{uri}"
                #@logger.debug "X-NFSN-Authentication: #{auth_str}"
                data = begin
                        response = http.start { |http| http.request(req) }
                        if response.kind_of? Net::HTTPSuccess
                                response.body
                        else
                                response.error!
                        end
                rescue Net::HTTPServerException
                        @server_error = "#{$!}"
                        @error = JSON.parse(response.body)
                        @error_response = response

                        @logger.debug "Server returned: #{@server_error}"
                        if response.code =~ /40\d/
                                handle40x(response)
                        end

                        fail $!              # fallback
                end
                if (not data.nil?) and (data.size > 0)
                        @logger.debug "Got #{data.size} bytes"
                        return data
                end
                @logger.debug "Got empty return value"
                return nil
        end

Returns an NFSN::Email object.

[Source]

# File nfsn-api.rb, line 239
        def emailHandle(hostname)
                NFSN::Email.new(self, hostname)
        end

Returns an NFSN::Member object.

[Source]

# File nfsn-api.rb, line 229
        def memberHandle(login = nil)
                NFSN::Member.new(self, login || @login)
        end

[Source]

# File nfsn-api.rb, line 105
        def setTimeNudge(time_nudge)
                # TODO: sanity checking
                @time_nudge = time_nudge
        end

Returns an NFSN::Site object.

[Source]

# File nfsn-api.rb, line 234
        def siteHandle(shortname)
                NFSN::Site.new(self, shortname)
        end

Private Instance methods

Generate the X-NFSN-Authentication HTTP header.

[Source]

# File nfsn-api.rb, line 118
        def genAuthHeader(uri, body = "")
                @timestamp = (Time.now + @time_nudge).to_i
                salt = genSalt
                #@logger.debug "body: #{body}"
                body_hash = Digest::SHA1.hexdigest(body)

                check_str = [@login, @timestamp.to_s, salt,
                                @api_key, uri.request_uri, body_hash].join(";")
                #@logger.debug "check_str: #{check_str}"
                hash = Digest::SHA1.hexdigest(check_str)

                auth_str = [@login, @timestamp.to_s, salt, hash].join(";")
                auth_str
        end

Generate a random 16-character salt.

[Source]

# File nfsn-api.rb, line 111
        def genSalt
                charset = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
                return (1..16).map { charset[rand(charset.size)] }.join
        end

Throws an appropriate NFSN::Error exception.

[Source]

# File nfsn-api.rb, line 135
        def handle40x(response)
                code = response.code
                @logger.debug "Got a #{code}! (msg=#{response.message})"
                if code == "401" and @error["debug"] =~ /timestamp/
                        hdr = response["WWW-Authenticate"]
                        delta = hdr.scan(/time=(\d+)/)[0]
                        delta = (delta[0].to_i - @timestamp) if delta
                        raise NFSN::BadTimestampError.new(@error, delta)
                elsif code == "401" and @error["debug"] =~ /authentication hash/
                        raise NFSN::BadAuthenticationError.new(@error)
                elsif code == "404" and @error["error"] =~ /API.*not valid/
                        raise NFSN::NotImplementedError.new(@error)
                else
                        raise NFSN::Error.new("Unknown error!", @error)
                end
        end

[Validate]