[Pkg-sogo-maintainers] Bug#1109884: unblock: sogo/5.12.1-3
Jordi Mallach
jordi at debian.org
Fri Jul 25 13:11:47 BST 2025
Package: release.debian.org
Severity: normal
X-Debbugs-Cc: sogo at packages.debian.org
Control: affects -1 + src:sogo
User: release.debian.org at packages.debian.org
Usertags: unblock
Please unblock package sogo
This update adds a couple additional fixes from upstream git
for two parts of the code:
- OpenId authentication using an unreliable HTTP implementation
- Calendar freebusy information miscalculations
[ Reason ]
To improve setups using OpenId, the internal HTTP lib was replaced
with cURL, as the other one was causing request errors and was in
general unreliable.
Additionally, a high impact bug for the calendar module is included,
to fix freebusy calculation.
[ Impact ]
OpenId setups might see issues when contacting the configured IdP for
the authentication flow.
Additionally, the calendar module will not calculate the freebusy
information reliably in some conditions.
[ Tests ]
No automated tests, but extensive local testing, specially for the
HTTP change.
[ Risks ]
The freebusy code is not trivial, and in fact the initial fix introduced
another issue (a fix included in our patch.
Similarly, the change to libcurl is not small, but we swap some custom code
with a widely tested implementation from libcurl.
[ Checklist ]
[x] all changes are documented in the d/changelog
[x] I reviewed all changes and I approve them
[x] attach debdiff against the package in testing
unblock sogo/5.12.1-3
-------------- next part --------------
diff -Nru sogo-5.12.1/debian/changelog sogo-5.12.1/debian/changelog
--- sogo-5.12.1/debian/changelog 2025-06-06 11:37:50.000000000 +0200
+++ sogo-5.12.1/debian/changelog 2025-07-25 11:26:33.000000000 +0200
@@ -1,3 +1,10 @@
+sogo (5.12.1-3) unstable; urgency=medium
+
+ * Add upstream patch to fix freebusy calculation.
+ * Add upstream patch to use libcurl for OpenId HTTP requests.
+
+ -- Jordi Mallach <jordi at debian.org> Fri, 25 Jul 2025 11:26:33 +0200
+
sogo (5.12.1-2) unstable; urgency=medium
* Replace vendoring of lodash, FileSaver and angularjs with packaged versions.
diff -Nru sogo-5.12.1/debian/patches/series sogo-5.12.1/debian/patches/series
--- sogo-5.12.1/debian/patches/series 2025-06-06 09:45:21.000000000 +0200
+++ sogo-5.12.1/debian/patches/series 2025-07-25 11:24:14.000000000 +0200
@@ -13,3 +13,5 @@
cross.patch
upstream_openid_fixes.patch
upstream_password_regex.patch
+upstream_fix_evaluation_freebusy.patch
+upstream_use_openid_libcurl.patch
diff -Nru sogo-5.12.1/debian/patches/upstream_fix_evaluation_freebusy.patch sogo-5.12.1/debian/patches/upstream_fix_evaluation_freebusy.patch
--- sogo-5.12.1/debian/patches/upstream_fix_evaluation_freebusy.patch 1970-01-01 01:00:00.000000000 +0100
+++ sogo-5.12.1/debian/patches/upstream_fix_evaluation_freebusy.patch 2025-07-22 23:12:28.000000000 +0200
@@ -0,0 +1,381 @@
+commit 8766b7c6b32aedf37d7f8f350e461931b253a4fb
+Author: Hivert Quentin <quentin.hivert.fr at gmail.com>
+Date: Tue Jun 17 11:31:00 2025 +0200
+
+ fix(calendar): properly evalute last occurance freebusy
+
+diff --git a/SOPE/NGCards/iCalDailyRecurrenceCalculator.m b/SOPE/NGCards/iCalDailyRecurrenceCalculator.m
+index 817f4629e..7ecc8f09c 100644
+--- a/SOPE/NGCards/iCalDailyRecurrenceCalculator.m
++++ b/SOPE/NGCards/iCalDailyRecurrenceCalculator.m
+@@ -55,7 +55,7 @@
+ - (NSArray *) recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *) _r
+ {
+ NSMutableArray *ranges;
+- NSCalendarDate *firStart, *startDate, *endDate, *currentStartDate, *currentEndDate;
++ NSCalendarDate *firStart, *firEnd, *startDate, *endDate, *currentStartDate, *currentEndDate;
+ iCalByDayMask *dayMask;
+ long i, count, repeatCount;
+ unsigned interval;
+@@ -63,6 +63,7 @@
+ //[self logWithFormat: @"Recurrence rule is %@", rrule];
+
+ firStart = [firstRange startDate];
++ firEnd = [firstRange endDate];
+ startDate = [_r startDate];
+ endDate = [_r endDate];
+ dayMask = nil;
+@@ -84,13 +85,14 @@
+ // If rule is bound, check the bounds
+ if (![rrule isInfinite])
+ {
+- NSCalendarDate *until, *lastDate;
++ NSCalendarDate *until, *lastStartDate, *lastEndDate;
+
+- lastDate = nil;
++ lastStartDate = nil;
++ lastEndDate = nil;
+ until = [rrule untilDate];
+ if (until)
+ {
+- lastDate = until;
++ lastStartDate = until;
+ }
+ else
+ {
+@@ -98,20 +100,23 @@
+ if (dayMask == nil)
+ // If there's no day mask, we can compute the date of the last
+ // occurrence of the recurrent rule.
+- lastDate = [firStart dateByAddingYears: 0 months: 0
++ lastStartDate = [firStart dateByAddingYears: 0 months: 0
++ days: (interval
++ * (repeatCount - 1))];
++ lastEndDate = [firEnd dateByAddingYears: 0 months: 0
+ days: (interval
+ * (repeatCount - 1))];
+ }
+
+- if (lastDate != nil)
++ if (lastStartDate != nil && lastEndDate != nil)
+ {
+- if ([lastDate compare: startDate] == NSOrderedAscending)
++ if ([lastEndDate compare: startDate] == NSOrderedAscending)
+ // Range starts after last occurrence
+ return nil;
+
+- if ([lastDate compare: endDate] == NSOrderedAscending)
++ if ([lastStartDate compare: endDate] == NSOrderedAscending)
+ // Range ends after last occurence; adjust end date
+- endDate = lastDate;
++ endDate = lastStartDate;
+ }
+ }
+
+diff --git a/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m b/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m
+index 6cd6814ba..5879ed252 100644
+--- a/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m
++++ b/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m
+@@ -185,7 +185,7 @@ static inline unsigned iCalDoWForNSDoW (int dow)
+ // TODO: check whether this is OK for multiday-events!
+ NSMutableArray *ranges;
+ NSTimeZone *timeZone;
+- NSCalendarDate *eventStartDate, *rStart, *rEnd, *until, *referenceDate;
++ NSCalendarDate *eventStartDate, *eventEndDate, *rStart, *rEnd, *untilStart, *untilEnd, *referenceDate;
+ int eventDayOfMonth;
+ unsigned monthIdxInRange, numberOfMonthsInRange, interval, repeatCount;
+ int diff, count;
+@@ -199,12 +199,14 @@ static inline unsigned iCalDoWForNSDoW (int dow)
+ iCalByDayMask *byDayMask;
+
+ eventStartDate = [firstRange startDate];
++ eventEndDate = [firstRange endDate];
+ eventDayOfMonth = [eventStartDate dayOfMonth];
+ timeZone = [eventStartDate timeZone];
+ rStart = [_r startDate];
+ rEnd = [_r endDate];
+ interval = [rrule repeatInterval];
+- until = nil;
++ untilStart = nil;
++ untilEnd = nil;
+ repeatCount = [rrule repeatCount];
+ byMonth = [rrule byMonth];
+ byMonthDay = [rrule byMonthDay];
+@@ -218,24 +220,27 @@ static inline unsigned iCalDoWForNSDoW (int dow)
+ {
+ // When there's no BYxxx mask, we can find the date of the last
+ // occurrence.
+- until = [eventStartDate dateByAddingYears: 0
++ untilStart = [eventStartDate dateByAddingYears: 0
+ months: (interval * (repeatCount - 1))
+ days: 0];
++ untilEnd = [eventEndDate dateByAddingYears: 0
++ months: (interval * (repeatCount - 1))
++ days: 0];
+ }
+ else
+ {
+- until = [rrule untilDate];
++ untilStart = [rrule untilDate];
+ }
+ }
+
+- if (until != nil)
++ if (untilStart != nil)
+ {
+- if ([until compare: rStart] == NSOrderedAscending)
++ if ([untilEnd compare: rStart] == NSOrderedAscending)
+ // Range starts after last occurrence
+ return nil;
+- if ([until compare: rEnd] == NSOrderedAscending)
++ if ([untilStart compare: rEnd] == NSOrderedAscending)
+ // Range ends after last occurence; adjust end date
+- rEnd = until;
++ rEnd = untilStart;
+ }
+
+ if (byMonth && [byMonth count] > 0)
+@@ -441,7 +446,7 @@ static inline unsigned iCalDoWForNSDoW (int dow)
+
+ start = [cursor dateByAddingYears: 0 months: 0 days: (dom - 1)];
+ doCont = [self _addInstanceWithStartDate: start
+- limitDate: until
++ limitDate: untilStart
+ limitRange: _r
+ toArray: ranges];
+ //NSLog(@"*** MONTHLY [%i/%i] adding %@%@ (count = %i)", dom, numDaysInMonth, start, (doCont?@"":@" .. NOT!"), count);
+diff --git a/SOPE/NGCards/iCalWeeklyRecurrenceCalculator.m b/SOPE/NGCards/iCalWeeklyRecurrenceCalculator.m
+index e3786ba7a..5be2a1344 100644
+--- a/SOPE/NGCards/iCalWeeklyRecurrenceCalculator.m
++++ b/SOPE/NGCards/iCalWeeklyRecurrenceCalculator.m
+@@ -64,7 +64,7 @@
+ - (NSArray *) recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *) _r
+ {
+ NSMutableArray *ranges;
+- NSCalendarDate *firStart, *startDate, *endDate, *currentStartDate, *currentEndDate;
++ NSCalendarDate *firStart, *firEnd, *startDate, *endDate, *currentStartDate, *currentEndDate;
+ long i, repeatCount, count;
+ unsigned interval;
+ iCalByDayMask *dayMask;
+@@ -73,6 +73,7 @@
+ //[self logWithFormat: @"Recurrence rule is %@", rrule];
+
+ firStart = [firstRange startDate];
++ firEnd = [firstRange endDate];
+ startDate = [_r startDate];
+ endDate = [_r endDate];
+ dayMask = nil;
+@@ -95,31 +96,35 @@
+ // If rule is bound, check the bounds
+ if (![rrule isInfinite])
+ {
+- NSCalendarDate *until, *lastDate;
++ NSCalendarDate *until, *lastStartDate, *lastEndDate;
+
+- lastDate = nil;
++ lastStartDate = nil;
++ lastEndDate = nil;
+ until = [rrule untilDate];
+ if (until)
+- lastDate = until;
++ lastStartDate = until;
+ else
+ {
+ repeatCount = [rrule repeatCount];
+ if (dayMask == nil)
+ // When there's no BYxxx mask, we can find the date of the last
+ // occurrence.
+- lastDate = [firStart dateByAddingYears: 0 months: 0
++ lastStartDate = [firStart dateByAddingYears: 0 months: 0
++ days: (interval
++ * (repeatCount - 1) * 7)];
++ lastEndDate = [firEnd dateByAddingYears: 0 months: 0
+ days: (interval
+ * (repeatCount - 1) * 7)];
+ }
+
+- if (lastDate != nil)
++ if (lastStartDate != nil && lastEndDate != nil)
+ {
+- if ([lastDate compare: startDate] == NSOrderedAscending)
++ if ([lastEndDate compare: startDate] == NSOrderedAscending)
+ // Range starts after last occurrence
+ return nil;
+- if ([lastDate compare: endDate] == NSOrderedAscending)
++ if ([lastStartDate compare: endDate] == NSOrderedAscending)
+ // Range ends after last occurence; adjust end date
+- endDate = [lastDate addTimeInterval: [firstRange duration]];
++ endDate = [lastStartDate addTimeInterval: [firstRange duration]];
+ }
+ }
+
+diff --git a/SOPE/NGCards/iCalYearlyRecurrenceCalculator.m b/SOPE/NGCards/iCalYearlyRecurrenceCalculator.m
+index 5e4fadc6f..bdf285dc7 100644
+--- a/SOPE/NGCards/iCalYearlyRecurrenceCalculator.m
++++ b/SOPE/NGCards/iCalYearlyRecurrenceCalculator.m
+@@ -44,13 +44,14 @@
+ {
+ NSMutableArray *ranges;
+ NSArray *byMonth;
+- NSCalendarDate *firStart, *lastDate, *rStart, *rEnd, *until, *referenceDate, *rTemp;
++ NSCalendarDate *firStart, *firEnd, *lastStartDate, *lastEndDate, *rStart, *rEnd, *until, *referenceDate, *rTemp;
+ NSInteger *hoursOfOffset;
+ iCalMonthlyRecurrenceCalculator *monthlyCalc;
+ unsigned j, yearIdxInRange, numberOfYearsInRange, count, interval, monthDiff;
+ int diff, repeatCount, currentMonth, origNbDaysInMonth;
+
+ firStart = [firstRange startDate];
++ firEnd = [firstRange endDate];
+ rStart = [_r startDate];
+ rEnd = [_r endDate];
+ interval = [rrule repeatInterval];
+@@ -71,33 +72,37 @@
+ // If rule is bound, check the bounds
+ if (![rrule isInfinite])
+ {
+- lastDate = nil;
++ lastStartDate = nil;
++ lastEndDate = nil;
+ until = [rrule untilDate];
+ repeatCount = [rrule repeatCount];
+
+ if (until)
+ {
+- lastDate = until;
++ lastStartDate = until;
+ }
+ if (repeatCount > 0)
+ {
+- if (lastDate == nil && ![rrule hasByMask])
++ if (lastStartDate == nil && ![rrule hasByMask])
+ // When there's no BYxxx mask, we can find the date of the last
+ // occurrence.
+- lastDate = [firStart dateByAddingYears: (interval * (repeatCount - 1))
++ lastStartDate = [firStart dateByAddingYears: (interval * (repeatCount - 1))
++ months: 0
++ days: 0];
++ lastEndDate = [firEnd dateByAddingYears: (interval * (repeatCount - 1))
+ months: 0
+ days: 0];
+ referenceDate = firStart;
+ }
+
+- if (lastDate != nil)
++ if (lastStartDate != nil)
+ {
+- if ([lastDate compare: rStart] == NSOrderedAscending)
++ if ([lastEndDate compare: rStart] == NSOrderedAscending)
+ // Range starts after last occurrence
+ return nil;
+- if ([lastDate compare: rEnd] == NSOrderedAscending)
++ if ([lastStartDate compare: rEnd] == NSOrderedAscending)
+ // Range ends after last occurence; adjust end date
+- rEnd = [lastDate addTimeInterval: [firstRange duration]];
++ rEnd = [lastStartDate addTimeInterval: [firstRange duration]];
+ }
+ }
+
+commit 3ab86776e2ea826e043e3a0519097538853d82e3
+Author: Hivert Quentin <quentin.hivert.fr at gmail.com>
+Date: Tue Jul 8 15:26:09 2025 +0200
+
+ fix(calendar): fix recurrent event last date
+
+ Fix a bug introduces by #8766b7c
+
+diff --git a/SOPE/NGCards/iCalDailyRecurrenceCalculator.m b/SOPE/NGCards/iCalDailyRecurrenceCalculator.m
+index 7ecc8f09c..c8b5d0e43 100644
+--- a/SOPE/NGCards/iCalDailyRecurrenceCalculator.m
++++ b/SOPE/NGCards/iCalDailyRecurrenceCalculator.m
+@@ -93,11 +93,13 @@
+ if (until)
+ {
+ lastStartDate = until;
++ lastEndDate = until;
+ }
+ else
+ {
+ repeatCount = [rrule repeatCount];
+ if (dayMask == nil)
++ {
+ // If there's no day mask, we can compute the date of the last
+ // occurrence of the recurrent rule.
+ lastStartDate = [firStart dateByAddingYears: 0 months: 0
+@@ -106,6 +108,7 @@
+ lastEndDate = [firEnd dateByAddingYears: 0 months: 0
+ days: (interval
+ * (repeatCount - 1))];
++ }
+ }
+
+ if (lastStartDate != nil && lastEndDate != nil)
+diff --git a/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m b/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m
+index 5879ed252..afbbd2742 100644
+--- a/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m
++++ b/SOPE/NGCards/iCalMonthlyRecurrenceCalculator.m
+@@ -230,10 +230,11 @@ static inline unsigned iCalDoWForNSDoW (int dow)
+ else
+ {
+ untilStart = [rrule untilDate];
++ untilEnd = [rrule untilDate];
+ }
+ }
+
+- if (untilStart != nil)
++ if (untilStart != nil && untilEnd != nil)
+ {
+ if ([untilEnd compare: rStart] == NSOrderedAscending)
+ // Range starts after last occurrence
+diff --git a/SOPE/NGCards/iCalWeeklyRecurrenceCalculator.m b/SOPE/NGCards/iCalWeeklyRecurrenceCalculator.m
+index 5be2a1344..a78ca4d22 100644
+--- a/SOPE/NGCards/iCalWeeklyRecurrenceCalculator.m
++++ b/SOPE/NGCards/iCalWeeklyRecurrenceCalculator.m
+@@ -102,11 +102,15 @@
+ lastEndDate = nil;
+ until = [rrule untilDate];
+ if (until)
++ {
+ lastStartDate = until;
++ lastEndDate = until;
++ }
+ else
+ {
+ repeatCount = [rrule repeatCount];
+ if (dayMask == nil)
++ {
+ // When there's no BYxxx mask, we can find the date of the last
+ // occurrence.
+ lastStartDate = [firStart dateByAddingYears: 0 months: 0
+@@ -115,6 +119,7 @@
+ lastEndDate = [firEnd dateByAddingYears: 0 months: 0
+ days: (interval
+ * (repeatCount - 1) * 7)];
++ }
+ }
+
+ if (lastStartDate != nil && lastEndDate != nil)
+diff --git a/SOPE/NGCards/iCalYearlyRecurrenceCalculator.m b/SOPE/NGCards/iCalYearlyRecurrenceCalculator.m
+index bdf285dc7..8f0733a5e 100644
+--- a/SOPE/NGCards/iCalYearlyRecurrenceCalculator.m
++++ b/SOPE/NGCards/iCalYearlyRecurrenceCalculator.m
+@@ -80,10 +80,12 @@
+ if (until)
+ {
+ lastStartDate = until;
++ lastEndDate = until;
+ }
+ if (repeatCount > 0)
+ {
+ if (lastStartDate == nil && ![rrule hasByMask])
++ {
+ // When there's no BYxxx mask, we can find the date of the last
+ // occurrence.
+ lastStartDate = [firStart dateByAddingYears: (interval * (repeatCount - 1))
+@@ -92,6 +94,7 @@
+ lastEndDate = [firEnd dateByAddingYears: (interval * (repeatCount - 1))
+ months: 0
+ days: 0];
++ }
+ referenceDate = firStart;
+ }
+
diff -Nru sogo-5.12.1/debian/patches/upstream_use_openid_libcurl.patch sogo-5.12.1/debian/patches/upstream_use_openid_libcurl.patch
--- sogo-5.12.1/debian/patches/upstream_use_openid_libcurl.patch 1970-01-01 01:00:00.000000000 +0100
+++ sogo-5.12.1/debian/patches/upstream_use_openid_libcurl.patch 2025-07-25 11:23:25.000000000 +0200
@@ -0,0 +1,538 @@
+commit a782424a30cfe8e9c6f2769a45bcdd3498679237
+Author: Hivert Quentin <quentin.hivert.fr at gmail.com>
+Date: Mon Jun 23 09:24:02 2025 +0200
+
+ feat(openid): swicth to libcurl for http request
+
+ It was using an internal library before and there were too much errors due to incomplete http's protocol implementation
+
+diff --git a/SOPE/GDLContentStore/GCSOpenIdFolder.m b/SOPE/GDLContentStore/GCSOpenIdFolder.m
+index dc6e90b64..a889a768f 100644
+--- a/SOPE/GDLContentStore/GCSOpenIdFolder.m
++++ b/SOPE/GDLContentStore/GCSOpenIdFolder.m
+@@ -303,8 +303,8 @@ static NSString *openIdFolderURLString = nil;
+ newRecord = [NSDictionary dictionaryWithObjectsAndKeys: _user_session, @"c_user_session",
+ _old_session, @"c_old_session",
+ [NSNumber numberWithInt:now], @"c_session_started",
+- _refresh_token, @"c_refresh_token",
+ [NSNumber numberWithInt:nowExpire] , @"c_access_token_expires_in",
++ _refresh_token, @"c_refresh_token",
+ [NSNumber numberWithInt:nowRefreshExpire] , @"c_refresh_token_expires_in",
+ nil];
+ record = [self recordForSession: _user_session useOldSession: NO];
+diff --git a/SoObjects/SOGo/GNUmakefile b/SoObjects/SOGo/GNUmakefile
+index d661d8c2e..3740f1098 100644
+--- a/SoObjects/SOGo/GNUmakefile
++++ b/SoObjects/SOGo/GNUmakefile
+@@ -231,7 +231,7 @@ endif
+ ADDITIONAL_TOOL_LIBS += -Lobj -lSOGo$(LIBRARY_NAME_SUFFIX)
+ ADDITIONAL_INCLUDE_DIRS += -I../../SOPE/
+ ADDITIONAL_LIB_DIRS += -L../../SOPE/GDLContentStore/obj/
+-ADDITIONAL_LDFLAGS += -lmemcached -lzip -lytnef
++ADDITIONAL_LDFLAGS += -lmemcached -lzip -lytnef -lcurl
+
+ -include GNUmakefile.preamble
+ ifneq ($(FHS_INSTALL_ROOT),)
+diff --git a/SoObjects/SOGo/SOGoOpenIdSession.h b/SoObjects/SOGo/SOGoOpenIdSession.h
+index d24d1e93e..fd9d848bc 100644
+--- a/SoObjects/SOGo/SOGoOpenIdSession.h
++++ b/SoObjects/SOGo/SOGoOpenIdSession.h
+@@ -33,6 +33,25 @@
+ @class NSURL;
+ @class NSJSONSerialization;
+
++size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer);
++
++ at interface SimpleOpenIdResponse: NSObject
++{
++ unsigned int status;
++ NSString *content;
++ NSString *headers;
++}
++
++- (id)initWithResponse: (NSString *)_data andHeaders: (NSString *)_headers andStatus:(unsigned int )_status;
++
++- (void)setStatus:(unsigned int)_status;
++- (unsigned int)status;
++- (void)setContent:(NSString *)_data;
++- (NSString *)contentString;
++- (void)setHearders:(NSString *)_data;
++- (NSString *)headers;
++
++ at end
+
+ @interface SOGoOpenIdSession : SOGoObject
+ {
+@@ -47,6 +66,7 @@
+ NSString *openIdClient;
+ NSString *openIdClientSecret;
+ NSString *openIdEmailParam;
++ NSString *openIdHttpVersion;
+ BOOL openIdEnableRefreshToken;
+ BOOL sendDomainInfo;
+
+@@ -80,12 +100,12 @@
+ - (void) initialize;
+ - (void) initializeWithConfig: (NSDictionary *) _config;
+ - (BOOL) sessionIsOK;
+-- (WOResponse *) _performOpenIdRequest: (NSString *) endpoint
++- (SimpleOpenIdResponse *) _performOpenIdRequest: (NSString *) endpoint
+ method: (NSString *) method
+ headers: (NSDictionary *) headers
+ body: (NSData *) body;
+ - (NSMutableDictionary *) fecthConfiguration: (NSString *) _domain;
+-- (void) setAccessToken;
++- (void) setAccessToken: (NSString* ) token;
+ - (NSString *) getRefreshToken;
+ - (NSString *) getToken;
+ - (NSString *) getCurrentToken;
+diff --git a/SoObjects/SOGo/SOGoOpenIdSession.m b/SoObjects/SOGo/SOGoOpenIdSession.m
+index 38710f4a1..98fc5bb81 100644
+--- a/SoObjects/SOGo/SOGoOpenIdSession.m
++++ b/SoObjects/SOGo/SOGoOpenIdSession.m
+@@ -18,8 +18,11 @@
+ * Boston, MA 02111-1307, USA.
+ */
+
++
+ #import <Foundation/NSProcessInfo.h>
+
++#import <curl/curl.h>
++
+ #import <NGObjWeb/WOHTTPConnection.h>
+ #import <NGObjWeb/WORequest.h>
+ #import <NGObjWeb/WOResponse.h>
+@@ -27,12 +30,12 @@
+
+ #import <SOGo/SOGoUser.h>
+
+-
+ #import <GDLContentStore/GCSOpenIdFolder.h>
+ #import <GDLContentStore/GCSFolderManager.h>
+
+ #import "NSDictionary+Utilities.h"
+-#import "NSString+Utilities.h"
++#import <SOGo/NSString+Utilities.h>
++#import <SOGo/NSString+Crypto.h>
+ #import "SOGoCache.h"
+ #import "SOGoSystemDefaults.h"
+
+@@ -40,6 +43,88 @@
+
+ static BOOL SOGoOpenIDDebugEnabled = YES;
+
++
++size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
++{
++ size_t total;
++
++ total = size * nmemb;
++ [(NSMutableData *)buffer appendBytes: ptr length: total];
++
++ return total;
++}
++
++
++ at implementation SimpleOpenIdResponse
++
++- (id)init {
++ if ((self = [super init])) {
++ }
++ return self;
++}
++
++- (id)initWithResponse: (NSString *)_data andHeaders: (NSString *)_headers andStatus:(unsigned int )_status{
++ if ((self = [self init])) {
++ [self setStatus: _status];
++ [self setContent: _data];
++ [self setHeaders: _headers];
++ }
++ return self;
++}
++
++- (void)setStatus:(unsigned int)_status
++{
++ self->status = _status;
++}
++
++- (unsigned int)status
++{
++ if(self->status)
++ return self->status;
++ return 0;
++}
++
++- (void)setContent:(NSString *)_data
++{
++ self->content = _data;
++}
++
++- (NSString *)contentString
++{
++ if(self->content)
++ return self->content;
++ return nil;
++}
++
++- (void)setHeaders:(NSString *)_data
++{
++ self->headers = _data;
++}
++
++- (NSString *)headers
++{
++ if(self->headers)
++ return self->headers;
++ return nil;
++}
++
++- (NSString*)description {
++ NSString *co, *hd;
++ unsigned int st;
++ st = 0;
++ co = @"nil";
++ hd = @"nil";
++ if(self->status)
++ st = self->status;
++ if(self->headers)
++ hd = self->headers;
++ if(self->content)
++ co = self->content;
++ return [NSString stringWithFormat: @"<SimpleOpenIdResponse> <status: %d>, <headers: %@>, <content: %@>", st, hd, co];
++}
++
++ at end
++
+ @implementation SOGoOpenIdSession
+
+ /// Check if all required parameters to set up a OpenIdSession are in sogo.conf
+@@ -72,6 +157,7 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
+ openIdClient = [_config objectForKey: @"SOGoOpenIdClient"];
+ openIdClientSecret = [_config objectForKey: @"SOGoOpenIdClientSecret"];
+ openIdEmailParam = [_config objectForKey: @"SOGoOpenIdEmailParam"];
++ openIdHttpVersion = [_config objectForKey: @"SOGoOpenIdHttpVersion"];
+
+ openIdEnableRefreshToken = NO;
+ refreshTokenBool = [_config objectForKey: @"SOGoOpenIdEnableRefreshToken"];
+@@ -130,6 +216,7 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
+ openIdClient = [sd openIdClient];
+ openIdClientSecret = [sd openIdClientSecret];
+ openIdEmailParam = [sd openIdEmailParam];
++ openIdHttpVersion = [sd openIdHttpVersion];
+ openIdEnableRefreshToken = [sd openIdEnableRefreshToken];
+ userTokenInterval = [sd openIdTokenCheckInterval];
+ sendDomainInfo = [sd openIdSendDomainInfo];
+@@ -149,66 +236,147 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
+ }
+ }
+
+-
+-- (WOResponse *) _performOpenIdRequest: (NSString *) endpoint
++- (SimpleOpenIdResponse *) _performOpenIdRequest: (NSString *) endpoint
+ method: (NSString *) method
+ headers: (NSDictionary *) headers
+ body: (NSData *) body
+ {
+ NSURL *url;
+- NSUInteger status;
+- WORequest *request;
+- WOResponse *response;
+- WOHTTPConnection *httpConnection;
+-
++ NSMutableData *buffer, *buffHeaders;
++ SimpleOpenIdResponse *response;
+
++ CURL *curl;
++ struct curl_slist *headerlist=NULL;
++ NSUInteger status;
++ NSString *content, *headerResp;
++ CURLcode rc;
++ char error[CURL_ERROR_SIZE];
++
+ url = [NSURL URLWithString: endpoint];
+- if (url)
++ if(!url)
+ {
+- if(SOGoOpenIDDebugEnabled)
++ [self errorWithFormat: @"OpenID can't handle endpoint (not a url): '%@'", endpoint];
++ return nil;
++ }
++
++ if(SOGoOpenIDDebugEnabled)
++ {
++ NSLog(@"OpenId perform request: %@ %@", method, endpoint);
++ NSLog(@"OpenId perform request, headers %@", headers);
++ }
++ if(SOGoOpenIDDebugEnabled)
++ NSLog(@"OpenId perform request, body raw %@", body);
++
++ curl_global_init(CURL_GLOBAL_SSL);
++ curl = curl_easy_init();
++
++ if (curl)
++ {
++ error[0] = 0;
++ curl_easy_setopt(curl, CURLOPT_URL, [endpoint UTF8String]);
++
++ //add form
++ if(body)
+ {
+- NSLog(@"OpenId perform request: %@ %@", method, endpoint);
+- NSLog(@"OpenId perform request, headers %@", headers);
+- // if(body)
+- // NSLog(@"OpenId perform request: content %@", [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding]);
++ //Trick because sometimes NSData bytes don't add the \0 at the end and junk character may be added
++ const char *myBodyTmp = (const char*)[body bytes];
++ char myBody[[body length]+1];
++ strncpy(myBody, myBodyTmp, [body length]);
++ myBody[[body length]]='\0';
++
++ if(SOGoOpenIDDebugEnabled)
++ NSLog(@"OpenId perform request, myBodyTmp %s", myBodyTmp);
++
++ if(SOGoOpenIDDebugEnabled)
++ NSLog(@"OpenId perform request, myBody %s", myBody);
++
++ curl_easy_setopt(curl, CURLOPT_POST, 1);
++ curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, myBody);
+ }
+-
+- httpConnection = [[WOHTTPConnection alloc] initWithURL: url];
+- [httpConnection autorelease];
+-
+- request = [[WORequest alloc] initWithMethod: method
+- uri: [endpoint hostlessURL]
+- httpVersion: @"HTTP/1.1"
+- headers: headers content: body
+- userInfo: nil];
+- [request autorelease];
+- [httpConnection sendRequest: request];
+- response = [httpConnection readResponse];
+- status = [response status];
+- if(status >= 200 && status <500 && status != 404)
+- return response;
+- else if (status == 404)
++
++ //add headers
++ if(headers)
++ {
++ NSEnumerator *enumerator = [headers keyEnumerator];
++ NSString *key, *header;
++ while((key = [enumerator nextObject]))
++ {
++ header = [NSString stringWithFormat: @"%@: %@", key, [headers objectForKey: key]];
++ headerlist = curl_slist_append(headerlist, [header UTF8String]);
++ }
++ }
++ if(headerlist != NULL)
++ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
++
++
++ curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60L);
++ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
++ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
++
++ buffer = [NSMutableData data];
++ buffHeaders = [NSMutableData data];
++ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_body_function);
++ curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer);
++ curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_body_function);
++ curl_easy_setopt(curl, CURLOPT_HEADERDATA, buffHeaders);
++ curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error);
++
++ // Perform SOAP request
++ rc = curl_easy_perform(curl);
++ if (rc == CURLE_OK)
+ {
+- [self errorWithFormat: @"OpenID endpoint not found (404): %@", endpoint];
+- return nil;
++ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
++
++ response = [SimpleOpenIdResponse alloc];
++ headerResp = [[NSString alloc] initWithData: buffHeaders
++ encoding: NSUTF8StringEncoding];
++
++ response = [response initWithResponse: nil andHeaders: headerResp andStatus: status];
++
++ if(status >= 200 && status <500 && status != 404)
++ {
++ content = [[NSString alloc] initWithData: buffer
++ encoding: NSUTF8StringEncoding];
++ if (!content)
++ content = [[NSString alloc] initWithData: buffer
++ encoding: NSISOLatin1StringEncoding];
++ [response setContent: content];
++
++ if(SOGoOpenIDDebugEnabled)
++ NSLog(@"OpenId perform request: response is: %@", response);
++
++ return [response autorelease];
++ }
++ else if (status == 404)
++ {
++ [self errorWithFormat: @"OpenID endpoint not found (404): %@", endpoint];
++ return nil;
++ }
++ else
++ {
++ [self errorWithFormat: @"OpenID server internal error during %@: %@", endpoint, response];
++ return nil;
++ }
+ }
+ else
+ {
+- [self errorWithFormat: @"OpenID server internal error during %@: %@", endpoint, response];
+- return nil;
++ [self errorWithFormat: @"CURL error while accessing %@ (%d): %@", endpoint, rc,
++ [NSString stringWithCString: strlen(error) ? error : curl_easy_strerror(rc)]];
+ }
++ curl_easy_cleanup (curl);
+ }
+ else
+ {
+- [self errorWithFormat: @"OpenID can't handle endpoint (not a url): '%@'", endpoint];
+- return nil;
++ [self errorWithFormat: @"OpenID error when setting curl request for: %@", endpoint];
++ return nil;
+ }
+ }
+
+ - (NSMutableDictionary *) fecthConfiguration: (NSString*) _domain
+ {
+ NSString *content;
+- WOResponse * response;
++ SimpleOpenIdResponse *response;
++ // WOResponse * response;
+ NSUInteger status;
+ NSMutableDictionary *result;
+ NSDictionary *config, *headers;
+@@ -498,7 +666,8 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
+ - (NSMutableDictionary *) fetchToken: (NSString * ) code redirect: (NSString *) oldLocation
+ {
+ NSString *location, *form, *content;
+- WOResponse *response;
++ SimpleOpenIdResponse *response;
++ // WOResponse *response;
+ NSUInteger status;
+ NSMutableDictionary *result;
+ NSDictionary *headers;
+@@ -523,7 +692,10 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
+ self->forDomain, @"sogo-user-domain", nil];
+ else
+ headers = [NSDictionary dictionaryWithObject: @"application/x-www-form-urlencoded" forKey: @"content-type"];
+-
++
++ if(SOGoOpenIDDebugEnabled)
++ NSLog(@"OpenId fetch token, form %@", form);
++
+ response = [self _performOpenIdRequest: location
+ method: @"POST"
+ headers: headers
+@@ -566,7 +738,8 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
+ - (NSMutableDictionary *) refreshToken: (NSString * ) userRefreshToken
+ {
+ NSString *location, *form, *content;
+- WOResponse *response;
++ SimpleOpenIdResponse *response;
++ // WOResponse *response;
+ NSUInteger status;
+ NSMutableDictionary *result;
+ NSDictionary *headers;
+@@ -639,7 +812,8 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
+ - (NSMutableDictionary *) fetchUserInfo
+ {
+ NSString *location, *auth, *content;
+- WOResponse *response;
++ SimpleOpenIdResponse *response;
++ // WOResponse *response;
+ NSUInteger status;
+ NSMutableDictionary *result;
+ NSDictionary *profile, *headers;
+@@ -695,7 +869,7 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
+ }
+ else
+ {
+- [self logWithFormat: @"Error during fetching the token (status %d), response: %@", status, response];
++ [self logWithFormat: @"Error fetching userInfo (status %d), response: %@", status, response];
+ [result setObject: @"http-error" forKey: @"error"];
+ }
+ }
+diff --git a/SoObjects/SOGo/SOGoSystemDefaults.h b/SoObjects/SOGo/SOGoSystemDefaults.h
+index 3dce05cf6..fc5729ee3 100644
+--- a/SoObjects/SOGo/SOGoSystemDefaults.h
++++ b/SoObjects/SOGo/SOGoSystemDefaults.h
+@@ -106,6 +106,7 @@ NSComparisonResult languageSort(id el1, id el2, void *context);
+ - (NSString *) openIdClient;
+ - (NSString *) openIdClientSecret;
+ - (NSString *) openIdEmailParam;
++- (NSString *) openIdHttpVersion;
+ - (BOOL) openIdEnableRefreshToken;
+ - (BOOL) openIdLogoutEnabled: (NSString *) _domain;
+ - (int) openIdTokenCheckInterval;
+diff --git a/SoObjects/SOGo/SOGoSystemDefaults.m b/SoObjects/SOGo/SOGoSystemDefaults.m
+index b47fbf6d6..a64ff76c9 100644
+--- a/SoObjects/SOGo/SOGoSystemDefaults.m
++++ b/SoObjects/SOGo/SOGoSystemDefaults.m
+@@ -779,6 +779,15 @@ NSComparisonResult languageSort(id el1, id el2, void *context)
+ return emailParam;
+ }
+
++- (NSString *) openIdHttpVersion
++{
++ NSString *httpVersion;
++ httpVersion = [self stringForKey: @"SOGoOpenIdHttpVersion"];
++ if(!httpVersion)
++ httpVersion = @"HTTP/1.1";
++ return httpVersion;
++}
++
+ - (BOOL) openIdLogoutEnabled: (NSString *) _domain
+ {
+ if(_domain && [self doesLoginTypeByDomain])
+commit 42f620e56201e17391532507c02ae370f117c574
+Author: Hivert Quentin <quentin.hivert.fr at gmail.com>
+Date: Thu Jul 24 14:46:45 2025 +0200
+
+ fix(curl): properly close curl connection
+
+diff --git a/SoObjects/SOGo/SOGoOpenIdSession.m b/SoObjects/SOGo/SOGoOpenIdSession.m
+index fda50d85e..b81b26dea 100644
+--- a/SoObjects/SOGo/SOGoOpenIdSession.m
++++ b/SoObjects/SOGo/SOGoOpenIdSession.m
+@@ -54,7 +54,6 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
+ return total;
+ }
+
+-
+ @implementation SimpleOpenIdResponse
+
+ - (id)init {
+@@ -352,16 +351,19 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
+ if(SOGoOpenIDDebugEnabled)
+ NSLog(@"OpenId perform request: response is: %@", response);
+
++ curl_easy_cleanup(curl);
+ return [response autorelease];
+ }
+ else if (status == 404)
+ {
+ [self errorWithFormat: @"OpenID endpoint not found (404): %@", endpoint];
++ curl_easy_cleanup(curl);
+ return nil;
+ }
+ else
+ {
+ [self errorWithFormat: @"OpenID server internal error during %@: %@", endpoint, response];
++ curl_easy_cleanup(curl);
+ return nil;
+ }
+ }
+@@ -370,7 +372,7 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
+ [self errorWithFormat: @"CURL error while accessing %@ (%d): %@", endpoint, rc,
+ [NSString stringWithCString: strlen(error) ? error : curl_easy_strerror(rc)]];
+ }
+- curl_easy_cleanup (curl);
++ curl_easy_cleanup(curl);
+ }
+ else
+ {
More information about the Pkg-sogo-maintainers
mailing list