mirror of
https://github.com/mCaptcha/mCaptcha.git
synced 2026-02-11 10:05:41 +00:00
widget static resources are now built locally
This commit is contained in:
@@ -5,7 +5,5 @@
|
||||
href="<.= &*crate::VERIFICATIN_WIDGET_CSS .>"
|
||||
/>
|
||||
<script src="<.= &*crate::VERIFICATIN_WIDGET_JS .>"></script>
|
||||
<script src="<.= &*crate::WIDGET_ROUTES.js .>"></script>
|
||||
<script src="<.= &*crate::WIDGET_ROUTES.wasm .>"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
152
templates/widget/js/const.ts
Normal file
152
templates/widget/js/const.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* mCaptcha is a PoW based DoS protection software.
|
||||
* This is the frontend web component of the mCaptcha system
|
||||
* Copyright © 2021 Aravinth Manivnanan <realaravinth@batsense.net>.
|
||||
*
|
||||
* Use of this source code is governed by Apache 2.0 or MIT license.
|
||||
* You shoud have received a copy of MIT and Apache 2.0 along with
|
||||
* this program. If not, see <https://spdx.org/licenses/MIT.html> for
|
||||
* MIT or <http://www.apache.org/licenses/LICENSE-2.0> for Apache.
|
||||
*/
|
||||
|
||||
/** mcaptcha checkbox ID **/
|
||||
export const btnId = 'widget__verification-checkbox';
|
||||
|
||||
/** get sitekey */
|
||||
export const sitekey = () => {
|
||||
let sitekey;
|
||||
return (() => {
|
||||
if (sitekey === null || sitekey === undefined) {
|
||||
sitekey = new URL(window.location.href).searchParams.get('sitekey');
|
||||
if (sitekey === null || sitekey === undefined) {
|
||||
throw new Error(`Define sitekey in query parameter`);
|
||||
}
|
||||
}
|
||||
return sitekey;
|
||||
})();
|
||||
};
|
||||
|
||||
/** mCaptcha API routes */
|
||||
export const ROUTES = (() => {
|
||||
const getConfig = '/api/v1/pow/config';
|
||||
const verififyPoW = '/api/v1/pow/verify';
|
||||
|
||||
return {
|
||||
/** get URL to fetch PoW configuration */
|
||||
getConfig,
|
||||
/** get URL to verify PoW*/
|
||||
verififyPoW,
|
||||
};
|
||||
})();
|
||||
|
||||
/** get mCaptcha verifify checkbox button */
|
||||
export const btn = () => {
|
||||
let btn;
|
||||
return (() => {
|
||||
if (btn === null || btn === undefined) {
|
||||
btn = <HTMLInputElement>document.getElementById(btnId);
|
||||
if (btn === null || btn === undefined) {
|
||||
throw new Error(`mCaptcha button not found)`);
|
||||
}
|
||||
}
|
||||
return btn;
|
||||
})();
|
||||
};
|
||||
|
||||
export const messageText = () => {
|
||||
let beforeClass = 'widget__verification-text--before';
|
||||
let duringClass = 'widget__verification-text--during';
|
||||
let errorClass = 'widget__verification-text--error';
|
||||
let afterClass = 'widget__verification-text--after';
|
||||
|
||||
let before: HTMLElement;
|
||||
let after: HTMLElement;
|
||||
let during: HTMLElement;
|
||||
let error: HTMLElement;
|
||||
|
||||
/** runner fn to display HTMLElement **/
|
||||
const showMsg = (e: HTMLElement) => (e.style.display = 'block');
|
||||
/** runner fn to hide HTMLElement **/
|
||||
const hideMsg = (e: HTMLElement) => (e.style.display = 'none');
|
||||
|
||||
/** lazy init and get before elementt **/
|
||||
const getBefore = () => {
|
||||
if (before === null || before === undefined) {
|
||||
before = <HTMLElement>document.querySelector(`.${beforeClass}`);
|
||||
if (before === null || before === undefined) {
|
||||
throw new Error(`before element not found)`);
|
||||
}
|
||||
return before;
|
||||
}
|
||||
};
|
||||
|
||||
/** lazy init and get after elementt **/
|
||||
const getAfter = () => {
|
||||
if (after === null || after === undefined) {
|
||||
after = <HTMLSpanElement>document.querySelector(`.${afterClass}`);
|
||||
if (after === null || after === undefined) {
|
||||
throw new Error(`after element not found)`);
|
||||
}
|
||||
}
|
||||
|
||||
return after;
|
||||
};
|
||||
|
||||
/** lazy init and get error elementt **/
|
||||
const getError = () => {
|
||||
if (error === null || error === undefined) {
|
||||
error = <HTMLSpanElement>document.querySelector(`.${errorClass}`);
|
||||
if (error === null || error === undefined) {
|
||||
throw new Error(`before error not found)`);
|
||||
}
|
||||
}
|
||||
return error;
|
||||
};
|
||||
|
||||
/** lazy init and get during elementt **/
|
||||
const getDuring = () => {
|
||||
if (during === null || during === undefined) {
|
||||
during = <HTMLSpanElement>document.querySelector(`.${duringClass}`);
|
||||
if (during === null || during === undefined) {
|
||||
throw new Error(`before during not found)`);
|
||||
}
|
||||
}
|
||||
|
||||
return during;
|
||||
};
|
||||
return {
|
||||
/** display "before" message **/
|
||||
before: () => {
|
||||
showMsg(getBefore());
|
||||
hideMsg(getAfter());
|
||||
hideMsg(getDuring());
|
||||
hideMsg(getError());
|
||||
},
|
||||
|
||||
/** display "after" message **/
|
||||
after: () => {
|
||||
hideMsg(getBefore());
|
||||
showMsg(getAfter());
|
||||
hideMsg(getDuring());
|
||||
hideMsg(getError());
|
||||
},
|
||||
|
||||
/** display "during" message **/
|
||||
during: () => {
|
||||
hideMsg(getBefore());
|
||||
hideMsg(getAfter());
|
||||
showMsg(getDuring());
|
||||
hideMsg(getError());
|
||||
},
|
||||
|
||||
/** display "error" message **/
|
||||
error: () => {
|
||||
hideMsg(getBefore());
|
||||
hideMsg(getAfter());
|
||||
hideMsg(getDuring());
|
||||
showMsg(getError());
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const inputId = 'mcaptcha-response';
|
||||
48
templates/widget/js/fetchPoWConfig.ts
Normal file
48
templates/widget/js/fetchPoWConfig.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* mCaptcha is a PoW based DoS protection software.
|
||||
* This is the frontend web component of the mCaptcha system
|
||||
* Copyright © 2021 Aravinth Manivnanan <realaravinth@batsense.net>.
|
||||
*
|
||||
* Use of this source code is governed by Apache 2.0 or MIT license.
|
||||
* You shoud have received a copy of MIT and Apache 2.0 along with
|
||||
* this program. If not, see <https://spdx.org/licenses/MIT.html> for
|
||||
* MIT or <http://www.apache.org/licenses/LICENSE-2.0> for Apache.
|
||||
*/
|
||||
|
||||
import genJsonPayload from './utils/genJsonPayload';
|
||||
import * as CONST from './const';
|
||||
|
||||
type GetConfigPayload = {
|
||||
key: string;
|
||||
};
|
||||
|
||||
export type PoWConfig = {
|
||||
string: string;
|
||||
difficulty_factor: number;
|
||||
salt: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* fetch proof-of-work configuration
|
||||
* @returns {PoWConfig} pow config
|
||||
* */
|
||||
export const fetchPoWConfig = async () => {
|
||||
try {
|
||||
const payload: GetConfigPayload = {
|
||||
key: CONST.sitekey(),
|
||||
};
|
||||
|
||||
const res = await fetch(CONST.ROUTES.getConfig, genJsonPayload(payload));
|
||||
if (res.ok) {
|
||||
const config: PoWConfig = await res.json();
|
||||
return config;
|
||||
} else {
|
||||
const err = await res.json();
|
||||
throw new Error(err);
|
||||
}
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
export default fetchPoWConfig;
|
||||
68
templates/widget/js/index.ts
Normal file
68
templates/widget/js/index.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* mCaptcha is a PoW based DoS protection software.
|
||||
* This is the frontend web component of the mCaptcha system
|
||||
* Copyright © 2021 Aravinth Manivnanan <realaravinth@batsense.net>.
|
||||
*
|
||||
* Use of this source code is governed by Apache 2.0 or MIT license.
|
||||
* You shoud have received a copy of MIT and Apache 2.0 along with
|
||||
* this program. If not, see <https://spdx.org/licenses/MIT.html> for
|
||||
* MIT or <http://www.apache.org/licenses/LICENSE-2.0> for Apache.
|
||||
*/
|
||||
|
||||
import prove from './prove';
|
||||
import fetchPoWConfig from './fetchPoWConfig';
|
||||
import sendWork from './sendWork';
|
||||
import sendToParent from './sendToParent';
|
||||
import * as CONST from './const';
|
||||
|
||||
import '../main.scss';
|
||||
|
||||
let LOCK = false;
|
||||
|
||||
/** add mcaptcha widget element to DOM */
|
||||
export const registerVerificationEventHandler = () => {
|
||||
const verificationContainer = <HTMLElement>(
|
||||
document.querySelector('.widget__verification-container')
|
||||
);
|
||||
verificationContainer.style.display = 'flex';
|
||||
CONST.btn().addEventListener('click', e => solveCaptchaRunner(e));
|
||||
};
|
||||
|
||||
export const solveCaptchaRunner = async (e: Event) => {
|
||||
if (LOCK) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
LOCK = true;
|
||||
if (CONST.btn().checked == false) {
|
||||
CONST.messageText().before();
|
||||
LOCK = false;
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
// steps:
|
||||
|
||||
// 1. show during
|
||||
CONST.messageText().during();
|
||||
// 1. get config
|
||||
const config = await fetchPoWConfig();
|
||||
// 2. prove work
|
||||
const proof = await prove(config);
|
||||
// 3. submit work
|
||||
const token = await sendWork(proof);
|
||||
// 4. send token
|
||||
sendToParent(token);
|
||||
// 5. mark checkbox checked
|
||||
CONST.btn().checked = true;
|
||||
CONST.messageText().after();
|
||||
LOCK = false;
|
||||
} catch (e) {
|
||||
CONST.messageText().error();
|
||||
console.error(e);
|
||||
LOCK = false;
|
||||
}
|
||||
};
|
||||
|
||||
registerVerificationEventHandler();
|
||||
55
templates/widget/js/prove.ts
Normal file
55
templates/widget/js/prove.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* mCaptcha is a PoW based DoS protection software.
|
||||
* This is the frontend web component of the mCaptcha system
|
||||
* Copyright © 2021 Aravinth Manivnanan <realaravinth@batsense.net>.
|
||||
*
|
||||
* Use of this source code is governed by Apache 2.0 or MIT license.
|
||||
* You shoud have received a copy of MIT and Apache 2.0 along with
|
||||
* this program. If not, see <https://spdx.org/licenses/MIT.html> for
|
||||
* MIT or <http://www.apache.org/licenses/LICENSE-2.0> for Apache.
|
||||
*/
|
||||
|
||||
import {gen_pow} from '../../../browser/pkg/index';
|
||||
import {PoWConfig} from './fetchPoWConfig';
|
||||
import * as CONST from './const';
|
||||
|
||||
export type Work = {
|
||||
result: string;
|
||||
nonce: number;
|
||||
string: string;
|
||||
key: string;
|
||||
};
|
||||
|
||||
type WasmWork = {
|
||||
result: string;
|
||||
nonce: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* proove work
|
||||
* @param {PoWConfig} config - the proof-of-work configuration using which
|
||||
* work needs to be computed
|
||||
* */
|
||||
const prove = async (config: PoWConfig) => {
|
||||
try {
|
||||
const proofString = gen_pow(
|
||||
config.salt,
|
||||
config.string,
|
||||
config.difficulty_factor,
|
||||
);
|
||||
const proof: WasmWork = JSON.parse(proofString);
|
||||
|
||||
const res: Work = {
|
||||
key: CONST.sitekey(),
|
||||
string: config.string,
|
||||
nonce: proof.nonce,
|
||||
result: proof.result,
|
||||
};
|
||||
|
||||
return res;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
export default prove;
|
||||
24
templates/widget/js/sendToParent.ts
Normal file
24
templates/widget/js/sendToParent.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* mCaptcha is a PoW based DoS protection software.
|
||||
* This is the frontend web component of the mCaptcha system
|
||||
* Copyright © 2021 Aravinth Manivnanan <realaravinth@batsense.net>.
|
||||
*
|
||||
* Use of this source code is governed by Apache 2.0 or MIT license.
|
||||
* You shoud have received a copy of MIT and Apache 2.0 along with
|
||||
* this program. If not, see <https://spdx.org/licenses/MIT.html> for
|
||||
* MIT or <http://www.apache.org/licenses/LICENSE-2.0> for Apache.
|
||||
*/
|
||||
import {Token} from './sendWork';
|
||||
|
||||
/**
|
||||
* send pow validation token as message to parant of the iframe
|
||||
* @param {Token} token: token received from mCaptcha service
|
||||
* upon successful PoW validation
|
||||
* */
|
||||
export const sendToParent = (token: Token) => {
|
||||
window.parent.postMessage(token, '*');
|
||||
// TODO set origin. Make parent send origin as query parameter
|
||||
// or as a message to iframe
|
||||
};
|
||||
|
||||
export default sendToParent;
|
||||
42
templates/widget/js/sendWork.ts
Normal file
42
templates/widget/js/sendWork.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* mCaptcha is a PoW based DoS protection software.
|
||||
* This is the frontend web component of the mCaptcha system
|
||||
* Copyright © 2021 Aravinth Manivnanan <realaravinth@batsense.net>.
|
||||
*
|
||||
* Use of this source code is governed by Apache 2.0 or MIT license.
|
||||
* You shoud have received a copy of MIT and Apache 2.0 along with
|
||||
* this program. If not, see <https://spdx.org/licenses/MIT.html> for
|
||||
* MIT or <http://www.apache.org/licenses/LICENSE-2.0> for Apache.
|
||||
*/
|
||||
|
||||
import genJsonPayload from './utils/genJsonPayload';
|
||||
import * as CONST from './const';
|
||||
import {Work} from './prove';
|
||||
|
||||
export type Token = {
|
||||
token: string;
|
||||
};
|
||||
|
||||
export const sendWork = async (payload: Work) => {
|
||||
try {
|
||||
const res = await fetch(CONST.ROUTES.verififyPoW, genJsonPayload(payload));
|
||||
if (res.ok) {
|
||||
console.debug('work verified');
|
||||
const token: Token = await res.json();
|
||||
console.debug(`token ${token.token}`);
|
||||
return token;
|
||||
} else {
|
||||
const err = await res.json();
|
||||
console.error(`error: ${err.error}`);
|
||||
throw new Error(err);
|
||||
}
|
||||
} catch (err) {
|
||||
CONST.messageText().error();
|
||||
console.error(err);
|
||||
await new Promise(r => setTimeout(r, 1000));
|
||||
window.location.reload();
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
export default sendWork;
|
||||
50
templates/widget/js/tests/const.test.ts
Normal file
50
templates/widget/js/tests/const.test.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* mCaptcha is a PoW based DoS protection software.
|
||||
* This is the frontend web component of the mCaptcha system
|
||||
* Copyright © 2021 Aravinth Manivnanan <realaravinth@batsense.net>.
|
||||
*
|
||||
* Use of this source code is governed by Apache 2.0 or MIT license.
|
||||
* You shoud have received a copy of MIT and Apache 2.0 along with
|
||||
* this program. If not, see <https://spdx.org/licenses/MIT.html> for
|
||||
* MIT or <http://www.apache.org/licenses/LICENSE-2.0> for Apache.
|
||||
*/
|
||||
import * as CONST from '../const';
|
||||
|
||||
import {getBaseHtml, sitekey, checkbox} from './setupTests';
|
||||
import * as TESTElements from './setupTests';
|
||||
|
||||
it('const works', () => {
|
||||
const body = document.querySelector('body');
|
||||
const container = getBaseHtml();
|
||||
body.appendChild(container);
|
||||
expect(CONST.sitekey()).toBe(sitekey);
|
||||
expect(CONST.btn()).toBe(checkbox);
|
||||
|
||||
// display after
|
||||
CONST.messageText().after();
|
||||
expect(TESTElements.afterMsg.style.display).toBe('block');
|
||||
expect(TESTElements.beforeMsg.style.display).toBe('none');
|
||||
expect(TESTElements.duringMsg.style.display).toBe('none');
|
||||
expect(TESTElements.errorMsg.style.display).toBe('none');
|
||||
|
||||
// display before
|
||||
CONST.messageText().before();
|
||||
expect(TESTElements.afterMsg.style.display).toBe('none');
|
||||
expect(TESTElements.beforeMsg.style.display).toBe('block');
|
||||
expect(TESTElements.duringMsg.style.display).toBe('none');
|
||||
expect(TESTElements.errorMsg.style.display).toBe('none');
|
||||
|
||||
// display during
|
||||
CONST.messageText().during();
|
||||
expect(TESTElements.afterMsg.style.display).toBe('none');
|
||||
expect(TESTElements.beforeMsg.style.display).toBe('none');
|
||||
expect(TESTElements.duringMsg.style.display).toBe('block');
|
||||
expect(TESTElements.errorMsg.style.display).toBe('none');
|
||||
|
||||
// display error
|
||||
CONST.messageText().error();
|
||||
expect(TESTElements.afterMsg.style.display).toBe('none');
|
||||
expect(TESTElements.beforeMsg.style.display).toBe('none');
|
||||
expect(TESTElements.duringMsg.style.display).toBe('none');
|
||||
expect(TESTElements.errorMsg.style.display).toBe('block');
|
||||
});
|
||||
40
templates/widget/js/tests/setupTests.ts
Normal file
40
templates/widget/js/tests/setupTests.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* mCaptcha is a PoW based DoS protection software.
|
||||
* This is the frontend web component of the mCaptcha system
|
||||
* Copyright © 2021 Aravinth Manivnanan <realaravinth@batsense.net>.
|
||||
*
|
||||
* Use of this source code is governed by Apache 2.0 or MIT license.
|
||||
* You shoud have received a copy of MIT and Apache 2.0 along with
|
||||
* this program. If not, see <https://spdx.org/licenses/MIT.html> for
|
||||
* MIT or <http://www.apache.org/licenses/LICENSE-2.0> for Apache.
|
||||
*/
|
||||
import * as CONST from '../const';
|
||||
|
||||
export const sitekey = 'imbatman';
|
||||
|
||||
export const checkbox = <HTMLInputElement>document.createElement('input');
|
||||
checkbox.type = 'checkbox';
|
||||
checkbox.id = CONST.btnId;
|
||||
|
||||
const getMessages = (state: string) => {
|
||||
const msg = <HTMLElement>document.createElement('span');
|
||||
msg.className = `widget__verification-text--${state}`;
|
||||
return msg;
|
||||
};
|
||||
|
||||
export const beforeMsg = getMessages('before');
|
||||
export const afterMsg = getMessages('after');
|
||||
export const duringMsg = getMessages('during');
|
||||
export const errorMsg = getMessages('error');
|
||||
|
||||
/** get base HTML with empty mCaptcha container */
|
||||
export const getBaseHtml = () => {
|
||||
const form = <HTMLFormElement>document.createElement('form');
|
||||
form.appendChild(checkbox);
|
||||
form.appendChild(beforeMsg);
|
||||
form.appendChild(duringMsg);
|
||||
form.appendChild(afterMsg);
|
||||
form.appendChild(errorMsg);
|
||||
|
||||
return form;
|
||||
};
|
||||
30
templates/widget/js/utils/genJsonPayload.test.ts
Normal file
30
templates/widget/js/utils/genJsonPayload.test.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* mCaptcha is a PoW based DoS protection software.
|
||||
* This is the frontend web component of the mCaptcha system
|
||||
* Copyright © 2021 Aravinth Manivnanan <realaravinth@batsense.net>.
|
||||
*
|
||||
* Use of this source code is governed by Apache 2.0 or MIT license.
|
||||
* You shoud have received a copy of MIT and Apache 2.0 along with
|
||||
* this program. If not, see <https://spdx.org/licenses/MIT.html> for
|
||||
* MIT or <http://www.apache.org/licenses/LICENSE-2.0> for Apache.
|
||||
*/
|
||||
|
||||
import genJsonPayload from './genJsonPayload';
|
||||
|
||||
'use strict';
|
||||
|
||||
const payload = {
|
||||
username: 'Jhon',
|
||||
};
|
||||
|
||||
const value = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
};
|
||||
|
||||
it('getFromUrl workds', () => {
|
||||
expect(genJsonPayload(payload)).toEqual(value);
|
||||
});
|
||||
23
templates/widget/js/utils/genJsonPayload.ts
Normal file
23
templates/widget/js/utils/genJsonPayload.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* mCaptcha is a PoW based DoS protection software.
|
||||
* This is the frontend web component of the mCaptcha system
|
||||
* Copyright © 2021 Aravinth Manivnanan <realaravinth@batsense.net>.
|
||||
*
|
||||
* Use of this source code is governed by Apache 2.0 or MIT license.
|
||||
* You shoud have received a copy of MIT and Apache 2.0 along with
|
||||
* this program. If not, see <https://spdx.org/licenses/MIT.html> for
|
||||
* MIT or <http://www.apache.org/licenses/LICENSE-2.0> for Apache.
|
||||
*/
|
||||
|
||||
const genJsonPayload = (payload: any) => {
|
||||
const value = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
};
|
||||
return value;
|
||||
};
|
||||
|
||||
export default genJsonPayload;
|
||||
Reference in New Issue
Block a user