14 votes

Need a simple way to password protect a webpage

Hey Tildes!

I've got a static, basic website, HTML and CSS. It's one page only. But I'd like to create a second page with some more private content that is password protected.

I know that I can accomplish this via .htaccess but what I don't like about this method is that when the user navigates to the page, they get a pop up asking for a username and password. What I would like is having the user navigate to the page, and then they are met with a simple form asking for just a password (no username). After they enter the password, the "veil" lifts or the page forwards and they get the private content.

Here's the thing... the content really only needs to seem private. It's not super secret, personal information. I don't want it indexed by search engines (nofollow), and I want it basically hidden, but the password is only there to make the user feel exclusive. If some tech-minded person encountered this page and jumped through a bunch of hoops to get in without the password, it's not a big deal to me. In reality, 99.9% of people accessing this page will not be able to bypass the password.

I'm guessing this can be accomplished easily in Javascript, but I don't really know much Javascript apart from finding code snippets and plunking them in. I also want to be able to fully design the password entry page so that it looks branded, so a code snippet plunked down into my HTML doc would be great for this.

If there is an easy way to actually protect the content behind the password, that would be excellent. In this case, I imagine it would be much like a news site with an ad-blocker-blocker. Just some kind of pop-up that blocks all the content. Enter the password, and you're in.

Anyhow, I hope I've described what I'm looking for accurately enough. Anybody have any easy and quick ways to accomplish this?

35 comments

  1. [17]
    cptcobalt
    Link
    Here is an extremely brief all-in-one page PHP implementation, if you just need something that "works". It doesn't necessarily follow über best practices nor is it necessarily cryptographically...

    Here is an extremely brief all-in-one page PHP implementation, if you just need something that "works". It doesn't necessarily follow über best practices nor is it necessarily cryptographically secure, but that doesn't seem to be your #1 goal here—you might just be looking for something simple to get the job done in a minimal nonsense way. With this, there's zero chance of the secret stuff being indexed/accidentally accessed/etc—unlike many of the JS proposals above (and the absurdly shocking display:none suggestions which provoked me to actually comment).

    It's up to you to style/format/add content as you want. To use this, change the password on line 4, and the filename on line 28. Even if you don't know PHP, it should just be visually simple—the secret stuff goes between the if/endif blocks—don't modify those (but you can add as much content/whitespace/etc as you'll need) and you'll be solid. Here you go.

    7 votes
    1. [14]
      unknown user
      Link Parent
      Wow, thank you for writing that up for me. I really appreciate you taking the time. In this method, someone viewing source would be able to see the password (not a deal breaker for me). Reading...

      Wow, thank you for writing that up for me. I really appreciate you taking the time. In this method, someone viewing source would be able to see the password (not a deal breaker for me). Reading the code, I want to make sure I understand what it does, so please correct me if I'm wrong in my understanding. When a user navigates to secret.php, they'll see a password entry screen. When they enter the correct password, it will simply reload the page with the revealed content. Incorrect password will simply show text informing the password is incorrect.

      This is quite elegant and minimal, and precisely what I had in mind. I know it's not secure, though as I've stated before my intention is to make the user feel exclusive. This entire exercise is really a way for me to offer free content on my own site, rather than rely on other free content distributors that essentially harvest email addresses from my customers.

      Again, thank you for writing this up for me. I can read it and understand in plainly and it suits my purposes perfectly. I find it funny you warn "don't use this" to any others who might be driving by. However, I don't think I'm the only one who would find something like this very useful.

      5 votes
      1. [13]
        cptcobalt
        Link Parent
        This is an ambiguous question, so a bit of a specific answer: If someone has access to the raw PHP file, yes, they will be able to see your password and hidden contents. If someone on the web (in...

        In this method, someone viewing source would be able to see the password (not a deal breaker for me).

        This is an ambiguous question, so a bit of a specific answer:

        • If someone has access to the raw PHP file, yes, they will be able to see your password and hidden contents.
        • If someone on the web (in a web browser) accesses this web page and does the whole "right click, view source"/web inspector thing, they will not see your password or secret contents—your web server will not send or expose this data until the user has entered the text on the textbox.

        When they enter the correct password, it will simply reload the page with the revealed content. Incorrect password will simply show text informing the password is incorrect.

        Precisely.

        I find it funny you warn "don't use this" to any others who might be driving by.

        The gross simplicity of this is why I make the "don't use this" warning—the trend these days is to make things extremely complex, so I'm sure a programmer-bro could roll by and say "this should be a class with static methods" or "you're not sanitizing user input" or "you should use a templating engine instead of inline PHP" or "you should set an encrypted cookie", of which there'd be elements of truth to their comment. Nor would this be even close to anything I'd write if someone was paying me to do it, but I figured you'd just want something simple, and it took 10 minutes of my time. There's dozens of ways this could be improved. I wouldn't use this myself in production, but if you look at my projects (in my tildes comment history) you'll see I have higher polish standards for things I do myself. This, however, will likely suit you just fine. 😀

        4 votes
        1. unknown user
          Link Parent
          Thanks for the clarification. Yep, I see now that I was incorrect about the password being visible. This is honestly exactly what I was looking for. To me, the simplicity is great. I prefer the...

          Thanks for the clarification. Yep, I see now that I was incorrect about the password being visible. This is honestly exactly what I was looking for. To me, the simplicity is great. I prefer the elegance of it. I can read your code and understand it, having just a very basic knowledge of PHP from my WordPress adventures. Really, just what I needed and I appreciate the 10 minutes of your time.

          I see from your bio that you're a writer. I'm actually a pro pulp writer, and this code is going to help me deliver freebie books to my fans. If you ever have any questions about the pulp world, self-publishing, and earning money from writing books, let me know. I owe you my knowledge!

          3 votes
        2. [11]
          Emerald_Knight
          (edited )
          Link Parent
          Edit It seems like I didn't communicate very well here, so I'm going to preface this comment with a quick point of clarification: The provided solution is perfect for the OP. Security is not an...

          Edit

          It seems like I didn't communicate very well here, so I'm going to preface this comment with a quick point of clarification:

          The provided solution is perfect for the OP. Security is not an essential consideration and the code perfectly suits this kind of use case. Furthermore, it's absolutely a major step up from a pure JavaScript solution. I would recommend this solution above all of the others I've seen in here.

          With that in mind, there's still the lingering question of "why" this code should not be used in a serious application where security is a major concern, particularly production-level applications. Everything that follows in my original comment is meant to expand on this subject to help provide a deeper understanding of just how complex security is.

          The OP doesn't need to consider any of these details for their own use case, and no new programmer fresh out of the gates should be concerned about these subjects, either. That being said, it could be helpful--or just interesting--for those who want to really understand the "why" of "don't use this".


          Original

          I'm sure a programmer-bro could roll by

          And here I am! There are a number of reasons why you wouldn't want to do this in any serious application. Here's a non-exhaustive list:

          1. Your password is in plaintext. Ideally you would hash the password using password_hash() and then store this hash instead. Then, on verifying the password, you would call password_verify(). This ensures that even with access to the source code, they would need to actually crack the password before gaining access.

          2. The password is hard-coded. In a serious application, the password should be stored securely and virtually untouchable. One such solution would be to give your application database access with a read-only user for the password hash. This would ensure that even if someone gained access to your database credentials, they wouldn't be able to cause any damage; they would only be able to read that particular database entry, with no permissions to replace it. You would then have a separate user with write access for actually updating the password entry.

          3. The existing solution does a direct string comparison for the stored and user-provided passwords. This leaves you vulnerable to something called a "timing attack". The short version is this: when checking if two strings are equal, the quickest way to do it is to compare them one character at a time until you find the first character that doesn't match. This is how string comparisons are usually done. But because of this, there is a very tiny amount of time difference between, say, two correct characters and three correct characters. With enough attempts being made, you could use some simple statistics to figure out what the next correct character is in the password and construct the entire password one character at a time. This makes cracking the password really fast.

          4. The password attempts are "inexpensive", meaning that they take virtually no time at all to complete. Modern hashing algorithms try to introduce a "cost" that makes trying to brute-force the password prohibitive in the amount of time it takes to try the different combinations. This "cost" is non-existent for simple string comparisons.

          5. There is no punishment for trying all of the passwords you want to try. If you fail a login attempt 500,000 times, you can still try a 500,001st attempt with no delay whatsoever. Modern systems try to prevent you from brute-forcing passwords by punishing you for too many failed login attempts.

          6. A single set of shared login credentials means that if you ever want to update the password, everyone else that you want to give access to will need to receive the updated password. This is just a potentially massive headache for people who don't get the memo and end up having to hound you down for the new password. By not having separate login credentials for each person, it's also impossible to hold people accountable for their actions. You can't, for instance, just ban a single person who you know to be causing problems.

          Those are just a few major reasons to chew on. Certainly not a problem for a non-sensitive application like your own, but definitely something you should steer clear of if security is any concern to you whatsoever.

          3 votes
          1. [2]
            unknown user
            Link Parent
            I think you missed OP’s point that this doesn’t need to be actually secure, so I’m not sure what this comment adds to the discussion since in my view it’s out of scope. Thus why every “programmer...

            I think you missed OP’s point that this doesn’t need to be actually secure, so I’m not sure what this comment adds to the discussion since in my view it’s out of scope.

            Thus why every “programmer bro” needs an “architect & manager bro” to keep them on track :P

            3 votes
            1. Emerald_Knight
              Link Parent
              Alright, with three people including the OP replying with the same point, I've clearly failed spectacularly at communicating what I intended to. That's my fault. I've edited my comment to clarify.

              Alright, with three people including the OP replying with the same point, I've clearly failed spectacularly at communicating what I intended to. That's my fault. I've edited my comment to clarify.

              1 vote
          2. [3]
            cptcobalt
            Link Parent
            You're right! The implementation totally fails in trying to be secure, but that wasn't the goal. I tried to give caveats in my comments/gist, even saying "don't use this" and "it doesn't...

            You're right! The implementation totally fails in trying to be secure, but that wasn't the goal.

            I tried to give caveats in my comments/gist, even saying "don't use this" and "it doesn't necessarily follow über best practices nor is it necessarily cryptographically secure", but also I don't think suggesting everything you did would have met their goals. I tried to provide a lot of hints in my comments to show what the issues could be here, but I don't find that this should prevent someone from experimenting with new things.

            They can start with this, and grow into something awesome—taking all this feedback—later. (I worry a comment like this is just gatekeeping by way of extreme complexity.)

            2 votes
            1. [2]
              Emerald_Knight
              Link Parent
              We've discussed this in PMs already, but clearly I miscommunicated. Spectacularly. I don't expect the OP to implement any of these things or even be worried about them. With three different people...

              We've discussed this in PMs already, but clearly I miscommunicated. Spectacularly. I don't expect the OP to implement any of these things or even be worried about them. With three different people interpreting my comment differently from what I'd intended, I clearly messed up. That's my bad. I've edited my comment to clarify.

              2 votes
              1. cptcobalt
                Link Parent
                Ah, cheers—that edit actually provides really good context that rounds out the comment as a whole. I absolutely believe it was in good faith and well intended from the start, but your edit that...

                Ah, cheers—that edit actually provides really good context that rounds out the comment as a whole. I absolutely believe it was in good faith and well intended from the start, but your edit that smooths it out makes it better. My "programmer-bro" quip was also a fair bit of bait too. 😅

                3 votes
          3. [5]
            unknown user
            Link Parent
            Yep, I see where @cptcobalt's code fails in these regards but as I've outlined here, my personal need is not "serious." It's more for show, and I imagine there are others out there like me who...

            Yep, I see where @cptcobalt's code fails in these regards but as I've outlined here, my personal need is not "serious." It's more for show, and I imagine there are others out there like me who just want something that puts up the facade of making the user feel exclusive. Also, I really don't want my content behind the password to be indexed by search engines so that just anybody can stumble upon it without at least jumping through the hoop of giving me their email address. This is, at the end of the day, a marketing ploy, not any kind of serious secure web application. At the same time, I'm also saving my customers from giving their email address to an outsourced company that will do with it what they will. I'm personally benevolent. I don't spam, and I only send an email once a month at most. People signup for my list, get the password, and get the content. They really only do this once. So for my application, something this simple is actually perfect.

            1 vote
            1. [4]
              Emerald_Knight
              Link Parent
              Oh, absolutely. This works for your use case. Security isn't essential here for you, so a simple solution like this one is perfect for you. The point of my comment was really to touch on the...

              Oh, absolutely. This works for your use case. Security isn't essential here for you, so a simple solution like this one is perfect for you.

              The point of my comment was really to touch on the "don't use this" subject, and specifically why you shouldn't use it in a serious application where security is an important consideration.

              That's really what I wanted to communicate. I apologize for not clarifying that point a bit better.

              1 vote
              1. [3]
                unknown user
                Link Parent
                I think it should also be noted that I would have gladly paid $20 for this code had I stumbled upon it from some website, even knowing that it wasn't best practices secure. I know you developers...

                I think it should also be noted that I would have gladly paid $20 for this code had I stumbled upon it from some website, even knowing that it wasn't best practices secure. I know you developers can make a lot of money doing what you do, but I'm much more interested in divorcing my hours worked from the money I earn (which is why I left IT and became a writer). So if someone had been selling basic code snippets, like this one, that I could use to accomplish my very basic goals without thinking too hard about it, I would have pulled out my credit card without a second thought. I don't think I'm unique in thinking like this. Just something to chew on.

                1 vote
                1. [2]
                  Emerald_Knight
                  Link Parent
                  My comment was never meant to disparage the quality of the code at all. I clearly messed up with my intended message and for that I sincerely apologize. I've edited my comment to clarify. Again,...

                  My comment was never meant to disparage the quality of the code at all. I clearly messed up with my intended message and for that I sincerely apologize. I've edited my comment to clarify.

                  Again, this code is perfect for your use case. It does exactly what you need it to, no more and no less. I only intended to provide some insight as to why the code shouldn't be used outside of a use case as relaxed as your own.

                  1. unknown user
                    Link Parent
                    Oh, I'm not meaning to harp on you. I understood your friendly addendum. And my comment that you're now responding to was just to hint at additional ways to earn money from quantity and relative...

                    Oh, I'm not meaning to harp on you. I understood your friendly addendum. And my comment that you're now responding to was just to hint at additional ways to earn money from quantity and relative mediocrity. After all, that's how I earn money. I appreciate your additional insight and I did read it with thoughtful consideration.

                    1 vote
    2. [2]
      Comment deleted by author
      Link Parent
      1. json
        Link Parent
        Hey if using CSS to hide a pay walled article is secure enough for a news website then I'm sure it's secure enough for a lot of things.

        Hey if using CSS to hide a pay walled article is secure enough for a news website then I'm sure it's secure enough for a lot of things.

        4 votes
    3. archevel
      (edited )
      Link Parent
      Happy to provoke :) but to be honest if OP needs something more secure, and don't feel confident in setting it up themselves, then using a CMS is really a better way to go. There are plenty of...

      With this, there's zero chance of the secret stuff being indexed/accidentally accessed/etc—unlike many of the JS proposals above (and the absurdly shocking display:none suggestions which provoked me to actually comment).

      Happy to provoke :) but to be honest if OP needs something more secure, and don't feel confident in setting it up themselves, then using a CMS is really a better way to go. There are plenty of providers and there are plenty of plugins for managing users, emailing etcetc. Rolling your own security should be one of the last thing one does. Obfuscation (like the JS solutions suggested) is not in the same category of requirements as security concerns.

      1 vote
  2. [2]
    Comment deleted by author
    Link
    1. unknown user
      Link Parent
      I like your third suggestion, using AJAX... completely forgot about AJAX. Can you expound a little more on this possibility and the steps involved? Using htaccess, would it be the standard...

      I like your third suggestion, using AJAX... completely forgot about AJAX. Can you expound a little more on this possibility and the steps involved? Using htaccess, would it be the standard protected file with a username and password, but I could only ask the user for the password and AJAX would then insert both for me? It should be noted, I'm only planning to have one password that all users would receive, so it's not unique user accounts.

      If you have any links you could point me to about using AJAX for this, I'd appreciate it.

  3. [2]
    nic
    Link
    Dead simplest approach is to redirect to a sub-directory to an html page based on the password entered, and have a 404 page that basically says the password was wrong. If they type in the right...

    Dead simplest approach is to redirect to a sub-directory to an html page based on the password entered, and have a 404 page that basically says the password was wrong.

    function answer() { location.href('/membersonly/' + document.getElementById('answer').value + '.html'); }

    <form onSubmit="answer()" id="answer" target="_self"> <input type="text" maxlength="55" class="box" autofocus /> <input type="submit" class="submit" value="SUBMIT" /> </form>

    If they type in the right html page name, they see the content, if not , they get the 404 error.

    3 votes
    1. unknown user
      Link Parent
      Hmm. That is pretty dead simple. Is there a way to display "incorrect password" on the page rather than redirect to a 404? As it stands now, I don't have a 404 page -- if a user inputs an...

      Hmm. That is pretty dead simple. Is there a way to display "incorrect password" on the page rather than redirect to a 404? As it stands now, I don't have a 404 page -- if a user inputs an incorrect url, it just redirects to the homepage.

  4. mftrhu
    Link
    You could encrypt the payload, put it into the page as a blob, and then add some JS that decrypts it on the fly with the given password. There's a few pastebins that work like this, like...

    You could encrypt the payload, put it into the page as a blob, and then add some JS that decrypts it on the fly with the given password. There's a few pastebins that work like this, like PrivateBin, and IIRC there used to be a TiddlyWiki Classic plugin that allowed you to do this with single tiddlers.

    If you actually want people to be able to bypass your "security", you could use something like the Vigenere cypher instead of AES.

    3 votes
  5. [5]
    Wes
    Link
    If you build it in Javascript, the password will be exposed in the source code. You can try to obfuscate it but it will be there. To guard it it any meaningful way you'd need to use a server-side...

    If you build it in Javascript, the password will be exposed in the source code. You can try to obfuscate it but it will be there. To guard it it any meaningful way you'd need to use a server-side language, or .htaccess like you suggested.

    I'd suggest a basic login page that submits a form to the server to check a password. If it checks out, you set a cookie with authorized=true and that lets the user in. Each page on the exclusive site then checks the cookie and kicks you out if it's not there. Easy peasy.

    Now you could amp up the cookie with all sorts of user hash checks and other nonsense, but that seems overkill for your purposes. This seems like a decent compromise between security and complexity.

    1 vote
    1. [2]
      unknown user
      Link Parent
      Thank you. I really have no experiences in creating cookies. My web design skills are pretty rudimentary, as I stepped out of the programming world a long time ago. In your method, where is the...

      Thank you. I really have no experiences in creating cookies. My web design skills are pretty rudimentary, as I stepped out of the programming world a long time ago. In your method, where is the password stored on the server? Is it in htaccess? What language am I using it accomplish all this? If you have any links that might expound upon your method, I'd appreciate it.

      1. Wes
        Link Parent
        The language would most likely be PHP simply due to ubiquity on servers. The password would thus be stored in a .php file, alongside the logic to check it. I'm unavailable to expand on that right...

        The language would most likely be PHP simply due to ubiquity on servers. The password would thus be stored in a .php file, alongside the logic to check it.

        I'm unavailable to expand on that right now (or actually today), but this looks like a close approximation to what I described. It might give you a better idea. Good luck!

        https://stackoverflow.com/a/45869294/582883

    2. [2]
      ali
      Link Parent
      Checking for an aurhorized=true cookie is too trivial to fake imo. Of course op needs to know how secure he wants to be.

      Checking for an aurhorized=true cookie is too trivial to fake imo. Of course op needs to know how secure he wants to be.

      1. Wes
        Link Parent
        Well, I'd suggest that giving it a slightly more secretive name might be ideal. Hooray for security through obscurity. But faking a cookie is definitely a step up above checking the page source...

        Well, I'd suggest that giving it a slightly more secretive name might be ideal. Hooray for security through obscurity. But faking a cookie is definitely a step up above checking the page source for a password in JS, which I think most beginner techies could do.

  6. [4]
    archevel
    Link
    One way (if it's only a single page) would be to wrap the actual content in a div with "display: none" and then have a simple password prompt that when filled in correctly toggles the docs display...

    One way (if it's only a single page) would be to wrap the actual content in a div with "display: none" and then have a simple password prompt that when filled in correctly toggles the docs display attribute.

    Something like this is very light weight and could be extended so once a user has entered the pwd, store something in local storage so they don't need to enter the pwd again.

    <div id="content" style="display:none">...secret content...</div>
    <form onsubmit="(e) => checkPwd(e)" id="pwdForm"><input id="pwd" type="text"/><input type="submit"/></form>
    <script type="text/javascript">
    function checkPwd(e) {
      e.preventDefault();
      let input = document.getElementById("pwd");
      if (input.value === "bananahamock") {
        let content = document.getElementById("content");
        content.style.display = "block";
        let pwdForm = document.getElementById("pwdForm");
        pwdForm.parentNode.removeChild(pwdForm); 
      }
      
      return false;
    }
    </script>
    

    (Wrote this on my phone so code is probably wrong :) )

    The downside is that there is no real security involved (the "password" is sent in plain text) and if there are multiple pages involved it's probably easier to use a proper CMS with login capabilities.

    1 vote
    1. [3]
      unknown user
      Link Parent
      Honestly, I'm not completely adverse to using this method. I'm going to be using one password for all potential users, and it's really only about making them feel exclusive. If someone looked at...

      Honestly, I'm not completely adverse to using this method. I'm going to be using one password for all potential users, and it's really only about making them feel exclusive. If someone looked at the source code, got in, and got to the content... well, it's free content anyway, and it's really only there to grow my fanbase. The idea is that this content is a carrot I'm using to get people to signup for my mailing list. Sign up, get the password, get the content. But if a few techie freebie seekers sneak past without signing up for my mailing list, well, maybe the free content will turn them into fans. I'm mostly concerned with blocking it from search indexing.

      Anyhow, does your code simply display a password screen and then upon password entry, does it lift the veil on the page or does it forward to another page?

      1. [2]
        archevel
        Link Parent
        This would NOT prevent the content from being indexed. Even if you added a robot.txt file indicating you don't want it to be indexed doesn't prevent anyone from indexing the site (it's basically...

        This would NOT prevent the content from being indexed. Even if you added a robot.txt file indicating you don't want it to be indexed doesn't prevent anyone from indexing the site (it's basically just starting your preference).

        If you need something smarter and if you expect to update the content I'd go with some CMS instead.

        1. unknown user
          Link Parent
          Thanks. I'm going with @cptcobalt's PHP solution above, as it fits my needs pretty perfectly. I don't need anything smarter or more secure, and the content will be very rarely updated (as in,...

          Thanks. I'm going with @cptcobalt's PHP solution above, as it fits my needs pretty perfectly. I don't need anything smarter or more secure, and the content will be very rarely updated (as in, maybe once a year or even less). My site is so small and basic, a CMS would just be too much. I'm pretty happy to be off the CMS train.

  7. [3]
    toly
    Link
    Don't know if you want everything to be self contained one one page without redirects but another option is to make a "password entry" page that will take user input. You then hash that user...

    Don't know if you want everything to be self contained one one page without redirects but another option is to make a "password entry" page that will take user input. You then hash that user inputted password and redirect to a path with the hash. For incorrect password attempts just have the 404 page state the password was incorrect, for a correct password it will bring up the page that corresponds to the hashed passsword.

    1 vote
    1. [2]
      unknown user
      Link Parent
      Are you talking about something similar to what @nic suggested here?

      Are you talking about something similar to what @nic suggested here?

      1. toly
        Link Parent
        Yep, and here I thought I read all the comments carefully not to repeat someone elses idea :| Regarding the 404, it should be as simple as just adding a 404.html page.

        Yep, and here I thought I read all the comments carefully not to repeat someone elses idea :|
        Regarding the 404, it should be as simple as just adding a 404.html page.

  8. [2]
    notopygos
    Link
    You should use the top answer (one with php code) or if you and your friends are familiar with Tor, I would suggest creating a hidden service and password protecting it. Your friends will have to...

    You should use the top answer (one with php code) or if you and your friends are familiar with Tor, I would suggest creating a hidden service and password protecting it. Your friends will have to enter a string in their torrc to access the website only once. As long as they don't mess up torrc, they will be able to view the webpage.

    Other users will not be able to connect to your hidden service if that string is absent in torrc.

    Edit: Don't use css or other methods that rely on hiding the content if you don't want anyone to index it. robots.txt is what you want the robots to do, nothing is stopping a bad robot from indexing your website.

    1. unknown user
      Link Parent
      Yep, I'll be going with the PHP solution. Tor is way overkill. This isn't for my friends. This is for my customers. Security is hardly a concern, because all this is is a way to deliver them some...

      Yep, I'll be going with the PHP solution. Tor is way overkill. This isn't for my friends. This is for my customers. Security is hardly a concern, because all this is is a way to deliver them some free content for signing up for my mailing list. I'm actually doing this specifically to leave a third-party service I use to deliver freebies, as it harvests my customers emails and sends them newsletters from their own list.

      1 vote