diff --git a/fail2ban/server/strptime.py b/fail2ban/server/strptime.py index 68ff2f41..56f1c753 100644 --- a/fail2ban/server/strptime.py +++ b/fail2ban/server/strptime.py @@ -27,7 +27,7 @@ from .mytime import MyTime locale_time = LocaleTime() timeRE = TimeRE() -FIXED_OFFSET_TZ_RE = re.compile(r'(?:Z|UTC|GMT)?([+-]\d{2}(?:\d{2}))?$') +FIXED_OFFSET_TZ_RE = re.compile(r'(?:Z|UTC|GMT)?([+-]\d{2}(?::?\d{2})?)?$') def _getYearCentRE(cent=(0,3), distance=3, now=(MyTime.now(), MyTime.alternateNow)): """ Build century regex for last year and the next years (distance). @@ -108,8 +108,15 @@ def zone2offset(tz, dt): dt: datetime instance for offset computation """ if isinstance(tz, basestring): - # [+-]1 * (hh*60 + mm) - return int(tz[0]+'1') * (int(tz[1:3])*60 + int(tz[3:5])) + if len(tz) <= 3: # short tz (hh only) + # [+-]hh --> [+-]hh*60 + return int(tz)*60 + if tz[3] != ':': + # [+-]hhmm --> [+-]1 * (hh*60 + mm) + return int(tz[0]+'1') * (int(tz[1:3])*60 + int(tz[3:5])) + else: + # [+-]hh:mm --> [+-]1 * (hh*60 + mm) + return int(tz[0]+'1') * (int(tz[1:3])*60 + int(tz[4:6])) return tz def reGroupDictStrptime(found_dict, msec=False, default_tz=None): @@ -202,11 +209,7 @@ def reGroupDictStrptime(found_dict, msec=False, default_tz=None): if z in ("Z", "UTC", "GMT"): tzoffset = 0 else: - tzoffset = int(z[1:3]) * 60 # Hours... - if len(z)>3: - tzoffset += int(z[-2:]) # ...and minutes - if z.startswith("-"): - tzoffset = -tzoffset + tzoffset = zone2offset(z, 0); # currently offset-based only elif key == 'Z': z = val if z in ("UTC", "GMT"): diff --git a/fail2ban/tests/datedetectortestcase.py b/fail2ban/tests/datedetectortestcase.py index 6d728b5e..cbf1ac21 100644 --- a/fail2ban/tests/datedetectortestcase.py +++ b/fail2ban/tests/datedetectortestcase.py @@ -90,21 +90,31 @@ class DateDetectorTest(LogCaptureTestCase): self.assertEqual(matchlog.group(1), 'Jan 23 21:59:59') def testDefaultTimeZone(self): - log = "2017-01-23 15:00:00" dd = self.datedetector - dd.default_tz='UTC+0300'; datelog, _ = dd.getTime(log) - # so in UTC, it was noon - self.assertEqual(datetime.datetime.utcfromtimestamp(datelog), - datetime.datetime(2017, 1, 23, 12, 0, 0)) - - dd.default_tz='UTC'; datelog, _ = dd.getTime(log) - self.assertEqual(datetime.datetime.utcfromtimestamp(datelog), - datetime.datetime(2017, 1, 23, 15, 0, 0)) - self.assertEqual(dd.default_tz, 0); # utc == 0 - - dd.default_tz='UTC-0430'; datelog, _ = dd.getTime(log) - self.assertEqual(datetime.datetime.utcfromtimestamp(datelog), - datetime.datetime(2017, 1, 23, 19, 30, 0)) + dt = datetime.datetime + logdt = "2017-01-23 15:00:00" + dtUTC = dt(2017, 1, 23, 15, 0) + for tz, log, desired in ( + ('UTC+0300', logdt, dt(2017, 1, 23, 12, 0)), # so in UTC, it was noon + ('UTC', logdt, dtUTC), # UTC + ('UTC-0430', logdt, dt(2017, 1, 23, 19, 30)), + ('GMT+12', logdt, dt(2017, 1, 23, 3, 0)), + (None, logdt, dt(2017, 1, 23, 14, 0)), # default CET in our test-framework + ('UTC+0300', logdt+' GMT', dtUTC), # GMT wins + ('UTC', logdt+' GMT', dtUTC), # GMT wins + ('UTC-0430', logdt+' GMT', dtUTC), # GMT wins + (None, logdt+' GMT', dtUTC), # GMT wins + ('UTC', logdt+' -1045', dt(2017, 1, 24, 1, 45)), # -1045 wins + (None, logdt+' -10:45', dt(2017, 1, 24, 1, 45)), # -1045 wins + ('UTC', logdt+' +0945', dt(2017, 1, 23, 5, 15)), # +0945 wins + (None, logdt+' +09:45', dt(2017, 1, 23, 5, 15)), # +0945 wins + (None, logdt+' Z', dtUTC), # Z wins (UTC) + ): + logSys.debug('== test %r with TZ %r', log, tz) + dd.default_tz=tz; datelog, _ = dd.getTime(log) + val = dt.utcfromtimestamp(datelog) + self.assertEqual(val, desired, + "wrong offset %r != %r by %r with TZ %r (%r)" % (val, desired, log, tz, dd.default_tz)) self.assertRaises(ValueError, setattr, dd, 'default_tz', 'WRONG-TZ') dd.default_tz = None