go v1.20+, redis v7.x, docker compose v2.x
captcha code sequence generator, image render and verify code service with gRPC interfaces
based on lite (render, random) version of https://github.com/dchest/captcha
180x80px 4 digits png image
docker run --rm -it -p 1111:1111 -p 2222:2222 --env-file=.deploy/env/local.env -e CAPTCHA_REDIS_HOST=0.0.0.0 -e CAPTCHA_REDIS_PORT=6379 -e CAPTCHA_REDIS_DB=0 -e CAPTCHA_REDIS_PASS=YQ3dvPx3fVzv gtsh77workshop/grpc-captcha:v1.0.0
docker compose -f docker-compose.local.yml up
export $(grep -v '^#' ./deploy/env/local.env | xargs)
./bin/grpc-captcha_linux_amd64
grpcurl -H 'x-api-key: 1ace3bed-3aaf-4642-adb1-d63aef85895f' -plaintext -import-path pkg/proto/grpc-captcha -proto grpc-captcha.proto 0.0.0.0:2222 werkstatt.captcha.CaptchaService.Generate |jq
{
"id": "acf26399-0aa3-4fea-89ef-495476315998",
"data": "iVBORw0KGgoAAAANSUhEUgAAALQAAABQCAMAAACHxq+UAAAAP1BMVEUAAAA5QBDe5bWzuord5LSwt4fZ4LBzekq5wJDHzp7g57dzekp6gVEyOQlUWyuMk2NSWSmZoHDHzp6Ij1+xuIidZE4xAAAAAXRSTlMAQObYZgAAA29JREFUeJzsmt2yqyoMx5Npay9qp07f/2HPVBGSEL4R19ljerF3K4Qff0KIuuCyyy677LLLLrvsVMOzASoMERHwf4aOK/bfJ5+myf7f4h4Bbr293+9GV9MkqS3w+m8f21cQNuZWagWaKh2lfuThEikOgQbjOq60+fXxSFAzYB36+XxWUnvMbkwNxbZJMXNg64wz11HzgRIRARlRY1uyHaK26QKd3HsF+zMneXZSOk4U2J9oP17ThPVgTkpNlH6yTnSrZXnqafGxiNJWIwRtu41kjq/qekUojdJc26FKB7aPQWJXUPnAeKFZ7aExUx4hrvs2FBp47eFd0g4g5ZubyjIIO1DlIQGi85B5jk1sWZZxke2fIk56ssXkahBmE/3L0DjhSCTIvV95h31eoCXvUdAGlOhLlZablYS0euRk2dRGDUo20PRHQhrJ3ZnMUxs1OQJZjhBJjtAxfHvDUkjdxsyovmQe7CIQefdp2UNGS55Hm5Pr+/3an9TINfxKdh/MbAdFBK40okpt2opyb/jjCG8v2d3nItcGhGnKDs0TmH2lnJw8SvaL7tJ50DIDsLPSr+9MFy1ZVg3eAD3PM81hIn/4IaSf+lVjV/ecf8Y2HpA6lijOp4rYqnR+X3nbaqB5hgCub0jrltxR0lnZeEJpYPThEbAlSxdOmEchmpgGVen4GAOZ+Q0AWWT+nE/UFNp9pVuYGuii1MHuXOTuY0+xfUKFuUbu4iILQL4SkAOjWmWo5XUlN9ZlaOTjsVPObUa/i/jOFqto7Apmr4hTr/k9ZKnEe3Rhjnvx48J6DcY0qaA04XOwk+2SbnQPwewhg6qMJi/TpbJRwEUkT8d2XjK0Mw+jeBYNDrLJeLvd/Ed5YeYEtVmbrBAKNYy+llsX/vYzKS0J6ogMxOm7ghlsYKN/nx33sUL7FXVyk7AnxutbIwSXQ8vyIhXLHYkRH1Lp3NHIkYuIbzdUYW4mSttFTvv4Ca2+b8ka0hW1ez6oKlDc9ItnXWF6hVvrC0tuGNqtz1jYcD952b9q97MBKux+P5Y6+YcWVXY48yHUh9og6Lmrt2ro9djNtXnuTl3TbavKsq0vc60VQrdbj8UaDb09AGy18UJ33hcDTIM+5VVGkanMf57as0OgX70dCtugP119vl4DqOHz6Uzd1VvI2pj/CwAA//9L/w3JNJ6cGwAAAABJRU5ErkJggg=="
}
grpcurl -H 'x-api-key: 1ace3bed-3aaf-4642-adb1-d63aef85895f' -plaintext -import-path pkg/proto/grpc-captcha -proto grpc-captcha.proto -d '{"id":"acf26399-0aa3-4fea-89ef-495476315998", "otp": "5485"}' 0.0.0.0:2222 werkstatt.captcha.CaptchaService.Verify |jq
{}
paste data field value into https://onlinepngtools.com/convert-base64-to-png
docker run -it --rm --network host redis:7.2-alpine redis-cli -p 6379 -a YQ3dvPx3fVzv
For most cases we recommend simple use local proxy (eg nginx) with TLS enabled which upstreams non-tls captcha service or even simpler you can use k8s which already have its own TLS proxy/balancer
If in some cases there is no possibility to have a local proxy we prepared this full operable example for direct interaction with service's interfaces through TLS
-
load our test self-signed crt/keys data into env variables or use own (crt, key and ca crt) [using data instead of file path helps with k8s pod implementation, so you need to load them in advance]
export CAPTCHA_HTTP_TLS_CRT_DATA=`cat .deploy/crt/secure.nd.crt` CAPTCHA_GRPC_TLS_CRT_DATA=`cat .deploy/crt/secure.nd.crt` CAPTCHA_REDIS_TLS_CRT_DATA=`cat .deploy/crt/secure.nd.crt` CAPTCHA_HTTP_TLS_KEY_DATA=`cat .deploy/crt/secure.nd.key` CAPTCHA_GRPC_TLS_KEY_DATA=`cat .deploy/crt/secure.nd.key` CAPTCHA_REDIS_TLS_KEY_DATA=`cat .deploy/crt/secure.nd.key` CAPTCHA_HTTP_TLS_CRT_CA_DATA=`cat .deploy/crt/ca.crt` CAPTCHA_GRPC_TLS_CRT_CA_DATA=`cat .deploy/crt/ca.crt` CAPTCHA_REDIS_TLS_CRT_CA_DATA=`cat .deploy/crt/ca.crt` -
start via docker compose (tls variant)
docker compose -f docker-compose.tls.yml up -
add crt to trusted (only if self-signed) to be able to interact with grpc interface via tls
apt install ca-certificates cp .deploy/crt/secure.nd.crt /usr/local/share/ca-certificates/. update-ca-certificates -
set local domain which corresponds to your crt's CN (opt) [below example for test self-signed crt/key provided within repo]
vi /etc/hosts captcha.secure.nd 127.0.0.1
grpcurl -H 'x-api-key: 1ace3bed-3aaf-4642-adb1-d63aef85895f' -import-path pkg/proto/grpc-captcha -proto grpc-captcha.proto captcha.secure.nd:2222 werkstatt.captcha.CaptchaService.Generate |jq
{
"id": "acf26399-0aa3-4fea-89ef-495476315998",
"data": "iVBORw0KGgoAAAANSUhEUgAAALQAAABQCAMAAACHxq+UAAAAP1BMVEUAAAA5QBDe5bWzuord5LSwt4fZ4LBzekq5wJDHzp7g57dzekp6gVEyOQlUWyuMk2NSWSmZoHDHzp6Ij1+xuIidZE4xAAAAAXRSTlMAQObYZgAAA29JREFUeJzsmt2yqyoMx5Npay9qp07f/2HPVBGSEL4R19ljerF3K4Qff0KIuuCyyy677LLLLrvsVMOzASoMERHwf4aOK/bfJ5+myf7f4h4Bbr293+9GV9MkqS3w+m8f21cQNuZWagWaKh2lfuThEikOgQbjOq60+fXxSFAzYB36+XxWUnvMbkwNxbZJMXNg64wz11HzgRIRARlRY1uyHaK26QKd3HsF+zMneXZSOk4U2J9oP17ThPVgTkpNlH6yTnSrZXnqafGxiNJWIwRtu41kjq/qekUojdJc26FKB7aPQWJXUPnAeKFZ7aExUx4hrvs2FBp47eFd0g4g5ZubyjIIO1DlIQGi85B5jk1sWZZxke2fIk56ssXkahBmE/3L0DjhSCTIvV95h31eoCXvUdAGlOhLlZablYS0euRk2dRGDUo20PRHQhrJ3ZnMUxs1OQJZjhBJjtAxfHvDUkjdxsyovmQe7CIQefdp2UNGS55Hm5Pr+/3an9TINfxKdh/MbAdFBK40okpt2opyb/jjCG8v2d3nItcGhGnKDs0TmH2lnJw8SvaL7tJ50DIDsLPSr+9MFy1ZVg3eAD3PM81hIn/4IaSf+lVjV/ecf8Y2HpA6lijOp4rYqnR+X3nbaqB5hgCub0jrltxR0lnZeEJpYPThEbAlSxdOmEchmpgGVen4GAOZ+Q0AWWT+nE/UFNp9pVuYGuii1MHuXOTuY0+xfUKFuUbu4iILQL4SkAOjWmWo5XUlN9ZlaOTjsVPObUa/i/jOFqto7Apmr4hTr/k9ZKnEe3Rhjnvx48J6DcY0qaA04XOwk+2SbnQPwewhg6qMJi/TpbJRwEUkT8d2XjK0Mw+jeBYNDrLJeLvd/Ed5YeYEtVmbrBAKNYy+llsX/vYzKS0J6ogMxOm7ghlsYKN/nx33sUL7FXVyk7AnxutbIwSXQ8vyIhXLHYkRH1Lp3NHIkYuIbzdUYW4mSttFTvv4Ca2+b8ka0hW1ez6oKlDc9ItnXWF6hVvrC0tuGNqtz1jYcD952b9q97MBKux+P5Y6+YcWVXY48yHUh9og6Lmrt2ro9djNtXnuTl3TbavKsq0vc60VQrdbj8UaDb09AGy18UJ33hcDTIM+5VVGkanMf57as0OgX70dCtugP119vl4DqOHz6Uzd1VvI2pj/CwAA//9L/w3JNJ6cGwAAAABJRU5ErkJggg=="
}
grpcurl -H 'x-api-key: 1ace3bed-3aaf-4642-adb1-d63aef85895f' -import-path pkg/proto/grpc-captcha -proto grpc-captcha.proto -d '{"id":"acf26399-0aa3-4fea-89ef-495476315998", "code": "5485"}' captcha.secure.nd:2222 werkstatt.captcha.CaptchaService.Verify |jq
{}
use curl -k https://host... instead of curl host...
docker run -it --rm --network host -v $(pwd)/.deploy/crt/ca.crt:/ca.crt -v $(pwd)/.deploy/crt/secure.nd.crt:/server.crt -v $(pwd)/.deploy/crt/secure.nd.key:/server.key redis:7.2-alpine redis-cli -p 6379 -a YQ3dvPx3fVzv --tls --cacert /ca.crt --cert /server.crt --key /server.key
paste data field value into https://onlinepngtools.com/convert-base64-to-png
Generate new sequence code of [0-9] digits in quantity of CAPTCHA_RENDER_DIG_CNT, render png image CAPTCHA_RENDER_WIDTH x CAPTCHA_RENDER_HEIGHT px, store code sequence in redis db with TTL CAPTCHA_RENDER_TTL and return base64 encoding of image and uniqique captcha id to identify the sequence (uuidv4)
compare code sequences in payload and value stored in redis by provided key (id), if no such key ret NotFound, if values are not equal ret FailedPrecondition, if eq ret OK and remove key from redis
make && make run
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.55.1
make lint
make test
make env
curl 0.0.0.0:1111/health/check
curl 0.0.0.0:1111/health/operable
curl 0.0.0.0:1111/metrics
define B =
go build -ldflags "-s -w -X main.name=$(APP) -X main.version=$(RELEASE) -X main.compiledAt=$(BUILD_TIME)" -o
