From cd7c72beb51048b641d55acabdc314ea338f1cde Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 18 May 2025 14:30:15 +0200 Subject: [PATCH] Adding upstream version 1.0.1. Signed-off-by: Daniel Baumann --- .forgejo/workflows/test.yml | 23 +++ .gitignore | 8 ++ .golangci.yaml | 27 ++++ LICENSE | 19 +++ README.md | 220 ++++++++++++++++++++++++++++ capexample/main.go | 83 +++++++++++ capgen/example.png | Bin 0 -> 2459 bytes capgen/example.wav | Bin 0 -> 137258 bytes capgen/main.go | 46 ++++++ captcha.go | 153 ++++++++++++++++++++ captcha_test.go | 52 +++++++ font.go | 215 ++++++++++++++++++++++++++++ go.mod | 5 + image.go | 278 ++++++++++++++++++++++++++++++++++++ image_test.go | 17 +++ random.go | 109 ++++++++++++++ renovate.json | 4 + server.go | 84 +++++++++++ store.go | 117 +++++++++++++++ store_test.go | 79 ++++++++++ 20 files changed, 1539 insertions(+) create mode 100644 .forgejo/workflows/test.yml create mode 100644 .gitignore create mode 100644 .golangci.yaml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 capexample/main.go create mode 100644 capgen/example.png create mode 100644 capgen/example.wav create mode 100644 capgen/main.go create mode 100644 captcha.go create mode 100644 captcha_test.go create mode 100644 font.go create mode 100644 go.mod create mode 100644 image.go create mode 100644 image_test.go create mode 100644 random.go create mode 100644 renovate.json create mode 100644 server.go create mode 100644 store.go create mode 100644 store_test.go diff --git a/.forgejo/workflows/test.yml b/.forgejo/workflows/test.yml new file mode 100644 index 0000000..8587af3 --- /dev/null +++ b/.forgejo/workflows/test.yml @@ -0,0 +1,23 @@ +name: test +on: + pull_request: + push: + branches: + - main + +jobs: + test: + runs-on: docker-global-bookworm + container: + image: 'code.forgejo.org/oci/node:20-bookworm' + steps: + - uses: https://code.forgejo.org/actions/checkout@v4 + - uses: https://code.forgejo.org/actions/setup-go@v5 + with: + go-version-file: "go.mod" + - name: golangci-lint + uses: https://github.com/golangci/golangci-lint-action@v6 + with: + version: v1.60.3 # renovate: datasource=go depName=golangci-lint packageName=github.com/golangci/golangci-lint/cmd/golangci-lint + - name: test + run: go test -v ./... diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea1cde5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# Generated test captchas +capgen/*.png +capgen/*.wav + +# Programs +capgen/capgen +cangensounds/cangensounds +capexample/capexample diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 0000000..25287ce --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,27 @@ +linters: + enable-all: false + disable-all: true + fast: false + enable: + - bidichk + - dupl + - errcheck + - forbidigo + - gocritic + - gofmt + - gofumpt + - gosimple + - govet + - ineffassign + - nakedret + - nolintlint + - revive + - staticcheck + - stylecheck + - tenv + - testifylint + - typecheck + - unconvert + - unused + - unparam + - wastedassign diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0ad73ae --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2011-2014 Dmitry Chestnykh + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..72146b8 --- /dev/null +++ b/README.md @@ -0,0 +1,220 @@ +Package captcha +===================== + +This is a fork of https://github.com/dchest/captcha + +**:warning: Warning: this captcha can be broken by advanced OCR captcha breaking algorithms.** + + import "code.forgejo.org/go-chi/captcha" + +Package captcha implements generation and verification of image CAPTCHAs. + +A captcha solution is the sequence of digits 0-9 with the defined length. +There is one captcha representations: image. + +An image representation is a PNG-encoded image with the solution printed on +it in such a way that makes it hard for computers to solve it using OCR. + +This package doesn't require external files or libraries to generate captcha +representations; it is self-contained. + +To make captchas one-time, the package includes a memory storage that stores +captcha ids, their solutions, and expiration time. Used captchas are removed +from the store immediately after calling Verify or VerifyString, while +unused captchas (user loaded a page with captcha, but didn't submit the +form) are collected automatically after the predefined expiration time. +Developers can also provide custom store (for example, which saves captcha +ids and solutions in database) by implementing Store interface and +registering the object with SetCustomStore. + +Captchas are created by calling New, which returns the captcha id. Their +representations, though, are created on-the-fly by calling WriteImage function. +Created representations are not stored anywhere, but subsequent calls to these +functions with the same id will write the same captcha solution. Reload function +will create a new different solution for the provided captcha, allowing users to +"reload" captcha if they can't solve the displayed one without reloading the +whole page. Verify and VerifyString are used to verify that the given solution +is the right one for the given captcha id. + +Server provides an http.Handler which can serve image representations of +captchas automatically from the URL. It can also be used to reload captchas. +Refer to Server function documentation for details, or take a look at the +example in "capexample" subdirectory. + + +Examples +-------- + +![Image](https://github.com/dchest/captcha/raw/master/capgen/example.png) + +Constants +--------- + +``` go +const ( + // Default number of digits in captcha solution. + DefaultLen = 6 + // The number of captchas created that triggers garbage collection used + // by default store. + CollectNum = 100 + // Expiration time of captchas used by default store. + Expiration = 10 * time.Minute +) +``` + +``` go +const ( + // Standard width and height of a captcha image. + StdWidth = 240 + StdHeight = 80 +) +``` + + +Variables +--------- + +``` go +var ( + ErrNotFound = errors.New("captcha: id not found") +) +``` + + + +Functions +--------- + +### func New + + func New() string + +New creates a new captcha with the standard length, saves it in the internal +storage and returns its id. + +### func NewLen + + func NewLen(length int) (id string) + +NewLen is just like New, but accepts length of a captcha solution as the +argument. + +### func RandomDigits + + func RandomDigits(length int) (b []byte) + +RandomDigits returns a byte slice of the given length containing +pseudorandom numbers in range 0-9. The slice can be used as a captcha +solution. + +### func Reload + + func Reload(id string) bool + +Reload generates and remembers new digits for the given captcha id. This +function returns false if there is no captcha with the given id. + +After calling this function, the image presented to a user must be refreshed to +show the new captcha representation (WriteImage will write the new one). + +### func Server + + func Server(imgWidth, imgHeight int) http.Handler + +Server returns a handler that serves HTTP requests with image or +representations of captchas. Image dimensions are accepted as +arguments. The server decides which captcha to serve based on the last URL +path component: file name part must contain a captcha id, file extension — +its format (PNG or WAV). + +For example, for file name "LBm5vMjHDtdUfaWYXiQX.png" it serves an image captcha +with id "LBm5vMjHDtdUfaWYXiQX". + +To reload captcha (get a different solution for the same captcha id), append +"?reload=x" to URL, where x may be anything (for example, current time or a +random number to make browsers refetch an image instead of loading it from +cache). + +### func SetCustomStore + + func SetCustomStore(s Store) + +SetCustomStore sets custom storage for captchas, replacing the default +memory store. This function must be called before generating any captchas. + +### func Verify + + func Verify(id string, digits []byte) bool + +Verify returns true if the given digits are the ones that were used to +create the given captcha id. + +The function deletes the captcha with the given id from the internal +storage, so that the same captcha can't be verified anymore. + +### func VerifyString + + func VerifyString(id string, digits string) bool + +VerifyString is like Verify, but accepts a string of digits. It removes +spaces and commas from the string, but any other characters, apart from +digits and listed above, will cause the function to return false. + +### func WriteImage + + func WriteImage(w io.Writer, id string, width, height int) error + +WriteImage writes PNG-encoded image representation of the captcha with the +given id. The image will have the given width and height. + + +Types +----- + +``` go +type Image struct { + *image.Paletted + // contains unexported fields +} +``` + + +### func NewImage + + func NewImage(id string, digits []byte, width, height int) *Image + +NewImage returns a new captcha image of the given width and height with the +given digits, where each digit must be in range 0-9. + +### func (*Image) WriteTo + + func (m *Image) WriteTo(w io.Writer) (int64, error) + +WriteTo writes captcha image in PNG format into the given writer. + +``` go +type Store interface { + // Set sets the digits for the captcha id. + Set(id string, digits []byte) + + // Get returns stored digits for the captcha id. Clear indicates + // whether the captcha must be deleted from the store. + Get(id string, clear bool) (digits []byte) +} +``` + +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. + +It is the responsibility of an object to delete expired and used captchas +when necessary (for example, the default memory store collects them in Set +method after the certain amount of captchas has been stored.) + +### func NewMemoryStore + + func NewMemoryStore(collectNum int, expiration time.Duration) Store + +NewMemoryStore returns a new standard memory store for captchas with the +given collection threshold and expiration time in seconds. The returned +store must be registered with SetCustomStore to replace the default one. diff --git a/capexample/main.go b/capexample/main.go new file mode 100644 index 0000000..ab7e932 --- /dev/null +++ b/capexample/main.go @@ -0,0 +1,83 @@ +// Copyright 2011 Dmitry Chestnykh. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +// example of HTTP server that uses the captcha package. +// +//nolint:forbidigo +package main + +import ( + "fmt" + "io" + "log" + "net/http" + "text/template" + + "code.forgejo.org/go-chi/captcha" +) + +var formTemplate = template.Must(template.New("example").Parse(formTemplateSrc)) + +func showFormHandler(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/" { + http.NotFound(w, r) + return + } + d := struct { + CaptchaID string + }{ + captcha.New(), + } + if err := formTemplate.Execute(w, &d); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } +} + +func processFormHandler(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + if !captcha.VerifyString(r.FormValue("captchaId"), r.FormValue("captchaSolution")) { + _, _ = io.WriteString(w, "Wrong captcha solution! No robots allowed!\n") + } else { + _, _ = io.WriteString(w, "Great job, human! You solved the captcha.\n") + } + _, _ = io.WriteString(w, "
Try another one") +} + +func main() { + http.HandleFunc("/", showFormHandler) + http.HandleFunc("/process", processFormHandler) + http.Handle("/captcha/", captcha.Server(captcha.StdWidth, captcha.StdHeight)) + fmt.Println("Server is at localhost:8666") + if err := http.ListenAndServe("localhost:8666", nil); err != nil { + log.Fatal(err) + } +} + +const formTemplateSrc = ` +Captcha Example + + +
+

