Support from Acquia helps fund testing for Drupal Acquia logo

Comments

AdamPS created an issue. See original summary.

AdamPS’s picture

Project: Simplenews » Mime Mail

Update - it looks like the original fix to #2145659 was fine. The code in _mimemail_url has been changed more recently in dev to run preg_replace of itok unconditionally rather than in else of if ($is_image) {

(And sorry, wrong module first time.)

AdamPS’s picture

Also I think we never embed absolute URLs. So should only strip the itok if $is_absolute is FALSE.

AdamPS’s picture

Priority: Normal » Major
Related issues: +#2312747: URLs to linked images broken

OK the problem was caused by #2312747

This has now been released in beta4. For anybody using "Link images only" images may now not be working at all.

AdamPS’s picture

Title: Missing itok with "Link images only" option » Broken images URLs - missing itok
Priority: Major » Normal
Issue summary: View changes

In fact it isn't only sites with "Link images only" that are affected. The images will be linked anyway if they are absolute URLs - which Drupal does by default for an image field (theme_image_style() => image_style_url() => file_create_url() = absolute URL).

However it will only affect sites where the appropriate style hasn't been generated yet. In the majority of sites, the style will be generated because after saving the node, Drupal redirects to the view of the node, and that view uses the same image style as the newsletter. This bug affects sites that use different display modes for the newsletters. Also it could affect any site if the display modes are edited after a newsletter has been sent.

I think that we should never remove the itok from a URL. It should only be removed from a variable such as $file that is testing whether embedding is possible.

AdamPS’s picture

Maybe the best way to solve this is to fix #1309248: Force generation of Image Styles. So generate the required image styles prior to sending the email.

This could be the best for everyone:

  • This eliminates any possibility the images will fail to exist.
  • It means we can remove the itok, helping some sites where they cause a problem. And perhaps the resulting URLs are slightly more user-friendly.
  • It solves a problem for anyone interested in embedding images.

On my sites, I have a workaround to #1309248: Force generation of Image Styles which I have documented in that issue.

mpotter’s picture

I don't think #6 is the right way either. The itok is needed when using images stored in the private file system. I have a site where the image caches are already cached, but without the itok I get a Access Denied, but with the itok they work fine. This is with Open Atrium which stores all images in the private file system and implements access control to ensure a user has access to the image.

So I'm back to #7 where:

I think that we should never remove the itok from a URL.

I'll probably post a patch that un-does the #2312747: URLs to linked images broken patch just so I can run a new build of Atrium that uses the latest release of mimemail since we need the latest security updates.

I'm also tempted to mark it as "major" because this was a regression and effects more people than mentioned in #5 if they are using the private file system.

mpotter’s picture

Status: Active » Needs review
FileSize
901 bytes

Here is the patch to undo #2312747: URLs to linked images broken until/unless a better solution is found.

mpotter’s picture

Hmm, actually this is worse than I thought. As mentioned in #5, this affects images no matter what. So I had to completely remove the preg_replace for itok. So here is the new patch that just eliminates the removal of itok.

AdamPS’s picture

Thanks for the updates.

However I think the patch needs to be more sophisticated than that. As I said in my issue summary, the code was introduced to solve the related issue #2145659: Images with 'itok' token are not embedded. If you simply remove it again, you will undo the fix to that issue.

See #4 for my suggestion of the correct fix:

I think that we should never remove the itok from a URL. It should only be removed from a variable such as $file that is testing whether embedding is possible.

So yes, remove the itok code in _mimemail_url. But then add code in _mimemail_file around line 185 immediately before the call to drupal_realpath. Something like

$url_for_file = preg_replace('/\\?itok=.*$/', '', $url);
        $file = (drupal_realpath($url_for_file)) ? drupal_realpath($url_for_file) : file_create_url($url_for_file);

However it may be a bit more complex than that. I expect there would be changes to the tests required at least - the fix for the related issue seemed to add a test that specifically checked the behaviour of _mimemail_url.

As I explained above, I do have a workaround that I'm using. I don't have time to put together the full patch myself, but I will try to follow the thread at least - I agree with you it is worth doing this way to solve problems for private files etc.

AdamPS’s picture

Status: Needs review » Needs work
FileSize
9.19 KB

OK, here is a patch. I thought hard to get something that suits everybody.

  • Don't ever accidentally encode a query string.
  • Allow image with query string to embed
  • Keep query string on URL to avoid 404 errors.
  • Added some comments so hopefully it's a bit easier to understand the code.

