Jump to content
Roope

Email Obfuscation (EMO)

Recommended Posts

ProcessWire Email Obfuscation (EMO)

Download | GitHub
 

Email Obfuscation module for email addresses with 64 base crypting.

This module finds all plaintext emails and email links from the document and replaces them with span elements including configurable replace text. All the addresses are encoded to 64 base strings and stored in spans data attributes. Then on client side we decode these strings back to their original state.

Install

  1. Create new 'EmailObfuscation' folder into /site/modules/ and place the content of this repository into the directory.
  2. Login to processwire and go to Modules page and click 'Check for new modules'. Find 'EmailObfuscation' and click install.
  3. You can make optional configuration changes in the module admin page.

Thanks

This is a ProcessWire module fork from MODX Evolution plugin emo E-Mail Obfuscation.
http://modx.com/extras/package/emoemailobfuscation
 

EDITED ON:
2013-03-03 - Added description.
2020-04-16 - Fixed GitHub links and updated description.


Hello all. Just found PW few days ago and it's already looking awesome! Here comes first contribute and some questions for developing it further.

There was one existing email obfuscator on reposity that didn't use any crypting for addresses so I decided to do a little test run and port the one that we currenly use with MODX Evo to ProcessWire module.

I'd like to make PageAutocomplete like gonfigure option to admin so that one could select and set templates to exclude module action. It looks like autocomplete is tied to pages and since templates are not set to system as pages this is option is no go, am I right?

  • Like 9

Share this post


Link to post
Share on other sites

Welcome!

I think ASMSelect would be a good fit instead of autocomplete in module config - I know that works.

Share this post


Link to post
Share on other sites

OK, ASMSelect did the job perfectly. Thanks!

Another question:

In Hello world example module admin pages are restricted by: if($page->template == 'admin') return;

$template array also holds another admin pages like role and user so is there some easy way skip these in loop without naming all of them?

foreach ($this->templates as $t) {
    if ($t != 'admin') { // !in_array($t, array(admin,role,user)); is this proposed way?
        $f->addOption($t->id, $t->name);
    }
}

I just need same template names that are visible on Setup > Templates.

Share this post


Link to post
Share on other sites

What I've been doing in another module is removing all templates flagged as system. That's probably what you want to do here too.

foreach ($this->templates as $t) {
    // skip system templates
    if (!($t->flags & Template::flagSystem)) {
       $f->addOption($t->id, $t->name);
    }
} 
  • Like 2

Share this post


Link to post
Share on other sites

Is there a reason why $field->collapsed = Inputfield::collapsedBlank; works as expected with InputfieldAsmSelect but does nothing with InputfieldCheckbox in module config?

Share this post


Link to post
Share on other sites
Is there a reason why $field->collapsed = Inputfield::collapsedBlank; works as expected with InputfieldAsmSelect but does nothing with InputfieldCheckbox in module config?

I think we had a bug related to this awhile back. It should be fixed in 2.3. But for now this might work:

$field->collapsed = $field->attr('checked') ? Inputfield::collapsedYes : Inputfield::collapsedNo; 

Thanks for your work with this module. When you get a chance, please add to the modules.processwire.com directory. 

Share this post


Link to post
Share on other sites

Thanks Ryan! This got work done perfectly.

There's still one thing I can't get figured out. With InputfieldPageAutocomplete in module config I can set parent_id and template_id to limit results. How could I configure it so that all admin pages plus the ones limited in $this->exclude_tpls config would be left out from results?

I get what I want by using InputfieldAsmSelect but I think InputfieldPageAutocomplete would fit much better here:

$f = $this->modules->get('InputfieldAsmSelect');
$f->label = 'Exclude in pages';
$f->attr('name', 'exclude_pages');
$f->attr('value', $this->exclude_pages);
$home = $this->pages->get("/");
$pages = $home->children;
$pages->prepend($home);
foreach ($pages as $p) {
    if (!in_array($p->template->id, $this->exclude_tpls)) {
        $f->addOption($p->id, $p->name);
    }
}
$inputfields->add($f);

Share this post


Link to post
Share on other sites

The parent_id and template_id are one way to go, but you could instead use 'findPagesSelector'. You can set this to a Field object, or you can set it to an InputfieldPageAutocomplete instance, like this:

$f = $this->modules->get('InputfieldPageAutocomplete');
$f->label = 'Exclude in pages';
$f->attr('name', 'exclude_pages');
$f->attr('value', $this->exclude_pages);
 
$selector = "parent_id=1, template!=admin";
foreach($this->exclude_tpls as $name) {
  $selector .= "|$name";
}
// example: parent_id=1, template!=admin|this|that|whatever
$f->findPagesSelector = $selector; 

  • Like 1

