Skip to content

Commit

Permalink
Properly format PEMs
Browse files Browse the repository at this point in the history
  • Loading branch information
johnnyshields committed Jul 11, 2024
1 parent 626140b commit d985988
Show file tree
Hide file tree
Showing 9 changed files with 161 additions and 120 deletions.
3 changes: 3 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ AllCops:
- 'tmp/**/*'
- 'vendor/**/*'

Style/ModuleFunction:
EnforcedStyle: extend_self

Style/NumericPredicate:
EnforcedStyle: comparison

Expand Down
44 changes: 16 additions & 28 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2024-07-10 16:10:44 UTC using RuboCop version 1.64.1.
# on 2024-07-11 13:04:30 UTC using RuboCop version 1.64.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
Expand Down Expand Up @@ -127,7 +127,7 @@ Layout/SpaceAroundOperators:
- 'lib/ruby_saml/xml/document.rb'
- 'lib/ruby_saml/xml/signed_document.rb'

# Offense count: 5
# Offense count: 3
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters.
# SupportedStyles: space, no_space
Expand Down Expand Up @@ -180,7 +180,7 @@ Lint/UselessAssignment:
Exclude:
- 'lib/ruby_saml/slo_logoutrequest.rb'

# Offense count: 42
# Offense count: 41
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
Metrics/AbcSize:
Max: 100
Expand All @@ -191,21 +191,26 @@ Metrics/AbcSize:
Metrics/BlockLength:
Max: 27

# Offense count: 9
# Offense count: 8
# Configuration parameters: CountComments, CountAsOne.
Metrics/ClassLength:
Max: 652

# Offense count: 25
# Offense count: 26
# Configuration parameters: AllowedMethods, AllowedPatterns.
Metrics/CyclomaticComplexity:
Max: 21

# Offense count: 59
# Offense count: 58
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
Metrics/MethodLength:
Max: 63

# Offense count: 1
# Configuration parameters: CountComments, CountAsOne.
Metrics/ModuleLength:
Max: 244

# Offense count: 2
# Configuration parameters: Max, CountKeywordArgs.
Metrics/ParameterLists:
Expand Down Expand Up @@ -279,22 +284,20 @@ Performance/RedundantEqualityComparisonBlock:
Exclude:
- 'lib/ruby_saml/settings.rb'

# Offense count: 5
# Offense count: 3
# This cop supports unsafe autocorrection (--autocorrect-all).
Performance/StringInclude:
Exclude:
- 'lib/ruby_saml/authrequest.rb'
- 'lib/ruby_saml/logoutrequest.rb'
- 'lib/ruby_saml/slo_logoutresponse.rb'
- 'lib/ruby_saml/utils.rb'

# Offense count: 8
# Offense count: 4
# This cop supports safe autocorrection (--autocorrect).
Performance/StringReplacement:
Exclude:
- 'lib/ruby_saml/metadata.rb'
- 'lib/ruby_saml/saml_message.rb'
- 'lib/ruby_saml/utils.rb'
- 'lib/ruby_saml/xml/document.rb'

# Offense count: 48
Expand Down Expand Up @@ -409,14 +412,6 @@ Style/IfUnlessModifier:
- 'lib/ruby_saml/xml/document.rb'
- 'lib/ruby_saml/xml/signed_document.rb'

# Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: EnforcedStyle, Autocorrect.
# SupportedStyles: module_function, extend_self, forbidden
Style/ModuleFunction:
Exclude:
- 'lib/ruby_saml/logging.rb'

# Offense count: 16
# Configuration parameters: AllowedMethods.
# AllowedMethods: respond_to_missing?
Expand All @@ -432,18 +427,11 @@ Style/OptionalBooleanParameter:
- 'lib/ruby_saml/utils.rb'
- 'lib/ruby_saml/xml/signed_document.rb'

# Offense count: 1
# This cop supports safe autocorrection (--autocorrect).
Style/RedundantBegin:
Exclude:
- 'lib/ruby_saml/utils.rb'

# Offense count: 8
# Offense count: 3
# This cop supports safe autocorrection (--autocorrect).
Style/RedundantRegexpArgument:
Exclude:
- 'lib/ruby_saml/saml_message.rb'
- 'lib/ruby_saml/utils.rb'
- 'lib/ruby_saml/xml/document.rb'

# Offense count: 3
Expand Down Expand Up @@ -472,7 +460,7 @@ Style/StringConcatenation:
- 'lib/ruby_saml/saml_message.rb'
- 'lib/ruby_saml/slo_logoutrequest.rb'

# Offense count: 351
# Offense count: 339
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline.
# SupportedStyles: single_quotes, double_quotes
Expand Down Expand Up @@ -509,7 +497,7 @@ Style/SymbolArray:
Exclude:
- 'lib/ruby_saml/settings.rb'

# Offense count: 92
# Offense count: 104
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns.
# URISchemes: http, https
Expand Down
1 change: 1 addition & 0 deletions lib/ruby_saml.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
require 'ruby_saml/validation_error'
require 'ruby_saml/metadata'
require 'ruby_saml/idp_metadata_parser'
require 'ruby_saml/pem_formatter'
require 'ruby_saml/utils'
require 'ruby_saml/version'

Expand Down
68 changes: 68 additions & 0 deletions lib/ruby_saml/pem_formatter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# frozen_string_literal: true

module RubySaml
# Formats PEM-encoded X.509 certificates and private keys to
# canonical PEM format with 64-char lines and BEGIN/END headers.
#
# @api private
module PemFormatter
extend self

# Formats one or many X.509 certificate(s) to canonical
# PEM format with 64-char lines and BEGIN/END headers.
#
# @param cert [String] The original certificate(s)
# @param multi [true|false] Whether to return multiple keys delimited by newline
# @return [String|nil] The formatted certificate(s)
def format_cert(cert, multi: false)
detect_pems(cert, 'CERTIFICATE', multi: multi) do |pem|
format_cert_single(pem)
end
end

# Formats one or many private key(s) to canonical PEM format
# with 64-char lines and BEGIN/END headers.
#
# @param key [String] The original private key(s)
# @param multi [true|false] Whether to return multiple keys delimited by newline
# @return [String|nil] The formatted private key(s)
def format_private_key(key, multi: false)
detect_pems(key, '(?:RSA|DSA|EC|ECDSA) PRIVATE KEY', multi: multi) do |pem|
format_private_key_single(pem)
end
end

private

def detect_pems(str, label, multi: false, &block)
return if str.nil? || str.empty?
return str unless str.ascii_only?
return if str.match?(/\A\s*\z/)

pems = str.scan(/-{5}\s*BEGIN #{label}\s*-{5}.*?-{5}\s*END #{label}\s*-{5}?/m).map(&block)

# Try to format the original string if no pems were found
return yield(str) if pems.empty?

multi ? pems.join("\n") : pems.first
end

def format_cert_single(cert)
format_pem(cert, 'CERTIFICATE')
end

def format_private_key_single(key)
algo = key.match(/((?:RSA|ECDSA|EC|DSA) )PRIVATE KEY/)&.[](1)
label = "#{algo}PRIVATE KEY"
format_pem(key, label)
end

# Strips all whitespace and the BEGIN/END lines,
# then splits the string into 64-character lines,
# and re-applies BEGIN/END labels
def format_pem(str, label)
str = str.gsub(/\s|-{5}\s*(BEGIN|END) [A-Z\d\s]+-{5}/, '').scan(/.{1,64}/).join("\n")
"-----BEGIN #{label}-----\n#{str}\n-----END #{label}-----"
end
end
end
Loading

0 comments on commit d985988

Please sign in to comment.