feat: add python example server
This commit is contained in:
commit
51802bc4f8
7 changed files with 343 additions and 0 deletions
133
.gitignore
vendored
Normal file
133
.gitignore
vendored
Normal file
|
@ -0,0 +1,133 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
.temp
|
||||
.cache
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
.env
|
||||
.env.local
|
||||
tmp/
|
3
python/.env_sample
Normal file
3
python/.env_sample
Normal file
|
@ -0,0 +1,3 @@
|
|||
SITEKEY=
|
||||
SECRET=
|
||||
INSTANCE_URL=
|
1
python/.gitignore
vendored
Normal file
1
python/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
__pycache__/
|
40
python/README.md
Normal file
40
python/README.md
Normal file
|
@ -0,0 +1,40 @@
|
|||
# Example Server with mCaptcha protection
|
||||
|
||||
The example server shows a dummy form with the mCaptcha widget. When the
|
||||
form is submitted, it validates the [authorization
|
||||
token](https://mcaptcha.org/docs/webmasters/terminology#authorization-token)
|
||||
presented by the visitor against the mCaptcha instance that the server
|
||||
is configured with.
|
||||
|
||||
The example server is built with the Flask webframework and uses the
|
||||
[Python API library for mCaptcha](https://pypi.org/project/mcaptcha-api/0.1.0/) for validation.
|
||||
|
||||
## 1. Configuration
|
||||
|
||||
Before running, please configure the server:
|
||||
|
||||
```bash
|
||||
cp .env_sample .env
|
||||
```
|
||||
|
||||
And fill in the configuration parameters in `.env` file with:
|
||||
|
||||
1. [Sitekey](https://mcaptcha.org/docs/webmasters/terminology#sitekey)
|
||||
2. Account secret: Available in the settings page on the mCaptcha
|
||||
dashboard
|
||||
3. Instance URL
|
||||
|
||||
## 2. Install dependencies
|
||||
|
||||
```bash
|
||||
virtualenv venv && . venv/bin/activate && pip install -r ./requirements.txt
|
||||
```
|
||||
|
||||
## 3. Launch server
|
||||
|
||||
```bash
|
||||
flask --app server run
|
||||
```
|
||||
|
||||
If all configuration parameters are properly filled in, the example server must
|
||||
work.
|
13
python/requirements.txt
Normal file
13
python/requirements.txt
Normal file
|
@ -0,0 +1,13 @@
|
|||
blinker==1.7.0
|
||||
certifi==2023.11.17
|
||||
charset-normalizer==3.3.2
|
||||
click==8.1.7
|
||||
Flask==3.0.0
|
||||
idna==3.6
|
||||
itsdangerous==2.1.2
|
||||
Jinja2==3.1.2
|
||||
MarkupSafe==2.1.3
|
||||
mcaptcha_api==0.1.0
|
||||
requests==2.31.0
|
||||
urllib3==2.1.0
|
||||
Werkzeug==3.0.1
|
43
python/server.py
Normal file
43
python/server.py
Normal file
|
@ -0,0 +1,43 @@
|
|||
import os
|
||||
from flask import Flask, render_template, request
|
||||
from mcaptcha_api import MCaptcha
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
sitekey = os.environ["SITEKEY"]
|
||||
secret = os.environ["SECRET"]
|
||||
instance_url = os.environ["INSTANCE_URL"]
|
||||
|
||||
if len(sitekey) == 0:
|
||||
print("please enter sitekey")
|
||||
exit(-1)
|
||||
|
||||
|
||||
if len(secret) == 0:
|
||||
print("please enter secret")
|
||||
exit(-1)
|
||||
|
||||
|
||||
if len(instance_url) == 0:
|
||||
print("please enter instance url")
|
||||
exit(-1)
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
return render_template(
|
||||
"index.html.j2", widget_link=f"{instance_url}/widget?sitekey={sitekey}"
|
||||
)
|
||||
|
||||
|
||||
mcaptcha = MCaptcha(instance_url=instance_url, sitekey=sitekey, secret=secret)
|
||||
|
||||
|
||||
@app.route("/login", methods=["POST"])
|
||||
def login_page():
|
||||
username = request.form["username"]
|
||||
token = request.form["mcaptcha__token"]
|
||||
if mcaptcha.verify(token=token):
|
||||
return "<p> Success. Click <a href="/">here</a> to retry</p>"
|
||||
else:
|
||||
return '<p> Failed. Click <a href="/">here</a> to retry</p>'
|
110
python/templates/index.html.j2
Normal file
110
python/templates/index.html.j2
Normal file
|
@ -0,0 +1,110 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Home | mCaptcha Example SErver</title>
|
||||
|
||||
<meta name="referrer" content="no-referrer-when-downgrade" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta
|
||||
name="description"
|
||||
content="mCaptcha is an AGPL'd, privacy focued, proof-of-work based CAPTCHA System"
|
||||
/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<form action="/" method="post">
|
||||
<h1>Demo Form</h1>
|
||||
<label for="name">
|
||||
Name
|
||||
<input type="text" name="name" id="name" />
|
||||
</label>
|
||||
<label for="comment">
|
||||
Comment
|
||||
<input type="password" name="comment" id="comment" />
|
||||
</label>
|
||||
|
||||
<label
|
||||
for="mcaptcha__token"
|
||||
data-mcaptcha_url="{{ widget_link }}"
|
||||
id="mcaptcha__token-label"
|
||||
>
|
||||
mCaptcha authorization token.
|
||||
<a
|
||||
href="https://mcaptcha.org/docs/user-manual/how-to-mcaptcha-without-js/"
|
||||
>Instructions</a
|
||||
>.
|
||||
<input type="text" name="mcaptcha__token" id="mcaptcha__token" />
|
||||
</label>
|
||||
<div id="mcaptcha__widget-container"></div>
|
||||
<script src="https://unpkg.com/@mcaptcha/vanilla-glue@0.1.0-rc2/dist/index.js"></script>
|
||||
|
||||
<button type="submit">Register</button>
|
||||
</form>
|
||||
|
||||
<style>
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
input {
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin: 5px 0 auto;
|
||||
height: 26px;
|
||||
}
|
||||
|
||||
/*
|
||||
#mcaptcha__token {
|
||||
display: none;
|
||||
}
|
||||
*/
|
||||
|
||||
button {
|
||||
background: none;
|
||||
border: none;
|
||||
background: green;
|
||||
color: #fff;
|
||||
height: 26px;
|
||||
border-radius: 5px;
|
||||
margin: 5px 0 auto;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
align-self: center;
|
||||
margin: 40px auto;
|
||||
}
|
||||
|
||||
#mcaptcha__widget-container {
|
||||
height: 78px;
|
||||
width: 100%;
|
||||
margin: 10px 0;
|
||||
}
|
||||
</style>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue