Output QR Code to Make Login Easier

This commit is contained in:
Stephen Lee 2022-04-03 11:07:42 -04:00
parent 12302ba1bf
commit a82765244e
21 changed files with 2040 additions and 5 deletions

View File

@ -23,13 +23,22 @@ const (
callbackStoreURL = "https://login.cloudflareaccess.org/"
)
var (
outputQrcodeFlag = &cli.BoolFlag{
Name: "output-qr-code",
Usage: "Output a QR Code containing a link to tunnel login authorization workflow",
Aliases: []string{"qr"},
}
)
func buildLoginSubcommand(hidden bool) *cli.Command {
return &cli.Command{
Name: "login",
Action: cliutil.ConfiguredAction(login),
Usage: "Generate a configuration file with your login details",
ArgsUsage: " ",
UsageText: "cloudflared tunnel [tunnel command options] login [subcommand options]",
Hidden: hidden,
Flags: []cli.Flag{outputQrcodeFlag},
}
}
@ -57,6 +66,7 @@ func login(c *cli.Context) error {
callbackStoreURL,
false,
false,
c.Bool("output-qr-code"),
log,
)
if err != nil {

2
go.mod
View File

@ -19,6 +19,7 @@ require (
github.com/json-iterator/go v1.1.12
github.com/lucas-clemente/quic-go v0.24.0
github.com/mattn/go-colorable v0.1.8
github.com/mdp/qrterminal/v3 v3.0.0
github.com/miekg/dns v1.1.45
github.com/mitchellh/go-homedir v1.1.0
github.com/pkg/errors v0.9.1
@ -93,6 +94,7 @@ require (
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
rsc.io/qr v0.2.0 // indirect
)
replace github.com/urfave/cli/v2 => github.com/ipostelnik/cli/v2 v2.3.1-0.20210324024421-b6ea8234fe3d

9
go.sum
View File

@ -399,8 +399,10 @@ github.com/marten-seemann/qtls-go1-17 v0.1.0 h1:P9ggrs5xtwiqXv/FHNwntmuLMNq3KaSI
github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8=
github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1 h1:EnzzN9fPUkUck/1CuY1FlzBaIYMoiBsdwTNmNGkwUUM=
github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
@ -408,6 +410,10 @@ github.com/mattn/go-runewidth v0.0.8 h1:3tS41NlGYSmhhe/8fhGRzc+z3AYCw1Fe1WAyLuuj
github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mdp/qrterminal v1.0.1 h1:07+fzVDlPuBlXS8tB0ktTAyf+Lp1j2+2zK3fBOL5b7c=
github.com/mdp/qrterminal v1.0.1/go.mod h1:Z33WhxQe9B6CdW37HaVqcRKzP+kByF3q/qLxOGe12xQ=
github.com/mdp/qrterminal/v3 v3.0.0 h1:ywQqLRBXWTktytQNDKFjhAvoGkLVN3J2tAFZ0kMd9xQ=
github.com/mdp/qrterminal/v3 v3.0.0/go.mod h1:NJpfAs7OAm77Dy8EkWrtE4aq+cE6McoLXlBqXQEwvE0=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/miekg/dns v1.1.45 h1:g5fRIhm9nx7g8osrAvgb16QJfmyMsyOCb+J7LSv+Qzk=
@ -732,6 +738,7 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -1093,6 +1100,8 @@ k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lV
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY=
rsc.io/qr v0.2.0/go.mod h1:IF+uZjkb9fqyeF/4tlBoynqmQxUoPfWEKh921coOuXs=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=

View File

@ -218,7 +218,7 @@ func getTokensFromEdge(appURL *url.URL, appTokenPath, orgTokenPath string, useHo
// this weird parameter is the resource name (token) and the key/value
// we want to send to the transfer service. the key is token and the value
// is blank (basically just the id generated in the transfer service)
resourceData, err := RunTransfer(appURL, keyName, keyName, "", true, useHostOnly, log)
resourceData, err := RunTransfer(appURL, keyName, keyName, "", true, useHostOnly, false, log)
if err != nil {
return "", errors.Wrap(err, "failed to run transfer service")
}

View File

@ -10,6 +10,7 @@ import (
"os"
"time"
"github.com/mdp/qrterminal/v3"
"github.com/pkg/errors"
"github.com/rs/zerolog"
)
@ -25,7 +26,7 @@ const (
// The "dance" we refer to is building a HTTP request, opening that in a browser waiting for
// the user to complete an action, while it long polls in the background waiting for an
// action to be completed to download the resource.
func RunTransfer(transferURL *url.URL, resourceName, key, value string, shouldEncrypt bool, useHostOnly bool, log *zerolog.Logger) ([]byte, error) {
func RunTransfer(transferURL *url.URL, resourceName, key, value string, shouldEncrypt bool, useHostOnly bool, outputQrCode bool, log *zerolog.Logger) ([]byte, error) {
encrypterClient, err := NewEncrypter("cloudflared_priv.pem", "cloudflared_pub.pem")
if err != nil {
return nil, err
@ -37,10 +38,16 @@ func RunTransfer(transferURL *url.URL, resourceName, key, value string, shouldEn
// See AUTH-1423 for why we use stderr (the way git wraps ssh)
err = OpenBrowser(requestURL)
qrcode := ""
if outputQrCode {
buf := new(bytes.Buffer)
qrterminal.GenerateHalfBlock(requestURL, qrterminal.H, buf)
qrcode = fmt.Sprintf("%s\n", buf.String())
}
if err != nil {
fmt.Fprintf(os.Stderr, "Please open the following URL and log in with your Cloudflare account:\n\n%s\n\nLeave cloudflared running to download the %s automatically.\n", requestURL, resourceName)
fmt.Fprintf(os.Stderr, "Please open the following URL and log in with your Cloudflare account:\n\n%s%s\n\nLeave cloudflared running to download the %s automatically.\n", qrcode, requestURL, resourceName)
} else {
fmt.Fprintf(os.Stderr, "A browser window should have opened at the following URL:\n\n%s\n\nIf the browser failed to open, please visit the URL above directly in your browser.\n", requestURL)
fmt.Fprintf(os.Stderr, "A browser window should have opened at the following URL:\n\n%s%s\n\nIf the browser failed to open, please visit the URL above directly in your browser.\n", qrcode, requestURL)
}
var resourceData []byte

18
vendor/github.com/mdp/qrterminal/v3/.goreleaser generated vendored Normal file
View File

@ -0,0 +1,18 @@
#!/bin/bash
source $HOME/.config/goreleaser.env
if [ -x "$(command -v goreleaser)" ]; then
goreleaser @$
else
GO_SRC="/app"
docker run --rm \
-v $PWD:$GO_SRC \
-v /var/run/docker.sock:/var/run/docker.sock \
-w $GO_SRC \
-e GITHUB_TOKEN=$GITHUB_TOKEN \
-e DOCKER_USERNAME=$DOCKER_USERNAME \
-e DOCKER_PASSWORD=$DOCKER_PASSWORD \
goreleaser/goreleaser $@
fi

57
vendor/github.com/mdp/qrterminal/v3/.goreleaser.yml generated vendored Normal file
View File

@ -0,0 +1,57 @@
# This is an example goreleaser.yaml file with some sane defaults.
# Make sure to check the documentation at http://goreleaser.com
before:
hooks:
# you may remove this if you don't use vgo
- go mod download
# you may remove this if you don't need go generate
- go generate ./...
builds:
-
main: ./cmd/qrterminal/main.go
binary: qrterminal
env:
- CGO_ENABLED=0
goarch:
- amd64
- 386
- arm
goos:
- linux
- darwin
- windows
ignore:
- goos: darwin
goarch: 386
- goos: windows
goarch: arm
archives:
- replacements:
386: i386
amd64: x86_64
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ .Tag }}-next"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
brew:
name: qrterminal
github:
owner: mdp
name: homebrew-tap
commit_author:
name: mdp
email: m@mdp.im
homepage: https://github.com/mdp/qrterminal
description: 'Create and display QR codes on the command line'
dockers:
-
image_templates:
- "mpercival/qrterminal:latest"
- "mpercival/qrterminal:{{ .Tag }}"

4
vendor/github.com/mdp/qrterminal/v3/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,4 @@
language: go
go:
- tip

27
vendor/github.com/mdp/qrterminal/v3/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,27 @@
## 3.0.0
Adjust go.mod to include required version string
## 2.0.1
Add goreleaser and release to Homebrew and Github
## 2.0.0
Add a command line tool and QuietZone around QRCode
## 1.0.1
Add go.mod
## 1.0.0
Update to add a quiet zone border to the QR Code - #5 and fixed by [WindomZ](https://github.com/WindomZ) #8
- This can be configured with the `QuietZone int` option
- Defaults to 4 'pixels' wide to match the QR Code spec
- This alters the size of the barcode considerably and is therefore a breaking change, resulting in a bump to v1.0.0
## 0.2.1
Fix direction of the qr code #6 by (https://github.com/mattn)

3
vendor/github.com/mdp/qrterminal/v3/Dockerfile generated vendored Normal file
View File

@ -0,0 +1,3 @@
FROM scratch
COPY qrterminal /
ENTRYPOINT ["/qrterminal"]

19
vendor/github.com/mdp/qrterminal/v3/LICENSE generated vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright 2019 Mark Percival <m@mdp.im>
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.

13
vendor/github.com/mdp/qrterminal/v3/Makefile generated vendored Normal file
View File

@ -0,0 +1,13 @@
APP ?= "./cmd/qrterminal"
build:
@go build "$(APP)"
release:
./.goreleaser release --rm-dist
reltest:
./.goreleaser release --snapshot --rm-dist --skip-publish
test:
@go test -cover

103
vendor/github.com/mdp/qrterminal/v3/README.md generated vendored Normal file
View File

@ -0,0 +1,103 @@
# QRCode Terminal
[![Build Status](https://api.travis-ci.org/mdp/qrterminal.svg)](https://travis-ci.org/mdp/qrterminal)
A golang library for generating QR codes in the terminal.
Originally this was a port of the [NodeJS version](https://github.com/gtanner/qrcode-terminal). Recently it's been updated to allow for smaller code generation using ASCII 'half blocks'
## Example
Full size ASCII block QR Code:
<img src="https://user-images.githubusercontent.com/2868/37992336-0ba06b56-31d1-11e8-9d32-5c6bb008dc74.png" alt="alt text" width="225" height="225">
Smaller 'half blocks' in the terminal:
<img src="https://user-images.githubusercontent.com/2868/37992371-243d4238-31d1-11e8-92f8-e34a794b21af.png" alt="alt text" width="225" height="225">
## Install
For command line usage [see below](https://github.com/mdp/qrterminal#command-line), or grab the binary from the [releases page](https://github.com/mdp/qrterminal/releases)
As a library in an application
`go get github.com/mdp/qrterminal/v3`
## Usage
```go
import (
"github.com/mdp/qrterminal/v3"
"os"
)
func main() {
// Generate a 'dense' qrcode with the 'Low' level error correction and write it to Stdout
qrterminal.Generate("https://github.com/mdp/qrterminal", qrterminal.L, os.Stdout)
}
```
### More complicated
Large Inverted barcode with medium redundancy and a 1 pixel border
```go
import (
"github.com/mdp/qrterminal/v3"
"os"
)
func main() {
config := qrterminal.Config{
Level: qrterminal.M,
Writer: os.Stdout,
BlackChar: qrterminal.WHITE,
WhiteChar: qrterminal.BLACK,
QuietZone: 1,
}
qrterminal.GenerateWithConfig("https://github.com/mdp/qrterminal", config)
}
```
HalfBlock barcode with medium redundancy
```go
import (
"github.com/mdp/qrterminal/v3"
"os"
)
func main() {
config := qrterminal.Config{
HalfBlocks: true,
Level: qrterminal.M,
Writer: os.Stdout,
}
qrterminal.Generate("https://github.com/mdp/qrterminal", config)
}
```
## Command Line
#### Installation
OSX: `brew install mdp/tap/qrterminal`
Others: Download from the [releases page](https://github.com/mdp/qrterminal/releases)
Source: `go get -u github.com/mdp/qrterminal/v3/cmd/qrterminal`
#### Usage
Print out a basic QR code in your terminal:
`qrterminal https://github.com/mdp/qrterminal`
Using 'medium' error correction:
`qrterminal https://github.com/mdp/qrterminal -l M`
Or just use Docker: `docker run --rm mpercival/qrterminal:latest 'https://github.com/mdp/qrterminal'`
### Contributors/Credits:
- [Mark Percival](https://github.com/mdp)
- [Matthew Kennerly](https://github.com/mtkennerly)
- [Viric](https://github.com/viric)
- [WindomZ](https://github.com/WindomZ)
- [mattn](https://github.com/mattn)

153
vendor/github.com/mdp/qrterminal/v3/qrterminal.go generated vendored Normal file
View File

@ -0,0 +1,153 @@
package qrterminal
import (
"io"
"strings"
"rsc.io/qr"
)
const WHITE = "\033[47m \033[0m"
const BLACK = "\033[40m \033[0m"
// Use ascii blocks to form the QR Code
const BLACK_WHITE = "▄"
const BLACK_BLACK = " "
const WHITE_BLACK = "▀"
const WHITE_WHITE = "█"
// Level - the QR Code's redundancy level
const H = qr.H
const M = qr.M
const L = qr.L
// default is 4-pixel-wide white quiet zone
const QUIET_ZONE = 4
//Config for generating a barcode
type Config struct {
Level qr.Level
Writer io.Writer
HalfBlocks bool
BlackChar string
BlackWhiteChar string
WhiteChar string
WhiteBlackChar string
QuietZone int
}
func (c *Config) writeFullBlocks(w io.Writer, code *qr.Code) {
white := c.WhiteChar
black := c.BlackChar
// Frame the barcode in a 1 pixel border
w.Write([]byte(stringRepeat(stringRepeat(white,
code.Size+c.QuietZone*2)+"\n", c.QuietZone))) // top border
for i := 0; i <= code.Size; i++ {
w.Write([]byte(stringRepeat(white, c.QuietZone))) // left border
for j := 0; j <= code.Size; j++ {
if code.Black(j, i) {
w.Write([]byte(black))
} else {
w.Write([]byte(white))
}
}
w.Write([]byte(stringRepeat(white, c.QuietZone-1) + "\n")) // right border
}
w.Write([]byte(stringRepeat(stringRepeat(white,
code.Size+c.QuietZone*2)+"\n", c.QuietZone-1))) // bottom border
}
func (c *Config) writeHalfBlocks(w io.Writer, code *qr.Code) {
ww := c.WhiteChar
bb := c.BlackChar
wb := c.WhiteBlackChar
bw := c.BlackWhiteChar
// Frame the barcode in a 4 pixel border
// top border
if c.QuietZone%2 != 0 {
w.Write([]byte(stringRepeat(bw, code.Size+c.QuietZone*2) + "\n"))
w.Write([]byte(stringRepeat(stringRepeat(ww,
code.Size+c.QuietZone*2)+"\n", c.QuietZone/2)))
} else {
w.Write([]byte(stringRepeat(stringRepeat(ww,
code.Size+c.QuietZone*2)+"\n", c.QuietZone/2)))
}
for i := 0; i <= code.Size; i += 2 {
w.Write([]byte(stringRepeat(ww, c.QuietZone))) // left border
for j := 0; j <= code.Size; j++ {
next_black := false
if i+1 < code.Size {
next_black = code.Black(j, i+1)
}
curr_black := code.Black(j, i)
if curr_black && next_black {
w.Write([]byte(bb))
} else if curr_black && !next_black {
w.Write([]byte(bw))
} else if !curr_black && !next_black {
w.Write([]byte(ww))
} else {
w.Write([]byte(wb))
}
}
w.Write([]byte(stringRepeat(ww, c.QuietZone-1) + "\n")) // right border
}
// bottom border
if c.QuietZone%2 == 0 {
w.Write([]byte(stringRepeat(stringRepeat(ww,
code.Size+c.QuietZone*2)+"\n", c.QuietZone/2-1)))
w.Write([]byte(stringRepeat(wb, code.Size+c.QuietZone*2) + "\n"))
} else {
w.Write([]byte(stringRepeat(stringRepeat(ww,
code.Size+c.QuietZone*2)+"\n", c.QuietZone/2)))
}
}
func stringRepeat(s string, count int) string {
if count <= 0 {
return ""
}
return strings.Repeat(s, count)
}
// GenerateWithConfig expects a string to encode and a config
func GenerateWithConfig(text string, config Config) {
if config.QuietZone < 1 {
config.QuietZone = 1 // at least 1-pixel-wide white quiet zone
}
w := config.Writer
code, _ := qr.Encode(text, config.Level)
if config.HalfBlocks {
config.writeHalfBlocks(w, code)
} else {
config.writeFullBlocks(w, code)
}
}
// Generate a QR Code and write it out to io.Writer
func Generate(text string, l qr.Level, w io.Writer) {
config := Config{
Level: l,
Writer: w,
BlackChar: BLACK,
WhiteChar: WHITE,
QuietZone: QUIET_ZONE,
}
GenerateWithConfig(text, config)
}
// Generate a QR Code with half blocks and write it out to io.Writer
func GenerateHalfBlock(text string, l qr.Level, w io.Writer) {
config := Config{
Level: l,
Writer: w,
HalfBlocks: true,
BlackChar: BLACK_BLACK,
WhiteBlackChar: WHITE_BLACK,
WhiteChar: WHITE_WHITE,
BlackWhiteChar: BLACK_WHITE,
QuietZone: QUIET_ZONE,
}
GenerateWithConfig(text, config)
}

8
vendor/modules.txt vendored
View File

@ -232,6 +232,9 @@ github.com/mattn/go-runewidth
# github.com/matttproud/golang_protobuf_extensions v1.0.1
## explicit
github.com/matttproud/golang_protobuf_extensions/pbutil
# github.com/mdp/qrterminal/v3 v3.0.0
## explicit
github.com/mdp/qrterminal/v3
# github.com/miekg/dns v1.1.45
## explicit; go 1.14
github.com/miekg/dns
@ -548,6 +551,11 @@ gopkg.in/yaml.v2
# gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
## explicit
gopkg.in/yaml.v3
# rsc.io/qr v0.2.0
## explicit
rsc.io/qr
rsc.io/qr/coding
rsc.io/qr/gf256
# zombiezen.com/go/capnproto2 v2.18.0+incompatible
## explicit
zombiezen.com/go/capnproto2

27
vendor/rsc.io/qr/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

3
vendor/rsc.io/qr/README.md generated vendored Normal file
View File

@ -0,0 +1,3 @@
Basic QR encoder.
go get [-u] rsc.io/qr

815
vendor/rsc.io/qr/coding/qr.go generated vendored Normal file
View File

@ -0,0 +1,815 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package coding implements low-level QR coding details.
package coding // import "rsc.io/qr/coding"
import (
"fmt"
"strconv"
"strings"
"rsc.io/qr/gf256"
)
// Field is the field for QR error correction.
var Field = gf256.NewField(0x11d, 2)
// A Version represents a QR version.
// The version specifies the size of the QR code:
// a QR code with version v has 4v+17 pixels on a side.
// Versions number from 1 to 40: the larger the version,
// the more information the code can store.
type Version int
const MinVersion = 1
const MaxVersion = 40
func (v Version) String() string {
return strconv.Itoa(int(v))
}
func (v Version) sizeClass() int {
if v <= 9 {
return 0
}
if v <= 26 {
return 1
}
return 2
}
// DataBytes returns the number of data bytes that can be
// stored in a QR code with the given version and level.
func (v Version) DataBytes(l Level) int {
vt := &vtab[v]
lev := &vt.level[l]
return vt.bytes - lev.nblock*lev.check
}
// Encoding implements a QR data encoding scheme.
// The implementations--Numeric, Alphanumeric, and String--specify
// the character set and the mapping from UTF-8 to code bits.
// The more restrictive the mode, the fewer code bits are needed.
type Encoding interface {
Check() error
Bits(v Version) int
Encode(b *Bits, v Version)
}
type Bits struct {
b []byte
nbit int
}
func (b *Bits) Reset() {
b.b = b.b[:0]
b.nbit = 0
}
func (b *Bits) Bits() int {
return b.nbit
}
func (b *Bits) Bytes() []byte {
if b.nbit%8 != 0 {
panic("fractional byte")
}
return b.b
}
func (b *Bits) Append(p []byte) {
if b.nbit%8 != 0 {
panic("fractional byte")
}
b.b = append(b.b, p...)
b.nbit += 8 * len(p)
}
func (b *Bits) Write(v uint, nbit int) {
for nbit > 0 {
n := nbit
if n > 8 {
n = 8
}
if b.nbit%8 == 0 {
b.b = append(b.b, 0)
} else {
m := -b.nbit & 7
if n > m {
n = m
}
}
b.nbit += n
sh := uint(nbit - n)
b.b[len(b.b)-1] |= uint8(v >> sh << uint(-b.nbit&7))
v -= v >> sh << sh
nbit -= n
}
}
// Num is the encoding for numeric data.
// The only valid characters are the decimal digits 0 through 9.
type Num string
func (s Num) String() string {
return fmt.Sprintf("Num(%#q)", string(s))
}
func (s Num) Check() error {
for _, c := range s {
if c < '0' || '9' < c {
return fmt.Errorf("non-numeric string %#q", string(s))
}
}
return nil
}
var numLen = [3]int{10, 12, 14}
func (s Num) Bits(v Version) int {
return 4 + numLen[v.sizeClass()] + (10*len(s)+2)/3
}
func (s Num) Encode(b *Bits, v Version) {
b.Write(1, 4)
b.Write(uint(len(s)), numLen[v.sizeClass()])
var i int
for i = 0; i+3 <= len(s); i += 3 {
w := uint(s[i]-'0')*100 + uint(s[i+1]-'0')*10 + uint(s[i+2]-'0')
b.Write(w, 10)
}
switch len(s) - i {
case 1:
w := uint(s[i] - '0')
b.Write(w, 4)
case 2:
w := uint(s[i]-'0')*10 + uint(s[i+1]-'0')
b.Write(w, 7)
}
}
// Alpha is the encoding for alphanumeric data.
// The valid characters are 0-9A-Z$%*+-./: and space.
type Alpha string
const alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"
func (s Alpha) String() string {
return fmt.Sprintf("Alpha(%#q)", string(s))
}
func (s Alpha) Check() error {
for _, c := range s {
if strings.IndexRune(alphabet, c) < 0 {
return fmt.Errorf("non-alphanumeric string %#q", string(s))
}
}
return nil
}
var alphaLen = [3]int{9, 11, 13}
func (s Alpha) Bits(v Version) int {
return 4 + alphaLen[v.sizeClass()] + (11*len(s)+1)/2
}
func (s Alpha) Encode(b *Bits, v Version) {
b.Write(2, 4)
b.Write(uint(len(s)), alphaLen[v.sizeClass()])
var i int
for i = 0; i+2 <= len(s); i += 2 {
w := uint(strings.IndexRune(alphabet, rune(s[i])))*45 +
uint(strings.IndexRune(alphabet, rune(s[i+1])))
b.Write(w, 11)
}
if i < len(s) {
w := uint(strings.IndexRune(alphabet, rune(s[i])))
b.Write(w, 6)
}
}
// String is the encoding for 8-bit data. All bytes are valid.
type String string
func (s String) String() string {
return fmt.Sprintf("String(%#q)", string(s))
}
func (s String) Check() error {
return nil
}
var stringLen = [3]int{8, 16, 16}
func (s String) Bits(v Version) int {
return 4 + stringLen[v.sizeClass()] + 8*len(s)
}
func (s String) Encode(b *Bits, v Version) {
b.Write(4, 4)
b.Write(uint(len(s)), stringLen[v.sizeClass()])
for i := 0; i < len(s); i++ {
b.Write(uint(s[i]), 8)
}
}
// A Pixel describes a single pixel in a QR code.
type Pixel uint32
const (
Black Pixel = 1 << iota
Invert
)
func (p Pixel) Offset() uint {
return uint(p >> 6)
}
func OffsetPixel(o uint) Pixel {
return Pixel(o << 6)
}
func (r PixelRole) Pixel() Pixel {
return Pixel(r << 2)
}
func (p Pixel) Role() PixelRole {
return PixelRole(p>>2) & 15
}
func (p Pixel) String() string {
s := p.Role().String()
if p&Black != 0 {
s += "+black"
}
if p&Invert != 0 {
s += "+invert"
}
s += "+" + strconv.FormatUint(uint64(p.Offset()), 10)
return s
}
// A PixelRole describes the role of a QR pixel.
type PixelRole uint32
const (
_ PixelRole = iota
Position // position squares (large)
Alignment // alignment squares (small)
Timing // timing strip between position squares
Format // format metadata
PVersion // version pattern
Unused // unused pixel
Data // data bit
Check // error correction check bit
Extra
)
var roles = []string{
"",
"position",
"alignment",
"timing",
"format",
"pversion",
"unused",
"data",
"check",
"extra",
}
func (r PixelRole) String() string {
if Position <= r && r <= Check {
return roles[r]
}
return strconv.Itoa(int(r))
}
// A Level represents a QR error correction level.
// From least to most tolerant of errors, they are L, M, Q, H.
type Level int
const (
L Level = iota
M
Q
H
)
func (l Level) String() string {
if L <= l && l <= H {
return "LMQH"[l : l+1]
}
return strconv.Itoa(int(l))
}
// A Code is a square pixel grid.
type Code struct {
Bitmap []byte // 1 is black, 0 is white
Size int // number of pixels on a side
Stride int // number of bytes per row
}
func (c *Code) Black(x, y int) bool {
return 0 <= x && x < c.Size && 0 <= y && y < c.Size &&
c.Bitmap[y*c.Stride+x/8]&(1<<uint(7-x&7)) != 0
}
// A Mask describes a mask that is applied to the QR
// code to avoid QR artifacts being interpreted as
// alignment and timing patterns (such as the squares
// in the corners). Valid masks are integers from 0 to 7.
type Mask int
// http://www.swetake.com/qr/qr5_en.html
var mfunc = []func(int, int) bool{
func(i, j int) bool { return (i+j)%2 == 0 },
func(i, j int) bool { return i%2 == 0 },
func(i, j int) bool { return j%3 == 0 },
func(i, j int) bool { return (i+j)%3 == 0 },
func(i, j int) bool { return (i/2+j/3)%2 == 0 },
func(i, j int) bool { return i*j%2+i*j%3 == 0 },
func(i, j int) bool { return (i*j%2+i*j%3)%2 == 0 },
func(i, j int) bool { return (i*j%3+(i+j)%2)%2 == 0 },
}
func (m Mask) Invert(y, x int) bool {
if m < 0 {
return false
}
return mfunc[m](y, x)
}
// A Plan describes how to construct a QR code
// with a specific version, level, and mask.
type Plan struct {
Version Version
Level Level
Mask Mask
DataBytes int // number of data bytes
CheckBytes int // number of error correcting (checksum) bytes
Blocks int // number of data blocks
Pixel [][]Pixel // pixel map
}
// NewPlan returns a Plan for a QR code with the given
// version, level, and mask.
func NewPlan(version Version, level Level, mask Mask) (*Plan, error) {
p, err := vplan(version)
if err != nil {
return nil, err
}
if err := fplan(level, mask, p); err != nil {
return nil, err
}
if err := lplan(version, level, p); err != nil {
return nil, err
}
if err := mplan(mask, p); err != nil {
return nil, err
}
return p, nil
}
func (b *Bits) Pad(n int) {
if n < 0 {
panic("qr: invalid pad size")
}
if n <= 4 {
b.Write(0, n)
} else {
b.Write(0, 4)
n -= 4
n -= -b.Bits() & 7
b.Write(0, -b.Bits()&7)
pad := n / 8
for i := 0; i < pad; i += 2 {
b.Write(0xec, 8)
if i+1 >= pad {
break
}
b.Write(0x11, 8)
}
}
}
func (b *Bits) AddCheckBytes(v Version, l Level) {
nd := v.DataBytes(l)
if b.nbit < nd*8 {
b.Pad(nd*8 - b.nbit)
}
if b.nbit != nd*8 {
panic("qr: too much data")
}
dat := b.Bytes()
vt := &vtab[v]
lev := &vt.level[l]
db := nd / lev.nblock
extra := nd % lev.nblock
chk := make([]byte, lev.check)
rs := gf256.NewRSEncoder(Field, lev.check)
for i := 0; i < lev.nblock; i++ {
if i == lev.nblock-extra {
db++
}
rs.ECC(dat[:db], chk)
b.Append(chk)
dat = dat[db:]
}
if len(b.Bytes()) != vt.bytes {
panic("qr: internal error")
}
}
func (p *Plan) Encode(text ...Encoding) (*Code, error) {
var b Bits
for _, t := range text {
if err := t.Check(); err != nil {
return nil, err
}
t.Encode(&b, p.Version)
}
if b.Bits() > p.DataBytes*8 {
return nil, fmt.Errorf("cannot encode %d bits into %d-bit code", b.Bits(), p.DataBytes*8)
}
b.AddCheckBytes(p.Version, p.Level)
bytes := b.Bytes()
// Now we have the checksum bytes and the data bytes.
// Construct the actual code.
c := &Code{Size: len(p.Pixel), Stride: (len(p.Pixel) + 7) &^ 7}
c.Bitmap = make([]byte, c.Stride*c.Size)
crow := c.Bitmap
for _, row := range p.Pixel {
for x, pix := range row {
switch pix.Role() {
case Data, Check:
o := pix.Offset()
if bytes[o/8]&(1<<uint(7-o&7)) != 0 {
pix ^= Black
}
}
if pix&Black != 0 {
crow[x/8] |= 1 << uint(7-x&7)
}
}
crow = crow[c.Stride:]
}
return c, nil
}
// A version describes metadata associated with a version.
type version struct {
apos int
astride int
bytes int
pattern int
level [4]level
}
type level struct {
nblock int
check int
}
var vtab = []version{
{},
{100, 100, 26, 0x0, [4]level{{1, 7}, {1, 10}, {1, 13}, {1, 17}}}, // 1
{16, 100, 44, 0x0, [4]level{{1, 10}, {1, 16}, {1, 22}, {1, 28}}}, // 2
{20, 100, 70, 0x0, [4]level{{1, 15}, {1, 26}, {2, 18}, {2, 22}}}, // 3
{24, 100, 100, 0x0, [4]level{{1, 20}, {2, 18}, {2, 26}, {4, 16}}}, // 4
{28, 100, 134, 0x0, [4]level{{1, 26}, {2, 24}, {4, 18}, {4, 22}}}, // 5
{32, 100, 172, 0x0, [4]level{{2, 18}, {4, 16}, {4, 24}, {4, 28}}}, // 6
{20, 16, 196, 0x7c94, [4]level{{2, 20}, {4, 18}, {6, 18}, {5, 26}}}, // 7
{22, 18, 242, 0x85bc, [4]level{{2, 24}, {4, 22}, {6, 22}, {6, 26}}}, // 8
{24, 20, 292, 0x9a99, [4]level{{2, 30}, {5, 22}, {8, 20}, {8, 24}}}, // 9
{26, 22, 346, 0xa4d3, [4]level{{4, 18}, {5, 26}, {8, 24}, {8, 28}}}, // 10
{28, 24, 404, 0xbbf6, [4]level{{4, 20}, {5, 30}, {8, 28}, {11, 24}}}, // 11
{30, 26, 466, 0xc762, [4]level{{4, 24}, {8, 22}, {10, 26}, {11, 28}}}, // 12
{32, 28, 532, 0xd847, [4]level{{4, 26}, {9, 22}, {12, 24}, {16, 22}}}, // 13
{24, 20, 581, 0xe60d, [4]level{{4, 30}, {9, 24}, {16, 20}, {16, 24}}}, // 14
{24, 22, 655, 0xf928, [4]level{{6, 22}, {10, 24}, {12, 30}, {18, 24}}}, // 15
{24, 24, 733, 0x10b78, [4]level{{6, 24}, {10, 28}, {17, 24}, {16, 30}}}, // 16
{28, 24, 815, 0x1145d, [4]level{{6, 28}, {11, 28}, {16, 28}, {19, 28}}}, // 17
{28, 26, 901, 0x12a17, [4]level{{6, 30}, {13, 26}, {18, 28}, {21, 28}}}, // 18
{28, 28, 991, 0x13532, [4]level{{7, 28}, {14, 26}, {21, 26}, {25, 26}}}, // 19
{32, 28, 1085, 0x149a6, [4]level{{8, 28}, {16, 26}, {20, 30}, {25, 28}}}, // 20
{26, 22, 1156, 0x15683, [4]level{{8, 28}, {17, 26}, {23, 28}, {25, 30}}}, // 21
{24, 24, 1258, 0x168c9, [4]level{{9, 28}, {17, 28}, {23, 30}, {34, 24}}}, // 22
{28, 24, 1364, 0x177ec, [4]level{{9, 30}, {18, 28}, {25, 30}, {30, 30}}}, // 23
{26, 26, 1474, 0x18ec4, [4]level{{10, 30}, {20, 28}, {27, 30}, {32, 30}}}, // 24
{30, 26, 1588, 0x191e1, [4]level{{12, 26}, {21, 28}, {29, 30}, {35, 30}}}, // 25
{28, 28, 1706, 0x1afab, [4]level{{12, 28}, {23, 28}, {34, 28}, {37, 30}}}, // 26
{32, 28, 1828, 0x1b08e, [4]level{{12, 30}, {25, 28}, {34, 30}, {40, 30}}}, // 27
{24, 24, 1921, 0x1cc1a, [4]level{{13, 30}, {26, 28}, {35, 30}, {42, 30}}}, // 28
{28, 24, 2051, 0x1d33f, [4]level{{14, 30}, {28, 28}, {38, 30}, {45, 30}}}, // 29
{24, 26, 2185, 0x1ed75, [4]level{{15, 30}, {29, 28}, {40, 30}, {48, 30}}}, // 30
{28, 26, 2323, 0x1f250, [4]level{{16, 30}, {31, 28}, {43, 30}, {51, 30}}}, // 31
{32, 26, 2465, 0x209d5, [4]level{{17, 30}, {33, 28}, {45, 30}, {54, 30}}}, // 32
{28, 28, 2611, 0x216f0, [4]level{{18, 30}, {35, 28}, {48, 30}, {57, 30}}}, // 33
{32, 28, 2761, 0x228ba, [4]level{{19, 30}, {37, 28}, {51, 30}, {60, 30}}}, // 34
{28, 24, 2876, 0x2379f, [4]level{{19, 30}, {38, 28}, {53, 30}, {63, 30}}}, // 35
{22, 26, 3034, 0x24b0b, [4]level{{20, 30}, {40, 28}, {56, 30}, {66, 30}}}, // 36
{26, 26, 3196, 0x2542e, [4]level{{21, 30}, {43, 28}, {59, 30}, {70, 30}}}, // 37
{30, 26, 3362, 0x26a64, [4]level{{22, 30}, {45, 28}, {62, 30}, {74, 30}}}, // 38
{24, 28, 3532, 0x27541, [4]level{{24, 30}, {47, 28}, {65, 30}, {77, 30}}}, // 39
{28, 28, 3706, 0x28c69, [4]level{{25, 30}, {49, 28}, {68, 30}, {81, 30}}}, // 40
}
func grid(siz int) [][]Pixel {
m := make([][]Pixel, siz)
pix := make([]Pixel, siz*siz)
for i := range m {
m[i], pix = pix[:siz], pix[siz:]
}
return m
}
// vplan creates a Plan for the given version.
func vplan(v Version) (*Plan, error) {
p := &Plan{Version: v}
if v < 1 || v > 40 {
return nil, fmt.Errorf("invalid QR version %d", int(v))
}
siz := 17 + int(v)*4
m := grid(siz)
p.Pixel = m
// Timing markers (overwritten by boxes).
const ti = 6 // timing is in row/column 6 (counting from 0)
for i := range m {
p := Timing.Pixel()
if i&1 == 0 {
p |= Black
}
m[i][ti] = p
m[ti][i] = p
}
// Position boxes.
posBox(m, 0, 0)
posBox(m, siz-7, 0)
posBox(m, 0, siz-7)
// Alignment boxes.
info := &vtab[v]
for x := 4; x+5 < siz; {
for y := 4; y+5 < siz; {
// don't overwrite timing markers
if (x < 7 && y < 7) || (x < 7 && y+5 >= siz-7) || (x+5 >= siz-7 && y < 7) {
} else {
alignBox(m, x, y)
}
if y == 4 {
y = info.apos
} else {
y += info.astride
}
}
if x == 4 {
x = info.apos
} else {
x += info.astride
}
}
// Version pattern.
pat := vtab[v].pattern
if pat != 0 {
v := pat
for x := 0; x < 6; x++ {
for y := 0; y < 3; y++ {
p := PVersion.Pixel()
if v&1 != 0 {
p |= Black
}
m[siz-11+y][x] = p
m[x][siz-11+y] = p
v >>= 1
}
}
}
// One lonely black pixel
m[siz-8][8] = Unused.Pixel() | Black
return p, nil
}
// fplan adds the format pixels
func fplan(l Level, m Mask, p *Plan) error {
// Format pixels.
fb := uint32(l^1) << 13 // level: L=01, M=00, Q=11, H=10
fb |= uint32(m) << 10 // mask
const formatPoly = 0x537
rem := fb
for i := 14; i >= 10; i-- {
if rem&(1<<uint(i)) != 0 {
rem ^= formatPoly << uint(i-10)
}
}
fb |= rem
invert := uint32(0x5412)
siz := len(p.Pixel)
for i := uint(0); i < 15; i++ {
pix := Format.Pixel() + OffsetPixel(i)
if (fb>>i)&1 == 1 {
pix |= Black
}
if (invert>>i)&1 == 1 {
pix ^= Invert | Black
}
// top left
switch {
case i < 6:
p.Pixel[i][8] = pix
case i < 8:
p.Pixel[i+1][8] = pix
case i < 9:
p.Pixel[8][7] = pix
default:
p.Pixel[8][14-i] = pix
}
// bottom right
switch {
case i < 8:
p.Pixel[8][siz-1-int(i)] = pix
default:
p.Pixel[siz-1-int(14-i)][8] = pix
}
}
return nil
}
// lplan edits a version-only Plan to add information
// about the error correction levels.
func lplan(v Version, l Level, p *Plan) error {
p.Level = l
nblock := vtab[v].level[l].nblock
ne := vtab[v].level[l].check
nde := (vtab[v].bytes - ne*nblock) / nblock
extra := (vtab[v].bytes - ne*nblock) % nblock
dataBits := (nde*nblock + extra) * 8
checkBits := ne * nblock * 8
p.DataBytes = vtab[v].bytes - ne*nblock
p.CheckBytes = ne * nblock
p.Blocks = nblock
// Make data + checksum pixels.
data := make([]Pixel, dataBits)
for i := range data {
data[i] = Data.Pixel() | OffsetPixel(uint(i))
}
check := make([]Pixel, checkBits)
for i := range check {
check[i] = Check.Pixel() | OffsetPixel(uint(i+dataBits))
}
// Split into blocks.
dataList := make([][]Pixel, nblock)
checkList := make([][]Pixel, nblock)
for i := 0; i < nblock; i++ {
// The last few blocks have an extra data byte (8 pixels).
nd := nde
if i >= nblock-extra {
nd++
}
dataList[i], data = data[0:nd*8], data[nd*8:]
checkList[i], check = check[0:ne*8], check[ne*8:]
}
if len(data) != 0 || len(check) != 0 {
panic("data/check math")
}
// Build up bit sequence, taking first byte of each block,
// then second byte, and so on. Then checksums.
bits := make([]Pixel, dataBits+checkBits)
dst := bits
for i := 0; i < nde+1; i++ {
for _, b := range dataList {
if i*8 < len(b) {
copy(dst, b[i*8:(i+1)*8])
dst = dst[8:]
}
}
}
for i := 0; i < ne; i++ {
for _, b := range checkList {
if i*8 < len(b) {
copy(dst, b[i*8:(i+1)*8])
dst = dst[8:]
}
}
}
if len(dst) != 0 {
panic("dst math")
}
// Sweep up pair of columns,
// then down, assigning to right then left pixel.
// Repeat.
// See Figure 2 of http://www.pclviewer.com/rs2/qrtopology.htm
siz := len(p.Pixel)
rem := make([]Pixel, 7)
for i := range rem {
rem[i] = Extra.Pixel()
}
src := append(bits, rem...)
for x := siz; x > 0; {
for y := siz - 1; y >= 0; y-- {
if p.Pixel[y][x-1].Role() == 0 {
p.Pixel[y][x-1], src = src[0], src[1:]
}
if p.Pixel[y][x-2].Role() == 0 {
p.Pixel[y][x-2], src = src[0], src[1:]
}
}
x -= 2
if x == 7 { // vertical timing strip
x--
}
for y := 0; y < siz; y++ {
if p.Pixel[y][x-1].Role() == 0 {
p.Pixel[y][x-1], src = src[0], src[1:]
}
if p.Pixel[y][x-2].Role() == 0 {
p.Pixel[y][x-2], src = src[0], src[1:]
}
}
x -= 2
}
return nil
}
// mplan edits a version+level-only Plan to add the mask.
func mplan(m Mask, p *Plan) error {
p.Mask = m
for y, row := range p.Pixel {
for x, pix := range row {
if r := pix.Role(); (r == Data || r == Check || r == Extra) && p.Mask.Invert(y, x) {
row[x] ^= Black | Invert
}
}
}
return nil
}
// posBox draws a position (large) box at upper left x, y.
func posBox(m [][]Pixel, x, y int) {
pos := Position.Pixel()
// box
for dy := 0; dy < 7; dy++ {
for dx := 0; dx < 7; dx++ {
p := pos
if dx == 0 || dx == 6 || dy == 0 || dy == 6 || 2 <= dx && dx <= 4 && 2 <= dy && dy <= 4 {
p |= Black
}
m[y+dy][x+dx] = p
}
}
// white border
for dy := -1; dy < 8; dy++ {
if 0 <= y+dy && y+dy < len(m) {
if x > 0 {
m[y+dy][x-1] = pos
}
if x+7 < len(m) {
m[y+dy][x+7] = pos
}
}
}
for dx := -1; dx < 8; dx++ {
if 0 <= x+dx && x+dx < len(m) {
if y > 0 {
m[y-1][x+dx] = pos
}
if y+7 < len(m) {
m[y+7][x+dx] = pos
}
}
}
}
// alignBox draw an alignment (small) box at upper left x, y.
func alignBox(m [][]Pixel, x, y int) {
// box
align := Alignment.Pixel()
for dy := 0; dy < 5; dy++ {
for dx := 0; dx < 5; dx++ {
p := align
if dx == 0 || dx == 4 || dy == 0 || dy == 4 || dx == 2 && dy == 2 {
p |= Black
}
m[y+dy][x+dx] = p
}
}
}

241
vendor/rsc.io/qr/gf256/gf256.go generated vendored Normal file
View File

@ -0,0 +1,241 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package gf256 implements arithmetic over the Galois Field GF(256).
package gf256 // import "rsc.io/qr/gf256"
import "strconv"
// A Field represents an instance of GF(256) defined by a specific polynomial.
type Field struct {
log [256]byte // log[0] is unused
exp [510]byte
}
// NewField returns a new field corresponding to the polynomial poly
// and generator α. The Reed-Solomon encoding in QR codes uses
// polynomial 0x11d with generator 2.
//
// The choice of generator α only affects the Exp and Log operations.
func NewField(poly, α int) *Field {
if poly < 0x100 || poly >= 0x200 || reducible(poly) {
panic("gf256: invalid polynomial: " + strconv.Itoa(poly))
}
var f Field
x := 1
for i := 0; i < 255; i++ {
if x == 1 && i != 0 {
panic("gf256: invalid generator " + strconv.Itoa(α) +
" for polynomial " + strconv.Itoa(poly))
}
f.exp[i] = byte(x)
f.exp[i+255] = byte(x)
f.log[x] = byte(i)
x = mul(x, α, poly)
}
f.log[0] = 255
for i := 0; i < 255; i++ {
if f.log[f.exp[i]] != byte(i) {
panic("bad log")
}
if f.log[f.exp[i+255]] != byte(i) {
panic("bad log")
}
}
for i := 1; i < 256; i++ {
if f.exp[f.log[i]] != byte(i) {
panic("bad log")
}
}
return &f
}
// nbit returns the number of significant in p.
func nbit(p int) uint {
n := uint(0)
for ; p > 0; p >>= 1 {
n++
}
return n
}
// polyDiv divides the polynomial p by q and returns the remainder.
func polyDiv(p, q int) int {
np := nbit(p)
nq := nbit(q)
for ; np >= nq; np-- {
if p&(1<<(np-1)) != 0 {
p ^= q << (np - nq)
}
}
return p
}
// mul returns the product x*y mod poly, a GF(256) multiplication.
func mul(x, y, poly int) int {
z := 0
for x > 0 {
if x&1 != 0 {
z ^= y
}
x >>= 1
y <<= 1
if y&0x100 != 0 {
y ^= poly
}
}
return z
}
// reducible reports whether p is reducible.
func reducible(p int) bool {
// Multiplying n-bit * n-bit produces (2n-1)-bit,
// so if p is reducible, one of its factors must be
// of np/2+1 bits or fewer.
np := nbit(p)
for q := 2; q < 1<<(np/2+1); q++ {
if polyDiv(p, q) == 0 {
return true
}
}
return false
}
// Add returns the sum of x and y in the field.
func (f *Field) Add(x, y byte) byte {
return x ^ y
}
// Exp returns the base-α exponential of e in the field.
// If e < 0, Exp returns 0.
func (f *Field) Exp(e int) byte {
if e < 0 {
return 0
}
return f.exp[e%255]
}
// Log returns the base-α logarithm of x in the field.
// If x == 0, Log returns -1.
func (f *Field) Log(x byte) int {
if x == 0 {
return -1
}
return int(f.log[x])
}
// Inv returns the multiplicative inverse of x in the field.
// If x == 0, Inv returns 0.
func (f *Field) Inv(x byte) byte {
if x == 0 {
return 0
}
return f.exp[255-f.log[x]]
}
// Mul returns the product of x and y in the field.
func (f *Field) Mul(x, y byte) byte {
if x == 0 || y == 0 {
return 0
}
return f.exp[int(f.log[x])+int(f.log[y])]
}
// An RSEncoder implements Reed-Solomon encoding
// over a given field using a given number of error correction bytes.
type RSEncoder struct {
f *Field
c int
gen []byte
lgen []byte
p []byte
}
func (f *Field) gen(e int) (gen, lgen []byte) {
// p = 1
p := make([]byte, e+1)
p[e] = 1
for i := 0; i < e; i++ {
// p *= (x + Exp(i))
// p[j] = p[j]*Exp(i) + p[j+1].
c := f.Exp(i)
for j := 0; j < e; j++ {
p[j] = f.Mul(p[j], c) ^ p[j+1]
}
p[e] = f.Mul(p[e], c)
}
// lp = log p.
lp := make([]byte, e+1)
for i, c := range p {
if c == 0 {
lp[i] = 255
} else {
lp[i] = byte(f.Log(c))
}
}
return p, lp
}
// NewRSEncoder returns a new Reed-Solomon encoder
// over the given field and number of error correction bytes.
func NewRSEncoder(f *Field, c int) *RSEncoder {
gen, lgen := f.gen(c)
return &RSEncoder{f: f, c: c, gen: gen, lgen: lgen}
}
// ECC writes to check the error correcting code bytes
// for data using the given Reed-Solomon parameters.
func (rs *RSEncoder) ECC(data []byte, check []byte) {
if len(check) < rs.c {
panic("gf256: invalid check byte length")
}
if rs.c == 0 {
return
}
// The check bytes are the remainder after dividing
// data padded with c zeros by the generator polynomial.
// p = data padded with c zeros.
var p []byte
n := len(data) + rs.c
if len(rs.p) >= n {
p = rs.p
} else {
p = make([]byte, n)
}
copy(p, data)
for i := len(data); i < len(p); i++ {
p[i] = 0
}
// Divide p by gen, leaving the remainder in p[len(data):].
// p[0] is the most significant term in p, and
// gen[0] is the most significant term in the generator,
// which is always 1.
// To avoid repeated work, we store various values as
// lv, not v, where lv = log[v].
f := rs.f
lgen := rs.lgen[1:]
for i := 0; i < len(data); i++ {
c := p[i]
if c == 0 {
continue
}
q := p[i+1:]
exp := f.exp[f.log[c]:]
for j, lg := range lgen {
if lg != 255 { // lgen uses 255 for log 0
q[j] ^= exp[lg]
}
}
}
copy(check, p[len(data):])
rs.p = p
}

400
vendor/rsc.io/qr/png.go generated vendored Normal file
View File

@ -0,0 +1,400 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package qr
// PNG writer for QR codes.
import (
"bytes"
"encoding/binary"
"hash"
"hash/crc32"
)
// PNG returns a PNG image displaying the code.
//
// PNG uses a custom encoder tailored to QR codes.
// Its compressed size is about 2x away from optimal,
// but it runs about 20x faster than calling png.Encode
// on c.Image().
func (c *Code) PNG() []byte {
var p pngWriter
return p.encode(c)
}
type pngWriter struct {
tmp [16]byte
wctmp [4]byte
buf bytes.Buffer
zlib bitWriter
crc hash.Hash32
}
var pngHeader = []byte("\x89PNG\r\n\x1a\n")
func (w *pngWriter) encode(c *Code) []byte {
scale := c.Scale
siz := c.Size
w.buf.Reset()
// Header
w.buf.Write(pngHeader)
// Header block
binary.BigEndian.PutUint32(w.tmp[0:4], uint32((siz+8)*scale))
binary.BigEndian.PutUint32(w.tmp[4:8], uint32((siz+8)*scale))
w.tmp[8] = 1 // 1-bit
w.tmp[9] = 0 // gray
w.tmp[10] = 0
w.tmp[11] = 0
w.tmp[12] = 0
w.writeChunk("IHDR", w.tmp[:13])
// Comment
w.writeChunk("tEXt", comment)
// Data
w.zlib.writeCode(c)
w.writeChunk("IDAT", w.zlib.bytes.Bytes())
// End
w.writeChunk("IEND", nil)
return w.buf.Bytes()
}
var comment = []byte("Software\x00QR-PNG http://qr.swtch.com/")
func (w *pngWriter) writeChunk(name string, data []byte) {
if w.crc == nil {
w.crc = crc32.NewIEEE()
}
binary.BigEndian.PutUint32(w.wctmp[0:4], uint32(len(data)))
w.buf.Write(w.wctmp[0:4])
w.crc.Reset()
copy(w.wctmp[0:4], name)
w.buf.Write(w.wctmp[0:4])
w.crc.Write(w.wctmp[0:4])
w.buf.Write(data)
w.crc.Write(data)
crc := w.crc.Sum32()
binary.BigEndian.PutUint32(w.wctmp[0:4], crc)
w.buf.Write(w.wctmp[0:4])
}
func (b *bitWriter) writeCode(c *Code) {
const ftNone = 0
b.adler32.Reset()
b.bytes.Reset()
b.nbit = 0
scale := c.Scale
siz := c.Size
// zlib header
b.tmp[0] = 0x78
b.tmp[1] = 0
b.tmp[1] += uint8(31 - (uint16(b.tmp[0])<<8+uint16(b.tmp[1]))%31)
b.bytes.Write(b.tmp[0:2])
// Start flate block.
b.writeBits(1, 1, false) // final block
b.writeBits(1, 2, false) // compressed, fixed Huffman tables
// White border.
// First row.
b.byte(ftNone)
n := (scale*(siz+8) + 7) / 8
b.byte(255)
b.repeat(n-1, 1)
// 4*scale rows total.
b.repeat((4*scale-1)*(1+n), 1+n)
for i := 0; i < 4*scale; i++ {
b.adler32.WriteNByte(ftNone, 1)
b.adler32.WriteNByte(255, n)
}
row := make([]byte, 1+n)
for y := 0; y < siz; y++ {
row[0] = ftNone
j := 1
var z uint8
nz := 0
for x := -4; x < siz+4; x++ {
// Raw data.
for i := 0; i < scale; i++ {
z <<= 1
if !c.Black(x, y) {
z |= 1
}
if nz++; nz == 8 {
row[j] = z
j++
nz = 0
}
}
}
if j < len(row) {
row[j] = z
}
for _, z := range row {
b.byte(z)
}
// Scale-1 copies.
b.repeat((scale-1)*(1+n), 1+n)
b.adler32.WriteN(row, scale)
}
// White border.
// First row.
b.byte(ftNone)
b.byte(255)
b.repeat(n-1, 1)
// 4*scale rows total.
b.repeat((4*scale-1)*(1+n), 1+n)
for i := 0; i < 4*scale; i++ {
b.adler32.WriteNByte(ftNone, 1)
b.adler32.WriteNByte(255, n)
}
// End of block.
b.hcode(256)
b.flushBits()
// adler32
binary.BigEndian.PutUint32(b.tmp[0:], b.adler32.Sum32())
b.bytes.Write(b.tmp[0:4])
}
// A bitWriter is a write buffer for bit-oriented data like deflate.
type bitWriter struct {
bytes bytes.Buffer
bit uint32
nbit uint
tmp [4]byte
adler32 adigest
}
func (b *bitWriter) writeBits(bit uint32, nbit uint, rev bool) {
// reverse, for huffman codes
if rev {
br := uint32(0)
for i := uint(0); i < nbit; i++ {
br |= ((bit >> i) & 1) << (nbit - 1 - i)
}
bit = br
}
b.bit |= bit << b.nbit
b.nbit += nbit
for b.nbit >= 8 {
b.bytes.WriteByte(byte(b.bit))
b.bit >>= 8
b.nbit -= 8
}
}
func (b *bitWriter) flushBits() {
if b.nbit > 0 {
b.bytes.WriteByte(byte(b.bit))
b.nbit = 0
b.bit = 0
}
}
func (b *bitWriter) hcode(v int) {
/*
Lit Value Bits Codes
--------- ---- -----
0 - 143 8 00110000 through
10111111
144 - 255 9 110010000 through
111111111
256 - 279 7 0000000 through
0010111
280 - 287 8 11000000 through
11000111
*/
switch {
case v <= 143:
b.writeBits(uint32(v)+0x30, 8, true)
case v <= 255:
b.writeBits(uint32(v-144)+0x190, 9, true)
case v <= 279:
b.writeBits(uint32(v-256)+0, 7, true)
case v <= 287:
b.writeBits(uint32(v-280)+0xc0, 8, true)
default:
panic("invalid hcode")
}
}
func (b *bitWriter) byte(x byte) {
b.hcode(int(x))
}
func (b *bitWriter) codex(c int, val int, nx uint) {
b.hcode(c + val>>nx)
b.writeBits(uint32(val)&(1<<nx-1), nx, false)
}
func (b *bitWriter) repeat(n, d int) {
for ; n >= 258+3; n -= 258 {
b.repeat1(258, d)
}
if n > 258 {
// 258 < n < 258+3
b.repeat1(10, d)
b.repeat1(n-10, d)
return
}
if n < 3 {
panic("invalid flate repeat")
}
b.repeat1(n, d)
}
func (b *bitWriter) repeat1(n, d int) {
/*
Extra Extra Extra
Code Bits Length(s) Code Bits Lengths Code Bits Length(s)
---- ---- ------ ---- ---- ------- ---- ---- -------
257 0 3 267 1 15,16 277 4 67-82
258 0 4 268 1 17,18 278 4 83-98
259 0 5 269 2 19-22 279 4 99-114
260 0 6 270 2 23-26 280 4 115-130
261 0 7 271 2 27-30 281 5 131-162
262 0 8 272 2 31-34 282 5 163-194
263 0 9 273 3 35-42 283 5 195-226
264 0 10 274 3 43-50 284 5 227-257
265 1 11,12 275 3 51-58 285 0 258
266 1 13,14 276 3 59-66
*/
switch {
case n <= 10:
b.codex(257, n-3, 0)
case n <= 18:
b.codex(265, n-11, 1)
case n <= 34:
b.codex(269, n-19, 2)
case n <= 66:
b.codex(273, n-35, 3)
case n <= 130:
b.codex(277, n-67, 4)
case n <= 257:
b.codex(281, n-131, 5)
case n == 258:
b.hcode(285)
default:
panic("invalid repeat length")
}
/*
Extra Extra Extra
Code Bits Dist Code Bits Dist Code Bits Distance
---- ---- ---- ---- ---- ------ ---- ---- --------
0 0 1 10 4 33-48 20 9 1025-1536
1 0 2 11 4 49-64 21 9 1537-2048
2 0 3 12 5 65-96 22 10 2049-3072
3 0 4 13 5 97-128 23 10 3073-4096
4 1 5,6 14 6 129-192 24 11 4097-6144
5 1 7,8 15 6 193-256 25 11 6145-8192
6 2 9-12 16 7 257-384 26 12 8193-12288
7 2 13-16 17 7 385-512 27 12 12289-16384
8 3 17-24 18 8 513-768 28 13 16385-24576
9 3 25-32 19 8 769-1024 29 13 24577-32768
*/
if d <= 4 {
b.writeBits(uint32(d-1), 5, true)
} else if d <= 32768 {
nbit := uint(16)
for d <= 1<<(nbit-1) {
nbit--
}
v := uint32(d - 1)
v &^= 1 << (nbit - 1) // top bit is implicit
code := uint32(2*nbit - 2) // second bit is low bit of code
code |= v >> (nbit - 2)
v &^= 1 << (nbit - 2)
b.writeBits(code, 5, true)
// rest of bits follow
b.writeBits(uint32(v), nbit-2, false)
} else {
panic("invalid repeat distance")
}
}
func (b *bitWriter) run(v byte, n int) {
if n == 0 {
return
}
b.byte(v)
if n-1 < 3 {
for i := 0; i < n-1; i++ {
b.byte(v)
}
} else {
b.repeat(n-1, 1)
}
}
type adigest struct {
a, b uint32
}
func (d *adigest) Reset() { d.a, d.b = 1, 0 }
const amod = 65521
func aupdate(a, b uint32, pi byte, n int) (aa, bb uint32) {
// TODO(rsc): 6g doesn't do magic multiplies for b %= amod,
// only for b = b%amod.
// invariant: a, b < amod
if pi == 0 {
b += uint32(n%amod) * a
b = b % amod
return a, b
}
// n times:
// a += pi
// b += a
// is same as
// b += n*a + n*(n+1)/2*pi
// a += n*pi
m := uint32(n)
b += (m % amod) * a
b = b % amod
b += (m * (m + 1) / 2) % amod * uint32(pi)
b = b % amod
a += (m % amod) * uint32(pi)
a = a % amod
return a, b
}
func afinish(a, b uint32) uint32 {
return b<<16 | a
}
func (d *adigest) WriteN(p []byte, n int) {
for i := 0; i < n; i++ {
for _, pi := range p {
d.a, d.b = aupdate(d.a, d.b, pi, 1)
}
}
}
func (d *adigest) WriteNByte(pi byte, n int) {
d.a, d.b = aupdate(d.a, d.b, pi, n)
}
func (d *adigest) Sum32() uint32 { return afinish(d.a, d.b) }

116
vendor/rsc.io/qr/qr.go generated vendored Normal file
View File

@ -0,0 +1,116 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package qr encodes QR codes.
*/
package qr // import "rsc.io/qr"
import (
"errors"
"image"
"image/color"
"rsc.io/qr/coding"
)
// A Level denotes a QR error correction level.
// From least to most tolerant of errors, they are L, M, Q, H.
type Level int
const (
L Level = iota // 20% redundant
M // 38% redundant
Q // 55% redundant
H // 65% redundant
)
// Encode returns an encoding of text at the given error correction level.
func Encode(text string, level Level) (*Code, error) {
// Pick data encoding, smallest first.
// We could split the string and use different encodings
// but that seems like overkill for now.
var enc coding.Encoding
switch {
case coding.Num(text).Check() == nil:
enc = coding.Num(text)
case coding.Alpha(text).Check() == nil:
enc = coding.Alpha(text)
default:
enc = coding.String(text)
}
// Pick size.
l := coding.Level(level)
var v coding.Version
for v = coding.MinVersion; ; v++ {
if v > coding.MaxVersion {
return nil, errors.New("text too long to encode as QR")
}
if enc.Bits(v) <= v.DataBytes(l)*8 {
break
}
}
// Build and execute plan.
p, err := coding.NewPlan(v, l, 0)
if err != nil {
return nil, err
}
cc, err := p.Encode(enc)
if err != nil {
return nil, err
}
// TODO: Pick appropriate mask.
return &Code{cc.Bitmap, cc.Size, cc.Stride, 8}, nil
}
// A Code is a square pixel grid.
// It implements image.Image and direct PNG encoding.
type Code struct {
Bitmap []byte // 1 is black, 0 is white
Size int // number of pixels on a side
Stride int // number of bytes per row
Scale int // number of image pixels per QR pixel
}
// Black returns true if the pixel at (x,y) is black.
func (c *Code) Black(x, y int) bool {
return 0 <= x && x < c.Size && 0 <= y && y < c.Size &&
c.Bitmap[y*c.Stride+x/8]&(1<<uint(7-x&7)) != 0
}
// Image returns an Image displaying the code.
func (c *Code) Image() image.Image {
return &codeImage{c}
}
// codeImage implements image.Image
type codeImage struct {
*Code
}
var (
whiteColor color.Color = color.Gray{0xFF}
blackColor color.Color = color.Gray{0x00}
)
func (c *codeImage) Bounds() image.Rectangle {
d := (c.Size + 8) * c.Scale
return image.Rect(0, 0, d, d)
}
func (c *codeImage) At(x, y int) color.Color {
if c.Black(x, y) {
return blackColor
}
return whiteColor
}
func (c *codeImage) ColorModel() color.Model {
return color.GrayModel
}