You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
44 lines
1.6 KiB
44 lines
1.6 KiB
# frozen_string_literal: true |
|
|
|
class SignatureParser |
|
class ParsingError < StandardError; end |
|
|
|
# The syntax of this header is defined in: |
|
# https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-12#section-4 |
|
# See https://datatracker.ietf.org/doc/html/rfc7235#appendix-C |
|
# and https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6 |
|
|
|
# In addition, ignore a `Signature ` string prefix that was added by old versions |
|
# of `node-http-signatures` |
|
|
|
TOKEN_RE = /[0-9a-zA-Z!#$%&'*+.^_`|~-]+/ |
|
# qdtext and quoted_pair are not exactly according to spec but meh |
|
QUOTED_STRING_RE = /"([^\\"]|(\\.))*"/ |
|
PARAM_RE = /(?<key>#{TOKEN_RE})\s*=\s*((?<value>#{TOKEN_RE})|(?<quoted_value>#{QUOTED_STRING_RE}))/ |
|
|
|
def self.parse(raw_signature) |
|
# Old versions of node-http-signature add an incorrect "Signature " prefix to the header |
|
raw_signature = raw_signature.delete_prefix('Signature ') |
|
|
|
params = {} |
|
scanner = StringScanner.new(raw_signature) |
|
|
|
# Use `skip` instead of `scan` as we only care about the subgroups |
|
while scanner.skip(PARAM_RE) |
|
key = scanner[:key] |
|
# Detect a duplicate key |
|
raise Mastodon::SignatureVerificationError, 'Error parsing signature with duplicate keys' if params.key?(key) |
|
|
|
# This is not actually correct with regards to quoted pairs, but it's consistent |
|
# with our previous implementation, and good enough in practice. |
|
params[key] = scanner[:value] || scanner[:quoted_value][1...-1] |
|
|
|
scanner.skip(/\s*/) |
|
return params if scanner.eos? |
|
|
|
raise ParsingError unless scanner.skip(/\s*,\s*/) |
|
end |
|
|
|
raise ParsingError |
|
end |
|
end
|
|
|