@prosopo/procaptcha-frictionless 1.0.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,18 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const types = require("@prosopo/types");
4
- const Api = require("@polkadot/api/promise/Api");
3
+ const string = require("@polkadot/util/string");
5
4
  require("../../../account/dist/index.cjs");
6
- const keyring = require("@polkadot/keyring");
7
- const contract = require("@prosopo/contract");
8
- const common = require("@prosopo/common");
9
5
  const api = require("@prosopo/api");
10
- const ws = require("@polkadot/rpc-provider/ws");
11
- const contractInfo = require("@prosopo/captcha-contract/contract-info");
12
- const procaptchaCommon = require("@prosopo/procaptcha-common");
6
+ const common = require("@prosopo/common");
7
+ const loadBalancer = require("@prosopo/load-balancer");
13
8
  const procaptcha = require("@prosopo/procaptcha");
9
+ const procaptchaCommon = require("@prosopo/procaptcha-common");
10
+ const types = require("@prosopo/types");
14
11
  const util = require("@prosopo/util");
15
12
  const ExtensionWeb2 = require("../../../account/dist/extension/ExtensionWeb2.cjs");
13
+ const ExtensionWeb3 = require("../../../account/dist/extension/ExtensionWeb3.cjs");
16
14
  const Manager = (configInput, state, onStateUpdate, callbacks) => {
17
15
  const events = procaptchaCommon.getDefaultEvents(onStateUpdate, state, callbacks);
18
16
  const defaultState = () => {
@@ -31,39 +29,39 @@ const Manager = (configInput, state, onStateUpdate, callbacks) => {
31
29
  window.clearTimeout(state.timeout);
32
30
  updateState({ timeout: void 0 });
33
31
  };
32
+ const clearSuccessfulChallengeTimeout = () => {
33
+ window.clearTimeout(state.successfullChallengeTimeout);
34
+ updateState({ successfullChallengeTimeout: void 0 });
35
+ };
34
36
  const getConfig = () => {
35
37
  const config = {
36
38
  userAccountAddress: "",
37
39
  ...configInput
38
40
  };
41
+ if (state.account) {
42
+ config.userAccountAddress = state.account.account.address;
43
+ }
39
44
  return types.ProcaptchaConfigSchema.parse(config);
40
45
  };
41
46
  const getNetwork = (config) => {
42
47
  const network = config.networks[config.defaultNetwork];
43
48
  if (!network) {
44
49
  throw new common.ProsopoEnvError("DEVELOPER.NETWORK_NOT_FOUND", {
45
- context: { error: `No network found for environment ${config.defaultEnvironment}` }
50
+ context: {
51
+ error: `No network found for environment ${config.defaultEnvironment}`
52
+ }
46
53
  });
47
54
  }
48
55
  return network;
49
56
  };
50
- const loadContract = async () => {
51
- const network = getNetwork(getConfig());
52
- const api2 = await Api.ApiPromise.create({
53
- provider: new ws.WsProvider(network.endpoint),
54
- initWasm: false,
55
- noInitWarn: true
56
- });
57
- const type = "sr25519";
58
- const keyring$1 = new keyring.Keyring({ type, ss58Format: api2.registry.chainSS58 });
59
- return new contract.ProsopoCaptchaContract(api2, JSON.parse(contractInfo.ContractAbi), network.contract.address, "prosopo", 0, keyring$1.addFromAddress(getConfig().account.address || ""));
60
- };
61
57
  const getAccount = () => {
62
58
  if (!state.account) {
63
- throw new common.ProsopoEnvError("GENERAL.ACCOUNT_NOT_FOUND", { context: { error: "Account not loaded" } });
59
+ throw new common.ProsopoEnvError("GENERAL.ACCOUNT_NOT_FOUND", {
60
+ context: { error: "Account not loaded" }
61
+ });
64
62
  }
65
63
  const account = state.account;
66
- return account;
64
+ return { account };
67
65
  };
68
66
  const getDappAccount = () => {
69
67
  if (!state.dappAccount) {
@@ -75,6 +73,7 @@ const Manager = (configInput, state, onStateUpdate, callbacks) => {
75
73
  const updateState = procaptchaCommon.buildUpdateState(state, onStateUpdate);
76
74
  const resetState = () => {
77
75
  clearTimeout();
76
+ clearSuccessfulChallengeTimeout();
78
77
  updateState(defaultState());
79
78
  };
80
79
  const setValidChallengeTimeout = () => {
@@ -97,7 +96,7 @@ const Manager = (configInput, state, onStateUpdate, callbacks) => {
97
96
  loading: true
98
97
  });
99
98
  const config = getConfig();
100
- const ext = new ExtensionWeb2.ExtensionWeb2();
99
+ const ext = config.web2 ? new ExtensionWeb2.ExtensionWeb2() : new ExtensionWeb3.ExtensionWeb3();
101
100
  const userAccount = config.userAccountAddress || (await ext.getAccount(config)).account.address;
102
101
  updateState({
103
102
  account: { account: { address: userAccount } }
@@ -109,14 +108,27 @@ const Manager = (configInput, state, onStateUpdate, callbacks) => {
109
108
  context: { error: "Account address has not been set for web3 mode" }
110
109
  });
111
110
  }
112
- const contract$1 = await loadContract();
111
+ const getRandomProviderResponse = getRandomActiveProvider();
113
112
  const events2 = procaptchaCommon.getDefaultEvents(onStateUpdate, state, callbacks);
114
- const getRandomProviderResponse = await contract.wrapQuery(contract$1.query.getRandomActiveProvider, contract$1.query)(userAccount, getDappAccount());
115
- const providerUrl = common.trimProviderUrl(getRandomProviderResponse.provider.url.toString());
113
+ const providerUrl = getRandomProviderResponse.provider.url;
116
114
  const providerApi = new api.ProviderApi(getNetwork(getConfig()), providerUrl, getDappAccount());
117
115
  const challenge = await providerApi.getPowCaptchaChallenge(userAccount, getDappAccount());
118
116
  const solution = util.solvePoW(challenge.challenge, challenge.difficulty);
119
- const verifiedSolution = await providerApi.submitPowCaptchaSolution(challenge, getAccount().account.address, getDappAccount(), getRandomProviderResponse, solution, config.captchas.pow.verifiedTimeout);
117
+ const user = await ext.getAccount(getConfig());
118
+ const signer = user.extension?.signer;
119
+ if (!signer || !signer.signRaw) {
120
+ throw new common.ProsopoEnvError("GENERAL.CANT_FIND_KEYRINGPAIR", {
121
+ context: {
122
+ error: "Signer is not defined, cannot sign message to prove account ownership"
123
+ }
124
+ });
125
+ }
126
+ const userTimestampSignature = await signer.signRaw({
127
+ address: userAccount,
128
+ data: string.stringToHex(challenge[types.ApiParams.timestamp].toString()),
129
+ type: "bytes"
130
+ });
131
+ const verifiedSolution = await providerApi.submitPowCaptchaSolution(challenge, getAccount().account.account.address, getDappAccount(), solution, userTimestampSignature.signature.toString(), config.captchas.pow.verifiedTimeout);
120
132
  if (verifiedSolution[types.ApiParams.verified]) {
121
133
  updateState({
122
134
  isHuman: true,
@@ -124,17 +136,40 @@ const Manager = (configInput, state, onStateUpdate, callbacks) => {
124
136
  });
125
137
  events2.onHuman(types.encodeProcaptchaOutput({
126
138
  [types.ApiParams.providerUrl]: providerUrl,
127
- [types.ApiParams.user]: getAccount().account.address,
139
+ [types.ApiParams.user]: getAccount().account.account.address,
128
140
  [types.ApiParams.dapp]: getDappAccount(),
129
141
  [types.ApiParams.challenge]: challenge.challenge,
130
142
  [types.ApiParams.blockNumber]: getRandomProviderResponse.blockNumber,
131
- [types.ApiParams.nonce]: solution
143
+ [types.ApiParams.nonce]: solution,
144
+ [types.ApiParams.timestamp]: challenge.timestamp,
145
+ [types.ApiParams.signature]: {
146
+ [types.ApiParams.provider]: challenge.signature.provider,
147
+ [types.ApiParams.user]: {
148
+ [types.ApiParams.timestamp]: userTimestampSignature.signature.toString()
149
+ }
150
+ }
132
151
  }));
133
152
  setValidChallengeTimeout();
134
153
  }
135
154
  };
155
+ const getRandomActiveProvider = () => {
156
+ const randomIntBetween = (min, max) => Math.floor(Math.random() * (max - min + 1) + min);
157
+ const environment = getConfig().defaultEnvironment;
158
+ const PROVIDERS = loadBalancer.loadBalancer(environment);
159
+ const randomProvderObj = util.at(PROVIDERS, randomIntBetween(0, PROVIDERS.length - 1));
160
+ return {
161
+ providerAccount: randomProvderObj.address,
162
+ provider: {
163
+ url: randomProvderObj.url,
164
+ datasetId: randomProvderObj.datasetId,
165
+ datasetIdContent: randomProvderObj.datasetIdContent
166
+ },
167
+ blockNumber: 0
168
+ };
169
+ };
136
170
  return {
137
- start
171
+ start,
172
+ resetState
138
173
  };
139
174
  };
140
175
  exports.Manager = Manager;
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  const jsxRuntime = require("@emotion/react/jsx-runtime");
3
- const webComponents = require("@prosopo/web-components");
4
- const Manager = require("../Services/Manager.cjs");
5
3
  const procaptchaCommon = require("@prosopo/procaptcha-common");
4
+ const webComponents = require("@prosopo/web-components");
6
5
  const react = require("react");
6
+ const Manager = require("../Services/Manager.cjs");
7
7
  const Procaptcha = (props) => {
8
8
  const config = props.config;
9
9
  const themeColor = config.theme === "light" ? "light" : "dark";
@@ -11,8 +11,24 @@ const Procaptcha = (props) => {
11
11
  const callbacks = props.callbacks || {};
12
12
  const [state, _updateState] = procaptchaCommon.useProcaptcha(react.useState, react.useRef);
13
13
  const updateState = procaptchaCommon.buildUpdateState(state, _updateState);
14
- const manager = Manager.Manager(config, state, updateState, callbacks);
15
- return jsxRuntime.jsx("div", { children: jsxRuntime.jsx("div", { style: { maxWidth: "100%", maxHeight: "100%", overflowX: "auto" }, children: jsxRuntime.jsx(webComponents.ContainerDiv, { children: jsxRuntime.jsx(webComponents.WidthBasedStylesDiv, { children: jsxRuntime.jsxs("div", { style: webComponents.WIDGET_DIMENSIONS, "data-cy": "button-human", children: [" ", jsxRuntime.jsxs("div", { style: {
14
+ const manager = react.useRef(Manager.Manager(config, state, updateState, callbacks));
15
+ const captchaRef = react.useRef(null);
16
+ react.useEffect(() => {
17
+ const element = captchaRef.current;
18
+ if (!element)
19
+ return;
20
+ const form = element.closest("form");
21
+ if (!form)
22
+ return;
23
+ const handleSubmit = () => {
24
+ manager.current.resetState();
25
+ };
26
+ form.addEventListener("submit", handleSubmit);
27
+ return () => {
28
+ form.removeEventListener("submit", handleSubmit);
29
+ };
30
+ }, []);
31
+ return jsxRuntime.jsx("div", { ref: captchaRef, children: jsxRuntime.jsx("div", { style: { maxWidth: "100%", maxHeight: "100%", overflowX: "auto" }, children: jsxRuntime.jsx(webComponents.ContainerDiv, { children: jsxRuntime.jsx(webComponents.WidthBasedStylesDiv, { children: jsxRuntime.jsxs("div", { style: webComponents.WIDGET_DIMENSIONS, "data-cy": "button-human", children: [" ", jsxRuntime.jsxs("div", { style: {
16
32
  padding: webComponents.WIDGET_PADDING,
17
33
  border: webComponents.WIDGET_BORDER,
18
34
  backgroundColor: theme.palette.background.default,
@@ -37,6 +53,6 @@ const Procaptcha = (props) => {
37
53
  verticalAlign: "middle"
38
54
  }, children: jsxRuntime.jsx("div", { style: {
39
55
  display: "flex"
40
- }, children: jsxRuntime.jsx("div", { style: { flex: 1 }, children: state.loading ? jsxRuntime.jsx(webComponents.LoadingSpinner, { themeColor, "aria-label": "Loading spinner" }) : jsxRuntime.jsx(webComponents.Checkbox, { checked: state.isHuman, onChange: manager.start, themeColor, labelText: "I am human", "aria-label": "human checkbox" }) }) }) }) }) }), jsxRuntime.jsx("div", { style: { display: "inline-flex", flexDirection: "column" }, children: jsxRuntime.jsx("a", { href: webComponents.WIDGET_URL, target: "_blank", "aria-label": webComponents.WIDGET_URL_TEXT, children: jsxRuntime.jsx("div", { style: { flex: 1 }, children: jsxRuntime.jsx(webComponents.Logo, { themeColor, "aria-label": "Prosopo logo" }) }) }) })] })] }) }) }) }) });
56
+ }, children: jsxRuntime.jsx("div", { style: { flex: 1 }, children: state.loading ? jsxRuntime.jsx(webComponents.LoadingSpinner, { themeColor, "aria-label": "Loading spinner" }) : jsxRuntime.jsx(webComponents.Checkbox, { checked: state.isHuman, onChange: manager.current.start, themeColor, labelText: "I am human", "aria-label": "human checkbox" }) }) }) }) }) }), jsxRuntime.jsx("div", { style: { display: "inline-flex", flexDirection: "column" }, children: jsxRuntime.jsx("a", { href: webComponents.WIDGET_URL, target: "_blank", "aria-label": webComponents.WIDGET_URL_TEXT, rel: "noreferrer", children: jsxRuntime.jsx("div", { style: { flex: 1 }, children: jsxRuntime.jsx(webComponents.Logo, { themeColor, "aria-label": "Prosopo logo" }) }) }) })] })] }) }) }) }) });
41
57
  };
