Skip to content
This repository has been archived by the owner on Jun 21, 2023. It is now read-only.

Commit

Permalink
Implement HMAC signing for statsd messages
Browse files Browse the repository at this point in the history
  • Loading branch information
jssjr committed Jan 28, 2014
1 parent 5170749 commit 0d38b47
Showing 1 changed file with 27 additions and 3 deletions.
30 changes: 27 additions & 3 deletions lib/statsd.rb
@@ -1,4 +1,7 @@
require 'openssl'
require 'securerandom'
require 'socket'
require 'time'

# = Statsd: A Statsd client (https://github.com/etsy/statsd)
#
Expand All @@ -19,6 +22,9 @@ class Statsd
#characters that will be replaced with _ in stat names
RESERVED_CHARS_REGEX = /[\:\|\@]/

# Digest object as a constant
SHA256 = OpenSSL::Digest::SHA256.new

class << self
# Set to any standard logger instance (including stdlib's Logger) to enable
# stat logging using logger.debug
Expand All @@ -27,8 +33,8 @@ class << self

# @param [String] host your statsd host
# @param [Integer] port your statsd port
def initialize(host, port=8125)
@host, @port = host, port
def initialize(host, port=8125, key=nil)
@host, @port, @key = host, port, key
end

# Sends an increment (count = 1) for the given stat to the statsd server.
Expand Down Expand Up @@ -103,10 +109,28 @@ def send(stat, delta, type, sample_rate=1)

def send_to_socket(message)
self.class.logger.debug {"Statsd: #{message}"} if self.class.logger
socket.send(message, 0, @host, @port)
if @key.nil?
socket.send(message, 0, @host, @port)
else
socket.send(signed_payload(message), 0, @host, @port)
end
rescue => boom
self.class.logger.error {"Statsd: #{boom.class} #{boom}"} if self.class.logger
end

def signed_payload(message)
payload = timestamp + nonce + message
signature = OpenSSL::HMAC.digest(SHA256, @key, payload)
signature + payload
end

def timestamp
[Time.now.to_i].pack("Q<")
end

def nonce
SecureRandom.random_bytes(4)
end

def socket; @socket ||= UDPSocket.new end
end

0 comments on commit 0d38b47

Please sign in to comment.