Class: Mathpix::Configuration

Inherits:
Object
  • Object
show all
Defined in:
lib/mathpix/configuration.rb

Overview

Configuration class with security defaults and validation Seed: 1069 - Deterministic configuration values

Constant Summary collapse

HTTPS_ONLY =

Security constants

true
MAX_FILE_SIZE_MB =
10
MAX_PATH_LENGTH =
1024
ALLOWED_SCHEMES =
%w[https].freeze
MIN_LIMIT =

Resource limits

1
MAX_LIMIT =
100
DEFAULT_LIMIT =
10
CONFIDENCE_HIGH =

Confidence thresholds (balanced ternary seed 1069)

0.9
CONFIDENCE_MEDIUM =
0.7
CONFIDENCE_LOW =
0.5
RATE_LIMIT_DEFAULT =

Rate limiting (requests per minute)

60
RATE_LIMIT_BURST =
10

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeConfiguration

Returns a new instance of Configuration.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/mathpix/configuration.rb', line 36

def initialize
  @app_id = ENV.fetch('MATHPIX_APP_ID', nil)
  @app_key = ENV.fetch('MATHPIX_APP_KEY', nil)
  @api_url = ENV.fetch('MATHPIX_API_URL', 'https://api.mathpix.com/v3')
  @timeout = ENV.fetch('MATHPIX_TIMEOUT', '30').to_i
  @default_formats = [:latex_styled]
  @user_agent = "mathpix-ruby/#{Mathpix::VERSION}"

  # Security settings
  @enforce_https = HTTPS_ONLY
  @max_file_size_mb = MAX_FILE_SIZE_MB
  @max_path_length = MAX_PATH_LENGTH

  # Resource limits
  @min_limit = MIN_LIMIT
  @max_limit = MAX_LIMIT
  @default_limit = DEFAULT_LIMIT

  # Confidence thresholds
  @confidence_thresholds = {
    high: CONFIDENCE_HIGH,
    medium: CONFIDENCE_MEDIUM,
    low: CONFIDENCE_LOW
  }

  # Rate limiting
  @rate_limit = RATE_LIMIT_DEFAULT

  # Structured logging
  @logger = nil # Can be set to Logger instance
end

Instance Attribute Details

#api_urlObject Also known as: endpoint

Returns the value of attribute api_url.



27
28
29
# File 'lib/mathpix/configuration.rb', line 27

def api_url
  @api_url
end

#app_idObject

Returns the value of attribute app_id.



27
28
29
# File 'lib/mathpix/configuration.rb', line 27

def app_id
  @app_id
end

#app_keyObject

Returns the value of attribute app_key.



27
28
29
# File 'lib/mathpix/configuration.rb', line 27

def app_key
  @app_key
end

#confidence_thresholdsObject (readonly)

Returns the value of attribute confidence_thresholds.



30
31
32
# File 'lib/mathpix/configuration.rb', line 30

def confidence_thresholds
  @confidence_thresholds
end

#default_formatsObject

Returns the value of attribute default_formats.



27
28
29
# File 'lib/mathpix/configuration.rb', line 27

def default_formats
  @default_formats
end

#enforce_httpsObject

Returns the value of attribute enforce_https.



27
28
29
# File 'lib/mathpix/configuration.rb', line 27

def enforce_https
  @enforce_https
end

#loggerObject

Returns the value of attribute logger.



27
28
29
# File 'lib/mathpix/configuration.rb', line 27

def logger
  @logger
end

#max_file_size_mbObject

Returns the value of attribute max_file_size_mb.



27
28
29
# File 'lib/mathpix/configuration.rb', line 27

def max_file_size_mb
  @max_file_size_mb
end

#rate_limitObject (readonly)

Returns the value of attribute rate_limit.



30
31
32
# File 'lib/mathpix/configuration.rb', line 30

def rate_limit
  @rate_limit
end

#seedObject

Returns the value of attribute seed.



27
28
29
# File 'lib/mathpix/configuration.rb', line 27

def seed
  @seed
end

#timeoutObject

Returns the value of attribute timeout.



27
28
29
# File 'lib/mathpix/configuration.rb', line 27

