icalendar 2.12.1 → 2.12.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c581285bbacae9839202046bea20f80be28315865013f9f59e50851fbbed7a34
4
- data.tar.gz: 8be871aab3ba233a56a6442783f6a32cbf138ae145fc777bed68fdf4beff0826
3
+ metadata.gz: 7c417db33a0e54ccf03627a5e966cf86206e55e032dc66ba4aaf3f5ac9ec690a
4
+ data.tar.gz: cebd6eb2f86f758e92b23fb0dc990032b866f0d1ccc825b05d823c4a56927e04
5
5
  SHA512:
6
- metadata.gz: e847fc2a27df55033006bfc9b9d1572563a9a9bafc8cf286959e82e4a47f0c64fcda9a7b7470e37031e635a1e9b086eda769b75108a02e020782c1683fad763e
7
- data.tar.gz: 3a8f8503ace1467d352d586ede3e4c8c91b7ab5d1fec5271c5add7658014a1cc61fc4b2f2ec32b09d481746ff14139fb83b7d14f63b23526056b183bb9133de6
6
+ metadata.gz: e4674fc5afbca40a1852ffd90a8e7d4b13364c4b9c4a7c966ab4cc4bd1ec06abf3df9bf9651bd99fd6083710717ef72af2520c4dcc75a252bd84ce73e281096c
7
+ data.tar.gz: 835f7c88d1af3248ba9c57e7a68a8fc1198a3ed6cd73c540ca83f8e2fb831cebf364128f28d08384005df11f62c05d64462e60ced3a1cfbc799fee2effa7a0c7
@@ -22,9 +22,10 @@ jobs:
22
22
  - 3.2
23
23
  - 3.3
24
24
  - 3.4
25
+ - "4.0"
25
26
 
26
27
  steps:
27
- - uses: actions/checkout@v4
28
+ - uses: actions/checkout@v6
28
29
  - name: Set up Ruby
29
30
  uses: ruby/setup-ruby@v1
30
31
  with:
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  ## Unreleased
2
2
 
3
+ ## 2.12.3 - 2026-05-13
4
+ - Memory use optimization - Jared Menard
5
+ - Run CI against Ruby 4.0 - Artem Chubchenko
6
+
7
+ ## 2.12.2 - 2026-03-21
8
+ - Fix a potential property injection issue through escaping control characters in URI values - Wes Ring
9
+
3
10
  ## 2.12.1 - 2025-10-19
4
11
  - Fix a problem with invalid ics generation for calendars with custom properties that include a `tzid` parameter.
5
12
 
@@ -0,0 +1,27 @@
1
+ require 'memory_profiler'
2
+ require 'icalendar'
3
+
4
+ # Profiles the per-event calendar wrapping pattern:
5
+ # cal = Icalendar::Calendar.new
6
+ # ical_event.parent&.timezones&.each { |tz| cal.add_timezone tz }
7
+ # cal.add_event(ical_event)
8
+ # cal.to_ical
9
+
10
+ cal_string = File.read(File.join(__dir__, '..', 'spec/fixtures/timezone.ics'))
11
+ source_calendar = Icalendar::Calendar.parse(cal_string).first
12
+ events = source_calendar.events
13
+
14
+ ITERATIONS = 1000
15
+
16
+ report = MemoryProfiler.report do
17
+ ITERATIONS.times do
18
+ events.each do |ical_event|
19
+ cal = Icalendar::Calendar.new
20
+ ical_event.parent&.timezones&.each { |tz| cal.add_timezone tz }
21
+ cal.add_event(ical_event)
22
+ cal.to_ical
23
+ end
24
+ end
25
+ end
26
+
27
+ report.pretty_print(scale_bytes: true, top: 20)
data/icalendar.gemspec CHANGED
@@ -37,7 +37,7 @@ ActiveSupport is required for TimeWithZone support, but not required for general
37
37
  s.add_dependency 'ostruct'
38
38
 
39
39
  s.add_development_dependency 'rake', '~> 13.0'
40
- s.add_development_dependency 'bundler', '~> 2.0'
40
+ s.add_development_dependency 'bundler'
41
41
 
42
42
  # test with all groups of tzinfo dependencies
43
43
  # tzinfo 2.x
@@ -172,13 +172,11 @@ module Icalendar
172
172
  private
173
173
 
174
174
  def map_property_value(value, klass, multi_valued, new_property)
175
- params = {}
176
- if new_property
177
- params.merge!('VALUE': klass.value_type)
178
- end
179
- if value.nil? || value.is_a?(Icalendar::Value)
180
- value
181
- elsif value.is_a? ::Array
175
+ return value if value.nil? || value.is_a?(Icalendar::Value)
176
+
177
+ params = new_property ? {'VALUE': klass.value_type} : {}
178
+
179
+ if value.is_a? ::Array
182
180
  Icalendar::Values::Helpers::Array.new value, klass, params, {delimiter: (multi_valued ? ',' : ';')}
183
181
  else
