-
Notifications
You must be signed in to change notification settings - Fork 351
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
limit length of single fields in notification #332
Conversation
I'm not sure a user visible setting is the best approach here. I doubt that truncating based on the number of characters in a notification has any real use case other than preventing the DoS that happens in #248. I think a macro set to a high enough value that it's unlikely for anyone to bump into(Say 5000?) is the best and we can adjust that as needed. |
I thought long about this. But yes, it's better to have this inside a macro and not expose it to the user. IMHO a good notification is always less than 100 chars. If it's a long text, nevertheless you click on the notification to open the messenger and read it there. The introduced option would have made the truncation possible, which also prevents DoSing dunst. But it just creates too much noise in |
src/utils.c
Outdated
if (maxlen < 0 || strlen(string) < maxlen) { | ||
buffer = string; | ||
} else { | ||
size_t buffer_maxlen = maxlen; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why create a new variable instead of making the type of maxlen
be size_t
in the function definition? And with this change, there should be no need to check if maxlen < 0
since size_t
is unsigned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Full ACK.
src/utils.c
Outdated
buffer = string; | ||
} else { | ||
size_t buffer_maxlen = maxlen; | ||
buffer = calloc(buffer_maxlen, sizeof(char)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're using glib so instead of calloc
g_malloc0
should be used but since we already know we are going to fill the entire buffer there is no reason to zero it out so g_malloc
would probably be the correct function to use here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for pointing this out. My C-Skills are quite limited and I have not known the differences of all available allocation-functions yet.
src/utils.c
Outdated
} else { | ||
size_t buffer_maxlen = maxlen; | ||
buffer = calloc(buffer_maxlen, sizeof(char)); | ||
strncpy(buffer, string, buffer_maxlen); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quoting from strcpy(3)
If there is no terminating null byte in the first n bytes of src, strncpy() produces an unterminated string in dest.
In other words at this point buffer
is unterminated. The last character should be replaced with a null byte.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. Thanks.
src/utils.h
Outdated
@@ -9,6 +9,9 @@ char *string_replace_char(char needle, char replacement, char *haystack); | |||
char *string_replace_all(const char *needle, const char *replacement, | |||
char *haystack); | |||
|
|||
/* Cut the given string at buffer_maxlen */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parameter is named maxlen
not buffer_maxlen
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks.
Thanks for the feedback, @tsipinakis. I processed all requested changes. |
src/notification.h
Outdated
@@ -12,6 +12,8 @@ | |||
#define NORM 1 | |||
#define CRIT 2 | |||
|
|||
#define MAX_CHARS 5000 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tsipinakis Is there any naming convention for macros? IMHO MAX_CHARS
is too generic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really, but I do agree that it's too generic maybe NOTIFICATION_MAX_LENGTH
?
src/notification.c
Outdated
@@ -305,11 +305,11 @@ int notification_init(notification * n, int id) | |||
n->urls = notification_extract_markup_urls(&(n->body)); | |||
|
|||
n->msg = string_replace_all("\\n", "\n", g_strdup(n->format)); | |||
n->msg = notification_replace_format("%a", n->appname, n->msg, | |||
n->msg = notification_replace_format("%a", string_cut_maxlen(n->appname, MAX_CHARS), n->msg, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, I missed this earlier but this creates a memory leak since the memory you allocate in string_cut_maxlen
is never freed. Additionally I'm not sure if having a limit per-field is the correct option. In my opinion I'd change this to a single string_cut_maxlen
call at the end of the format replacements.
Also, it should probably be placed after the icon processing, since we have flags to add the icon path to the format and a huge icon path would cause the same problem.
src/utils.h
Outdated
@@ -2,13 +2,18 @@ | |||
#ifndef DUNST_UTILS_H | |||
#define DUNST_UTILS_H | |||
|
|||
#include <stdlib.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
size_t
is defined in stddef.h
. While stddlib
includes stddef
it's usually best practice to use the more specific header file.
src/utils.h
Outdated
/* replace all occurences of the character needle with the character replacement in haystack */ | ||
char *string_replace_char(char needle, char replacement, char *haystack); | ||
|
||
/* replace all occurrences of needle with replacement in haystack */ | ||
char *string_replace_all(const char *needle, const char *replacement, | ||
char *haystack); | ||
|
||
/* Cut the given string at maxlen */ | ||
char* string_cut_maxlen(char* string, size_t maxlen); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small nitpick, but I think string_truncate
would be a better name for this function.
4805aad
to
52d2885
Compare
Displaying too heavy notifications can DoS dunst. For example bad programs, which pipe raw image data into the notification. Limiting the maximum character length to 5000 circumvents this. 5000 should be ridiculously high to prevent DoS while still not truncating all correct notifications.
@tsipinakis Thank you for your feedback. I dropped the stuff in Do we care about broken HTML if the output got truncated? |
That's much better indeed, good call.
I don't think we should, any notification that reaches that limit will probably clip the monitor edges anyway. This is just a stopgap to stop dunst from freezing in case something messes up and sends much more data than it should. Thanks! |
Well, then will be there a 1.2 and close #263 ? |
This would be my 2 cents to fix #248 and remove the last blocker to have a new release.
This PR adds the option
max_fieldlength
to have a maximum of specific chars per field. So overlong messages will get truncated to the specified length.Also if it's not wanted to have a limit, a minus-value can be chosen to skip the cutting.
I'm not sure yet, what a reasonable default would be. I've used
100
, but I'd like to have other's opinions here. Alternatively-1
(=> no limit) would also be a good default.