Coder Social home page Coder Social logo

pdupavillon / express-recaptcha Goto Github PK

View Code? Open in Web Editor NEW
128.0 128.0 25.0 542 KB

Implementation of google recaptcha v2 & V3 solutions for express.js

License: MIT License

JavaScript 6.22% TypeScript 87.06% Pug 2.96% EJS 3.75%
captcha express-recaptcha expressjs google google-recaptcha javascript middleware nodejs recaptcha typescript

express-recaptcha's People

Contributors

dependabot[bot] avatar dogancelik avatar grega avatar pdupavillon avatar u-ways avatar zachmoreno avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

express-recaptcha's Issues

Embedding http script

return '<script src="//'+this._api.host+this._api.script+query_string+'" async defer></script>'+

My content security policy was flagging a request over http instead of https. Seems to be the above line causing the issue. I manually replaced it with the below (prepending 'https:') and seems to be ok now.
return '<script src="https://'+this._api.host+this._api.script+query_string+'" async defer></script>'+

Implemented the Example with EJS

Hey, I want to implement the example files with the Ejs.
As we all know that the lots of the nodeJs users use Ejs as their templating engine.

Kindly allow me to do that so that the Ejs users can refer it for their implementation in projects.

<html>

<head>
    <title> Express-Recaptcha example</title>
</head>

<body>
    <h1>
        Express-Recaptcha example
    </h1>
    <% if(captcha) {%>
        <form action="<%=path%>" method="POST">
           <%- captcha%>
           <button type='submit'>Verify captcha</button>
           <br>
        </form>
        <% if (path === '/v3') {%>
           <a href="/">Express Recaptcha V2</a>
        <%}else{%>

              <% if (path === '/dark') {%>
                 <a href="/">Light Theme</a>
                 <br>
                 <a href="/v3">Express Recaptcha V3</a>
                  <% }else{%>
                      <a href="/dark"> Dark Theme</a>
                    <br>
                      <a href="/v3">Express Recaptcha V3</a>
                   <%}%>
    <% } } else {%>
         <% if (error){%>
             <div style="color:red">Error : <%=error%></div>
             <% }else{ %>
                  <div style="color:green">Data : <%=data%></div>
               <a href="<%= path%>">Retry</a>
               <% }%>
    <%}%>
        <script>
            function cb(token) {
                console.log('token', token);
                var input = document.createElement('input');
                input.setAttribute('type', 'text');
                input.setAttribute('name', 'g-recaptcha-response');
                input.setAttribute('value', token);
                document.getElementsByTagName('form')[0].appendChild(input);
            }
        </script>
    </body>
</html>

I will be waiting for your respective reply.

Add `g-recaptcha-response` to req.headers.

Is there support for adding a g-recaptcha-response to the request header?

v*.ts
if(req.headers && req.headers['g-recaptcha-response']) response = req.headers['g-recaptcha-response'];

body-parser needed

First of all, thank you a lot for this package!

Now, I was trying to use it and at first, didn't get it to run
https://stackoverflow.com/a/12008719
This is the solution that worked for me. There's differences between express 2, 3 and 4, especially regarding how POST params are parsed. Well, works now. :)

Cannot set headers after they are sent to the client

I get following in my log:

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:470:11)
    at ServerResponse.header (/mycode/node_modules/express/lib/response.js:771:10)
    at ServerResponse.send (/mycode/node_modules/express/lib/response.js:170:12)
    at done (/mycode/node_modules/express/lib/response.js:1008:10)
    at Object.exports.renderFile (/mycode/node_modules/pug/lib/index.js:421:12)
    at View.exports.__express [as engine] (/mycode/node_modules/pug/lib/index.js:464:11)
    at View.render (/mycode/node_modules/express/lib/view.js:135:8)
    at tryRender (/mycode/node_modules/express/lib/application.js:640:10)
    at Function.render (/mycode/node_modules/express/lib/application.js:592:3)
    at ServerResponse.render (/mycode/node_modules/express/lib/response.js:1012:7)
    at app.get (/mycode/routes/index.js:9:7)
    at Layer.handle [as handle_request] (/mycode/node_modules/express/lib/router/layer.js:95:5)
    at next (/mycode/node_modules/express/lib/router/route.js:137:13)
    at render (/mycode/node_modules/express-recaptcha/dist/v3.js:32:21)
    at Layer.handle [as handle_request] (/mycode/node_modules/express/lib/router/layer.js:95:5)
    at next (/mycode/node_modules/express/lib/router/route.js:137:13)

