Categorygithub.com/forthxu/base64Captcha
modulepackage
1.3.7
Repository: https://github.com/forthxu/base64captcha.git
Documentation: pkg.go.dev

# README

A flexible and various captcha package

Test Go Report Card GoDoc Build Status codecov stability-stable Foundation

Base64captcha supports any unicode character and can easily be customized to support Math Chinese Korean Japanese Russian Arabic etc.

1. πŸ“–πŸ“–πŸ“– Doc & Demo

2. πŸš€πŸš€πŸš€ Quick start

2.1 🎬🎬🎬 Use history version

Tag v1.2.2

go get github.com/forthxu/[email protected]

or edit your go.mod file to

github.com/forthxu/[email protected]

2.2 πŸ“₯πŸ“₯πŸ“₯ Download package

go get -u github.com/forthxu/base64Captcha

For Gopher from mainland China without VPN go get golang.org/x/image failure solution:

  • go version > 1.11
  • set env GOPROXY=https://goproxy.io

2.3 πŸ‚πŸ‚πŸ‚ How to code with base64Captcha

2.3.1 πŸ‡πŸ‡πŸ‡ Implement Store interface or use build-in memory store

type Store interface {
	// Set sets the digits for the captcha id.
	Set(id string, value string)

	// Get returns stored digits for the captcha id. Clear indicates
	// whether the captcha must be deleted from the store.
	Get(id string, clear bool) string
	
    //Verify captcha's answer directly
	Verify(id, answer string, clear bool) bool
}

2.3.2 πŸ„πŸ„πŸ„ Implement Driver interface or use one of build-in drivers

There are some build-in drivers:

  1. Build-in Driver Digit
  2. Build-in Driver String
  3. Build-in Driver Math
  4. Build-in Driver Chinese
// Driver captcha interface for captcha engine to to write staff
type Driver interface {
	//DrawCaptcha draws binary item
	DrawCaptcha(content string) (item Item, err error)
	//GenerateIdQuestionAnswer creates rand id, content and answer
	GenerateIdQuestionAnswer(key string) (id, q, a string)
}

2.3.3 🚴🚴🚴 ‍Core code captcha.go

captcha.go is the entry of base64Captcha which is quite simple.

package base64Captcha

import (
	"math/rand"
	"time"
)

func init() {
	//init rand seed
	rand.Seed(time.Now().UnixNano())
}

// Captcha captcha basic information.
type Captcha struct {
	Driver Driver
	Store  Store
}

//NewCaptcha creates a captcha instance from driver and store
func NewCaptcha(driver Driver, store Store) *Captcha {
	return &Captcha{Driver: driver, Store: store}
}

//Generate generates a random id, base64 image string or an error if any
func (c *Captcha) Generate() (id, b64s string, err error) {
	id,content, answer := c.Driver.GenerateIdQuestionAnswer("")
	item, err := c.Driver.DrawCaptcha(content)
	if err != nil {
		return "", "", err
	}
	c.Store.Set(id, answer)
	b64s = item.EncodeB64string()
	return
}

//Verify by a given id key and remove the captcha value in store,
//return boolean value.
//if you has multiple captcha instances which share a same store.
//You may want to call `store.Verify` method instead.
func (c *Captcha) Verify(id, answer string, clear bool) (match bool) {
	match = c.Store.Get(id, clear) == answer
	return
}

2.3.4 🚡🚡🚡 ‍Generate Base64(image/audio) string

func (c *Captcha) Generate() (id, b64s string, err error) {
	id,content, answer := c.Driver.GenerateIdQuestionAnswer("")
	item, err := c.Driver.DrawCaptcha(content)
	if err != nil {
		return "", "", err
	}
	c.Store.Set(id, answer)
	b64s = item.EncodeB64string()
	return
}

2.3.5 🀸🀸🀸 Verify Answer

//if you has multiple captcha instances which shares a same store. You may want to use `store.Verify` method instead.
//Verify by given id key and remove the captcha value in store, return boolean value.
func (c *Captcha) Verify(id, answer string, clear bool) (match bool) {
	match = c.Store.Get(id, clear) == answer
	return
}

2.3.6 πŸƒπŸƒπŸƒ ‍Full Example

// example of HTTP server that uses the captcha package.
package main

import (
	"encoding/json"
	"fmt"
	"github.com/forthxu/base64Captcha"
	"log"
	"net/http"
)

//configJsonBody json request body.
type configJsonBody struct {
	Id            string
	CaptchaType   string
	VerifyValue   string
	DriverAudio   *base64Captcha.DriverAudio
	DriverString  *base64Captcha.DriverString
	DriverChinese *base64Captcha.DriverChinese
	DriverMath    *base64Captcha.DriverMath
	DriverDigit   *base64Captcha.DriverDigit
}

var store = base64Captcha.DefaultMemStore

