diff --git a/package.json b/package.json index a2a3957b..112584d6 100644 --- a/package.json +++ b/package.json @@ -37,8 +37,8 @@ "webpack-dev-server": "^4.15.1" }, "dependencies": { - "@mcaptcha/pow-wasm": "^0.1.0-rc1", - "@mcaptcha/pow_sha256-polyfill": "^0.1.0-rc1", - "@mcaptcha/vanilla-glue": "^0.1.0-rc1" + "@mcaptcha/pow_sha256-polyfill": "^0.1.0-rc2", + "@mcaptcha/vanilla-glue": "^0.1.0-rc1", + "@mcaptcha/pow-wasm": "^0.1.0-rc2" } } diff --git a/templates/widget/index.html b/templates/widget/index.html index 7ba878a2..3db7d637 100644 --- a/templates/widget/index.html +++ b/templates/widget/index.html @@ -6,51 +6,54 @@ SPDX-License-Identifier: MIT OR Apache-2.0 <. include!("../components/headers/widget-headers.html"); .> -
- - -
- - " - alt="mCaptcha logo" - /> -

mCaptcha

-
- - + +
+ <.include!("./footer.html"); .> diff --git a/templates/widget/index.ts b/templates/widget/index.ts index ad6dae1c..2fa5123c 100644 --- a/templates/widget/index.ts +++ b/templates/widget/index.ts @@ -3,7 +3,7 @@ // // SPDX-License-Identifier: MIT OR Apache-2.0 -import { Work, ServiceWorkerWork } from "./types"; +import { Work, ServiceWorkerMessage } from "./types"; import fetchPoWConfig from "./fetchPoWConfig"; import sendWork from "./sendWork"; import sendToParent from "./sendToParent"; @@ -24,6 +24,9 @@ export const registerVerificationEventHandler = (): void => { }; export const solveCaptchaRunner = async (e: Event): Promise => { + const PROGRESS_FILL = document.querySelector(".progress__fill"); + let width = 0; + if (LOCK) { e.preventDefault(); return; @@ -32,6 +35,8 @@ export const solveCaptchaRunner = async (e: Event): Promise => { try { LOCK = true; if (CONST.btn().checked == false) { + width = 0; + PROGRESS_FILL.style.width = `${width}%`; CONST.messageText().before(); LOCK = false; return; @@ -43,32 +48,49 @@ export const solveCaptchaRunner = async (e: Event): Promise => { CONST.messageText().during(); // 1. get config const config = await fetchPoWConfig(); + const max_recorded_nonce = config.max_recorded_nonce; // 2. prove work worker.postMessage(config); worker.onmessage = async (event: MessageEvent) => { - const resp: ServiceWorkerWork = event.data; - console.log( - `Proof generated. Difficuly: ${config.difficulty_factor} Duration: ${resp.work.time}` - ); + const resp: ServiceWorkerMessage = event.data; - const proof: Work = { - key: CONST.sitekey(), - string: config.string, - nonce: resp.work.nonce, - result: resp.work.result, - time: Math.trunc(resp.work.time), - worker_type: resp.work.worker_type, - }; + if (resp.type === "work") { + width = 80; + PROGRESS_FILL.style.width = `${width}%`; + console.log( + `Proof generated. Difficuly: ${config.difficulty_factor} Duration: ${resp.value.work.time}` + ); - // 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; + const proof: Work = { + key: CONST.sitekey(), + string: config.string, + nonce: resp.value.work.nonce, + result: resp.value.work.result, + time: Math.trunc(resp.value.work.time), + worker_type: resp.value.work.worker_type, + }; + + width = 90; + PROGRESS_FILL.style.width = `${width}%`; + // 3. submit work + const token = await sendWork(proof); + // 4. send token + sendToParent(token); + // 5. mark checkbox checked + CONST.btn().checked = true; + width = 100; + PROGRESS_FILL.style.width = `${width}%`; + CONST.messageText().after(); + LOCK = false; + } + if (resp.type === "progress") { + if (width < 80) { + width = (resp.nonce / max_recorded_nonce) * 100; + PROGRESS_FILL.style.width = `${width}%`; + } + console.log(`received nonce ${resp.nonce}`); + } }; } catch (e) { CONST.messageText().error(); diff --git a/templates/widget/main.scss b/templates/widget/main.scss index 68c029e7..a36a5c26 100644 --- a/templates/widget/main.scss +++ b/templates/widget/main.scss @@ -7,106 +7,138 @@ @import "../reset"; -.widget__contaienr { - align-items: center; - box-sizing: border-box; - display: flex; - height: 100%; +body { + display: flex; + flex-direction: column; + width: 100%; +} + +.widget__container { + align-items: center; + box-sizing: border-box; + display: flex; + flex-direction: column; + height: 100%; + margin: auto 0; +} + +.widget__inner-container { + align-items: center; + box-sizing: border-box; + display: flex; + height: 100%; + width: 100%; } .widget__noscript-container { - display: flex; - font-size: 0.7rem; - line-height: 20px; - flex-direction: column; - padding: 5px; - box-sizing: border-box; - height: 100%; - margin: auto; + display: flex; + font-size: 0.7rem; + line-height: 20px; + flex-direction: column; + padding: 5px; + box-sizing: border-box; + height: 100%; + margin: auto; } .widget__noscript-warning { - display: block; - margin: auto; - flex: 2; - width: 100%; - margin: auto; + display: block; + margin: auto; + flex: 2; + width: 100%; + margin: auto; } .widget__source-code { - display: block; - flex: 1; + display: block; + flex: 1; } .widget__verification-container { - align-items: center; - display: none; - line-height: 30px; - font-size: 1rem; + align-items: center; + display: none; + line-height: 30px; + font-size: 1rem; } .widget__verification-checkbox { - width: 30px; - height: 30px; - margin: 0 10px; + width: 30px; + height: 30px; + margin: 0 10px; } #widget__verification-text--during { - display: none; + display: none; } #widget__verification-text--after { - display: none; - color: green; + display: none; + color: green; } #widget__verification-text--error { - display: none; - color: red; + display: none; + color: red; } .widget__verification-checkbox:checked ~ #widget__verification-text--before { - display: none; + display: none; } .widget__verification-checkbox:checked ~ #widget__verification-text--during { - display: none; + display: none; } .widget__verification-checkbox:checked ~ #widget__verification-text--error { - display: none; + display: none; } .widget__verification-checkbox:checked ~ #widget__verification-text--after { - display: block; + display: block; } .widget__mcaptcha-details { - display: flex; - flex-direction: column; - margin-left: auto; - margin-right: 10px; + display: flex; + flex-direction: column; + margin-left: auto; + margin-right: 10px; } .widget__mcaptcha-brand-name { - font-size: 0.7rem; - font-weight: 600; - margin: auto; - text-align: center; + font-size: 0.7rem; + font-weight: 600; + margin: auto; + text-align: center; } .widget__mcaptcha-logo { - display: block; - width: 35px; - margin: auto; + display: block; + width: 35px; + margin: auto; } .widget__mcaptcha-info-container { - display: flex; - margin: auto; + display: flex; + margin: auto; } .widget__mcaptcha-info-link { - font-size: 0.5rem; - margin: 2px; + font-size: 0.5rem; + margin: 2px; +} + +/* progress bar courtesy of https://codepen.io/Bizzy-Coding/pen/poOymVJ?editors=1111 */ +.progress__bar { + position: relative; + height: 5px; + width: 100%; + background: #fff; + border-radius: 15px; +} + +.progress__fill { + background: #65a2e0; + border-radius: 15px; + height: 100%; + width: 0%; } diff --git a/templates/widget/prove.ts b/templates/widget/prove.ts index 619a80f4..c0576bc4 100644 --- a/templates/widget/prove.ts +++ b/templates/widget/prove.ts @@ -3,7 +3,7 @@ // // SPDX-License-Identifier: MIT OR Apache-2.0 -import { gen_pow } from "@mcaptcha/pow-wasm"; +import { stepped_gen_pow } from "@mcaptcha/pow-wasm"; import * as p from "@mcaptcha/pow_sha256-polyfill"; import { WasmWork, PoWConfig, SubmitWork } from "./types"; @@ -12,19 +12,25 @@ import { WasmWork, PoWConfig, SubmitWork } from "./types"; * @param {PoWConfig} config - the proof-of-work configuration using which * work needs to be computed * */ -const prove = async (config: PoWConfig): Promise => { +const prove = async ( + config: PoWConfig, + progress: (nonce: number) => void +): Promise => { const WASM = "wasm"; const JS = "js"; + const STEPS = 5000; if (WasmSupported) { let proof: WasmWork = null; let res: SubmitWork = null; let time: number = null; const t0 = performance.now(); - const proofString = gen_pow( + const proofString = stepped_gen_pow( config.salt, config.string, - config.difficulty_factor + config.difficulty_factor, + STEPS, + progress ); const t1 = performance.now(); time = t1 - t0; @@ -47,10 +53,12 @@ const prove = async (config: PoWConfig): Promise => { const t0 = performance.now(); - proof = await p.generate_work( + proof = await p.stepped_generate_work( config.salt, config.string, - config.difficulty_factor + config.difficulty_factor, + STEPS, + progress ); const t1 = performance.now(); time = t1 - t0; diff --git a/templates/widget/service-worker.ts b/templates/widget/service-worker.ts index 2672aa15..b8808618 100644 --- a/templates/widget/service-worker.ts +++ b/templates/widget/service-worker.ts @@ -6,17 +6,31 @@ import log from "../logger"; import prove from "./prove"; -import { PoWConfig, ServiceWorkerWork } from "./types"; +import { PoWConfig, ServiceWorkerMessage, ServiceWorkerWork } from "./types"; log.log("worker registered"); onmessage = async (e) => { console.debug("message received at worker"); const config: PoWConfig = e.data; - const work = await prove(config); - const res: ServiceWorkerWork = { + const progressCallback = (nonce: number) => { + const res: ServiceWorkerMessage = { + type: "progress", + nonce: nonce, + }; + + postMessage(res); + }; + + const work = await prove(config, progressCallback); + const w: ServiceWorkerWork = { work, }; + const res: ServiceWorkerMessage = { + type: "work", + value: w, + }; + postMessage(res); }; diff --git a/templates/widget/types.ts b/templates/widget/types.ts index f11777c9..59843596 100644 --- a/templates/widget/types.ts +++ b/templates/widget/types.ts @@ -32,8 +32,13 @@ export type PoWConfig = { string: string; difficulty_factor: number; salt: string; + max_recorded_nonce: number; }; export type Token = { token: string; }; + +export type ServiceWorkerMessage = + | { type: "work"; value: ServiceWorkerWork } + | { type: "progress"; nonce: number }; diff --git a/yarn.lock b/yarn.lock index c6b7caf9..32ff8618 100644 --- a/yarn.lock +++ b/yarn.lock @@ -631,15 +631,15 @@ resolved "https://registry.yarnpkg.com/@mcaptcha/core-glue/-/core-glue-0.1.0-rc1.tgz#76d665a3fc537062061e12e274f969ac3e053685" integrity sha512-P4SgUioJDR38QpnP9sPY72NyaYex8MXD6RbzrfKra+ngamT26XjqVZEHBiZU2RT7u0SsWhuko4N1ntNOghsgpg== -"@mcaptcha/pow-wasm@^0.1.0-rc1": - version "0.1.0-rc1" - resolved "https://registry.yarnpkg.com/@mcaptcha/pow-wasm/-/pow-wasm-0.1.0-rc1.tgz#eef8409e0c74e9c7261587bdebd80a8c4af92f9e" - integrity sha512-7+PGKoe1StFRsa9TEqztzK4/obbdY4OfavFX+geTk8b3K26D+eHPyimJ9BPlpI1VZl8ujR3CnbfbnQSRaqS7ZQ== +"@mcaptcha/pow-wasm@^0.1.0-rc2": + version "0.1.0-rc2" + resolved "https://registry.yarnpkg.com/@mcaptcha/pow-wasm/-/pow-wasm-0.1.0-rc2.tgz#c7aaa678325600a178b11a702e2aeb9f8143e605" + integrity sha512-2G0nQ2GQWECRcE5kzfULDsQ032s6/PDzE1rncMdQAR1Mu2YQfFZHgnX4zLJmQnjKIhy9meIjXvatVSyIllrbtg== -"@mcaptcha/pow_sha256-polyfill@^0.1.0-rc1": - version "0.1.0-rc1" - resolved "https://registry.yarnpkg.com/@mcaptcha/pow_sha256-polyfill/-/pow_sha256-polyfill-0.1.0-rc1.tgz#dfeee88f5f6fd99aeae65dbcff6fbb09fe8a1696" - integrity sha512-OFA4W3/vh8ORUnifbm8c/8eP22CbiXr4Un6/l4fMyqLj1aoQLMGAiuqab0trGqBnY0DU2bwTMyxflx26/cWgIw== +"@mcaptcha/pow_sha256-polyfill@^0.1.0-rc2": + version "0.1.0-rc2" + resolved "https://registry.yarnpkg.com/@mcaptcha/pow_sha256-polyfill/-/pow_sha256-polyfill-0.1.0-rc2.tgz#253320e7a6666e395ef9dfb123d1102066d72b87" + integrity sha512-ERIbxIo+ZnQKtti/T4FLmcY0neuc5R05L97qYc62Hm++i+3dx/W6A8oC4V9U0XKCPYnHZFoZozAZlbsGXjrsVQ== "@mcaptcha/vanilla-glue@^0.1.0-rc1": version "0.1.0-rc1"