And the code at:

at app.get (/mycode/routes/index.js:9:7)

is as follow:

	/* GET home page. */
	app.get('/', recaptcha.middleware.render, (req, res, next) => {
		res.render('index', {
			title: 'My Title',
			lastPath: '/',
			captcha: res.recaptcha
		})
	})

Typings for TypeScript

I used your project recently and created typings:

declare module 'express-recaptcha' {
  import { Handler, Request } from 'express';

  namespace e {
    type CaptchaError = 'missing-input-secret' | 'invalid-input-secret' | 'missing-input-response' | 'invalid-input-response';
    interface InitOptions {
      /**
       * The callback function that gets called when all the dependencies have loaded.
       */
      onload?(): void;
      /**
       * Value could be explicit OR onload, Whether to render the widget explicitly.
       */
      render?: 'explicit' | 'onload';
      /**
       * Forces the widget to render in a specific language (Auto-detects if unspecified).
       */
      hl?: string
      /**
       * Value could be dark OR light.
       * The color theme of the widget (default light).
       */
      theme?: 'dark' | 'light';
      /**
       * Value could be audio OR image,
       * The type of CAPTCHA to serve.
       */
      type?: 'audio' | 'image';
      /**
       * Your callback function that's executed when the user submits a successful CAPTCHA response.
       */
      callback?: () => void;
      /**
       * Your callback function that's executed when the recaptcha response expires
       * and the user needs to solve a new CAPTCHA.
       */
      expired_callback?: () => void
      /**
       * The size of the widget.
       */
      size?: number | 'invisible';
      /**
       * The tabindex of the widget and challenge.
       * If other elements in your page use tabindex, it should be set to make user navigation easier.
       */
      tabindex?: number;
      /**
       * Adding support of remoteip verification (based on x-forwarded-for header or remoteAddress.Value could be true OR false (default false).
       * more info on : https://developers.google.com/recaptcha/docs/verify
       */
      checkremoteip?: boolean;
    }
  }

  // Technically a class but this wouldn't work right...
  const e: {
    public readonly middleware: {
      verify: Handler;
      render: Handler;
    }
    public init(siteKey: string, privateKey: string): void;
    public render(): string;
    public verify(req: Request, cb: (error: CaptchaError, data?: { hostname: string}) => void): void;
  };
  export = e;

  declare global {
    namespace Express {
      export interface Request {
        /**
         * Will be string when the `render` middleware is used.
         * Will be `{ error: ...}` when the `verify` middleware is used.
         */
        recaptcha?: string | {
          error: 'missing-input-secret' | 'invalid-input-secret' | 'missing-input-response' | 'invalid-input-response';
        }
      }
    }
  }
}

You might want to change your exports tho, exporting an instance of a class as module.exports is very hard to model in TS.

Ideally you'd export exports.Recaptcha = Recaptcha.
I'd also suggest changing req.recaptcha to be { template: string; error: string }.
Or you just move the entire thing to TS, all of these changes are breaking anyways.

Multiple language support

I use this great lib with multiple language, but this need always create new instance by constructor. I think good idea on render accept some parameters - as options. This mean only one instance need, but by requests other and other language served.

Error: callback is required

When attempting to render the recaptcha, I would get an vague error only saying that "callback is required", but as far as I can tell I am doing just that. I copied the code in the example and did not change much else. What am I missing?