42
58
  module.exports = Procaptcha;
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const jsxRuntime = require("@emotion/react/jsx-runtime");
4
- const react = require("react");
5
4
  const webComponents = require("@prosopo/web-components");
5
+ const react = require("react");
6
6
  const _interopNamespaceDefaultOnly = (e) => Object.freeze(Object.defineProperty({ __proto__: null, default: e }, Symbol.toStringTag, { value: "Module" }));
7
7
  const ProcaptchaWidget = react.lazy(async () => Promise.resolve().then(() => /* @__PURE__ */ _interopNamespaceDefaultOnly(require("./Captcha.cjs"))));
8
8
  const ProcaptchaPow = (props) => jsxRuntime.jsx(react.Suspense, { fallback: jsxRuntime.jsx(webComponents.ProcaptchaPlaceholder, { darkMode: props.config.theme }), children: jsxRuntime.jsx(ProcaptchaWidget, { config: props.config, callbacks: props.callbacks }) });
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export * from './ProcaptchaFrictionless.js';
1
+ export * from "./ProcaptchaFrictionless.js";
2
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,cAAc,6BAA6B,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,cAAc,6BAA6B,CAAC"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export * from './ProcaptchaFrictionless.js';
1
+ export * from "./ProcaptchaFrictionless.js";
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,cAAc,6BAA6B,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,cAAc,6BAA6B,CAAC"}
package/package.json CHANGED
@@ -1,60 +1,53 @@
1
1
  {
2
- "name": "@prosopo/procaptcha-frictionless",
3
- "version": "1.0.2",
4
- "author": "PROSOPO LIMITED <info@prosopo.io>",
5
- "license": "Apache-2.0",
6
- "main": "./dist/index.js",
7
- "type": "module",
8
- "sideEffects": false,
9
- "engines": {
10
- "node": ">=20",
11
- "npm": ">=9"
12
- },
13
- "exports": {
14
- ".": {
15
- "import": "./dist/index.js",
16
- "require": "./dist/cjs/index.cjs"
17
- }
18
- },
19
- "types": "./dist/index.d.ts",
20
- "source": "./src/index.ts",
21
- "scripts": {
22
- "test": "echo \"No test specified\"",
23
- "clean": "tsc --build --clean",
24
- "build": "tsc --build --verbose tsconfig.json",
25
- "build:cjs": "npx vite --config vite.cjs.config.ts build",
26
- "eslint": "npx eslint . --cache --cache-location ../../node_modules/.cache/eslint/.eslintcache --no-error-on-unmatched-pattern --ignore-path ../../.eslintignore --quiet",
27
- "eslint:fix": "npm run eslint -- --fix",
28
- "prettier": "npx prettier . --cache --cache-location ../../node_modules/.cache/prettier/.prettiercache --check --no-error-on-unmatched-pattern --ignore-path ../../.eslintignore",
29
- "prettier:fix": "npm run prettier -- --write",
30
- "lint": "npm run eslint && npm run prettier",
31
- "lint:fix": "npm run eslint:fix && npm run prettier:fix"
32
- },
33
- "browserslist": [
34
- "> 0.5%, last 2 versions, not dead"
35
- ],
36
- "dependencies": {
37
- "@fingerprintjs/botd": "^1.9.0",
38
- "@prosopo/procaptcha-pow": "1.0.2",
39
- "@prosopo/procaptcha-react": "1.0.2",
40
- "@prosopo/types": "1.0.2",
41
- "@prosopo/web-components": "1.0.2",
42
- "react": "^18.3.1"
43
- },
44
- "devDependencies": {
45
- "tslib": "2.6.2",
46
- "typescript": "5.1.6"
47
- },
48
- "repository": {
49
- "type": "git",
50
- "url": "git+https://github.com/prosopo/captcha.git"
51
- },
52
- "bugs": {
53
- "url": "https://github.com/prosopo/captcha/issues"
54
- },
55
- "homepage": "https://github.com/prosopo/captcha#readme",
56
- "description": "",
57
- "publishConfig": {
58
- "registry": "https://registry.npmjs.org"
59
- }
2
+ "name": "@prosopo/procaptcha-frictionless",
3
+ "version": "2.0.0",
4
+ "author": "PROSOPO LIMITED <info@prosopo.io>",
5
+ "license": "Apache-2.0",
6
+ "main": "./dist/index.js",
7
+ "type": "module",
8
+ "sideEffects": false,
9
+ "engines": {
10
+ "node": ">=20",
11
+ "npm": ">=9"
12
+ },
13
+ "exports": {
14
+ ".": {
15
+ "import": "./dist/index.js",
16
+ "require": "./dist/cjs/index.cjs"
17
+ }
18
+ },
19
+ "types": "./dist/index.d.ts",
20
+ "source": "./src/index.ts",
21
+ "scripts": {
22
+ "test": "echo \"No test specified\"",
23
+ "clean": "tsc --build --clean",
24
+ "build": "tsc --build --verbose",
25
+ "build:cjs": "npx vite --config vite.cjs.config.ts build"
26
+ },
27
+ "browserslist": ["> 0.5%, last 2 versions, not dead"],
28
+ "dependencies": {
29
+ "@prosopo/detector": "2.0.0",
30
+ "@prosopo/procaptcha-pow": "2.0.0",
31
+ "@prosopo/procaptcha-react": "2.0.0",
32
+ "@prosopo/types": "2.0.0",
33
+ "@prosopo/web-components": "2.0.0",
34
+ "react": "^18.3.1"
35
+ },
36
+ "devDependencies": {
37
+ "@prosopo/config": "2.0.0",
38
+ "tslib": "2.6.2",
39
+ "typescript": "5.1.6"
40
+ },
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "git+https://github.com/prosopo/captcha.git"
44
+ },
45
+ "bugs": {
46
+ "url": "https://github.com/prosopo/captcha/issues"
47
+ },
48
+ "homepage": "https://github.com/prosopo/captcha#readme",
49
+ "description": "",
50
+ "publishConfig": {
51
+ "registry": "https://registry.npmjs.org"
52
+ }
60
53
  }
@@ -1,3 +1,4 @@
1
+ import path from "node:path";
1
2
  // Copyright 2021-2024 Prosopo (UK) Ltd.
2
3
  //
3
4
  // Licensed under the Apache License, Version 2.0 (the "License");
@@ -11,9 +12,11 @@
11
12
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
13
  // See the License for the specific language governing permissions and
13
14
  // limitations under the License.
14
- import { ViteCommonJSConfig } from '@prosopo/config'
15
- import path from 'path'
15
+ import { ViteCommonJSConfig } from "@prosopo/config";
16
16
 
17
17
  export default function () {
18
- return ViteCommonJSConfig('procaptcha-frictionless', path.resolve('./tsconfig.cjs.json'))
18
+ return ViteCommonJSConfig(
19
+ "procaptcha-frictionless",
20
+ path.resolve("./tsconfig.cjs.json"),
21
+ );
19
22
  }