Basically I have separated out the concepts of $local_path and $url.

  • $url is what will end up in the email. It is an absolute path, with the query string retained. Be careful not to end up with the query string being encoded, e.g. by file_create_url.
  • $local_path is used to try out finding a file to embed. Remove query strings, base path and so on and then try to find a matching file.

The patch slightly changes the semantics of _mimemail_url. It now always returns a URL (whereas before it was sometimes a path). The new code seems much clearer. However I did have to change the tests slightly.

Finally, this patch does a bit more than the minimum to fix the bug. Anyone who wants images to embed has likely noticed that Drupal often generates absolute URLs. There is a new option in this module to allow them to embed. And finally there is a hook to serve those who would like exact control over what embeds. It can be important to balance message size, likelihood of spam classification versus the visual impact of having the image appear even when remote images are blocked.

AdamPS’s picture

Status: Needs work » Needs review
Sebastien M.’s picture

#11 works for me, but I haven't tested all your patch.
"itok" parameters are preserved and it's mainly what is required in my case.
Thanks !

jan kellermann’s picture

#11 works fine. But we needed images from private filesystem and extended patch #11.

AdamPS’s picture

@jan kellermann Thanks for testing the patch.

In terms of your updated patch, I'm not saying you are wrong, but please can you explain a bit more why this is needed?

I don't see any code specially for system/files/ in the current checked in code, so I don't understand how such a URL gets handled correctly right now.

Equally I can't see what my patch has changed that stops it working. I removed a call to file_create_url because I couldn't see any way it could help to create a valid file path (after all it is a function for creating URLs!). I think file_create_url would add the base_dir in front of system/files/, often giving /system/files/ which doesn't seem useful.

If system/files/ path needs special handling, then might other paths also need it? It seems odd that we have to make a special case for it.

jan kellermann’s picture

@AdamPS: In _mimemail_file you try to open the file. But in case of private filesystem the filepath ist 'system/files/myfile.txt' and you cannot open this file in local filesystem. I replace 'system/files/' with 'private://' an so drupal can find the correct path for private file:
$file = drupal_realpath($local_path);

+ // Check whether private file
+ $local_path = preg_replace("!^system/files/!", 'private://', $local_path);

Todo: add handling for language prefix

AdamPS’s picture

@jan kellermann Thanks for the reply. I already understand what you say in #16 and I can see what you are doing.

My confusion is that it seems like you are adding new code unrelated to this patch/issue. Once you start doing that it becomes confusing to other people - including me!

Please see my questions from #15. Or perhaps I can explain more clearly:

  • Does system/files/ definitely work without my patch?
  • If so, please can you explain how? We can use this knowledge to fix the problem using the same code that was there before.
  • If not, then what you have is separate issue. It's a perfectly valid issue, and I've got no problem with your code, but it's a new thing, and not the same thing as we are talking about here.

Thanks

AdamPS’s picture

I have fixed a couple of bugs so here is an updated version of the patch.

@jan kellermann As per my previous remarks, you seem to have a separate bug - I tested the current dev module and it appears to lack this feature too. Your comment also indicates a "Todo" for your patch. So I have not included your fix here for the time being. If you create a separate issue with patch, I would be very happy to test, review and mark as RTBC.

I would be very grateful if you would mark this issue as RTBC seeing as you appear to have reviewed and test it. Thanks!

litzastark’s picture

I've just tested the patch in #18; it didn't apply cleanly to the latest release, but it was easy enough to make the changes manually. Everything is working well and it solves the issue we were having with itok parameters getting stripped. Thank you for the patch!

jan kellermann’s picture

Thank you @AdamPS for your feedback. I created a new issue https://www.drupal.org/node/2860557 and added a new patch based on your current patch no. 14.

ptmkenny’s picture

Status: Needs review » Needs work

Changing this to "needs work" because according to #19 it does not apply to the latest release.

AdamPS’s picture

I have recreated the patch to work with the latest code. To maximise the chance of the patch being accepted I have taken out the extra features and stripped the patch back to the minimum to fix the bug.

Please @litzastark, @jan kellermann and anyone else who is using the patch successfully can you set the status to RTBC?

@jan kellermann I see you other issue. If we can get this one committed then I will take a look at that.

Anybody’s picture

Status: Needs review » Reviewed & tested by the community