def timeout
  @timeout
end

#user_agentObject

Returns the value of attribute user_agent.



27
28
29
# File 'lib/mathpix/configuration.rb', line 27

def user_agent
  @user_agent
end

Instance Method Details

#log(level, message, data = {}) ⇒ Object

Log structured message

Parameters:

  • level (Symbol)

    log level (:debug, :info, :warn, :error)

  • message (String)

    log message

  • data (Hash) (defaults to: {})

    structured data



168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/mathpix/configuration.rb', line 168

def log(level, message, data = {})
  return unless @logger

  structured_message = {
    timestamp: Time.now.utc.iso8601,
    level: level,
    message: message,
    seed: 1069,
    **data
  }.to_json

  @logger.send(level, structured_message)
end

#sanitize_limit(limit) ⇒ Integer

Sanitize limit to be within bounds

Parameters:

  • limit (Integer)

    requested limit

Returns:

  • (Integer)

    clamped limit



85
86
87
# File 'lib/mathpix/configuration.rb', line 85

def sanitize_limit(limit)
  [[limit.to_i, @min_limit].max, @max_limit].min
end

#sanitize_path(path) ⇒ String?

Sanitize file path to prevent directory traversal

Parameters:

  • path (String)

    file path

Returns:

  • (String, nil)

    sanitized path or nil if invalid



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/mathpix/configuration.rb', line 137

def sanitize_path(path)
  return nil unless path.is_a?(String)
  return nil if path.length > @max_path_length

  # Remove null bytes
  path = path.tr("\0", '')

  # Normalize path
  normalized = File.expand_path(path)

  # Check for directory traversal attempts
  return nil if normalized.include?('../')
  return nil if normalized.match?(%r{\.\.[/\\]})

  # Check file exists (for local paths)
  return nil unless File.exist?(normalized)

  # Check file size
  size_mb = File.size(normalized).to_f / (1024 * 1024)
  return nil if size_mb > @max_file_size_mb

  normalized
rescue StandardError
  nil
end

#upgrade_to_https(url) ⇒ String

Auto-upgrade HTTP to HTTPS for remote URLs

This provides the same behavior for seamless URL support

Examples:

upgrade_to_https('http://example.com/img.png')
# => 'https://example.com/img.png'

Parameters:

  • url (String)

    URL that may be HTTP or HTTPS

Returns:

  • (String)

    URL with https:// scheme



126
127
128
129
130
131
# File 'lib/mathpix/configuration.rb', line 126

def upgrade_to_https(url)
  return url unless url.is_a?(String)
  return url unless url.start_with?('http://')

  url.sub(%r{^http://}, 'https://')
end

#valid_url?(url) ⇒ Boolean

Check if URL is allowed (HTTPS only)

Parameters:

  • url (String)

    URL to validate

Returns:

  • (Boolean)


93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/mathpix/configuration.rb', line 93

def valid_url?(url)
  return false unless url.is_a?(String)
  return false if url.length > @max_path_length

  uri = URI.parse(url)

  # Must be HTTP(S) scheme
  return false unless %w[http https].include?(uri.scheme)

  # Enforce HTTPS if enabled
  return false if enforce_https && uri.scheme != 'https'

  # Must have a host
  return false if uri.host.nil? || uri.host.empty?

  # Block localhost and private IPs
  return false if uri.host.match?(/^(localhost|127\.|0\.0\.0\.0|::1)/)
  return false if uri.host.match?(/^(10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.)/)

  true
rescue URI::InvalidURIError
  false
end

#validate!Object

Raises:



68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/mathpix/configuration.rb', line 68

def validate!
  raise ConfigurationError, 'app_id is required' if app_id.nil? || app_id.empty?
  raise ConfigurationError, 'app_key is required' if app_key.nil? || app_key.empty?

  # Validate API URL uses HTTPS
  raise ConfigurationError, 'API URL must use HTTPS' if enforce_https && !api_url.start_with?('https://')

  # Validate timeout
  raise ConfigurationError, 'Timeout must be between 1 and 300 seconds' if timeout <= 0 || timeout > 300

  true
end