// base64Captcha create http handler
func generateCaptchaHandler(w http.ResponseWriter, r *http.Request) {
	//parse request parameters
	decoder := json.NewDecoder(r.Body)
	var param configJsonBody
	err := decoder.Decode(&param)
	if err != nil {
		log.Println(err)
	}
	defer r.Body.Close()
	var driver base64Captcha.Driver

	//create base64 encoding captcha
	switch param.CaptchaType {
	case "audio":
		driver = param.DriverAudio
	case "string":
		driver = param.DriverString.ConvertFonts()
	case "math":
		driver = param.DriverMath.ConvertFonts()
	case "chinese":
		driver = param.DriverChinese.ConvertFonts()
	default:
		driver = param.DriverDigit
	}
	c := base64Captcha.NewCaptcha(driver, store)
	id, b64s, err := c.Generate()
	body := map[string]interface{}{"code": 1, "data": b64s, "captchaId": id, "msg": "success"}
	if err != nil {
		body = map[string]interface{}{"code": 0, "msg": err.Error()}
	}
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	json.NewEncoder(w).Encode(body)
}

// base64Captcha verify http handler
func captchaVerifyHandle(w http.ResponseWriter, r *http.Request) {

	//parse request json body
	decoder := json.NewDecoder(r.Body)
	var param configJsonBody
	err := decoder.Decode(&param)
	if err != nil {
		log.Println(err)
	}
	defer r.Body.Close()
	//verify the captcha
	body := map[string]interface{}{"code": 0, "msg": "failed"}
	if store.Verify(param.Id, param.VerifyValue, true) {
		body = map[string]interface{}{"code": 1, "msg": "ok"}
	}

	//set json response
	w.Header().Set("Content-Type", "application/json; charset=utf-8")

	json.NewEncoder(w).Encode(body)
}

//start a net/http server
func main() {
	//serve Vuejs+ElementUI+Axios Web Application
	http.Handle("/", http.FileServer(http.Dir("./static")))

	//api for create captcha
	http.HandleFunc("/api/getCaptcha", generateCaptchaHandler)

	//api for verify captcha
	http.HandleFunc("/api/verifyCaptcha", captchaVerifyHandle)

	fmt.Println("Server is at :8777")
	if err := http.ListenAndServe(":8777", nil); err != nil {
		log.Fatal(err)
	}
}

2.3.7 Example Use Etcd as store

captcha with etcd database as store

3. 🎨🎨🎨 Customization

You can customize your captcha display image by implementing interface driver and interface item.

There are some example for your reference.

  1. DriverMath
  2. DriverChinese
  3. ItemChar

You can even design the captcha struct to whatever you prefer.

4. πŸ’–πŸ’–πŸ’– Thanks

5. 🍭🍭🍭 Licence

base64Captcha source code is licensed under the Apache Licence, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0.html).

# Functions

NewCaptcha creates a captcha instance from driver and store.
NewDriverAudio creates a driver of audio.
NewDriverChinese creates a driver of Chinese characters.
NewDriverDigit creates a driver of digit.
NewDriverLanguage creates a driver.
NewDriverMath creates a driver of math.
NewDriverString creates driver.
No description provided by the author
NewItemChar creates a captcha item of characters.
NewItemDigit create a instance of item-digit.
NewMemoryStore returns a new standard memory store for captchas with the given collection threshold and expiration time (duration).
NewStoreSyncMap new a instance.
RandColor get random color.
RandDeepColor get random deep color.
RandLightColor get random ligth color.
RandomId returns a new random id key string.
RandText creates random text of given size.

# Constants

Emoji is a source string for randTxt.
MimeTypeAudio output base64 mine-type.
MimeTypeImage output base64 mine-type.
OptionShowHollowLine shows hollow line.
OptionShowSineLine shows sine line.
OptionShowSlimeLine shows slime line.
TxtAlphabet characters for alphabet.
TxtChineseCharaters makes characters in chinese.
TxtNumbers chacters for numbers.
TxtSimpleCharaters simple numbers and alphabet.

# Variables

DefaultDriverAudio is a default audio driver.
DefaultDriverDigit is a default driver of digit.
No description provided by the author
DefaultMemStore is a shared storage for captchas, generated by New function.
Expiration time of captchas used by default store.
GCLimitNumber The number of captchas created that triggers garbage collection used by default store.

# Structs

Captcha captcha basic information.
DriverAudio captcha config for captcha-engine-audio.
DriverChinese is a driver of unicode Chinese characters.
DriverDigit config for captcha-engine-digit.
DriverLanguage generates language unicode by lanuage.
DriverMath captcha config for captcha math.
DriverChar captcha config for captcha-engine-characters.
No description provided by the author
ItemAudio captcha-audio-engine return type.
ItemChar captcha item of unicode characters.
ItemDigit digits captcha Struct.
StoreSyncMap use sync.Map as store.

# Interfaces

Driver captcha interface for captcha engine to to write staff.
FontsStorage interface for working with fonts.
Item is captcha item interface.
Store An object implementing Store interface can be registered with SetCustomStore function to handle storage and retrieval of captcha ids and solutions for them, replacing the default memory store.