In fact the patch from #22 solves the issue cleanly. A new dev release should be created ASAP. Thank you all. RTBC!

GuillaumeG’s picture

I confirm that the patch works well and fix broken images URLs in emails. The generation of the itok parameter in the url works as expected with the patch.

Would be great to get it merged in a new release =) .

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 22: mimemail.fix-itok.2552613-22.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

jan kellermann’s picture

I adapted patch #18 to new version 7.x-1.1
I will also upload a new patch for private files in #2860557.

demonde’s picture

The last patch in #26 works for me.

Damien Laguerre’s picture

#26 works for me too.

Anybody’s picture

Status: Needs work » Reviewed & tested by the community

Resetting status to RTBC. Any chance to get this committed finally?

TR’s picture

Status: Reviewed & tested by the community » Needs work

"Patch Failed to Apply"

The patch in #22 failed tests, the patch in #26 does not apply. So not RTBC.

At a minimum, we need a patch that applies and passes the tests.

Anybody’s picture

Hi @TR, sorry my mistake. We were using the patch from #22 in several projects since 2017 successfully but I didn't look close enough into the results and thought it was an unrelated error. Attached is the rerolled patch against latest 7.x-1.x-dev. Hopefully testbot likes it :)

Anybody’s picture

Could someone else now review this?

TR’s picture

OK, well here's the current situation as I see it:

There are a number of other open and closed issues about itok. I added some related issues to collect them all here. All of them are at least somewhat related and touch the same code. I have no desire to fix one, only to have it break the others. I think any patch here should take into account all that information and make sure that any change we make here fixes those other issues as well. And the only way to ensure that is to have test cases which test the _mimemail_file() and _mimemail_url() functions so that we can be convinced that these and future changes are doing the right things.

The problem with tests is, I really don't have a clue as to what *exactly* these methods are supposed to do: _mimemail_file() is documented as "Helper function to extract local files." and _mimemail_url() as "Helper function to format URLs.". Crap documentation leads to crap code, and that's what we currently have. We can't say the current code is wrong or right unless we know what it's *supposed* to do. In particular, functions should never be designed so that their functionality and return types depends on which input parameters you pass - each of these functions should probably be split into two or three different functions which do one and only one thing each.

I made a lot of progress on this code in D8 and D9, and I documented the MimeMailFormatHelper::mimeMailFile() method which is the successor to _mimemail_file(). I didn't refactor the method yet - it is still trying to do way too much and do many different things, but at least its expected behavior is written down so it can be tested (that's the next step, see #3145400: Add test cases for MimeMailFormatHelper::mimeMailFile()). Reading that documentation makes it clear what I said above. For example, it returns a string content id or a complex array indexed by content id or a string containing a URL which is indistinguishable from the string content id unless you parse the string trying to identify it as a URL. How are you supposed to meaningfully use a method like this? And why is it called mimeMailFile if it's used for images? There are many issues related to this method that can't be fixed until there are tests to show it's doing those things correctly (or not).

Another big problem is that D7 is nearing its end of life, while D8 and D9 are in active development. As a matter of both principle and practice, it is wrong to fix this first in D7. It really should be fixed in D8/D9 first, then any changes should be backported to D7 if there is community interest. Fixing D7 first is almost certainly going to mean that it will never get fixed in D8/D9. I already have way too much work to do to try to figure out all the other D7 fixes that didn't make it into D8/D9 - I don't need yet another one. When the standard Drupal practices of fixing HEAD first and requiring a test case for each feature/bug fix aren't followed, projects become impossible to properly maintain. That is what happened here. The itok changes that were previously made didn't have tests, for example, so we have no way of demonstrating that those changes were needed, that those changes worked properly, and that the current patch doesn't break what the previous change supposedly fixed.

Likewise, this patch makes an API change, which is generally not allowed or desired between minor versions. API changes should be limited to major releases, by definition. If we are going to change the API and/or refactor these functions to make more sense, it should be done in a new major branch. This is why my D8/D9 work has been limited to documenting and writing tests for the code rather than refactoring - I want to get a stable release made before branching a new major version and switching to semantic versioning.

At this point my feeling is that this and the other itok issues need to be moved to 8.x-1.x, and that the fix should be done in 8.x-1.x first, accompanied by proper testing of the functions involved. This includes a test that demonstrates the problem in the current code so that we can evaluate whether a proposed patch fixes that problem, but also we need complete tests to make sure these functions are doing what they're supposed to.