justcaptcha/internal/captcha/dwelling_captcha.go

92 lines
2.0 KiB
Go

package captcha
import (
"crypto/rand"
"image"
"math/big"
"time"
"github.com/fogleman/gg"
)
const (
dwImageWidth = 160
dwImageHeight = 40
)
type DwellingCaptcha struct {
Captcha
}
func NewDwellingCaptcha(expiration time.Duration) *DwellingCaptcha {
return &DwellingCaptcha{
Captcha: Captcha{
Answer: GenerateAnswer(),
ExpireIn: ExpireDate(expiration)}}
}
func (c *DwellingCaptcha) GenerateImage() *image.Image {
ctx := gg.NewContext(dwImageWidth, dwImageHeight)
// fill background
ctx.SetRGB255(0x0a, 0x0a, 0x0a)
ctx.Clear()
// draw text
ctx.SetRGB255(0xf5, 0xf5, 0xf5)
ctx.Scale(4.0, 2.7)
ctx.DrawStringAnchored(string(c.GetAnswer()), 20, 5, .5, .5)
// draw lines and points
ctx.SetRGB255(0x9f, 0x2b, 0x68)
for i := 0; i < 16; i++ {
x0, _ := rand.Int(rand.Reader, big.NewInt(int64(ctx.Height())))
x1, _ := rand.Int(rand.Reader, big.NewInt(int64(ctx.Height())))
ctx.SetLineWidth(2)
r, _ := rand.Int(rand.Reader, big.NewInt(int64(4)))
ctx.DrawPoint(float64(x0.Int64()), float64(x1.Int64()), float64(r.Int64()))
ctx.DrawLine(float64(x0.Int64()), 0, float64(ctx.Height()), float64(x1.Int64()))
ctx.Stroke()
}
for i := 0; i < 16; i++ {
x0, _ := rand.Int(rand.Reader, big.NewInt(int64(ctx.Height())))
x1, _ := rand.Int(rand.Reader, big.NewInt(int64(ctx.Height())))
ctx.SetLineWidth(2)
ctx.DrawLine(0, float64(x0.Int64()), float64(x1.Int64()), float64(ctx.Height()))
r, _ := rand.Int(rand.Reader, big.NewInt(int64(4)))
ctx.DrawPoint(float64(x0.Int64()), float64(x1.Int64()), float64(r.Int64()))
ctx.Stroke()
}
c.Image = ctx.Image()
return &c.Image
}
func (c *DwellingCaptcha) GetImage() *image.Image {
if c.Image == nil {
return c.GenerateImage()
}
return &c.Image
}
func (c *DwellingCaptcha) Solve(answer Answer) bool {
c.Solved = c.Answer == answer
return c.Solved
}
func (c *DwellingCaptcha) GetAnswer() Answer {
return c.Answer
}
func (c *DwellingCaptcha) IsSolved() bool {
return c.Solved
}
func (c *DwellingCaptcha) Expire() time.Time {
return c.ExpireIn
}