@@ -77,6 +77,9 @@ func ParseDatetime(s string) (Datetime, error) {
77
77
return Datetime {}, fmt .Errorf ("%w: invalid month" , errDatetime )
78
78
}
79
79
month = 10 * int (rune (s [5 ])- '0' ) + int (rune (s [6 ])- '0' )
80
+ if month > 12 {
81
+ return Datetime {}, fmt .Errorf ("%w: month is out of range" , errDatetime )
82
+ }
80
83
81
84
if s [7 ] != '-' {
82
85
return Datetime {}, fmt .Errorf ("%w: unexpected character %s" , errDatetime , strconv .QuoteRune (rune (s [7 ])))
@@ -88,6 +91,9 @@ func ParseDatetime(s string) (Datetime, error) {
88
91
return Datetime {}, fmt .Errorf ("%w: invalid day" , errDatetime )
89
92
}
90
93
day = 10 * int (rune (s [8 ])- '0' ) + int (rune (s [9 ])- '0' )
94
+ if day > 31 {
95
+ return Datetime {}, fmt .Errorf ("%w: day is out of range" , errDatetime )
96
+ }
91
97
92
98
// If the length is 10, we only have a date and we're done.
93
99
if length == 10 {
@@ -117,6 +123,9 @@ func ParseDatetime(s string) (Datetime, error) {
117
123
return Datetime {}, fmt .Errorf ("%w: invalid hour" , errDatetime )
118
124
}
119
125
hour = 10 * int (rune (s [11 ])- '0' ) + int (rune (s [12 ])- '0' )
126
+ if hour > 23 {
127
+ return Datetime {}, fmt .Errorf ("%w: hour is out of range" , errDatetime )
128
+ }
120
129
121
130
if s [13 ] != ':' {
122
131
return Datetime {}, fmt .Errorf ("%w: unexpected character %s" , errDatetime , strconv .QuoteRune (rune (s [13 ])))
@@ -127,6 +136,9 @@ func ParseDatetime(s string) (Datetime, error) {
127
136
return Datetime {}, fmt .Errorf ("%w: invalid minute" , errDatetime )
128
137
}
129
138
minute = 10 * int (rune (s [14 ])- '0' ) + int (rune (s [15 ])- '0' )
139
+ if minute > 59 {
140
+ return Datetime {}, fmt .Errorf ("%w: minute is out of range" , errDatetime )
141
+ }
130
142
131
143
if s [16 ] != ':' {
132
144
return Datetime {}, fmt .Errorf ("%w: unexpected character %s" , errDatetime , strconv .QuoteRune (rune (s [16 ])))
@@ -137,6 +149,9 @@ func ParseDatetime(s string) (Datetime, error) {
137
149
return Datetime {}, fmt .Errorf ("%w: invalid second" , errDatetime )
138
150
}
139
151
second = 10 * int (rune (s [17 ])- '0' ) + int (rune (s [18 ])- '0' )
152
+ if second > 59 {
153
+ return Datetime {}, fmt .Errorf ("%w: second is out of range" , errDatetime )
154
+ }
140
155
141
156
// At this point, things are variable.
142
157
// 19 can be ., in which case we have milliseconds. (SSS)
@@ -189,9 +204,17 @@ func ParseDatetime(s string) (Datetime, error) {
189
204
return Datetime {}, fmt .Errorf ("%w: invalid time zone offset" , errDatetime )
190
205
}
191
206
192
- hh := time .Duration (10 * int64 (rune (s [trailerOffset + 1 ])- '0' )+ int64 (rune (s [trailerOffset + 2 ])- '0' )) * time .Hour
193
- mm := time .Duration (10 * int64 (rune (s [trailerOffset + 3 ])- '0' )+ int64 (rune (s [trailerOffset + 4 ])- '0' )) * time .Minute
194
- offset = time .Duration (sign ) * (hh + mm )
207
+ hh := time .Duration (10 * int64 (rune (s [trailerOffset + 1 ])- '0' ) + int64 (rune (s [trailerOffset + 2 ])- '0' ))
208
+ mm := time .Duration (10 * int64 (rune (s [trailerOffset + 3 ])- '0' ) + int64 (rune (s [trailerOffset + 4 ])- '0' ))
209
+
210
+ if hh > 23 {
211
+ return Datetime {}, fmt .Errorf ("%w: time zone offset hours are out of range" , errDatetime )
212
+ }
213
+ if mm > 59 {
214
+ return Datetime {}, fmt .Errorf ("%w: time zone offset minutes are out of range" , errDatetime )
215
+ }
216
+
217
+ offset = time .Duration (sign ) * ((hh * time .Hour ) + (mm * time .Minute ))
195
218
196
219
default :
197
220
return Datetime {}, fmt .Errorf ("%w: invalid time zone designator" , errDatetime )
@@ -201,15 +224,11 @@ func ParseDatetime(s string) (Datetime, error) {
201
224
hour , minute , second ,
202
225
int (time .Duration (milli )* time .Millisecond ), time .UTC )
203
226
204
- // Don't allow wrapping: https://github.com/cedar-policy/rfcs/pull/94
205
- tyear , tmonth , tday := t .Date ()
206
- if year != tyear || time .Month (month ) != tmonth || day != tday {
207
- return Datetime {}, fmt .Errorf ("%w: date would wrap" , errDatetime )
208
- }
209
-
210
- thour , tminute , tsecond := t .Hour (), t .Minute (), t .Second ()
211
- if hour != thour || minute != tminute || second != tsecond {
212
- return Datetime {}, fmt .Errorf ("%w: time would wrap" , errDatetime )
227
+ // Don't allow wrapping: https://github.com/cedar-policy/rfcs/pull/94, which can occur
228
+ // because not all months have 31 days, which is our validation range
229
+ _ , tmonth , tday := t .Date ()
230
+ if time .Month (month ) != tmonth || day != tday {
231
+ return Datetime {}, fmt .Errorf ("%w: invalid date" , errDatetime )
213
232
}
214
233
215
234
t = t .Add (offset )
0 commit comments