recaptcha

package module
v0.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 3, 2026 License: MIT Imports: 13 Imported by: 0

README

reCAPTCHA

An xpb plugin for Pocketbase that allows for the use of reCAPTCHA.

Provides an api endpoint for verifying reCAPTCHA responses, as well as a way to configure requiring reCAPTCHA for record request actions on designated collections.

Installation

Option 1: Download a build from PocketBuilds

Plugin Page

Option 2: Use the xpb builder
  1. Install XPB.
  2. Use the builder:
xpb build --with github.com/pocketbuilds/recaptcha@latest

Setup

Follow the guide here to setup your reCAPTCHA and get a secret and site key.

Endpoint

<script src="https://www.google.com/recaptcha/api.js?render=YOUR_SITE_KEY"></script>

<button id="recaptcha">Submit</button>

<script type="module">
  import PocketBase from '/js/pocketbase.es.mjs';
  
  const client = new PocketBase("http://localhost:8090");
  const siteKey = "YOUR_SITE_KEY";
  
  document.getElementById("recaptcha").addEventListener("click", onClick);
  
  async function onClick(e) {
    e.preventDefault();
    grecaptcha.ready(async function() {
      const token = await grecaptcha.execute(siteKey, {action: "submit"});
      const res = await client.send("/recaptcha", {
        method: "POST",
        body:   JSON.stringify({token: token}),
      });
      console.log(res);
    });
  }
</script>

Record Request Hooks

<script src="https://www.google.com/recaptcha/api.js?render=YOUR_SITE_KEY"></script>
<form id="example-form">
  <div class="form-field">
    <label for="email">Email</label>
    <input name="email" type="email" />
  </div>
  <div class="form-field">
    <label for="password">Password</label>
    <input name="password" type="password" />
  </div>
  <div class="form-field">
    <label for="passwordConfirm">PasswordConfirm</label>
    <input name="passwordConfirm" type="password" />
  </div>
  <button>Submit</button>
</form>
<script type="module">
  import PocketBase from '/js/pocketbase.es.mjs';
  
  const client = new PocketBase("http://localhost:8090");
  const siteKey = "YOUR_SITE_KEY";
  
  document.getElementById("example-form").addEventListener("submit", onSubmit);
  
  async function onSubmit(e) {
    e.preventDefault();
    const data = new FormData(e.target);
    grecaptcha.ready(async function() {
      const token = await grecaptcha.execute(siteKey, {action: "submit"});
      await client.collection("users").create(data, {
        headers: {
          "Recaptcha-Token": token,
        },
      });
    });
  }
</script>

Server Side Usage

Go
import "github.com/pocketbuilds/recaptcha"

// manual use of VerifyRecaptcha
result, err := recaptcha.VerifyRecaptcha(&RecaptchaVerifyParams{
    RemoteIp: e.RemoteIP(),
    Token:    body.Token,
})

// OnRecpatchaVerify hook
recaptcha.OnRecaptchaVerify().BindFunc(
    func(e *recaptcha.RecaptchaVerifyEvent) error {
        // do somthing before verify
        if err := e.Next(); err != nil {
            return err
        }
        // do somthing after verify
        return nil
    },
)
JS
// manual use of VerifyRecaptcha
let result = recaptcha.verifyRecaptcha({token: body.token});

// onRecpatchaVerify hook
recaptcha.onRecaptchaVerify(e => {
  // do somthing before verify
  e.next();
  // do somthing after verify
});

Plugin Config

[recaptcha]
secret = ""
[recaptcha.endpoint]
# Enable or disable the recaptcha endpoint feature.
# - default: false (feature is enabled)
disabled = false
uri = "/recaptcha"
[recaptcha.record_request_hooks]
# Enable or disable the record request hooks feature.
# - default: false (feature is enabled)
disabled = false
# Array of collections that will require recaptcha verification,
#   and which record request events will require it.
[[recaptcha.record_request_hooks.collections]]
# Name of the collection you want recaptcha verification checks for.
# - required
collection_name = "users"
# Array of record request events that will require recaptcha verification.
# - options: "create", "update", "delete", "view", "list"
events = ["create", "update", "delete", "view", "list"]

Documentation

Index

Constants

View Source
const DefaultRecaptchaVerifyUrl = "https://www.google.com/recaptcha/api/siteverify"

Variables

This section is empty.

Functions

func OnRecaptchaVerify

func OnRecaptchaVerify() *hook.Hook[*RecaptchaVerifyEvent]

func RecaptchaEndpointHandler