Here is the full error in question:

Error: callback is required
    at RecaptchaV3.renderWith (/home/sawyer/Documents/code/WebstormProjects/nyx website/node_modules/express-recaptcha/dist/v3.js:65:19)
    at RecaptchaV3.render (/home/sawyer/Documents/code/WebstormProjects/nyx website/node_modules/express-recaptcha/dist/v3.js:54:21)
    at render (/home/sawyer/Documents/code/WebstormProjects/nyx website/node_modules/express-recaptcha/dist/v3.js:32:43)
    at Layer.handle [as handle_request] (/home/sawyer/Documents/code/WebstormProjects/nyx website/node_modules/express/lib/router/layer.js:95:5)
    at next (/home/sawyer/Documents/code/WebstormProjects/nyx website/node_modules/express/lib/router/route.js:137:13)
    at Route.dispatch (/home/sawyer/Documents/code/WebstormProjects/nyx website/node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (/home/sawyer/Documents/code/WebstormProjects/nyx website/node_modules/express/lib/router/layer.js:95:5)
    at /home/sawyer/Documents/code/WebstormProjects/nyx website/node_modules/express/lib/router/index.js:281:22
    at Function.process_params (/home/sawyer/Documents/code/WebstormProjects/nyx website/node_modules/express/lib/router/index.js:335:12)
    at next (/home/sawyer/Documents/code/WebstormProjects/nyx website/node_modules/express/lib/router/index.js:275:10)

Question about captcha challenge

Hey @pdupavillon, I have a question about the verify process.
I am using this lib to perform validation on the server, and I see that the captcha is failing sometimes with the error: invalid-input-response

I am using the invisible captcha.

I don't understand how can I reproduce this error.
When I try to fail the challenge on purpose for over than 5 minutes, I don't see any error, just keep on getting a fresh new challenge.

So do you have any idea what can trigger that error?

Another question - When the challenge popup is visible, when you click outside of it the popup is closing. Is there any event for that? Something like onClose or something?

Thanks..

add data-size

insert after line 39:
if (this.options.size) captcha_attr += ' data-size="'+this.options.size+'"';

body-parser

For funkcionality is needed body-parser npm package. Because there are handled post requests.
I dont know why that information missing in readme. And on the other hand why is there present settings for public directory that is unrelated with such captcha feature.
It would be helpfull especialy for node noobies add such information. But I understand that everyone love keeping their modules without any additional dependency. And who knows maybe body-parser is de facto standard in node world. But anyway posted so maybe someone find help here.

App crashed

Not sure but i have two apps running on two separate servers, using express-recaptcha - it all worked well for past two month, and for some reason yesterday both apps on separate server crashed with this error.

Error: getaddrinfo ENOTFOUND www.google.com www.google.com:443
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:67:26)
Emitted 'error' event at:
at TLSSocket.socketErrorListener (_http_client.js:395:9)
at TLSSocket.emit (events.js:180:13)
at emitErrorNT (internal/streams/destroy.js:64:8)
at process._tickCallback (internal/process/next_tick.js:178:19)

And today it all went back to normal, I have changed nothing in my code! I wonder if there is a chance that google servers were down / had issues accepting requests and your code doesn't handle this kind of failure, and if not the case, how can I handle this kind of response so the app doesn't crash?

Just as a note! I have used your example to make it work, hence its been working fine for the past two months.

many thanks in advance for your hard work in bringing express-recaptcha to us.

TypeError: next is not a function

Hi,

I start to implement your example but I am facing the following issue:

express-recaptcha\dist\v3.js:45
                    next();
                    ^

TypeError: next is not a function

NodeJS: v10.20.1
NPM: 6.14.8
OS: Windows 10

Thanks in advance

Recaptcha is not a constructor

I've tried multiple attempts at implementing this package and every time I do I get the same error message.

I imported the package and configured with my two keys from google which caused the error, didn't try implementing it on any routes or views.

I also downloaded the sample code and tried to run that only to receive the same error.

JSON.parse SyntaxError

Hi,

This error caused the application to crash.
Dealing with "try catch" I believe it will solve.. :) thanks!

start-app.sh: at IncomingMessage. (/opt/app-root/src/node_modules/express-recaptcha/lib/express-recaptcha.js:86:25)
start-app.sh: at JSON.parse ()
start-app.sh: SyntaxError: Unexpected token < in JSON at position 0
start-app.sh: ^
start-app.sh:
start-app.sh: undefined:1

Cannot find module

Getting this error:

node_modules/express-recaptcha/typings/express.d.ts:1:33 - error TS2307: Cannot find module '../src/interfaces'. 1 import {RecaptchaResponse} from '../src/interfaces';

I manually adjust it for now from:
import {RecaptchaResponse} from '../src/interfaces';
to
import {RecaptchaResponse} from '../dist/interfaces';

but every time my node_modules change, it reverts back to its original value.
Is this something on my side? If not, could you guys please update this?

ejs v3 display problem

I recently update express-recaptcha to last version and update my code but my problem is in frontend just a frame shows that the page is recaptcha protected, and the recaptcha is not showing in div tag?
what is the solution?
I didn't receive any error
showRegsitrationForm(req , res) { res.render('register' , { messages : req.flash('errors') , recaptcha : this.recaptcha.render() }); }

`recaptchaConfig(){

    this.recaptcha = new Recaptcha(
        '!!!',
        '!!!' , 
      {callback:'cb'},{'hl' : 'en'}
    );
}

`

Express recaptcha on several routes

This may not be an issue with express-recaptcha itself, but this is driving me crazy, I've made some research on stackoverflow and Google but I couldn't find any solutions on how to do this. What I'm trying to do is:

userController.js

app.get('/user/login', recaptcha.middleware.render,this.login);

login: function (req, res) {
    if (req.user) {
        res.redirect('/admin');
    } else {
        res.render('user/login', {title: 'Login', catpcha: res.recaptcha});
    }
}

registerController.js

app.get('/register', recaptcha.middleware.render, this.register)

register: function(req, res) {
   res.render('index', {title: 'Home', captcha: res.recaptcha})
}

But recaptcha is only rendered on the first route, not the second.
This is a reduced version of my package.json:

   "express": "^4.13.4",
   "express-recaptcha": "^4.0.2"

I've included the packages I thought were needed.

NOTE: I've excluded Recaptcha constructor on purpose

I have 'g-recaptcha-response': array

I have 'g-recaptcha-response': [ '', '03AOLTBLTmXVEzta....]
temporarily solved the problem by replacing
var query_string = 'secret=' + this._secret_key + '&response=' + response;
on
var query_string = 'secret=' + this._secret_key + '&response=' + response[1];

Support for recaptcha v3?

I think currently this library only support google recaptcha v2,

There are plans to support recaptcha v3 in the future?

if not, could I make a fork and integrate the changes miself by a pullrequest?

Thank you

Working with Server Side HTTP Proxy

Hi,
I don't know where is my mistake but I cannot execute verify from server side.
It seems that there is no way to set an HTTP Proxy
Must I use any module like tunnel?

Regards
Vito

Support for hCaptcha as a 'swap out' service

Since hCaptcha is increasingly popular, it would be great to support this as well as reCaptcha - the two services can be interchanged easily: https://docs.hcaptcha.com/switch/

I don't believe this would be a huge change, mainly just offering a different set of endpoint URLs.

If there's appetite for this package to expand to support hCaptcha, then I can have a look into the work needed and create a PR.

Uncaught Exceptions

Hi,
I am using your package and what I can see is that it injects the recaptcha code on the web page (which works wonderful), example:

...., {action: 'homepage'})
.then(recaptchaReady);

Except when an error might occur due to, for example, a timeout (slow connection). In this case, the Promise code above does not handle the exception and the browser gives an error like:

