├── .gitignore ├── README ├── README.md ├── app.py ├── gunicorn.conf.py ├── requirements.txt ├── settings.py └── start.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # PyInstaller 26 | # Usually these files are written by a python script from a template 27 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 28 | *.manifest 29 | *.spec 30 | 31 | # Installer logs 32 | pip-log.txt 33 | pip-delete-this-directory.txt 34 | 35 | # Unit test / coverage reports 36 | htmlcov/ 37 | .tox/ 38 | .coverage 39 | .cache 40 | nosetests.xml 41 | coverage.xml 42 | 43 | # Translations 44 | *.mo 45 | *.pot 46 | 47 | # Django stuff: 48 | *.log 49 | 50 | # Sphinx documentation 51 | docs/_build/ 52 | 53 | # PyBuilder 54 | target/ 55 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | DESCRIPTION 2 | 3 | testcookie-recaptcha-processor is a simple web server proxying recaptcha responses to Google. 4 | Server should be used with testcookie-nginx-module for setting cookies after solving recaptchas. 5 | 6 | NOTE 7 | 8 | This project is Proof-of-Contept for those people, who ask me to add "Captcha functionality" to testcookie-nginx-module. 9 | Check the "doc" directory for the list of things you can do yourself. 10 | 11 | INSTALLATION 12 | 13 | Grab and install libraries: 14 | *) pip install -r requirements.txt 15 | 16 | Build nginx with testcookie-nginx-module, use example configuration. 17 | Set REcaptcha public key in nginx config and REcaptcha private key in settings.py config. 18 | Run testcookie-recaptcha-processor, run nginx. 19 | 20 | 21 | EXAMPLE CONFIGURATION 22 | 23 | server { 24 | listen 80; 25 | server_name domain.com; 26 | 27 | testcookie off; 28 | testcookie_name BPC; 29 | testcookie_secret keepmescret; 30 | testcookie_session $remote_addr; 31 | testcookie_arg attempt; 32 | testcookie_max_attempts 3; 33 | testcookie_fallback /cookies.html?backurl=http://$host$request_uri; 34 | testcookie_get_only on; 35 | testcookie_redirect_via_refresh on; 36 | testcookie_refresh_template "
"; 37 | 38 | location = /cookies.html { 39 | root /var/www/public_html; 40 | } 41 | 42 | location = /captcha { 43 | testcookie var; 44 | proxy_set_header Testcookie-Domain "domain.com"; 45 | proxy_set_header Testcookie-Value $testcookie_set; 46 | proxy_set_header Testcookie-Nexturl $testcookie_nexturl; 47 | proxy_set_header Testcookie-Name "BPC"; 48 | proxy_set_header X-Real-IP $remote_addr; 49 | proxy_pass http://127.0.0.1:10101/; 50 | } 51 | 52 | location / { 53 | testcookie on; 54 | proxy_set_header Host $host; 55 | proxy_set_header X-Real-IP $remote_addr; 56 | proxy_pass http://127.0.0.1:8080; 57 | } 58 | } 59 | 60 | 61 | SOURCES 62 | 63 | Available on github at kyprizel/testcookie-recaptcha-processor 64 | (). 65 | 66 | BUGS 67 | 68 | Feel free to report bugs and send patches to kyprizel@gmail.com 69 | or use github's issue tracker(). 70 | 71 | COPYRIGHT & LICENSE 72 | 73 | Copyright (C) 2012 Eldar Zaitov (kyprizel@gmail.com). 74 | 75 | All rights reserved. 76 | 77 | This module is licenced under the terms of BSD license. 78 | 79 | Redistribution and use in source and binary forms, with or without 80 | modification, are permitted provided that the following conditions are 81 | met: 82 | 83 | * Redistributions of source code must retain the above copyright 84 | notice, this list of conditions and the following disclaimer. 85 | 86 | * Redistributions in binary form must reproduce the above copyright 87 | notice, this list of conditions and the following disclaimer in the 88 | documentation and/or other materials provided with the distribution. 89 | 90 | * Neither the name of the authors nor the names of its contributors 91 | may be used to endorse or promote products derived from this 92 | software without specific prior written permission. 93 | 94 | THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 95 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 96 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 97 | ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 98 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 99 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 100 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 101 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 102 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 103 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 104 | SUCH DAMAGE. 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Description 2 | =========== 3 | 4 | **testcookie-recaptcha-processor** is a simple web server proxying recaptcha responses to Google. 5 | Server should be used with [testcookie-nginx-module](http://github.com/kyprizel/testcookie-nginx-module) for setting cookies after solving recaptchas. 6 | 7 | Note 8 | ==== 9 | 10 | This project is Proof-of-Contept for those people, who ask me to add "Captcha functionality" to testcookie-nginx-module. 11 | 12 | Installation 13 | ============ 14 | 15 | Grab and install libraries: 16 | *) pip install -r requirements.txt 17 | *) start.sh 18 | 19 | Build nginx with testcookie-nginx-module, use example configuration. 20 | Run testcookie-recaptcha-processor, run nginx. 21 | 22 | 23 | Example configuration 24 | ===================== 25 | 26 | server { 27 | listen 80; 28 | server_name domain.com; 29 | 30 | testcookie off; 31 | testcookie_name BPC; 32 | testcookie_secret keepmescret; 33 | testcookie_session $remote_addr; 34 | testcookie_arg attempt; 35 | testcookie_max_attempts 3; 36 | testcookie_fallback /cookies.html?backurl=http://$host$request_uri; 37 | testcookie_get_only on; 38 | testcookie_redirect_via_refresh on; 39 | testcookie_refresh_template "
"; 40 | 41 | location = /captcha { 42 | testcookie var; 43 | proxy_set_header Testcookie-Domain "domain.com"; 44 | proxy_set_header Testcookie-Value $testcookie_set; 45 | proxy_set_header Testcookie-Nexturl $testcookie_nexturl; 46 | proxy_set_header Testcookie-Name "BPC"; 47 | proxy_set_header X-Real-IP $remote_addr; 48 | proxy_pass http://127.0.0.1:10101/; 49 | } 50 | 51 | location / { 52 | testcookie on; 53 | proxy_set_header Host $host; 54 | proxy_set_header X-Real-IP $remote_addr; 55 | proxy_pass http://127.0.0.1:8080; 56 | } 57 | 58 | location = /cookies.html { 59 | root /var/www/public_html; 60 | } 61 | 62 | } 63 | 64 | 65 | Sources 66 | ======= 67 | 68 | Available on github at [kyprizel/testcookie-recaptcha-processor] 69 | (). 70 | 71 | Bugs 72 | ==== 73 | 74 | Feel free to report bugs and send patches to kyprizel@gmail.com 75 | or use github's issue tracker(). 76 | 77 | Copyright & License 78 | =================== 79 | 80 | Copyright (C) 2012 Eldar Zaitov (kyprizel@gmail.com). 81 | 82 | All rights reserved. 83 | 84 | This module is licenced under the terms of BSD license. 85 | 86 | Redistribution and use in source and binary forms, with or without 87 | modification, are permitted provided that the following conditions are 88 | met: 89 | 90 | * Redistributions of source code must retain the above copyright 91 | notice, this list of conditions and the following disclaimer. 92 | 93 | * Redistributions in binary form must reproduce the above copyright 94 | notice, this list of conditions and the following disclaimer in the 95 | documentation and/or other materials provided with the distribution. 96 | 97 | * Neither the name of the authors nor the names of its contributors 98 | may be used to endorse or promote products derived from this 99 | software without specific prior written permission. 100 | 101 | THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 102 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 103 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 104 | ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 105 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 106 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 107 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 108 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 109 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 110 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 111 | SUCH DAMAGE. 112 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import json 5 | from geventhttpclient import HTTPClient, URL 6 | from flask import Flask, request, redirect, abort 7 | 8 | import settings 9 | 10 | app = Flask(__name__) 11 | 12 | def get_client_addr(): 13 | if not request.headers.getlist("X-Real-IP"): 14 | ip = request.remote_addr 15 | else: 16 | ip = request.headers.getlist("X-Real-IP")[0] 17 | return ip 18 | 19 | def check_recaptcha(secret, resp, ip): 20 | try: 21 | url = URL('https://www.google.com/recaptcha/api/siteverify?secret=%s&response=%s&ip=%s' % (secret, resp, ip)) 22 | http = HTTPClient.from_url(url) 23 | response = http.get(url.request_uri) 24 | if response.status_code == 200: 25 | raw_res = response.read() 26 | res = json.loads(raw_res) 27 | if res.get('success'): 28 | return True 29 | except: 30 | pass 31 | return False 32 | 33 | @app.route('/', methods=['POST']) 34 | def handler(): 35 | domain = request.headers.get('Testcookie-Domain', '') 36 | nexturl = request.headers.get('Testcookie-Nexturl', '/') 37 | cookie_name = request.headers.get('Testcookie-Name') 38 | cookie_val = request.headers.get('Testcookie-Value') 39 | secret = settings.RE_SECRETS.get(domain) 40 | if not cookie_name or not cookie_val or not secret: 41 | abort(500) 42 | ip = get_client_addr() 43 | if check_recaptcha(secret, request.form['g-recaptcha-response'], ip): 44 | resp = redirect(nexturl) 45 | resp.set_cookie(cookie_name, cookie_val) 46 | return resp 47 | return redirect(nexturl) 48 | 49 | if __name__ == '__main__': 50 | import logging 51 | 52 | logging.basicConfig(level=logging.DEBUG) 53 | 54 | app.debug = True 55 | 56 | app.run('localhost', 10101) 57 | -------------------------------------------------------------------------------- /gunicorn.conf.py: -------------------------------------------------------------------------------- 1 | bind = "127.0.0.1:10101" 2 | workers = 10 3 | backlog = 2048 4 | #pidfile = "/home/recaptcher/run/server.pid" 5 | preload_app = True 6 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | geventhttpclient 2 | gunicorn 3 | flask 4 | -------------------------------------------------------------------------------- /settings.py: -------------------------------------------------------------------------------- 1 | DEBUG=False 2 | RE_SECRETS = { 'example-domain1.com': 'per_domain_recaptcha_secret_key1', 3 | 'example-domain2.com': 'per_domain_recaptcha_secret_key2' } 4 | 5 | -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | gunicorn -c gunicorn.conf.py app:app 4 | --------------------------------------------------------------------------------