Share this post


Link to post
Share on other sites
Almost one year later I'm happy to say that I finally got this autocomplete feature implemented to exclude pages option. Also forced mailto links can now be disabled from module config. Version got bumped to 1.0.2.

This also means that our love and relationship with PW is soon having it's first birthday. What a year! Still having butterflies in stomach.

  • Like 8

Share this post


Link to post
Share on other sites

I think we had a bug related to this awhile back. It should be fixed in 2.3. But for now this might work:

$field->collapsed = $field->attr('checked') ? Inputfield::collapsedYes : Inputfield::collapsedNo; 

Thanks for your work with this module. When you get a chance, please add to the modules.processwire.com directory. 

Hey Ryan,

I just came across this issue on the latest dev version - presumably with stable as well. I ended up going with your fix for now, although for anyone stumbling across this, the Yes and No need to be reversed in the ternary operator.

Share this post


Link to post
Share on other sites

Just installed this module.

It seems to be adding the classes to the email and adding mailto, but in the source, the actual email address is as clear as day... :)

Share this post


Link to post
Share on other sites

It seems to be adding the classes to the email and adding mailto, but in the source, the actual email address is as clear as day... :)

Hi Joss!

If classes are added and it turns email strings to mailto links then it sounds like it's working like it should be. My first guess is that you are looking at generated source code, e.g. using inspect element tool from the browser? Decryption is done on client side so in this case, all is fine.

Document source code from server should have predefined text string wrapped to span elements (with emo class and unique id) in place of email addresses.

Share this post


Link to post
Share on other sites

@Roope -

great module! Used on a recent site; And now trying to use it on a new site, but having 2 issues:

1.) There was a point where there was accidentally an email address in the meta description of the site, and that triggered the emo, which broke the page; any way to disable it in the head section?

2.) the emo is triggering on a retina image (@2x in the image name...)

Thanks!

Share this post


Link to post
Share on other sites

Thanks Macrura!

I just pushed fix for these, so if you can please see how it does. Thanks!

Share this post


Link to post
Share on other sites

@Roope - ok awesome - many thanks ! I will be back on the project soon and will report back..

Share this post


Link to post
Share on other sites

@roope - i downloaded the latest version, and replaced it, but it still picks up the retina images, which are marked up like this:

<a href="/" class="retina-logo" data-dark-logo="/site/templates/images/lk-logo-dark@2x.png">

i guess there is no way to prevent this sort of thing, because i see in the code that the module will exclude head, images and forms.., but this is a link with a data attribute...

but maybe there could be an option to allow the module to only work on parts of the page in a setting, for example, "container classes to apply the obfuscation to", then it would be possible for designers to limit to only specific places in the page, which would reduce the chance of it picking up images with the @ symbol..

thanks..!

Share this post


Link to post
Share on other sites

OK, this one is bit tricky..

 
Currently emo uses regex to leave head, form and img tags untouched. Link element can't be left untouched since we're parsing emails.
 
Parsing unregular language like html with regular expressions is always on risky side. For that reason adding support for emo container class like you suggested would need proper DOM parser and IMO that introduces too much heavy lifting for the small need.
 
So, at least for now, you have the following options:
 
1. Use @2x names on a img tag
2. Disable current page from module settings
3. Disable current template from module settings
 
From these I would personally just go with number one:
 
<a href="/" class="retina-logo">
   <img src="../lk-logo-dark.png" data-dark-logo="../lk-logo-dark@2x.png" />
</a>

  • Like 1

Share this post


Link to post
Share on other sites

@Roope - thanks - really appreciate the reply!

Will take a look at the options and come up with a workaround for this site...

thanks again for making this module..

Share this post


Link to post
Share on other sites

This worked great on my local server but when I installed it on the real server pages with email addresses fail. I get ERR_EMPTY_RESPONSE. I wasn't able to find any more clues but if I ever do I'll let you know. Both setups are running 2.5.10 dev.

Share this post


Link to post
Share on other sites

This module works great, but does it have to completely overwrite the classes of the containing element? Can it not just append emo_email to any existing classes?

Share this post


Link to post
Share on other sites

While testing your module I found out that it doesn't work properly in some cases:

//no need to obfuscate, since there is no E-Mail Adress
<a href="mailto:?subject=Lorem%20Ipsum&body=Lorem%20Ipsum!">Foo</a>
<a href="mailto:?subject=Lorem Ipsum!">Foo</a>

