xd
This commit is contained in:
commit
7e00837737
10 changed files with 219 additions and 0 deletions
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Fijxu <fijxu@nadeko.net>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
3
README.md
Normal file
3
README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# mcaptcha-backend-poc
|
||||||
|
|
||||||
|
Just a little Proof of concept that I did to learn how to use mCaptcha
|
5
config.example.yml
Normal file
5
config.example.yml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# https://mcaptcha.nadeko.net/sitekeys
|
||||||
|
mcaptchaSitekey: ""
|
||||||
|
# https://mcaptcha.nadeko.net/settings
|
||||||
|
mcaptchaAccountSecret: ""
|
||||||
|
mcaptchaInstance: "mcaptcha.nadeko.net"
|
17
shard.yml
Normal file
17
shard.yml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
name: mcaptcha-backend
|
||||||
|
version: 0.1.0
|
||||||
|
|
||||||
|
authors:
|
||||||
|
- Fijxu <fijxu@nadeko.net>
|
||||||
|
|
||||||
|
targets:
|
||||||
|
mcaptcha-backend:
|
||||||
|
main: src/mcaptcha-backend.cr
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
kemal:
|
||||||
|
github: kemalcr/kemal
|
||||||
|
|
||||||
|
crystal: '>= 1.13.1'
|
||||||
|
|
||||||
|
license: MIT
|
9
spec/mcaptcha-backend_spec.cr
Normal file
9
spec/mcaptcha-backend_spec.cr
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
require "./spec_helper"
|
||||||
|
|
||||||
|
describe Mcaptcha::Backend do
|
||||||
|
# TODO: Write tests
|
||||||
|
|
||||||
|
it "works" do
|
||||||
|
false.should eq(true)
|
||||||
|
end
|
||||||
|
end
|
2
spec/spec_helper.cr
Normal file
2
spec/spec_helper.cr
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
require "spec"
|
||||||
|
require "../src/mcaptcha-backend"
|
16
src/config.cr
Normal file
16
src/config.cr
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
require "yaml"
|
||||||
|
|
||||||
|
class Config
|
||||||
|
include YAML::Serializable
|
||||||
|
|
||||||
|
property mcaptchaSitekey : String
|
||||||
|
property mcaptchaAccountSecret : String
|
||||||
|
property mcaptchaInstance : String
|
||||||
|
|
||||||
|
def self.load
|
||||||
|
config_file = "./config.yml"
|
||||||
|
config_yaml = File.read(config_file)
|
||||||
|
config = Config.from_yaml(config_yaml)
|
||||||
|
config
|
||||||
|
end
|
||||||
|
end
|
48
src/mcaptcha-backend.cr
Normal file
48
src/mcaptcha-backend.cr
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
require "http/client"
|
||||||
|
require "kemal"
|
||||||
|
require "json"
|
||||||
|
require "./config"
|
||||||
|
|
||||||
|
CONFIG = Config.load
|
||||||
|
|
||||||
|
allowed_ips = Array(String).new
|
||||||
|
|
||||||
|
def ip_address(env) : String
|
||||||
|
begin
|
||||||
|
return env.request.headers.try &.["X-Forwarded-For"]
|
||||||
|
rescue
|
||||||
|
return env.request.remote_address.to_s.split(":").first
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
get "/" do |env|
|
||||||
|
if !allowed_ips.includes?(ip_address(env))
|
||||||
|
render "src/views/captcha.ecr"
|
||||||
|
else
|
||||||
|
render "src/views/main.html"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
post "/captcha" do |env|
|
||||||
|
# token = env.params.body["mcaptcha__token"]
|
||||||
|
token = env.params.json["token"]
|
||||||
|
data = JSON.build do |j|
|
||||||
|
j.object do
|
||||||
|
j.field "token", token
|
||||||
|
j.field "key", CONFIG.mcaptchaSitekey
|
||||||
|
j.field "secret", CONFIG.mcaptchaAccountSecret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
req = HTTP::Client.post("https://#{CONFIG.mcaptchaInstance}/api/v1/pow/siteverify",
|
||||||
|
headers: HTTP::Headers{"Content-Type" => "application/json"},
|
||||||
|
body: data)
|
||||||
|
|
||||||
|
if req.success?
|
||||||
|
res = JSON.parse(req.body)
|
||||||
|
end
|
||||||
|
|
||||||
|
allowed_ips << ip_address(env)
|
||||||
|
res
|
||||||
|
end
|
||||||
|
|
||||||
|
Kemal.run
|
97
src/views/captcha.ecr
Normal file
97
src/views/captcha.ecr
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
<!-- <form id="captcha-form">
|
||||||
|
<label
|
||||||
|
data-mcaptcha_url="https://mcaptcha.nadeko.net/widget/?sitekey=XyyQdgv8Qje0hgAhxgAkrXE8upwa2c2c"
|
||||||
|
for="mcaptcha__token"
|
||||||
|
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">Submit Form</button>
|
||||||
|
</form> -->
|
||||||
|
|
||||||
|
<!-- <html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<form id="mcaptchaForm" action="/submit-mcaptcha" method="POST">
|
||||||
|
<label data-mcaptcha_url="https://mcaptcha.nadeko.net/widget/?sitekey=XyyQdgv8Qje0hgAhxgAkrXE8upwa2c2c"
|
||||||
|
for="mcaptcha__token" id="mcaptcha__token-label">
|
||||||
|
mCaptcha authorization token.
|
||||||
|
<a href="https://mcaptcha.org/docs/user-manual/how-to-mcaptcha-without-js/">Instructions</a>
|
||||||
|
</label>
|
||||||
|
<div id="mcaptcha__widget-container"></div>
|
||||||
|
<input type="hidden" name="mcaptcha__token" id="mcaptcha__token" />
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
<script src="https://unpkg.com/@mcaptcha/vanilla-glue@0.1.0-rc2/dist/index.js"></script>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
const form = document.getElementById('mcaptchaForm');
|
||||||
|
const captchaInput = document.getElementById('mcaptcha__token');
|
||||||
|
|
||||||
|
form.addEventListener('change', function (e) {
|
||||||
|
if (captchaInput.value && captchaInput.value.trim() !== '') {
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</html> -->
|
||||||
|
|
||||||
|
<iframe name="xd" style="display:none;"></iframe>
|
||||||
|
<!-- <form id="mcaptchaForm" method="POST" action="/captcha" target="xd"> -->
|
||||||
|
<label data-mcaptcha_url="https://<%= CONFIG.mcaptchaInstance %>/widget/?sitekey=<%= CONFIG.mcaptchaSitekey %>"
|
||||||
|
for="mcaptcha__token" id="mcaptcha__token-label">
|
||||||
|
mCaptcha authorization token.
|
||||||
|
<a href="https://mcaptcha.org/docs/user-manual/how-to-mcaptcha-without-js/">Instructions</a>
|
||||||
|
</label>
|
||||||
|
<div id="mcaptcha__widget-container"></div>
|
||||||
|
<input type=" name=" mcaptcha__token" id="mcaptcha__token" />
|
||||||
|
<script src="https://unpkg.com/@mcaptcha/vanilla-glue@0.1.0-rc2/dist/index.js"></script>
|
||||||
|
<!-- </form> -->
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const tokenInput = document.getElementById('mcaptcha__token');
|
||||||
|
|
||||||
|
// Function to send the token value to the server
|
||||||
|
function sendToken(value) {
|
||||||
|
fetch('/captcha', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ token: value }),
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
console.log('Success:', data);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to monitor input changes
|
||||||
|
function monitorInput() {
|
||||||
|
let previousValue = '';
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
const currentValue = tokenInput.value;
|
||||||
|
if (currentValue && currentValue !== previousValue) {
|
||||||
|
previousValue = currentValue;
|
||||||
|
sendToken(currentValue);
|
||||||
|
}
|
||||||
|
}, 500); // Check every 500 milliseconds
|
||||||
|
}
|
||||||
|
|
||||||
|
monitorInput();
|
||||||
|
});
|
||||||
|
</script>
|
1
src/views/main.html
Normal file
1
src/views/main.html
Normal file
|
@ -0,0 +1 @@
|
||||||
|
passed
|
Loading…
Reference in a new issue