Compare commits
No commits in common. "960dbf92ea969632ec887a3fee38bb46332b1575" and "04400bdd678ad9d444ad361bb9f77040eaae0775" have entirely different histories.
960dbf92ea
...
04400bdd67
|
@ -1,27 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/lib")
|
|
||||||
require 'securerandom'
|
|
||||||
require 'landline'
|
|
||||||
require 'landline/util/cookie'
|
|
||||||
require 'irb'
|
|
||||||
|
|
||||||
KEY = SecureRandom.base64(64).freeze
|
|
||||||
|
|
||||||
app = Landline::Server.new do
|
|
||||||
get "/set-cookie" do
|
|
||||||
cookie "test", (rand * 500).floor.to_s, { hmac: KEY }
|
|
||||||
header "content-type", "text/plain"
|
|
||||||
"Cookie set! Visit /get-cookie to view it"
|
|
||||||
end
|
|
||||||
get "/get-cookie" do
|
|
||||||
header "content-type", "text/plain"
|
|
||||||
if request.cookies.dig('test', 0)&.verify(KEY)
|
|
||||||
"Cookie is valid and generated by server"
|
|
||||||
else
|
|
||||||
"Cookie either doesn't exist or is forged"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
run app
|
|
|
@ -1 +0,0 @@
|
||||||
../../lib
|
|
|
@ -1,3 +0,0 @@
|
||||||
shows basic usage of unsigned cookies
|
|
||||||
|
|
||||||
please note that this does not sign cookies.
|
|
|
@ -1,7 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require_relative "../probe"
|
require_relative "../probe"
|
||||||
require_relative "../util/mime"
|
|
||||||
|
|
||||||
module Landline
|
module Landline
|
||||||
module Handlers
|
module Handlers
|
||||||
|
@ -19,18 +18,12 @@ module Landline
|
||||||
# Method callback on successful request navigation.
|
# Method callback on successful request navigation.
|
||||||
# Tries to serve files matched by handler
|
# Tries to serve files matched by handler
|
||||||
# @param request [Landline::Request]
|
# @param request [Landline::Request]
|
||||||
# @return [Boolean, Array] true if file was found
|
# @return [Boolean] true if file was found
|
||||||
def process(request)
|
def process(request)
|
||||||
path = File.expand_path(request.filepath)
|
path = File.expand_path(request.filepath)
|
||||||
return unless path.start_with? @properties["path"]
|
return unless path.start_with? @properties["path"]
|
||||||
|
|
||||||
filepath = path.delete_suffix("/")
|
File.open(path.delete_suffix("/"))
|
||||||
|
|
||||||
[200,
|
|
||||||
{
|
|
||||||
"content-type" => Landline::MIME.get_mime_type(filepath)
|
|
||||||
},
|
|
||||||
File.open(filepath)]
|
|
||||||
rescue StandardError
|
rescue StandardError
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
|
@ -26,7 +26,7 @@ module Landline
|
||||||
def finalize
|
def finalize
|
||||||
@cookies.each do |_, cookie_array|
|
@cookies.each do |_, cookie_array|
|
||||||
cookie_array.each do |cookie|
|
cookie_array.each do |cookie|
|
||||||
add_header("set-cookie", cookie.finalize)
|
add_header("set-cookie", cookie.to_s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
[@status, @headers, @body]
|
[@status, @headers, @body]
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
require_relative 'parseutils'
|
require_relative 'parseutils'
|
||||||
require_relative 'errors'
|
require_relative 'errors'
|
||||||
require 'date'
|
require 'date'
|
||||||
require 'openssl'
|
|
||||||
HeaderRegexp = Landline::Util::HeaderRegexp
|
HeaderRegexp = Landline::Util::HeaderRegexp
|
||||||
ParserCommon = Landline::Util::ParserCommon
|
ParserCommon = Landline::Util::ParserCommon
|
||||||
|
|
||||||
|
@ -30,22 +29,15 @@ module Landline
|
||||||
raise Landline::ParsingError, "invalid cookie value: #{value}"
|
raise Landline::ParsingError, "invalid cookie value: #{value}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Make param keys strings
|
|
||||||
params.transform_keys!(&:to_s)
|
|
||||||
|
|
||||||
# Primary cookie parameters
|
# Primary cookie parameters
|
||||||
@key = key
|
@key = key
|
||||||
@value = value
|
@value = value
|
||||||
setup_params(params)
|
setup_params(params)
|
||||||
|
|
||||||
# Cookie signing parameters
|
|
||||||
setup_hmac(params)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Convert cookie to "Set-Cookie: " string representation.
|
# Convert cookie to "Set-Cookie: " string representation.
|
||||||
# @return [String]
|
# @return [String]
|
||||||
def finalize
|
def to_s
|
||||||
sign(@hmac, algorithm: @algorithm, sep: @sep) if @hmac
|
|
||||||
ParserCommon.make_value(
|
ParserCommon.make_value(
|
||||||
"#{key.to_s.strip}=#{value.to_s.strip}",
|
"#{key.to_s.strip}=#{value.to_s.strip}",
|
||||||
{
|
{
|
||||||
|
@ -62,31 +54,10 @@ module Landline
|
||||||
|
|
||||||
# Convert cookie to "Cookie: " string representation (no params)
|
# Convert cookie to "Cookie: " string representation (no params)
|
||||||
# @return [String]
|
# @return [String]
|
||||||
def finalize_short
|
def to_short
|
||||||
sign(@hmac, algorithm: @algorithm, sep: @sep) if @hmac
|
|
||||||
"#{key.to_s.strip}=#{value.to_s.strip}"
|
"#{key.to_s.strip}=#{value.to_s.strip}"
|
||||||
end
|
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_accessor :key, :value
|
||||||
attr_reader :domain, :path, :expires, :maxage, :samesite, :secure, :httponly
|
attr_reader :domain, :path, :expires, :maxage, :samesite, :secure, :httponly
|
||||||
|
|
||||||
|
@ -95,7 +66,7 @@ module Landline
|
||||||
# @return [Cookie]
|
# @return [Cookie]
|
||||||
def self.from_setcookie_string(data)
|
def self.from_setcookie_string(data)
|
||||||
kvpair, params = parse_value(data, regexp: HeaderRegexp::COOKIE_PARAM)
|
kvpair, params = parse_value(data, regexp: HeaderRegexp::COOKIE_PARAM)
|
||||||
key, value = kvpair.match(/([^=]+)=?(.*)/).to_a[1..].map(&:strip)
|
key, value = kvpair.split("=").map(&:strip)
|
||||||
Cookie.new(key, value, params)
|
Cookie.new(key, value, params)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -104,11 +75,8 @@ module Landline
|
||||||
# @return [Hash{String => Cookie}]
|
# @return [Hash{String => Cookie}]
|
||||||
def self.from_cookie_string(data)
|
def self.from_cookie_string(data)
|
||||||
hash = {}
|
hash = {}
|
||||||
return hash if data.nil?
|
|
||||||
|
|
||||||
data.split(";").map do |cookiestr|
|
data.split(";").map do |cookiestr|
|
||||||
key, value = cookiestr.match(/([^=]+)=?(.*)/).to_a[1..].map(&:strip)
|
cookie = Cookie.new(*cookiestr.split("=").map(&:strip))
|
||||||
cookie = Cookie.new(key, value)
|
|
||||||
if hash[cookie.key]
|
if hash[cookie.key]
|
||||||
hash[cookie.key].append(cookie)
|
hash[cookie.key].append(cookie)
|
||||||
else
|
else
|
||||||
|
@ -120,12 +88,6 @@ module Landline
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def setup_hmac(params)
|
|
||||||
@hmac = params['hmac']
|
|
||||||
@algorithm = (params['algorithm'] or "sha256")
|
|
||||||
@sep = (params['sep'] or "&")
|
|
||||||
end
|
|
||||||
|
|
||||||
def setup_params(params)
|
def setup_params(params)
|
||||||
# Extended cookie params
|
# Extended cookie params
|
||||||
params.transform_keys!(&:downcase)
|
params.transform_keys!(&:downcase)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue