HMAC cookie signing
This commit is contained in:
parent
04400bdd67
commit
757d34661c
|
@ -3,6 +3,7 @@
|
|||
require_relative 'parseutils'
|
||||
require_relative 'errors'
|
||||
require 'date'
|
||||
require 'openssl'
|
||||
HeaderRegexp = Landline::Util::HeaderRegexp
|
||||
ParserCommon = Landline::Util::ParserCommon
|
||||
|
||||
|
@ -29,15 +30,22 @@ module Landline
|
|||
raise Landline::ParsingError, "invalid cookie value: #{value}"
|
||||
end
|
||||
|
||||
# Make param keys strings
|
||||
params.transform_keys!(&:to_s)
|
||||
|
||||
# Primary cookie parameters
|
||||
@key = key
|
||||
@value = value
|
||||
setup_params(params)
|
||||
|
||||
# Cookie signing parameters
|
||||
setup_hmac(params)
|
||||
end
|
||||
|
||||
# Convert cookie to "Set-Cookie: " string representation.
|
||||
# @return [String]
|
||||
def to_s
|
||||
sign(@hmac, algorithm: @algorithm, sep: @sep) if @hmac
|
||||
ParserCommon.make_value(
|
||||
"#{key.to_s.strip}=#{value.to_s.strip}",
|
||||
{
|
||||
|
@ -58,6 +66,26 @@ module Landline
|
|||
"#{key.to_s.strip}=#{value.to_s.strip}"
|
||||
end
|
||||
|
||||
# Sign the cookie value with HMAC
|
||||
# @param key [String] HMAC signing key
|
||||
# @param algorithm [String] Hash algorithm to use
|
||||
# @param sep [String] Hash separator
|
||||
def sign(key, algorithm: "sha256", sep: "&")
|
||||
@value += sep + ::OpenSSL::HMAC.base64digest(algorithm, key, @value)
|
||||
end
|
||||
|
||||
# Verify HMAC signature
|
||||
# @param key [String] HMAC signing key
|
||||
# @param algorithm [String] Hash algorithm
|
||||
# @param sep [String] Hash separator
|
||||
# @return [Boolean] whether value is signed and valid
|
||||
def verify(key, algorithm: "sha256", sep: "&")
|
||||
val, sig = @value.match(/\A(.*)#{sep}([A-Za-z0-9+\/=]+)\Z/).to_a[1..]
|
||||
return false unless val and sig
|
||||
|
||||
sig == ::OpenSSL::HMAC.base64digest(algorithm, key, val)
|
||||
end
|
||||
|
||||
attr_accessor :key, :value
|
||||
attr_reader :domain, :path, :expires, :maxage, :samesite, :secure, :httponly
|
||||
|
||||
|
@ -66,7 +94,7 @@ module Landline
|
|||
# @return [Cookie]
|
||||
def self.from_setcookie_string(data)
|
||||
kvpair, params = parse_value(data, regexp: HeaderRegexp::COOKIE_PARAM)
|
||||
key, value = kvpair.split("=").map(&:strip)
|
||||
key, value = kvpair.match(/([^=]+)=?(.*)/).to_a[1..].map(&:strip)
|
||||
Cookie.new(key, value, params)
|
||||
end
|
||||
|
||||
|
@ -76,7 +104,8 @@ module Landline
|
|||
def self.from_cookie_string(data)
|
||||
hash = {}
|
||||
data.split(";").map do |cookiestr|
|
||||
cookie = Cookie.new(*cookiestr.split("=").map(&:strip))
|
||||
key, value = cookiestr.match(/([^=]+)=?(.*)/).to_a[1..].map(&:strip)
|
||||
cookie = Cookie.new(key, value)
|
||||
if hash[cookie.key]
|
||||
hash[cookie.key].append(cookie)
|
||||
else
|
||||
|
@ -88,6 +117,12 @@ module Landline
|
|||
|
||||
private
|
||||
|
||||
def setup_hmac(params)
|
||||
@hmac = params['hmac']
|
||||
@algorithm = (params['algorithm'] or "sha256")
|
||||
@sep = (params['sep'] or "&")
|
||||
end
|
||||
|
||||
def setup_params(params)
|
||||
# Extended cookie params
|
||||
params.transform_keys!(&:downcase)
|
||||
|
|
Loading…
Reference in New Issue