184
182
  klass.new value, params
@@ -6,6 +6,7 @@ module Icalendar
6
6
  module Values
7
7
 
8
8
  class Uri < Value
9
+ CONTROL_BYTES_REGEX = /[\x00-\x1F\x7F]/.freeze
9
10
 
10
11
  def initialize(value, *args)
11
12
  parsed = URI.parse(value) rescue value
@@ -13,7 +14,7 @@ module Icalendar
13
14
  end
14
15
 
15
16
  def value_ical
16
- value.to_s
17
+ value.to_s.gsub(CONTROL_BYTES_REGEX) { |char| "%%%02X" % char.ord }
17
18
  end
18
19
  end
19
20
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Icalendar
4
4
 
5
- VERSION = '2.12.1'
5
+ VERSION = '2.12.3'
6
6
 
7
7
  end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe Icalendar::Values::Uri do
4
+ describe '#value_ical' do
5
+ it 'percent-encodes CRLF to prevent content-line injection' do
6
+ value = described_class.new("https://a.example/ok\r\nATTENDEE:mailto:evil@example.com")
7
+
8
+ expect(value.value_ical).to eq('https://a.example/ok%0D%0AATTENDEE:mailto:evil@example.com')
9
+ end
10
+
11
+ it 'percent-encodes the full ASCII control range' do
12
+ raw = "https://example.com/a\tb\f#{0.chr}#{127.chr}"
13
+ value = described_class.new(raw)
14
+
15
+ expect(value.value_ical).to eq('https://example.com/a%09b%0C%00%7F')
16
+ end
17
+
18
+ it 'leaves valid printable URI characters unchanged' do
19
+ raw = 'https://example.com/a-path?q=one%20two&x=@tag#frag'
20
+ value = described_class.new(raw)
21
+
22
+ expect(value.value_ical).to eq(raw)
23
+ end
24
+ end
25
+
26
+ describe '#to_ical' do
27
+ it 'serializes injected CRLF on the same content line' do
28
+ value = described_class.new("https://a.example/ok\r\nATTENDEE:mailto:evil@example.com")
29
+
30
+ expect(value.to_ical(Icalendar::Values::Text)).to eq(
31
+ ';VALUE=URI:https://a.example/ok%0D%0AATTENDEE:mailto:evil@example.com'
32
+ )
33
+ end
34
+ end
35
+ end
36
+
37
+ describe Icalendar::Values::CalAddress do
38
+ it 'inherits URI control-byte encoding' do
39
+ value = described_class.new("mailto:user@example.com\r\nORGANIZER:mailto:evil@example.com")
40
+
41
+ expect(value.value_ical).to eq('mailto:user@example.com%0D%0AORGANIZER:mailto:evil@example.com')
42
+ end
43
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: icalendar
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.12.1
4
+ version: 2.12.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Ahearn
@@ -83,16 +83,16 @@ dependencies:
83
83
  name: bundler
84
84
  requirement: !ruby/object:Gem::Requirement
85
85
  requirements:
86
- - - "~>"
86
+ - - ">="
87
87
  - !ruby/object:Gem::Version
88
- version: '2.0'
88
+ version: '0'
89
89
  type: :development
90
90
  prerelease: false
91
91
  version_requirements: !ruby/object:Gem::Requirement
92
92
  requirements:
93
- - - "~>"
93
+ - - ">="
94
94
  - !ruby/object:Gem::Version
95
- version: '2.0'
95
+ version: '0'
96
96
  - !ruby/object:Gem::Dependency
97
97
  name: activesupport
98
98
  requirement: !ruby/object:Gem::Requirement
@@ -209,6 +209,7 @@ files:
209
209
  - LICENSE
210
210
  - README.md
211
211
  - Rakefile
212
+ - benchmarks/memory_per_event_ical.rb
212
213
  - icalendar.gemspec
213
214
  - lib/icalendar.rb
214
215
  - lib/icalendar/alarm.rb
@@ -292,6 +293,7 @@ files:
292
293
  - spec/values/period_spec.rb
293
294
  - spec/values/recur_spec.rb
294
295
  - spec/values/text_spec.rb
296
+ - spec/values/uri_spec.rb
295
297
  - spec/values/utc_offset_spec.rb
296
298
  homepage: https://github.com/icalendar/icalendar
297
299
  licenses:
@@ -318,7 +320,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
318
320
  - !ruby/object:Gem::Version
319
321
  version: '0'
320
322
  requirements: []
321
- rubygems_version: 3.6.9
323
+ rubygems_version: 4.0.6
322
324
  specification_version: 4
323
325
  summary: A ruby implementation of the iCalendar specification (RFC-5545).
324
326
  test_files:
@@ -361,4 +363,5 @@ test_files:
361
363
  - spec/values/period_spec.rb
362
364
  - spec/values/recur_spec.rb
363
365
  - spec/values/text_spec.rb
366
+ - spec/values/uri_spec.rb
364
367
  - spec/values/utc_offset_spec.rb