//doesn't work with the following examples
<a href="mailto:mail@example.org?subject=Lorem Ipsum!">Foo</a>
<a href="mailto:mail@example.org?subject=Lorem%20Ipsum&body=Lorem%20Ipsum!">Foo</a>

For the 1st Example the module should leave the code untouched. Replacement only necessary if '@' is found.

For 2nd Example I can offer a solution

REPLACE

// urlencode a possible subject
$matches[1] = preg_replace_callback("!(.*\?(subject|body)=)([^\?]*)!i",
function ($m) { return rawurlencode($m[3]); }, $matches[1]);

// the function removes the questionmark, the words 'subject' and 'body' and the equalsign from the querystring 

WITH

// urlencode a possible subject and body, no matter if already urlencoded
$_matches = preg_replace_callback("!(^\?*)?((\??subject|\??body)=([^&]+)){1,2}!i",
function ($m) { return $m[1].$m[3].'='.rawurlencode(rawurldecode($m[4])); }, $matches[1]);

I tested a little bit and it worked well with my solution.
 

  • Like 3

Share this post


Link to post
Share on other sites
Thanks for your input kixe!

Sorry I'm little late to the party but I finally got some time to look this through on summer vacation. There was also some other issues with the module that I wanted to fix while I'm there so here it goes:

I updated the mailto link regex to match only cases where actual email address is also present so your 1st example doesn't get obfuscated no more.

While your fix for the second example worked really well, I decided to leave whole url encoding part off since it didn't seem to be vital for this module to work.

I also changed the way emo avoids @2x named images to be triggered as false positives so now markup like what @Macrura had in the example here works. Before it was only possible with image tags which were skipped from obfuscation. Old method also failed when there was image inside mailto link.


And last but not least; matched mailto link markup doesn't get replaced anymore by new element. We'll use the original captured html and just add required emo_email class to the link - like what @joey102030 just suggested here one post earlier.

I've pushed a new commit to Github that contains all these modifications. Please test it out and report any issues you may find. Thanks!



Share this post


Link to post
Share on other sites