func RecaptchaEndpointHandler(params *RecaptchaEndpointHandlerParams) apis.HandleFunc

func RecordListRequestHandlerFunc

func RecordListRequestHandlerFunc(params *RequestHandlerParams) func(*core.RecordsListRequestEvent) error

func RecordRequestHandlerFunc

func RecordRequestHandlerFunc(params *RequestHandlerParams) func(*core.RecordRequestEvent) error

Types

type EndpointConfig

type EndpointConfig struct {
	// Defaults to false, meaning feature will be enabled.
	Disabled bool `json:"disabled"`
	// Defaults to /recaptcha
	Uri string `json:"uri"` // TODO: consider renaming and change in readme if you do
}

type Plugin

type Plugin struct {
	EndpointConfig           *EndpointConfig           `json:"endpoint"`
	RecordRequestHooksConfig *RecordRequestHooksConfig `json:"record_request_hooks"`
	// Can be set using an environment variable XPB__RECAPTCHA__SECRET
	Secret string `json:"secret" env:"SECRET"`
}

func (*Plugin) Description

func (p *Plugin) Description() string

Description implements xpb.Plugin.Description interface method.

func (*Plugin) Init

func (p *Plugin) Init(app core.App) error

Init implements xpb.Plugin.Init interface method.

func (*Plugin) Name

func (p *Plugin) Name() string

Name implements xpb.Plugin.Name interface method.

func (*Plugin) Validate

func (p *Plugin) Validate() error

Validate implements validation.Validatable.Validate interface method.

func (*Plugin) Version

func (p *Plugin) Version() string

Version implements xpb.Plugin.Version interface method.

type RecaptchaEndpointHandlerParams

type RecaptchaEndpointHandlerParams struct {
	Secret string
}

type RecaptchaEndpointRequestBody

type RecaptchaEndpointRequestBody struct {
	Token string `form:"token" json:"token"`
}

type RecaptchaVerifyEvent

type RecaptchaVerifyEvent struct {
	hook.Event

	RemoteIp  string
	Secret    string
	Token     string
	VerifyUrl string

	Result *RecaptchaVerifyResult
}

type RecaptchaVerifyParams

type RecaptchaVerifyParams struct {
	RemoteIp  string `json:"remoteIp"`
	Secret    string `json:"secret"`
	Token     string `json:"token"`
	VerifyUrl string `json:"verifyUrl"`
}

func (*RecaptchaVerifyParams) Validate

func (params *RecaptchaVerifyParams) Validate() error

type RecaptchaVerifyResult

type RecaptchaVerifyResult struct {
	Success bool    `json:"success"`
	Score   float64 `json:"score"`
}

func VerifyRecaptcha

func VerifyRecaptcha(params *RecaptchaVerifyParams) (*RecaptchaVerifyResult, error)

type RecordRequestHooksCollectionConfig

type RecordRequestHooksCollectionConfig struct {
	CollectionName string   `json:"collection_name"`
	Events         []string `json:"events"`
}

func (*RecordRequestHooksCollectionConfig) Validate

Validate implements validation.Validatable.Validate interface method.

type RecordRequestHooksConfig

type RecordRequestHooksConfig struct {
	// Defaults to false, meaning feature will be enabled.
	Disabled bool `json:"disabled"`
	// Defaults to "Recaptcha-Token"
	TokenHeaderKey string                                `json:"token_header_key"`
	Collections    []*RecordRequestHooksCollectionConfig `json:"collections"`
}

func (*RecordRequestHooksConfig) Validate

func (c *RecordRequestHooksConfig) Validate() error

Validate implements validation.Validatable.Validate interface method.

type RequestHandlerParams

type RequestHandlerParams struct {
	Secret         string
	TokenHeaderKey string
}

type VerificationError

type VerificationError string
const (
	ErrMissingInputSecret   VerificationError = "missing-input-secret"
	ErrInvalidInputSecret   VerificationError = "invalid-input-secret"
	ErrMissingInputResponse VerificationError = "missing-input-response"
	ErrInvalidInputResponse VerificationError = "invalid-input-response"
	ErrBadRequest           VerificationError = "bad-request"
	ErrTimoutOrDuplicate    VerificationError = "timeout-or-duplicate"
)

func (VerificationError) Code

func (err VerificationError) Code() string

func (VerificationError) Error

func (err VerificationError) Error() string

func (*VerificationError) UnmarshalJSON

func (errPtr *VerificationError) UnmarshalJSON(data []byte) error

grecaptcha seems to only ever return one error despite the api suggesting multiple, so to simplify things we reducing it to a single error.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL