mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-06-06 19:09:43 +00:00
Added message submissions rate-limiting support
This commit is contained in:
Binary file not shown.
@@ -5,7 +5,10 @@ Enhancements
|
||||
- updated CKEditor to version 4.1.1 (#2333)
|
||||
- new failed login attemps rate-limiting options. See the new
|
||||
SOGoMaximumFailedLoginCount, SOGoMaximumFailedLoginInterval and
|
||||
SOGoFailedLoginBlockInterval defaults
|
||||
SOGoFailedLoginBlockInterval defaults
|
||||
- new message submissions rate-limiting options. See the new
|
||||
SOGoMaximumMessageSubmissionCount, SOGoMaximumRecipientCount,
|
||||
SOGoMaximumSubmissionInterval and SOGoMessageSubmissionBlockInterval defaults
|
||||
|
||||
Bug fixes
|
||||
- Fixed decoding of the charset parameter when using single quotes (#2306)
|
||||
|
||||
@@ -103,6 +103,12 @@
|
||||
|
||||
- (NSDictionary *) failedCountForLogin: (NSString *) login;
|
||||
|
||||
- (void) setMessageSubmissionsCount: (int) theCount
|
||||
recipientsCount: (int) theRecipientsCount
|
||||
forLogin: (NSString *) theLogin;
|
||||
|
||||
- (NSDictionary *) messageSubmissionsCountForLogin: (NSString *) theLogin;
|
||||
|
||||
//
|
||||
// CAS support
|
||||
//
|
||||
|
||||
+71
-14
@@ -24,23 +24,24 @@
|
||||
/*
|
||||
* [ Cache Structure ]
|
||||
*
|
||||
* users value = instances of SOGoUser > flushed after the completion of every SOGo requests
|
||||
* groups value = instances of SOGoGroup > flushed after the completion of every SOGo requests
|
||||
* imap4Connections value =
|
||||
* localCache value = any value of what's in memcached - this is used to NOT query memcached within the same sogod instance
|
||||
* users value = instances of SOGoUser > flushed after the completion of every SOGo requests
|
||||
* groups value = instances of SOGoGroup > flushed after the completion of every SOGo requests
|
||||
* imap4Connections value =
|
||||
* localCache value = any value of what's in memcached - this is used to NOT query memcached within the same sogod instance
|
||||
*
|
||||
* [ Distributed (using memcached) cache structure ]
|
||||
*
|
||||
* <uid>+defaults value = NSDictionary instance > user's defaults
|
||||
* <uid>+settings value = NSDictionary instance > user's settings
|
||||
* <uid>+attributes value = NSMutableDictionary instance > user's LDAP attributes
|
||||
* <object path>+acl value = NSDictionary instance > ACLs on an object at specified path
|
||||
* <groupname>+<domain> value = NSString instance (array components separated by ",") or group member logins for a specific group in domain
|
||||
* cas-id:< > value =
|
||||
* cas-ticket:< > value =
|
||||
* cas-pgtiou:< > value =
|
||||
* session:< > value =
|
||||
* <uid>+failedlogins value = NSDictionary instance holding the failed count and the date of the first failed authentication
|
||||
* <uid>+defaults value = NSDictionary instance > user's defaults
|
||||
* <uid>+settings value = NSDictionary instance > user's settings
|
||||
* <uid>+attributes value = NSMutableDictionary instance > user's LDAP attributes
|
||||
* <object path>+acl value = NSDictionary instance > ACLs on an object at specified path
|
||||
* <groupname>+<domain> value = NSString instance (array components separated by ",") or group member logins for a specific group in domain
|
||||
* cas-id:< > value =
|
||||
* cas-ticket:< > value =
|
||||
* cas-pgtiou:< > value =
|
||||
* session:< > value =
|
||||
* <uid>+failedlogins value = NSDictionary instance holding the failed count and the date of the first failed authentication
|
||||
* <uid>+messagesubmissions value = NSDictionary instance holding the number of messages sent, and number of recipients
|
||||
*/
|
||||
|
||||
|
||||
@@ -545,6 +546,62 @@ static memcached_st *handle = NULL;
|
||||
return d;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (void) setMessageSubmissionsCount: (int) theCount
|
||||
recipientsCount: (int) theRecipientsCount
|
||||
forLogin: (NSString *) theLogin
|
||||
{
|
||||
NSNumber *messages_count, *recipients_count;
|
||||
NSMutableDictionary *d;
|
||||
|
||||
if (theCount)
|
||||
{
|
||||
messages_count = [NSNumber numberWithInt: theCount];
|
||||
recipients_count = [NSNumber numberWithInt: theRecipientsCount];
|
||||
|
||||
d = [NSMutableDictionary dictionaryWithDictionary: [self messageSubmissionsCountForLogin: theLogin]];
|
||||
|
||||
if (![d objectForKey: @"InitialDate"])
|
||||
{
|
||||
[d setObject: [NSNumber numberWithUnsignedInt: [[NSCalendarDate date] timeIntervalSince1970]] forKey: @"InitialDate"];
|
||||
}
|
||||
|
||||
[d setObject: messages_count forKey: @"MessagesCount"];
|
||||
[d setObject: recipients_count forKey: @"RecipientsCount"];
|
||||
|
||||
[self _cacheValues: [d jsonRepresentation]
|
||||
ofType: @"messagesubmissions"
|
||||
forKey: theLogin];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self removeValueForKey: [NSString stringWithFormat: @"%@+messagesubmissions", theLogin]];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// MessagesCount ->
|
||||
// RecipientsCount ->
|
||||
// InitialDate ->
|
||||
//
|
||||
- (NSDictionary *) messageSubmissionsCountForLogin: (NSString *) theLogin
|
||||
{
|
||||
NSDictionary *d;
|
||||
NSString *s;
|
||||
|
||||
s = [self _valuesOfType: @"messagesubmissions" forKey: theLogin];
|
||||
d = nil;
|
||||
|
||||
if (s)
|
||||
{
|
||||
d = [s objectFromJSONString];
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// CAS session support
|
||||
|
||||
@@ -88,7 +88,12 @@
|
||||
|
||||
- (int) maximumFailedLoginCount;
|
||||
- (int) maximumFailedLoginInterval;
|
||||
- (int) failedLoginBlockInternval;
|
||||
- (int) failedLoginBlockInterval;
|
||||
|
||||
- (int) maximumMessageSubmissionCount;
|
||||
- (int) maximumRecipientCount;
|
||||
- (int) maximumSubmissionInterval;
|
||||
- (int) messageSubmissionBlockInterval;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -513,6 +513,9 @@ _injectConfigurationFromFile (NSMutableDictionary *defaultsDict,
|
||||
return [self boolForKey: @"SOGoEnablePublicAccess"];
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (int) maximumFailedLoginCount
|
||||
{
|
||||
return [self integerForKey: @"SOGoMaximumFailedLoginCount"];
|
||||
@@ -542,4 +545,41 @@ _injectConfigurationFromFile (NSMutableDictionary *defaultsDict,
|
||||
return v;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (int) maximumMessageSubmissionCount
|
||||
{
|
||||
return [self integerForKey: @"SOGoMaximumMessageSubmissionCount"];
|
||||
}
|
||||
|
||||
- (int) maximumRecipientCount
|
||||
{
|
||||
return [self integerForKey: @"SOGoMaximumRecipientCount"];
|
||||
}
|
||||
|
||||
- (int) maximumSubmissionInterval
|
||||
{
|
||||
int v;
|
||||
|
||||
v = [self integerForKey: @"SOGoMaximumSubmissionInterval"];
|
||||
|
||||
if (!v)
|
||||
v = 30;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
- (int) messageSubmissionBlockInterval
|
||||
{
|
||||
int v;
|
||||
|
||||
v = [self integerForKey: @"SOGoMessageSubmissionBlockInterval"];
|
||||
|
||||
if (!v)
|
||||
v = 300;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -46,6 +46,8 @@
|
||||
#import <NGMime/NGMimeMultipartBody.h>
|
||||
#import <NGMime/NGMimeType.h>
|
||||
|
||||
#import <SOGo/SOGoCache.h>
|
||||
#import <SOGo/SOGoSystemDefaults.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserFolder.h>
|
||||
@@ -659,12 +661,57 @@ static NSArray *infoKeys = nil;
|
||||
return error;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (WOResponse *) sendAction
|
||||
{
|
||||
SOGoDraftObject *co;
|
||||
NSDictionary *jsonResponse;
|
||||
NSException *error;
|
||||
NSMutableArray *errorMsg;
|
||||
NSDictionary *messageSubmissions;
|
||||
SOGoSystemDefaults *dd;
|
||||
|
||||
int messages_count, recipients_count;
|
||||
|
||||
messageSubmissions = [[SOGoCache sharedCache] messageSubmissionsCountForLogin: [[context activeUser] login]];
|
||||
dd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
messages_count = recipients_count = 0;
|
||||
|
||||
if (messageSubmissions)
|
||||
{
|
||||
unsigned int current_time, start_time, delta, block_time;
|
||||
|
||||
current_time = [[NSCalendarDate date] timeIntervalSince1970];
|
||||
start_time = [[messageSubmissions objectForKey: @"InitialDate"] unsignedIntValue];
|
||||
delta = current_time - start_time;
|
||||
|
||||
block_time = [dd messageSubmissionBlockInterval];
|
||||
messages_count = [[messageSubmissions objectForKey: @"MessagesCount"] intValue];
|
||||
recipients_count = [[messageSubmissions objectForKey: @"RecipientsCount"] intValue];
|
||||
|
||||
if ((messages_count >= [dd maximumMessageSubmissionCount] || recipients_count >= [dd maximumRecipientCount]) &&
|
||||
delta >= [dd maximumSubmissionInterval] &&
|
||||
delta <= block_time )
|
||||
{
|
||||
jsonResponse = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"failure", @"status",
|
||||
[self labelForKey: @"Tried to send too many mails. Please wait."],
|
||||
@"message",
|
||||
nil];
|
||||
return [self responseWithStatus: 200
|
||||
andString: [jsonResponse jsonRepresentation]];
|
||||
}
|
||||
|
||||
if (delta > block_time)
|
||||
{
|
||||
[[SOGoCache sharedCache] setMessageSubmissionsCount: 0
|
||||
recipientsCount: 0
|
||||
forLogin: [[context activeUser] login]];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
co = [self clientObject];
|
||||
|
||||
@@ -691,11 +738,23 @@ static NSArray *infoKeys = nil;
|
||||
nil];
|
||||
}
|
||||
else
|
||||
jsonResponse = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"success", @"status",
|
||||
[co sourceFolder], @"sourceFolder",
|
||||
[NSNumber numberWithInt: [co IMAP4ID]], @"messageID",
|
||||
nil];
|
||||
{
|
||||
jsonResponse = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"success", @"status",
|
||||
[co sourceFolder], @"sourceFolder",
|
||||
[NSNumber numberWithInt: [co IMAP4ID]], @"messageID",
|
||||
nil];
|
||||
|
||||
recipients_count += [[co allRecipients] count];
|
||||
messages_count += 1;
|
||||
|
||||
if ([dd maximumMessageSubmissionCount] > 0 && [dd maximumRecipientCount] > 0)
|
||||
{
|
||||
[[SOGoCache sharedCache] setMessageSubmissionsCount: messages_count
|
||||
recipientsCount: recipients_count
|
||||
forLogin: [[context activeUser] login]];
|
||||
}
|
||||
}
|
||||
|
||||
return [self responseWithStatus: 200
|
||||
andString: [jsonResponse jsonRepresentation]];
|
||||
|
||||
Reference in New Issue
Block a user