I've doubled up on javascripts and apparently it's causing an issue.  I recently started working on an interactive map on my site, the problem is that since I'm rendering the HTML on an event (click of the state loads .html(<div>...john@email.com...) ), it's loading the replacement text instead of my email addresses.  Are there any steps I can take to make it work properly without blocking the template altogether?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By joshua
      This module is (yet another) way for implementing a cookie management solution.
      Of course there are several other possibilities:
      - https://processwire.com/talk/topic/22920-klaro-cookie-consent-manager/
      - https://github.com/webmanufaktur/CookieManagementBanner
      - https://github.com/johannesdachsel/cookiemonster
      - https://www.oiljs.org/
      - ... and so on ...
      In this module you can configure which kind of cookie categories you want to manage:

      You can also enable the support for respecting the Do-Not-Track (DNT) header to don't annoy users, who already decided for all their browsing experience.
      Currently there are four possible cookie groups:
      - Necessary (always enabled)
      - Statistics
      - Marketing
      - External Media
      All groups can be renamed, so feel free to use other cookie group names. I just haven't found a way to implement a "repeater like" field as configurable module field ...
      When you want to load specific scripts ( like Google Analytics, Google Maps, ...) only after the user's content to this specific category of cookies, just use the following script syntax:
      <script type="text/plain" data-type="text/javascript" data-category="statistics" data-src="/path/to/your/statistic/script.js"></script> <script type="text/plain" data-type="text/javascript" data-category="marketing" data-src="/path/to/your/mareketing/script.js"></script> <script type="text/plain" data-type="text/javascript" data-category="external_media" data-src="/path/to/your/external-media/script.js"></script> <script type="text/plain" data-type="text/javascript" data-category="marketing">console.log("Inline scripts are also working!");</script> The type has to be "optin" to get recognized by PrivacyWire, the data-attributes are giving hints, how the script shall be loaded, if the data-category is within the cookie consents of the user. These scripts are loaded asynchronously after the user made the decision.
      If you want to give the users the possibility to change their consent, you can use the following Textformatter:
      [[privacywire-choose-cookies]] It's planned to add also other Textformatters to opt-out of specific cookie groups or delete the whole consent cookie.
      You can also add a custom link to output the banner again with a link / button with following class:
      <a href="#" class="privacywire-show-options">Show Cookie Options</a> <button class="privacywire-show-options">Show Cookie Options</button> This module is still in development, but we already use it on several production websites.
      You find it here: PrivacyWire Git Repo
      Download as .zip
      I would love to hear your feedback 🙂
      CHANGELOG
      0.1.1 Debugging: fixed error during uninstall 0.1.0 Added new detection of async scripts for W3C Validation 0.0.6 CSS-Debugging for hiding unused buttons, added ProCache support for the JavaScript tag 0.0.5 Multi-language support included completely (also in TextFormatter). Added possibility to async load other assets (e.g. <img type="optin" data-category="marketing" data-src="https://via.placeholder.com/300x300">) 0.0.4 Added possibility to add an imprint link to the banner 0.0.3 Multi-language support for module config (still in development) 0.0.2 First release 0.0.1 Early development
    • By bernhard
      --- Please use RockFinder3 ---
    • By MoritzLost
      Cacheable Placeholders
      This module allows you to have pieces of dynamic content inside cached output. This aims to solve the common problem of having a mostly cacheable site, but with pieces of dynamic output here and there.  Consider this simple example, where you want to output a custom greeting to the current user:
      <h1>Good morning, <?= ucfirst($user->name) ?></h1> This snippet means you can't use the template cache (at least for logged-in users), because each user has a different name. Even if 99% of your output is static, you can only cache the pieces that you know won't include this personal greeting. A more common example would be CSRF tokens for HTML forms - those need to be unique by definition, so you can't cache the form wholesale.
      This module solves this problem by introducing cacheable placeholders - small placeholder tokens that get replaced during every request. The replacement is done inside a Page::render hook so it runs during every request, even if the response is served from the template cache. So you can use something like this:
      <h1>Good morning, {{{greeting}}}</h1> Replacement tokens are defined with a callback function that produces the appropriate output and added to the module through a simple hook:
      // site/ready.php wire()->addHookAfter('CachePlaceholders::getTokens', function (HookEvent $e) { $tokens = $e->return; $tokens['greeting'] = [ 'callback' => function (array $tokenData) { return ucfirst(wire('user')->name); } ]; $e->return = $tokens; }); Tokens can also include parameters that are parsed and passed to the callback function. There are more fully annotated examples and step-by-step instructions in the README on Github!
      Features
      A simple and fast token parser that calls the appropriate callback and runs automatically. Tokens may include multiple named or positional parameters, as well as multi-value parameters. A manual mode that allows you to replace tokens in custom pieces of cached content (useful if you're using the $cache API). Some built-in tokens for common use-cases: CSRF-Tokens, replacing values from superglobals and producing random hexadecimal strings. The token format is completely customizable, all delimiters can be changed to avoid collisions with existing tag parsers or template languages. Links
      Github Repository & documentation Module directory (pending approval) If you are interested in learning more, the README is very extensive, with more usage examples, code samples and usage instructions!
    • By Craig
      I've been using Fathom Analytics for a while now and on a growing number of sites, so thought it was about time there was a PW module for it.
      WayFathomAnalytics
      WayFathomAnalytics is a group of modules which will allow you to view your Fathom Analytics dashboard in the PW admin panel and (optionally) automatically add and configure the tracking code on front-end pages.
      Links
      GitHub Readme & documentation Download Zip Modules directory Module settings screenshot What is Fathom Analytics?
      Fathom Analytics is a simple, privacy-focused website analytics tool for bloggers and businesses.

      Stop scrolling through pages of reports and collecting gobs of personal data about your visitors, both of which you probably don't need. Fathom is a simple and private website analytics platform that lets you focus on what's important: your business.
      Privacy focused Fast-loading dashboards, all data is on a single screen Easy to get what you need, no training required Unlimited email reports Private or public dashboard sharing Cookie notices not required (it doesn't use cookies or collect personal data) Displays: top content, top referrers, top goals and more
    • By daniels
      This is a lightweight alternative to other newsletter & newsletter-subscription modules.
      You can find the Module in the Modules directory and on Github
      It can subscribe, update, unsubscribe & delete a user in a list in Mailchimp with MailChimp API 3.0. It does not provide any forms or validation, so you can feel free to use your own. To protect your users, it does not save any user data in logs or sends them to an admin.
      This module fits your needs if you...
      ...use Mailchimp as your newsletter / email-automation tool ...want to let users subscribe to your newsletter on your website ...want to use your own form, validation and messages (with or without the wire forms) ...don't want any personal user data saved in any way in your ProcessWire environment (cf. EU data regulation terms) ...like to subscribe, update, unsubscribe or delete users to/from different lists ...like the Mailchimp UI for creating / sending / reviewing email campaigns *I have only tested it with PHP 7.x so far, so use on owners risk
      EDIT:
      Since 0.0.4, instructions and changelog can be found in the README only. You can find it here  🙂
      If you have questions or like to contribute, just post a reply or create an issue or pr on github, thanks!
×
×
  • Create New...