Uncaught (in promise) Timeout
Promise.then (async)

How would I handle exceptions in the Promise (auto-generated by your package)?

For example:

...., {action: 'homepage'})
.then(recaptchaReady)
.catch((err) => {
  // Handle any error that occurred in any of the previous
  // promises in the chain.
});

Recaptcha not showing

Recaptcha is not showing
It shows when I change the script src in index.js
from
<script src='//www.google.com/recaptcha/api.js'></script>
to
<script src='https://www.google.com/recaptcha/api.js'></script>

Am I missing something ?

Is app.use(bodyParser.json()) a real requirement ?

Hi,

Our implementation seems to be functional without the app.use(bodyParser.json()); line (that we missed by error). Is it a real requirement for most implementations and we have an easy-lucky use case ?

Regards

Breaking Changes in v4.2.0

var Recaptcha = require('express-recaptcha').Recaptcha;
var recaptcha = new Recaptcha('xxx', 'xxx');

This code works in 4.1.1, but throws an error on 4.2.0.

Version 4.2.0 requires adding the V2.

var Recaptcha = require('express-recaptcha').RecaptchaV2;

This is a breaking change, so you should change the version number to 5.0.0 for this release. You should also release an update to 4.2.1 with this change reversed, to help people who depend on your package working as it usually did.

Please see the npm documentation page about semantic versioning for more information.

Error in documentation for verification without middleware

The documentation states

app.post('/', function(req, res){
  recaptcha.verify(req, function(error, data){
    if (!req.recaptcha.error) {
      // success code
    } else {
      // error code
    }
  });
});

I believe it should be

app.post('/', function(req, res){
  recaptcha.verify(req, function(error, data){
    if (!rerror) {
      // success code
    } else {
      // error code
    }
  });
});

Normal v2 Recaptcha works perfectly, INVISIBLE does not work

Hi, first of all thank you for the wonderful library. I have a get login url, a post login url and the pug file that does the login. I followed instructions as mentioned. If I change my type to a normal recaptcha it works perfectly but an invisible one does not

Pug file

Screen Shot 2019-08-15 at 9 57 41 PM

Get and POST login endpoints
Screen Shot 2019-08-15 at 10 00 46 PM

The router

const Recaptcha = require("express-recaptcha").RecaptchaV2;
const recaptcha = new Recaptcha(process.env.RECAPTCHA_SITE_KEY_V2, process.env.RECAPTCHA_SECRET_KEY_V2, { size: "invisible" });

router.get("/", homeController.index);
router.get("/login", recaptcha.middleware.render, userController.getLogin);
router.post("/login", recaptcha.middleware.verify, userController.postLogin);

A little debugging has led me to the point where
g-recaptcha-response is empty string
{ error: 'invalid-input-response', data: null }

Any suggestions are appreciated

Multiple recaptcha on a single page

Is there a way to use this module when there are multiple recaptcha on a single page? Right now, I am unable to figure out how to do it. But I am aware of a way to do it without using express-recaptcha. Thanks in advance.

Update documentation for usage on view side

The documentation is not very clear on the modification we have to setup in the view : the captcha element and the callback function.
Might be useful to update the documentation with the PUG from example folder and the EJS from issue #31

Expired Session / Cookie

Hi,

All is working fine, except when the Recaptcha session expires. Let's say you have a login page with recaptcha validation. Now, open the page and leave the form open for some time (so recaptcha session expires) - Not sure but I think more than 2 minutes. Then login. This gives a recaptcha validation error. How can one handle this type of behaviour? I am using v3

npm requires semver

I'm using this library in an application, and recently had a hell of a time debugging because you guys changed the way the library works in a breaking fashion and incremented the minor version instead of the major version.

The commit that pulls #1 should have changed the version to 2.0.0 to prevent this.

Whether or not you fix this in the existing package is irrelevant, but in the future please make sure your npm packages follow semver.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.