Type the numbers you see in the picture below:

+

Captcha image

+Reload +
+ + +
+` diff --git a/capgen/example.png b/capgen/example.png new file mode 100644 index 0000000000000000000000000000000000000000..e290c8e1105179dfc17ee18a231d3e2b6a7e2508 GIT binary patch literal 2459 zcmV;M31s$(P)mnYHDBf8`>~zA# zJ1#C>$8oyjA++O6j0@OtCdLKqtd{#uKYp0k#^*KS0(Pbc3N;n%+C_Y9X#-~9-iJbvwF2c}l30t=TYO{o*4X@-`uuaJlB8; zs5GwF*huC=+Fz-!+}v!Vh=5MiXLDzZ(1!FgZMzm|$08j|&G>5PqGtRk@j~D| z^;kQjFx<^)CfuT*9M}S}Xje*&c(Kh$+9tgBi# zL0~zaW|FDvEo%%^4y-LCmGW9m?P1B3Cbzk#)Yv$TfT^7~S3QOF6ftIN;E`vZ-Lx4+ zthGmCQ>iT|DDB3e=~sK5bQ2q;5)H>W{S3ahY7ZR9RZnZZRgE{wT^mF!6>r*Zt-x|Z z?NQ~o_P~~Ndg-lqHlJVp=!53>PT69$fetU=2*(4%?`!&OeVwFDO}jbq%<6$PHeh3r ziZ@a#V(yx36$K1a#45opXlRNT7Db)fVo9#hCAER_d{mLm0!)As`?2}ciZ^}kQK+MA z?NKbe2fp$Cr=M*m;@#I@>*k?zxh^#Tn0KiuXw`Tni(J)0Sd=$t<$W>xmlhs3O4EXk zUun~9#gWES@kW*qaY~PnR(h><#nYnl%(;hF`L9LAJlbQC`=_LBJ@Dk&gY-Wh*xTFN z`SYhAs>T`i(VJmHXt;w(L$F+%HP^y6Fgw%d+J3a+E!oj3XSa-AurdGk=ikJs5VSG= z9mE<$8y^z!ruSOvvnRs{xHdnda$rfpD|am=9SoN_*Kxd^^z-yP)OV%#XkFn=pDjXm>IjBA|I`s26mR-W zwL{r8qId&C8MUMbt__*7DsryqA@R}{VX=h=Ze7IDgys^DNqOMeyl%>H#88Lum#$xFG<@}xT+2Fb0J^a2UfwB zhOfEQq$cEVvB0U50C;4Td#_f!qg0qV3~OYq*C=^%i3jA^#$7m4K}e3lxP3}0wXMTu zsy|6eV(EEj5pHByV{0nO@IAPzb3MBz_u`6J8Y03zO8FwyheVLlP~8eneL$Kk!}hT? zQDgH`3~e-)`*9X}X~E`@E}o!!N$veDCd7UKXV*nzW^NG|`&jZ-QHu z)OcFz+8R+&ySv4PAqk~(NGrRkjhqbu>koTB6>o$Rag7(}+A|}=RiPnNRg!v7(kAs< z8+NDHQhiX*61#I_!nvNCicmEJ?YL{P67NjaWiC^N6WY8sA}thY>`PytI(2IE_uad9 zMfPyo=Z46Vel_iB`{H_F4Hok`1IObe_1;yblssId0*Pb(zF#5Hlm17lujRF6!d&2y-{vV{OF+tc>PwS(jJmu6eV z8#pXt#YLYx6HK3bQ;G~YVIzmyHquQH=DhKB?=htME7>u!U?Y@+8O_d?u+CE@=X$l| z4(qY^d)UAU8@UCh_?(8(t-|NjHaLcy0@Y|?a>}*~H=_Efpkz`@MJMe!CilA-=Ptgu z>FfLJU#smZRcm{1JQ&=Kw7oy}e`+(rHmY9tfvp#8E%mTvM8rQC#6q$7IaST3$c1&S7JP33W6ZGNIB698yk-AA z`kaxff(`Xq?pUhifm=_CR=@#nxKC|Fqvn$wdJ8HS1z7bl8!x@_=4MQ;UAcTX4kicZ z&djOv}8sP>^LmeE?&oR9A^@|3hg)(;{tY^iE#lt&cwKY9cN-(z>YI9{{{d6 Z|Nrk8j6u77dvE{%002ovPDHLkV1h`Y%Xa_( literal 0 HcmV?d00001 diff --git a/capgen/example.wav b/capgen/example.wav new file mode 100644 index 0000000000000000000000000000000000000000..31f2f0d40141426410c1e1997959400bfa843f41 GIT binary patch literal 137258 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ÐGwX!F+c(%!2_&$8}}Tj@?Hj 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 9 { + t.Errorf("digits not in range 0-9: %v", d1) + } + } + d2 := RandomDigits(10) + if bytes.Equal(d1, d2) { + t.Errorf("digits seem to be not random") + } +} diff --git a/font.go b/font.go new file mode 100644 index 0000000..2b5fae0 --- /dev/null +++ b/font.go @@ -0,0 +1,215 @@ +// Copyright 2011 Dmitry Chestnykh. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package captcha + +const ( + fontWidth = 11 + fontHeight = 18 + blackChar = 1 +) + +//nolint:dupl +var font = [][]byte{ + { // 0 + 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, + 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, + }, + { // 1 + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }, + { // 2 + 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + }, + { // 3 + 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, + }, + { // 4 + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, + 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, + 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, + 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, + 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + }, + { // 5 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, + }, + { // 6 + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, + 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, + 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, + 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, + 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, + }, + { // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, + }, + { // 8 + 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, + 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, + 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, + }, + { // 9 + 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, + 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, + 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, + }, +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ba2048e --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module code.forgejo.org/go-chi/captcha + +go 1.23 + +toolchain go1.23.4 diff --git a/image.go b/image.go new file mode 100644 index 0000000..ab656b8 --- /dev/null +++ b/image.go @@ -0,0 +1,278 @@ +// Copyright 2011-2014 Dmitry Chestnykh. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package captcha + +import ( + "bytes" + "image" + "image/color" + "image/png" + "io" + "math" + mathRand "math/rand/v2" +) + +const ( + // Standard width and height of a captcha image. + StdWidth = 240 + StdHeight = 80 + // Maximum absolute skew factor of a single digit. + maxSkew = 0.7 + // Number of background circles. + circleCount = 20 +) + +type Image struct { + *image.Paletted + numWidth int + numHeight int + dotSize int + rng *mathRand.Rand +} + +// Int returns a pseudorandom int in the half-open interval [from, to]. +func (m *Image) Int(from, to int) int { + return from + m.rng.IntN(to-from+1) +} + +// Float returns a pseudorandom float64 in the half-open interval [from, to). +func (m *Image) Float(from, to float64) float64 { + return from + (to-from)*m.rng.Float64() +} + +// NewImage returns a new captcha image of the given width and height with the +// given digits, where each digit must be in range 0-9. +func NewImage(id string, digits []byte, width, height int) *Image { + m := new(Image) + + // Initialize PRNG. + m.rng = mathRand.New(mathRand.NewChaCha8(deriveSeed(imageSeedPurpose, id, digits))) + + m.Paletted = image.NewPaletted(image.Rect(0, 0, width, height), m.getRandomPalette()) + m.calculateSizes(width, height, len(digits)) + // Randomly position captcha inside the image. + maxx := width - (m.numWidth+m.dotSize)*len(digits) - m.dotSize + maxy := height - m.numHeight - m.dotSize*2 + var border int + if width > height { + border = height / 5 + } else { + border = width / 5 + } + x := m.Int(border, maxx-border) + y := m.Int(border, maxy-border) + // Draw digits. + for _, n := range digits { + m.drawDigit(font[n], x, y) + x += m.numWidth + m.dotSize + } + // Draw strike-through line. + m.strikeThrough() + // Apply wave distortion. + m.distort(m.Float(5, 10), m.Float(100, 200)) + // Fill image with random circles. + m.fillWithCircles(circleCount, m.dotSize) + // Flip the image horizontally. + m.flipX() + return m +} + +func (m *Image) getRandomPalette() color.Palette { + p := make([]color.Color, circleCount+1) + // Transparent color. + p[0] = color.RGBA{0xFF, 0xFF, 0xFF, 0x00} + // Primary color. + prim := color.RGBA{ + uint8(m.rng.IntN(129)), + uint8(m.rng.IntN(129)), + uint8(m.rng.IntN(129)), + 0xFF, + } + p[1] = prim + // Circle colors. + for i := 2; i <= circleCount; i++ { + p[i] = m.randomBrightness(prim, 255) + } + return p +} + +// encodedPNG encodes an image to PNG and returns +// the result as a byte slice. +func (m *Image) encodedPNG() []byte { + var buf bytes.Buffer + if err := png.Encode(&buf, m.Paletted); err != nil { + panic(err.Error()) + } + return buf.Bytes() +} + +// WriteTo writes captcha image in PNG format into the given writer. +func (m *Image) WriteTo(w io.Writer) (int64, error) { + n, err := w.Write(m.encodedPNG()) + return int64(n), err +} + +func (m *Image) calculateSizes(width, height, ncount int) { + // Goal: fit all digits inside the image. + var border int + if width > height { + border = height / 4 + } else { + border = width / 4 + } + // Convert everything to floats for calculations. + w := float64(width - border*2) + h := float64(height - border*2) + // fw takes into account 1-dot spacing between digits. + fw := float64(fontWidth + 1) + fh := float64(fontHeight) + nc := float64(ncount) + // Calculate the width of a single digit taking into account only the + // width of the image. + nw := w / nc + // Calculate the height of a digit from this width. + nh := nw * fh / fw + // Digit too high? + if nh > h { + // Fit digits based on height. + nh = h + nw = fw / fh * nh + } + // Calculate dot size. + m.dotSize = int(nh / fh) + if m.dotSize < 1 { + m.dotSize = 1 + } + // Save everything, making the actual width smaller by 1 dot to account + // for spacing between digits. + m.numWidth = int(nw) - m.dotSize + m.numHeight = int(nh) +} + +func (m *Image) drawHorizLine(fromX, toX, y int, colorIdx uint8) { + for x := fromX; x <= toX; x++ { + m.SetColorIndex(x, y, colorIdx) + } +} + +func (m *Image) drawCircle(x, y, radius int, colorIdx uint8) { + f := 1 - radius + dfx := 1 + dfy := -2 * radius + xo := 0 + yo := radius + + m.SetColorIndex(x, y+radius, colorIdx) + m.SetColorIndex(x, y-radius, colorIdx) + m.drawHorizLine(x-radius, x+radius, y, colorIdx) + + for xo < yo { + if f >= 0 { + yo-- + dfy += 2 + f += dfy + } + xo++ + dfx += 2 + f += dfx + m.drawHorizLine(x-xo, x+xo, y+yo, colorIdx) + m.drawHorizLine(x-xo, x+xo, y-yo, colorIdx) + m.drawHorizLine(x-yo, x+yo, y+xo, colorIdx) + m.drawHorizLine(x-yo, x+yo, y-xo, colorIdx) + } +} + +func (m *Image) fillWithCircles(n, maxradius int) { + maxx := m.Bounds().Max.X + maxy := m.Bounds().Max.Y + for i := 0; i < n; i++ { + colorIdx := uint8(m.Int(1, circleCount-1)) + r := m.Int(1, maxradius) + m.drawCircle(m.Int(r, maxx-r), m.Int(r, maxy-r), r, colorIdx) + } +} + +func (m *Image) strikeThrough() { + maxx := m.Bounds().Max.X + maxy := m.Bounds().Max.Y + y := m.Int(maxy/3, maxy-maxy/3) + amplitude := m.Float(5, 20) + period := m.Float(80, 180) + dx := 2.0 * math.Pi / period + for x := 0; x < maxx; x++ { + xo := amplitude * math.Cos(float64(y)*dx) + yo := amplitude * math.Sin(float64(x)*dx) + for yn := 0; yn < m.dotSize; yn++ { + r := m.rng.IntN(m.dotSize + 1) + m.drawCircle(x+int(xo), y+int(yo)+(yn*m.dotSize), r/2, 1) + } + } +} + +func (m *Image) drawDigit(digit []byte, x, y int) { + skf := m.Float(-maxSkew, maxSkew) + xs := float64(x) + r := m.dotSize / 2 + y += m.Int(-r, r) + for yo := 0; yo < fontHeight; yo++ { + for xo := 0; xo < fontWidth; xo++ { + if digit[yo*fontWidth+xo] != blackChar { + continue + } + m.drawCircle(x+xo*m.dotSize, y+yo*m.dotSize, r, 1) + } + xs += skf + x = int(xs) + } +} + +func (m *Image) distort(amplude float64, period float64) { + w := m.Bounds().Max.X + h := m.Bounds().Max.Y + + oldm := m.Paletted + newm := image.NewPaletted(image.Rect(0, 0, w, h), oldm.Palette) + + dx := 2.0 * math.Pi / period + for x := 0; x < w; x++ { + for y := 0; y < h; y++ { + xo := amplude * math.Sin(float64(y)*dx) + yo := amplude * math.Cos(float64(x)*dx) + newm.SetColorIndex(x, y, oldm.ColorIndexAt(x+int(xo), y+int(yo))) + } + } + m.Paletted = newm +} + +func (m *Image) flipX() { + w := m.Bounds().Max.X + h := m.Bounds().Max.Y + + src := m.Paletted + dst := image.NewPaletted(image.Rect(0, 0, w, h), src.Palette) + + for x := 0; x < w; x++ { + for y := 0; y < h; y++ { + xo := w - x - 1 + dst.SetColorIndex(x, y, src.ColorIndexAt(xo, y)) + } + } + m.Paletted = dst +} + +func (m *Image) randomBrightness(c color.RGBA, maxB uint8) color.RGBA { + minc := min(min(c.R, c.G), c.B) + maxc := max(max(c.R, c.G), c.B) + if maxc > maxB { + return c + } + n := m.rng.IntN(int(maxB-maxc)) - int(minc) + return color.RGBA{ + uint8(int(c.R) + n), + uint8(int(c.G) + n), + uint8(int(c.B) + n), + c.A, + } +} diff --git a/image_test.go b/image_test.go new file mode 100644 index 0000000..ea44d4f --- /dev/null +++ b/image_test.go @@ -0,0 +1,17 @@ +// Copyright 2011 Dmitry Chestnykh. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package captcha + +import "testing" + +func BenchmarkNewImage(b *testing.B) { + b.StopTimer() + d := RandomDigits(DefaultLen) + id := randomID() + b.StartTimer() + for i := 0; i < b.N; i++ { + NewImage(id, d, StdWidth, StdHeight) + } +} diff --git a/random.go b/random.go new file mode 100644 index 0000000..478af3b --- /dev/null +++ b/random.go @@ -0,0 +1,109 @@ +// Copyright 2011-2014 Dmitry Chestnykh. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package captcha + +import ( + "crypto/hmac" + "crypto/rand" + "crypto/sha256" + "io" +) + +// idLen is a length of captcha id string. +// (20 bytes of 62-letter alphabet give ~119 bits.) +const idLen = 20 + +// idChars are characters allowed in captcha id. +var idChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") + +// rngKey is a secret key used to deterministically derive seeds for +// PRNGs used in image. Generated once during initialization. +var rngKey [32]byte + +func init() { + if _, err := io.ReadFull(rand.Reader, rngKey[:]); err != nil { + panic("captcha: error reading random source: " + err.Error()) + } +} + +// Purposes for seed derivation. The goal is to make deterministic PRNG produce +// different outputs for images and audio by using different derived seeds. +const ( + imageSeedPurpose = 0x01 + audioSeedPurpose = 0x02 +) + +// deriveSeed returns a 16-byte PRNG seed from rngKey, purpose, id and digits. +// Same purpose, id and digits will result in the same derived seed for this +// instance of running application. +// +// out = HMAC(rngKey, purpose || id || 0x00 || digits) +func deriveSeed(purpose byte, id string, digits []byte) (out [32]byte) { + var buf [sha256.Size]byte + + h := hmac.New(sha256.New, rngKey[:]) + h.Write([]byte{purpose}) + h.Write([]byte(id)) + h.Write([]byte{0}) + h.Write(digits) + + sum := h.Sum(buf[:0]) + copy(out[:], sum) + return +} + +// RandomDigits returns a byte slice of the given length containing +// pseudorandom numbers in range 0-9. The slice can be used as a captcha +// solution. +func RandomDigits(length int) []byte { + return randomBytesMod(length, 10) +} + +// randomBytes returns a byte slice of the given length read from CSPRNG. +func randomBytes(length int) (b []byte) { + b = make([]byte, length) + if _, err := io.ReadFull(rand.Reader, b); err != nil { + panic("captcha: error reading random source: " + err.Error()) + } + return +} + +// randomBytesMod returns a byte slice of the given length, where each byte is +// a random number modulo mod. +func randomBytesMod(length int, mod byte) (b []byte) { + if length == 0 { + return nil + } + if mod == 0 { + panic("captcha: bad mod argument for randomBytesMod") + } + + maxrb := 255 - byte(256%int(mod)) + b = make([]byte, length) + i := 0 + for { + r := randomBytes(length + (length / 4)) + for _, c := range r { + if c > maxrb { + // Skip this number to avoid modulo bias. + continue + } + b[i] = c % mod + i++ + if i == length { + return + } + } + } +} + +// randomID returns a new random id string. +func randomID() string { + b := randomBytesMod(idLen, byte(len(idChars))) + for i, c := range b { + b[i] = idChars[c] + } + return string(b) +} diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..3146f63 --- /dev/null +++ b/renovate.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["go-chi/renovate-config"] +} diff --git a/server.go b/server.go new file mode 100644 index 0000000..4d1518c --- /dev/null +++ b/server.go @@ -0,0 +1,84 @@ +// Copyright 2011 Dmitry Chestnykh. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package captcha + +import ( + "bytes" + "net/http" + "path" + "time" +) + +type captchaHandler struct { + imgWidth int + imgHeight int +} + +// Server returns a handler that serves HTTP requests with image +// representations of captchas. Image dimensions are accepted as +// arguments. The server decides which captcha to serve based on the last URL +// path component: file name part must contain a captcha id, file extension — +// its format (PNG or WAV). +// +// For example, for file name "LBm5vMjHDtdUfaWYXiQX.png" it serves an image captcha +// with id "LBm5vMjHDtdUfaWYXiQX", and for "LBm5vMjHDtdUfaWYXiQX.wav" it serves the +// same captcha in audio format. +// +// To serve a captcha as a downloadable file, the URL must be constructed in +// such a way as if the file to serve is in the "download" subdirectory: +// "/download/LBm5vMjHDtdUfaWYXiQX.wav". +// +// To reload captcha (get a different solution for the same captcha id), append +// "?reload=x" to URL, where x may be anything (for example, current time or a +// random number to make browsers refetch an image instead of loading it from +// cache). +// +// By default, the Server serves audio in English language. To serve audio +// captcha in one of the other supported languages, append "lang" value, for +// example, "?lang=ru". +func Server(imgWidth, imgHeight int) http.Handler { + return &captchaHandler{imgWidth, imgHeight} +} + +func (h *captchaHandler) serve(w http.ResponseWriter, r *http.Request, id, ext string, download bool) error { + w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") + w.Header().Set("Pragma", "no-cache") + w.Header().Set("Expires", "0") + + var content bytes.Buffer + switch ext { + case ".png": + w.Header().Set("Content-Type", "image/png") + if err := WriteImage(&content, id, h.imgWidth, h.imgHeight); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + default: + return ErrNotFound + } + + if download { + w.Header().Set("Content-Type", "application/octet-stream") + } + http.ServeContent(w, r, id+ext, time.Time{}, bytes.NewReader(content.Bytes())) + return nil +} + +func (h *captchaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + dir, file := path.Split(r.URL.Path) + ext := path.Ext(file) + id := file[:len(file)-len(ext)] + if ext == "" || id == "" { + http.NotFound(w, r) + return + } + if r.FormValue("reload") != "" { + Reload(id) + } + download := path.Base(dir) == "download" + if h.serve(w, r, id, ext, download) == ErrNotFound { + http.NotFound(w, r) + } + // Ignore other errors. +} diff --git a/store.go b/store.go new file mode 100644 index 0000000..9fc4497 --- /dev/null +++ b/store.go @@ -0,0 +1,117 @@ +// Copyright 2011 Dmitry Chestnykh. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package captcha + +import ( + "container/list" + "sync" + "time" +) + +// 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. +// +// It is the responsibility of an object to delete expired and used captchas +// when necessary (for example, the default memory store collects them in Set +// method after the certain amount of captchas has been stored.) +type Store interface { + // Set sets the digits for the captcha id. + Set(id string, digits []byte) + + // Get returns stored digits for the captcha id. Clear indicates + // whether the captcha must be deleted from the store. + Get(id string, clear bool) (digits []byte) +} + +// expValue stores timestamp and id of captchas. It is used in the list inside +// memoryStore for indexing generated captchas by timestamp to enable garbage +// collection of expired captchas. +type idByTimeValue struct { + timestamp time.Time + id string +} + +// memoryStore is an internal store for captcha ids and their values. +type memoryStore struct { + sync.RWMutex + digitsByID map[string][]byte + idByTime *list.List + // Number of items stored since last collection. + numStored int + // Number of saved items that triggers collection. + collectNum int + // Expiration time of captchas. + expiration time.Duration +} + +// NewMemoryStore returns a new standard memory store for captchas with the +// given collection threshold and expiration time (duration). The returned +// store must be registered with SetCustomStore to replace the default one. +func NewMemoryStore(collectNum int, expiration time.Duration) Store { + s := new(memoryStore) + s.digitsByID = make(map[string][]byte) + s.idByTime = list.New() + s.collectNum = collectNum + s.expiration = expiration + return s +} + +func (s *memoryStore) Set(id string, digits []byte) { + s.Lock() + s.digitsByID[id] = digits + s.idByTime.PushBack(idByTimeValue{time.Now(), id}) + s.numStored++ + if s.numStored <= s.collectNum { + s.Unlock() + return + } + s.Unlock() + go s.collect() +} + +func (s *memoryStore) Get(id string, clear bool) (digits []byte) { + if !clear { + // When we don't need to clear captcha, acquire read lock. + s.RLock() + defer s.RUnlock() + } else { + s.Lock() + defer s.Unlock() + } + digits, ok := s.digitsByID[id] + if !ok { + return + } + if clear { + delete(s.digitsByID, id) + // XXX(dchest) Index (s.idByTime) will be cleaned when + // collecting expired captchas. Can't clean it here, because + // we don't store reference to expValue in the map. + // Maybe store it? + } + return +} + +func (s *memoryStore) collect() { + now := time.Now() + s.Lock() + defer s.Unlock() + s.numStored = 0 + for e := s.idByTime.Front(); e != nil; { + ev, ok := e.Value.(idByTimeValue) + if !ok { + return + } + if ev.timestamp.Add(s.expiration).Before(now) { + delete(s.digitsByID, ev.id) + next := e.Next() + s.idByTime.Remove(e) + e = next + } else { + return + } + } +} diff --git a/store_test.go b/store_test.go new file mode 100644 index 0000000..6067292 --- /dev/null +++ b/store_test.go @@ -0,0 +1,79 @@ +// Copyright 2011 Dmitry Chestnykh. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package captcha + +import ( + "bytes" + "testing" +) + +func TestSetGet(t *testing.T) { + s := NewMemoryStore(CollectNum, Expiration) + id := "captcha id" + d := RandomDigits(10) + s.Set(id, d) + d2 := s.Get(id, false) + if d2 == nil || !bytes.Equal(d, d2) { + t.Errorf("saved %v, getDigits returned got %v", d, d2) + } +} + +func TestGetClear(t *testing.T) { + s := NewMemoryStore(CollectNum, Expiration) + id := "captcha id" + d := RandomDigits(10) + s.Set(id, d) + d2 := s.Get(id, true) + if d2 == nil || !bytes.Equal(d, d2) { + t.Errorf("saved %v, getDigitsClear returned got %v", d, d2) + } + d2 = s.Get(id, false) + if d2 != nil { + t.Errorf("getDigitClear didn't clear (%q=%v)", id, d2) + } +} + +func TestCollect(t *testing.T) { + // TODO(dchest): can't test automatic collection when saving, because + // it's currently launched in a different goroutine. + s := NewMemoryStore(10, -1) + // create 10 ids + ids := make([]string, 10) + d := RandomDigits(10) + for i := range ids { + ids[i] = randomID() + s.Set(ids[i], d) + } + s.(*memoryStore).collect() + // Must be already collected + nc := 0 + for i := range ids { + d2 := s.Get(ids[i], false) + if d2 != nil { + t.Errorf("%d: not collected", i) + nc++ + } + } + if nc > 0 { + t.Errorf("= not collected %d out of %d captchas", nc, len(ids)) + } +} + +func BenchmarkSetCollect(b *testing.B) { + b.StopTimer() + d := RandomDigits(10) + s := NewMemoryStore(9999, -1) + ids := make([]string, 1000) + for i := range ids { + ids[i] = randomID() + } + b.StartTimer() + for i := 0; i < b.N; i++ { + for j := 0; j < 1000; j++ { + s.Set(ids[j], d) + } + s.(*memoryStore).collect() + } +}