@myrasec/eu-captcha-vue 0.0.1 → 0.0.3
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.
- package/README.md +76 -23
- package/dist/eu-captcha-vue.js +56 -43
- package/dist/eu-captcha-vue.umd.cjs +1 -1
- package/package.json +1 -1
- package/publish.sh +5 -0
package/README.md
CHANGED
|
@@ -1,35 +1,88 @@
|
|
|
1
|
-
This package provides an easy integration of Myra Security
|
|
1
|
+
This package provides an easy integration of EU CAPTCHA from Myra Security for Vue 3 and Nuxt.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
For full documentation see **[docs.eu-captcha.eu](https://docs.eu-captcha.eu/)**. [Sign up for free](https://app.eu-captcha.eu/user-registration).
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
```bash
|
|
8
|
+
npm i @myrasec/eu-captcha-vue
|
|
9
|
+
```
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
## Basic usage
|
|
10
12
|
|
|
11
|
-
```
|
|
13
|
+
```vue
|
|
14
|
+
<script setup>
|
|
12
15
|
import { EuCaptcha, isEuCaptchaDone } from "@myrasec/eu-captcha-vue";
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
const captchaSitekey = "EUCAPTCHA_SITE_KEY";
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<form @submit.prevent="handleSubmit">
|
|
22
|
+
<!-- your fields -->
|
|
23
|
+
<EuCaptcha :sitekey="captchaSitekey" />
|
|
24
|
+
<button type="submit">Submit</button>
|
|
25
|
+
</form>
|
|
26
|
+
</template>
|
|
16
27
|
```
|
|
17
28
|
|
|
18
|
-
|
|
29
|
+
You can test the integration using any fake sitekey. If a sitekey does not exist, the captcha runs with default parameters which allow traffic to pass.
|
|
30
|
+
|
|
31
|
+
## Props
|
|
32
|
+
|
|
33
|
+
| Prop | Type | Default | Description |
|
|
34
|
+
|---|---|---|---|
|
|
35
|
+
| `sitekey` | `string` | — | Your public sitekey (required) |
|
|
36
|
+
| `theme` | `string` | `"light"` | Visual theme: `"light"` or `"dark"` |
|
|
37
|
+
| `width` | `number` | `330` | Widget width in pixels |
|
|
38
|
+
| `widgetId` | `string` | — | Custom widget ID. If omitted, an ID is auto-generated. Needed when calling `euCaptcha.execute()`. |
|
|
39
|
+
| `autostart` | `boolean` | `true` | Start the challenge automatically on mount. Set to `false` to defer until `euCaptcha.execute(widgetId)` is called. |
|
|
40
|
+
| `onComplete` | `(token: string) => void` | — | Called with the encoded token when the challenge completes. |
|
|
41
|
+
| `onExpired` | `() => void` | — | Called when the token expires (60 minutes after completion). |
|
|
42
|
+
| `onError` | `() => void` | — | Called when the challenge fails due to a network or server error. |
|
|
19
43
|
|
|
44
|
+
## Dark theme
|
|
45
|
+
|
|
46
|
+
```vue
|
|
47
|
+
<EuCaptcha :sitekey="captchaSitekey" theme="dark" />
|
|
20
48
|
```
|
|
21
|
-
|
|
49
|
+
|
|
50
|
+
## Custom width
|
|
51
|
+
|
|
52
|
+
```vue
|
|
53
|
+
<EuCaptcha :sitekey="captchaSitekey" :width="280" />
|
|
22
54
|
```
|
|
23
55
|
|
|
24
|
-
|
|
25
|
-
does not exist, then the captcha runs with default parameters which
|
|
26
|
-
allow traffic to pass.
|
|
56
|
+
## Deferred execution
|
|
27
57
|
|
|
28
|
-
|
|
58
|
+
Set `:autostart="false"` and provide a `widgetId`, then trigger the challenge manually:
|
|
29
59
|
|
|
30
|
-
|
|
60
|
+
```vue
|
|
61
|
+
<EuCaptcha
|
|
62
|
+
:sitekey="captchaSitekey"
|
|
63
|
+
widget-id="my-captcha"
|
|
64
|
+
:autostart="false"
|
|
65
|
+
/>
|
|
31
66
|
|
|
67
|
+
<button @click="euCaptcha.execute('my-captcha')">Verify</button>
|
|
32
68
|
```
|
|
69
|
+
|
|
70
|
+
## Callbacks
|
|
71
|
+
|
|
72
|
+
```vue
|
|
73
|
+
<EuCaptcha
|
|
74
|
+
:sitekey="captchaSitekey"
|
|
75
|
+
:on-complete="(token) => console.log('token:', token)"
|
|
76
|
+
:on-expired="() => console.log('token expired')"
|
|
77
|
+
:on-error="() => console.log('challenge error')"
|
|
78
|
+
/>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Querying state
|
|
82
|
+
|
|
83
|
+
Before submitting a form to a server, ensure EU CAPTCHA is done:
|
|
84
|
+
|
|
85
|
+
```js
|
|
33
86
|
import { isEuCaptchaDone } from "@myrasec/eu-captcha-vue";
|
|
34
87
|
|
|
35
88
|
function onSubmit(e) {
|
|
@@ -37,7 +90,6 @@ function onSubmit(e) {
|
|
|
37
90
|
|
|
38
91
|
if (!isEuCaptchaDone()) {
|
|
39
92
|
// computation has not been completed
|
|
40
|
-
|
|
41
93
|
return;
|
|
42
94
|
}
|
|
43
95
|
}
|
|
@@ -45,16 +97,17 @@ function onSubmit(e) {
|
|
|
45
97
|
|
|
46
98
|
## Listening to state change
|
|
47
99
|
|
|
48
|
-
|
|
49
|
-
set to 'euCaptchaDone', in case you want to be informed actively to change
|
|
50
|
-
e.g. the state of a button.
|
|
100
|
+
Listen for the `euCaptchaDone` window message to be notified when the challenge completes:
|
|
51
101
|
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
102
|
+
```js
|
|
103
|
+
import { onMounted, onUnmounted } from "vue";
|
|
104
|
+
|
|
105
|
+
function listenForCaptchaDone(msg) {
|
|
106
|
+
if (msg.data.type === "euCaptchaDone") {
|
|
107
|
+
// enable submit button, update reactive state, etc.
|
|
56
108
|
}
|
|
57
109
|
}
|
|
58
110
|
|
|
59
|
-
window.addEventListener("message", listenForCaptchaDone, false);
|
|
111
|
+
onMounted(() => window.addEventListener("message", listenForCaptchaDone, false));
|
|
112
|
+
onUnmounted(() => window.removeEventListener("message", listenForCaptchaDone, false));
|
|
60
113
|
```
|
package/dist/eu-captcha-vue.js
CHANGED
|
@@ -1,70 +1,83 @@
|
|
|
1
|
-
import { ref as
|
|
2
|
-
let
|
|
1
|
+
import { ref as E, createElementBlock as C, openBlock as p } from "vue";
|
|
2
|
+
let r = {
|
|
3
3
|
sitekey: "-",
|
|
4
4
|
locale: "",
|
|
5
|
-
theme: "light"
|
|
6
|
-
|
|
5
|
+
theme: "light",
|
|
6
|
+
width: 330
|
|
7
|
+
}, f = {
|
|
7
8
|
done: !1,
|
|
8
9
|
registered: !1
|
|
9
|
-
},
|
|
10
|
-
function
|
|
11
|
-
return typeof window > "u" ? Promise.reject("Cannot load script on server") :
|
|
10
|
+
}, l = null;
|
|
11
|
+
function k(e) {
|
|
12
|
+
return typeof window > "u" ? Promise.reject("Cannot load script on server") : l || (l = new Promise((t, i) => {
|
|
12
13
|
if (document.querySelector(`script[src="${e}"]`)) {
|
|
13
14
|
t();
|
|
14
15
|
return;
|
|
15
16
|
}
|
|
16
17
|
const n = document.createElement("script");
|
|
17
|
-
n.src = e, n.async = !0, n.onload = () => t(), n.onerror = () =>
|
|
18
|
-
}),
|
|
18
|
+
n.src = e, n.async = !0, n.onload = () => t(), n.onerror = () => i(new Error(`Failed to load ${e}`)), document.head.appendChild(n);
|
|
19
|
+
}), l);
|
|
19
20
|
}
|
|
20
|
-
function
|
|
21
|
-
e.data.type === "euCaptchaCompleted" && (
|
|
21
|
+
function _(e) {
|
|
22
|
+
e.data.type === "euCaptchaCompleted" && (f.done = !0);
|
|
22
23
|
}
|
|
23
|
-
function
|
|
24
|
-
return
|
|
24
|
+
function S() {
|
|
25
|
+
return f.done;
|
|
25
26
|
}
|
|
26
|
-
function
|
|
27
|
-
e = e || {}, typeof e.sitekey == "string" && (
|
|
28
|
-
|
|
29
|
-
}).catch((
|
|
30
|
-
console.error("error during load of eu captcha library: " +
|
|
27
|
+
function v(e, t) {
|
|
28
|
+
e = e || {}, typeof e.sitekey == "string" && (r.sitekey = e.sitekey), typeof e.locale == "string" && (r.locale = e.locale), typeof e.theme == "string" && (r.theme = e.theme), typeof e.width == "number" && (r.width = e.width), k("https://cdn.eu-captcha.eu/verify.js").then(() => {
|
|
29
|
+
f.registered || (f.registered = !0, window.addEventListener("message", _, !1)), t && t();
|
|
30
|
+
}).catch((i) => {
|
|
31
|
+
console.error("error during load of eu captcha library: " + i);
|
|
31
32
|
});
|
|
32
33
|
}
|
|
33
|
-
let c = null,
|
|
34
|
-
const
|
|
35
|
-
function
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
let m = null, h = null, w = null, c = null, y = !0, a = null, d = null, u = null, o = null;
|
|
35
|
+
const g = E("");
|
|
36
|
+
function x() {
|
|
37
|
+
g.value = window.getEuCaptchaElement(
|
|
38
|
+
m ?? r.sitekey,
|
|
39
|
+
h ?? r.theme,
|
|
40
|
+
w ?? r.width,
|
|
41
|
+
c ?? void 0,
|
|
42
|
+
y
|
|
39
43
|
);
|
|
40
44
|
}
|
|
41
|
-
const
|
|
42
|
-
props: ["sitekey", "theme"],
|
|
45
|
+
const b = {
|
|
46
|
+
props: ["sitekey", "theme", "width", "widgetId", "autostart", "onComplete", "onExpired", "onError"],
|
|
43
47
|
setup(e) {
|
|
44
|
-
e.sitekey && (
|
|
48
|
+
e.sitekey && (m = e.sitekey), e.theme && (h = e.theme), e.width && (w = e.width), e.widgetId && (c = e.widgetId), typeof e.autostart == "boolean" && (y = e.autostart), e.onComplete && (a = e.onComplete), e.onExpired && (d = e.onExpired), e.onError && (u = e.onError);
|
|
45
49
|
},
|
|
46
50
|
data() {
|
|
47
|
-
return
|
|
48
|
-
htmlContent:
|
|
51
|
+
return v(null, x), {
|
|
52
|
+
htmlContent: g
|
|
49
53
|
};
|
|
54
|
+
},
|
|
55
|
+
mounted() {
|
|
56
|
+
!a && !d && !u || (o = (e) => {
|
|
57
|
+
const t = e.data ?? {};
|
|
58
|
+
c && t.widgetId !== c || (t.type === "euCaptchaCompleted" && a && a(t.payload ?? ""), t.type === "euCaptchaExpired" && d && d(), t.type === "euCaptchaError" && u && u());
|
|
59
|
+
}, window.addEventListener("message", o, !1));
|
|
60
|
+
},
|
|
61
|
+
unmounted() {
|
|
62
|
+
o && (window.removeEventListener("message", o, !1), o = null);
|
|
50
63
|
}
|
|
51
|
-
},
|
|
52
|
-
const
|
|
53
|
-
for (const [n,
|
|
54
|
-
|
|
55
|
-
return
|
|
56
|
-
},
|
|
57
|
-
function
|
|
58
|
-
return
|
|
64
|
+
}, L = (e, t) => {
|
|
65
|
+
const i = e.__vccOpts || e;
|
|
66
|
+
for (const [n, s] of t)
|
|
67
|
+
i[n] = s;
|
|
68
|
+
return i;
|
|
69
|
+
}, I = ["innerHTML"];
|
|
70
|
+
function $(e, t, i, n, s, M) {
|
|
71
|
+
return p(), C("div", { innerHTML: s.htmlContent }, null, 8, I);
|
|
59
72
|
}
|
|
60
|
-
const
|
|
73
|
+
const H = /* @__PURE__ */ L(b, [["render", $]]), j = {
|
|
61
74
|
install: (e) => {
|
|
62
|
-
e.component("b-upload-files-modal",
|
|
75
|
+
e.component("b-upload-files-modal", H);
|
|
63
76
|
}
|
|
64
77
|
};
|
|
65
78
|
export {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
79
|
+
H as EuCaptcha,
|
|
80
|
+
j as default,
|
|
81
|
+
S as isEuCaptchaDone,
|
|
82
|
+
v as loadEuCaptcha
|
|
70
83
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(n,o){typeof exports=="object"&&typeof module<"u"?o(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],o):(n=typeof globalThis<"u"?globalThis:n||self,o(n["@myra/eu-captcha-vue"]={},n.Vue))})(this,(function(n,o){"use strict";let r={sitekey:"-",locale:"",theme:"light",width:330},d={done:!1,registered:!1},u=null;function _(e){return typeof window>"u"?Promise.reject("Cannot load script on server"):u||(u=new Promise((t,l)=>{if(document.querySelector(`script[src="${e}"]`)){t();return}const i=document.createElement("script");i.src=e,i.async=!0,i.onload=()=>t(),i.onerror=()=>l(new Error(`Failed to load ${e}`)),document.head.appendChild(i)}),u)}function k(e){e.data.type==="euCaptchaCompleted"&&(d.done=!0)}function b(){return d.done}function y(e,t){e=e||{},typeof e.sitekey=="string"&&(r.sitekey=e.sitekey),typeof e.locale=="string"&&(r.locale=e.locale),typeof e.theme=="string"&&(r.theme=e.theme),typeof e.width=="number"&&(r.width=e.width),_("https://cdn.eu-captcha.eu/verify.js").then(()=>{d.registered||(d.registered=!0,window.addEventListener("message",k,!1)),t&&t()}).catch(l=>{console.error("error during load of eu captcha library: "+l)})}let w=null,E=null,g=null,c=null,p=!0,f=null,s=null,h=null,a=null;const C=o.ref("");function x(){C.value=window.getEuCaptchaElement(w??r.sitekey,E??r.theme,g??r.width,c??void 0,p)}const L={props:["sitekey","theme","width","widgetId","autostart","onComplete","onExpired","onError"],setup(e){e.sitekey&&(w=e.sitekey),e.theme&&(E=e.theme),e.width&&(g=e.width),e.widgetId&&(c=e.widgetId),typeof e.autostart=="boolean"&&(p=e.autostart),e.onComplete&&(f=e.onComplete),e.onExpired&&(s=e.onExpired),e.onError&&(h=e.onError)},data(){return y(null,x),{htmlContent:C}},mounted(){!f&&!s&&!h||(a=e=>{const t=e.data??{};c&&t.widgetId!==c||(t.type==="euCaptchaCompleted"&&f&&f(t.payload??""),t.type==="euCaptchaExpired"&&s&&s(),t.type==="euCaptchaError"&&h&&h())},window.addEventListener("message",a,!1))},unmounted(){a&&(window.removeEventListener("message",a,!1),a=null)}},I=(e,t)=>{const l=e.__vccOpts||e;for(const[i,m]of t)l[i]=m;return l},M=["innerHTML"];function S(e,t,l,i,m,$){return o.openBlock(),o.createElementBlock("div",{innerHTML:m.htmlContent},null,8,M)}const v=I(L,[["render",S]]),T={install:e=>{e.component("b-upload-files-modal",v)}};n.EuCaptcha=v,n.default=T,n.isEuCaptchaDone=b,n.loadEuCaptcha=y,Object.defineProperties(n,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
|
package/package.json
CHANGED